       atom.workspace.open Path.join(selectedItem.projectPath, selectedItem.relPath)
 
   removeOnDispose: (o) ->
-    unless typeof o.dispose is 'function'
+    unless Disposable.isDisposable(o)
       if typeof o is 'function'
         o = new Disposable(o)
       else

  constructor: ({searchElementProp, itemsElementProp, resizedBodyHeightProp, selectedItemProp, resetStream, openStream}) ->
    @disposables = new CompositeDisposable

    sideEffects = [
      searchElementProp.onValue @createSearchPanel
      itemsElementProp.onValue @createItemsPanel
      resizedBodyHeightProp.debounce(500).onValue @saveResizedBodyHeight
      selectedItemProp.onValue @previewSelectedItem
      selectedItemProp.sampledBy(openStream).onValue @openSelectedItem

      @quickDoubleStream(resetStream).onValue R.pipe(
        @hideItemsPanel
        @hideSearchPanel
        -> atom.workspace.getActivePane()?.activate()
      )
      @quickDoubleStream(atoms.cancelCommand()).onValue R.pipe(
        @showItemsPanel
        @showSearchPanel
        @getSearchInput
        (input) -> input.select() and input.focus()
      )
    ]
    @removeOnDispose(sideEffect) for sideEffect in sideEffects

  # filter a given stream to only trigger if tow event are triggered within 300ms (e.g. double-ESC)
  quickDoubleStream: (stream) ->
    stream.bufferWithTimeOrCount(300, 2).filter R.propEq('length', 2)

  getSearchInput: ->
    @searchPanel.getItem()

  hideSearchPanel: ->
    @searchPanel.hide()

  showSearchPanel: ->
    @searchPanel.show()

  createSearchPanel: (el) =>
    unless @searchPanel
      @searchPanel = atom.workspace.addTopPanel(item: el)

  createItemsPanel: (el) =>
    unless @itemsPanel
      @itemsPanel = atom.workspace.addTopPanel(item: el)

