diff --git a/docs/React.md b/docs/React.md
index 4f5235e99..8d716770e 100644
--- a/docs/React.md
+++ b/docs/React.md
@@ -29,11 +29,11 @@ Here's a quick look at standard components you can require from `nylas-component
- **{RetinaImg}**: Replacement for standard `` tags which automatically resolves the best version of the image for the user's display and can apply many image transforms.
-- **{ListTabular}**: Component for creating a list of items backed by a paginating ModelView.
+- **{ListTabular}**: Component for creating a list of items backed by a paginating ListDataSource.
- **{MultiselectList}**: Component for creating a list that supports multi-selection. (Internally wraps ListTabular)
-- **{MultiselectActionBar}**: Component for creating a contextual toolbar that is activated when the user makes a selection on a ModelView.
+- **{MultiselectActionBar}**: Component for creating a contextual toolbar that is activated when the user makes a selection on a ListDataSource.
- **{ResizableRegion}**: Component that renders it's children inside a resizable region with a draggable handle.
diff --git a/internal_packages/thread-list/lib/draft-list-store.coffee b/internal_packages/thread-list/lib/draft-list-store.coffee
index 41959bc9f..798e3e1ae 100644
--- a/internal_packages/thread-list/lib/draft-list-store.coffee
+++ b/internal_packages/thread-list/lib/draft-list-store.coffee
@@ -6,7 +6,7 @@ _ = require 'underscore'
Actions,
AccountStore,
MutableQuerySubscription,
- QueryResultSetView,
+ ObservableListDataSource,
FocusedPerspectiveStore,
DatabaseStore} = require 'nylas-exports'
@@ -17,7 +17,7 @@ class DraftListStore extends NylasStore
@subscription = new MutableQuerySubscription(@_queryForCurrentAccount(), {asResultSet: true})
$resultSet = Rx.Observable.fromPrivateQuerySubscription('draft-list', @subscription)
- @_view = new QueryResultSetView $resultSet, ({start, end}) =>
+ @_view = new ObservableListDataSource $resultSet, ({start, end}) =>
@subscription.replaceQuery(@_queryForCurrentAccount().page(start, end))
view: =>
diff --git a/internal_packages/thread-list/lib/empty-state.cjsx b/internal_packages/thread-list/lib/empty-state.cjsx
index 3981737c8..b65cd3687 100644
--- a/internal_packages/thread-list/lib/empty-state.cjsx
+++ b/internal_packages/thread-list/lib/empty-state.cjsx
@@ -69,7 +69,7 @@ class EmptyState extends React.Component
@displayName = 'EmptyState'
@propTypes =
visible: React.PropTypes.bool.isRequired
- dataView: React.PropTypes.object
+ dataSource: React.PropTypes.object
constructor: (@props) ->
@state =
@@ -85,9 +85,9 @@ class EmptyState extends React.Component
@setState(active:true)
shouldComponentUpdate: (nextProps, nextState) ->
- # Avoid deep comparison of dataView, which is a very complex object
+ # Avoid deep comparison of dataSource, which is a very complex object
return true if nextProps.visible isnt @props.visible
- return true if nextProps.dataView isnt @props.dataView
+ return true if nextProps.dataSource isnt @props.dataSource
return not _.isEqual(nextState, @state)
componentWillUnmount: ->
diff --git a/internal_packages/thread-list/lib/thread-list-view-factory.coffee b/internal_packages/thread-list/lib/thread-list-view-factory.coffee
index 9a6fee973..8b4a8639f 100644
--- a/internal_packages/thread-list/lib/thread-list-view-factory.coffee
+++ b/internal_packages/thread-list/lib/thread-list-view-factory.coffee
@@ -5,7 +5,7 @@ Rx = require 'rx-lite'
DatabaseStore,
QuerySubscription,
QueryResultSet,
- QueryResultSetView,
+ ObservableListDataSource,
MutableQuerySubscription} = require 'nylas-exports'
PaginatingSearch = require './paginating-search'
@@ -85,7 +85,7 @@ module.exports = ThreadListViewFactory =
search = new PaginatingSearch(terms, accountId)
$resultSet = _flatMapJoiningMessages(search.observable())
- return new QueryResultSetView $resultSet, ({start, end}) =>
+ return new ObservableListDataSource $resultSet, ({start, end}) =>
search.setRange({start, end})
viewForQuery: (query) =>
@@ -93,5 +93,5 @@ module.exports = ThreadListViewFactory =
$resultSet = Rx.Observable.fromPrivateQuerySubscription('thread-list', subscription)
$resultSet = _flatMapJoiningMessages($resultSet)
- return new QueryResultSetView $resultSet, ({start, end}) =>
+ return new ObservableListDataSource $resultSet, ({start, end}) =>
subscription.replaceQuery(query.clone().page(start, end))
diff --git a/spec/components/multiselect-list-interaction-handler-spec.coffee b/spec/components/multiselect-list-interaction-handler-spec.coffee
index 189f159f3..70b855420 100644
--- a/spec/components/multiselect-list-interaction-handler-spec.coffee
+++ b/spec/components/multiselect-list-interaction-handler-spec.coffee
@@ -15,7 +15,7 @@ describe "MultiselectListInteractionHandler", ->
data = [@item, @itemFocus, @itemAfterFocus, @itemKeyboardFocus, @itemAfterKeyboardFocus]
- @dataView =
+ @dataSource =
selection:
toggle: jasmine.createSpy('toggle')
expandTo: jasmine.createSpy('expandTo')
@@ -29,7 +29,7 @@ describe "MultiselectListInteractionHandler", ->
count: -> data.length
@collection = 'threads'
- @handler = new MultiselectListInteractionHandler(@dataView, @collection)
+ @handler = new MultiselectListInteractionHandler(@dataSource, @collection)
@isRootSheet = true
spyOn(WorkspaceStore, 'topSheet').andCallFake => {root: @isRootSheet}
@@ -52,7 +52,7 @@ describe "MultiselectListInteractionHandler", ->
describe "onMetaClick", ->
it "shoud toggle selection", ->
@handler.onMetaClick(@item)
- expect(@dataView.selection.toggle).toHaveBeenCalledWith(@item)
+ expect(@dataSource.selection.toggle).toHaveBeenCalledWith(@item)
it "should focus the keyboard on the clicked item", ->
@handler.onMetaClick(@item)
@@ -61,7 +61,7 @@ describe "MultiselectListInteractionHandler", ->
describe "onShiftClick", ->
it "should expand selection", ->
@handler.onShiftClick(@item)
- expect(@dataView.selection.expandTo).toHaveBeenCalledWith(@item)
+ expect(@dataSource.selection.expandTo).toHaveBeenCalledWith(@item)
it "should focus the keyboard on the clicked item", ->
@handler.onShiftClick(@item)
@@ -77,13 +77,13 @@ describe "MultiselectListInteractionHandler", ->
it "should toggle the selection of the keyboard item", ->
@isRootSheet = true
@handler.onSelect()
- expect(@dataView.selection.toggle).toHaveBeenCalledWith(@itemKeyboardFocus)
+ expect(@dataSource.selection.toggle).toHaveBeenCalledWith(@itemKeyboardFocus)
describe "on the thread view", ->
it "should toggle the selection of the focused item", ->
@isRootSheet = false
@handler.onSelect()
- expect(@dataView.selection.toggle).toHaveBeenCalledWith(@itemFocus)
+ expect(@dataSource.selection.toggle).toHaveBeenCalledWith(@itemFocus)
describe "onShift", ->
describe "on the root view", ->
@@ -96,7 +96,7 @@ describe "MultiselectListInteractionHandler", ->
it "should walk selection if the select option is passed", ->
@handler.onShift(1, select: true)
- expect(@dataView.selection.walk).toHaveBeenCalledWith({current: @itemKeyboardFocus, next: @itemAfterKeyboardFocus})
+ expect(@dataSource.selection.walk).toHaveBeenCalledWith({current: @itemKeyboardFocus, next: @itemAfterKeyboardFocus})
describe "on the thread view", ->
beforeEach ->
diff --git a/spec/components/multiselect-split-interaction-handler-spec.coffee b/spec/components/multiselect-split-interaction-handler-spec.coffee
index b268aae72..cef262c6a 100644
--- a/spec/components/multiselect-split-interaction-handler-spec.coffee
+++ b/spec/components/multiselect-split-interaction-handler-spec.coffee
@@ -15,7 +15,7 @@ describe "MultiselectSplitInteractionHandler", ->
data = [@item, @itemFocus, @itemAfterFocus, @itemKeyboardFocus, @itemAfterKeyboardFocus]
@selection = []
- @dataView =
+ @dataSource =
selection:
toggle: jasmine.createSpy('toggle')
expandTo: jasmine.createSpy('expandTo')
@@ -35,7 +35,7 @@ describe "MultiselectSplitInteractionHandler", ->
count: -> data.length
@collection = 'threads'
- @handler = new MultiselectSplitInteractionHandler(@dataView, @collection)
+ @handler = new MultiselectSplitInteractionHandler(@dataSource, @collection)
@isRootSheet = true
spyOn(WorkspaceStore, 'topSheet').andCallFake => {root: @isRootSheet}
@@ -70,7 +70,7 @@ describe "MultiselectSplitInteractionHandler", ->
it "should turn the focused item into the first selected item", ->
@handler.onMetaClick(@item)
- expect(@dataView.selection.add).toHaveBeenCalledWith(@itemFocus)
+ expect(@dataSource.selection.add).toHaveBeenCalledWith(@itemFocus)
it "should clear the focus", ->
@handler.onMetaClick(@item)
@@ -78,7 +78,7 @@ describe "MultiselectSplitInteractionHandler", ->
it "should toggle selection", ->
@handler.onMetaClick(@item)
- expect(@dataView.selection.toggle).toHaveBeenCalledWith(@item)
+ expect(@dataSource.selection.toggle).toHaveBeenCalledWith(@item)
it "should call _checkSelectionAndFocusConsistency", ->
spyOn(@handler, '_checkSelectionAndFocusConsistency')
@@ -93,7 +93,7 @@ describe "MultiselectSplitInteractionHandler", ->
it "should turn the focused item into the first selected item", ->
@handler.onMetaClick(@item)
- expect(@dataView.selection.add).toHaveBeenCalledWith(@itemFocus)
+ expect(@dataSource.selection.add).toHaveBeenCalledWith(@itemFocus)
it "should clear the focus", ->
@handler.onMetaClick(@item)
@@ -101,7 +101,7 @@ describe "MultiselectSplitInteractionHandler", ->
it "should expand selection", ->
@handler.onShiftClick(@item)
- expect(@dataView.selection.expandTo).toHaveBeenCalledWith(@item)
+ expect(@dataSource.selection.expandTo).toHaveBeenCalledWith(@item)
it "should call _checkSelectionAndFocusConsistency", ->
spyOn(@handler, '_checkSelectionAndFocusConsistency')
@@ -127,13 +127,13 @@ describe "MultiselectSplitInteractionHandler", ->
spyOn(FocusedContentStore, 'focused').andCallFake => @itemFocus
spyOn(FocusedContentStore, 'focusedId').andCallFake -> 'focus'
@handler.onShift(1, {select: true})
- expect(@dataView.selection.add).toHaveBeenCalledWith(@itemFocus)
+ expect(@dataSource.selection.add).toHaveBeenCalledWith(@itemFocus)
it "should walk the selection to the shift target", ->
spyOn(FocusedContentStore, 'focused').andCallFake => @itemFocus
spyOn(FocusedContentStore, 'focusedId').andCallFake -> 'focus'
@handler.onShift(1, {select: true})
- expect(@dataView.selection.walk).toHaveBeenCalledWith({current: @itemFocus, next: @itemAfterFocus})
+ expect(@dataSource.selection.walk).toHaveBeenCalledWith({current: @itemFocus, next: @itemAfterFocus})
describe "when one or more items is selected", ->
it "should move the keyboard cursor", ->
@@ -160,5 +160,5 @@ describe "MultiselectSplitInteractionHandler", ->
it "should clear the selection and make the item focused", ->
@handler._checkSelectionAndFocusConsistency()
- expect(@dataView.selection.clear).toHaveBeenCalled()
+ expect(@dataSource.selection.clear).toHaveBeenCalled()
expect(Actions.setFocus).toHaveBeenCalledWith({collection: @collection, item: @item})
diff --git a/spec/model-view-selection-spec.coffee b/spec/model-view-selection-spec.coffee
index 579e9e17c..1c1b8ca51 100644
--- a/spec/model-view-selection-spec.coffee
+++ b/spec/model-view-selection-spec.coffee
@@ -1,30 +1,30 @@
_ = require 'underscore'
Thread = require '../src/flux/models/thread'
-ModelView = require '../src/flux/stores/model-view'
-ModelViewSelection = require '../src/flux/stores/model-view-selection'
+ListDataSource = require '../src/flux/stores/list-data-source'
+ListSelection = require '../src/flux/stores/list-selection'
-describe "ModelViewSelection", ->
+describe "ListSelection", ->
beforeEach ->
@trigger = jasmine.createSpy('trigger')
@items = []
@items.push(new Thread(id: "#{ii}")) for ii in [0..99]
- @view = new ModelView()
+ @view = new ListDataSource()
@view.indexOfId = jasmine.createSpy('indexOfId').andCallFake (id) =>
_.findIndex(@items, _.matcher({id}))
@view.get = jasmine.createSpy('get').andCallFake (idx) =>
@items[idx]
- @selection = new ModelViewSelection(@view, @trigger)
+ @selection = new ListSelection(@view, @trigger)
it "should initialize with an empty set", ->
expect(@selection.items()).toEqual([])
expect(@selection.ids()).toEqual([])
it "should throw an exception if a view is not provided", ->
- expect( => new ModelViewSelection(null, @trigger)).toThrow()
+ expect( => new ListSelection(null, @trigger)).toThrow()
describe "set", ->
it "should replace the current selection with the provided models", ->
diff --git a/spec/models/mutable-query-result-set-spec.coffee b/spec/models/mutable-query-result-set-spec.coffee
index 254ca1786..8007e19d7 100644
--- a/spec/models/mutable-query-result-set-spec.coffee
+++ b/spec/models/mutable-query-result-set-spec.coffee
@@ -70,7 +70,7 @@ describe "MutableQueryResultSet", ->
'C': {id: 'C', clientId: 'C-local'},
})
- fdescribe "addIdsInRange", ->
+ describe "addIdsInRange", ->
describe "when the set is currently empty", ->
it "should set the result set to the provided one", ->
@set = new MutableQueryResultSet()
diff --git a/src/components/list-tabular.cjsx b/src/components/list-tabular.cjsx
index 99b0c1ef4..76c23423e 100644
--- a/src/components/list-tabular.cjsx
+++ b/src/components/list-tabular.cjsx
@@ -68,7 +68,7 @@ class ListTabular extends React.Component
@displayName = 'ListTabular'
@propTypes =
columns: React.PropTypes.arrayOf(React.PropTypes.object).isRequired
- dataView: React.PropTypes.object
+ dataSource: React.PropTypes.object
itemPropsProvider: React.PropTypes.func
itemHeight: React.PropTypes.number
onSelect: React.PropTypes.func
@@ -93,7 +93,7 @@ class ListTabular extends React.Component
componentDidUpdate: (prevProps, prevState) =>
# If our view has been swapped out for an entirely different one,
# reset our scroll position to the top.
- if prevProps.dataView isnt @props.dataView
+ if prevProps.dataSource isnt @props.dataSource
@refs.container.scrollTop = 0
unless @updateRangeStateFiring
@@ -120,7 +120,7 @@ class ListTabular extends React.Component
# Expand the start/end so that you can advance the keyboard cursor fast and
# we have items to move to and then scroll to.
rangeStart = Math.max(0, rangeStart - 2)
- rangeEnd = Math.min(rangeEnd + 2, @props.dataView.count() + 1)
+ rangeEnd = Math.min(rangeEnd + 2, @props.dataSource.count() + 1)
# Final sanity check to prevent needless work
return if rangeStart is @state.renderedRangeStart and
@@ -128,7 +128,7 @@ class ListTabular extends React.Component
@updateRangeStateFiring = true
- @props.dataView.setRetainedRange
+ @props.dataSource.setRetainedRange
start: rangeStart
end: rangeEnd
@@ -138,7 +138,7 @@ class ListTabular extends React.Component
render: =>
innerStyles =
- height: @props.dataView.count() * @props.itemHeight
+ height: @props.dataSource.count() * @props.itemHeight
`thread:BulkAtion`)
diff --git a/src/components/multiselect-list-interaction-handler.coffee b/src/components/multiselect-list-interaction-handler.coffee
index 4d6d47282..02c772674 100644
--- a/src/components/multiselect-list-interaction-handler.coffee
+++ b/src/components/multiselect-list-interaction-handler.coffee
@@ -5,7 +5,7 @@ _ = require 'underscore'
module.exports =
class MultiselectListInteractionHandler
- constructor: (@dataView, @collection) ->
+ constructor: (@dataSource, @collection) ->
cssClass: ->
'handler-list'
@@ -20,35 +20,35 @@ class MultiselectListInteractionHandler
Actions.setFocus({collection: @collection, item: item})
onMetaClick: (item) ->
- @dataView.selection.toggle(item)
+ @dataSource.selection.toggle(item)
Actions.setCursorPosition({collection: @collection, item: item})
onShiftClick: (item) ->
- @dataView.selection.expandTo(item)
+ @dataSource.selection.expandTo(item)
Actions.setCursorPosition({collection: @collection, item: item})
onEnter: ->
keyboardCursorId = FocusedContentStore.keyboardCursorId(@collection)
if keyboardCursorId
- item = @dataView.getById(keyboardCursorId)
+ item = @dataSource.getById(keyboardCursorId)
Actions.setFocus({collection: @collection, item: item})
onSelect: ->
{id} = @_keyboardContext()
return unless id
- @dataView.selection.toggle(@dataView.getById(id))
+ @dataSource.selection.toggle(@dataSource.getById(id))
onShift: (delta, options = {}) ->
{id, action} = @_keyboardContext()
- current = @dataView.getById(id)
- index = @dataView.indexOfId(id)
- index = Math.max(0, Math.min(index + delta, @dataView.count() - 1))
- next = @dataView.get(index)
+ current = @dataSource.getById(id)
+ index = @dataSource.indexOfId(id)
+ index = Math.max(0, Math.min(index + delta, @dataSource.count() - 1))
+ next = @dataSource.get(index)
action({collection: @collection, item: next})
if options.select
- @dataView.selection.walk({current, next})
+ @dataSource.selection.walk({current, next})
_keyboardContext: ->
if WorkspaceStore.topSheet().root
diff --git a/src/components/multiselect-list.cjsx b/src/components/multiselect-list.cjsx
index e7c1ffb24..f87372173 100644
--- a/src/components/multiselect-list.cjsx
+++ b/src/components/multiselect-list.cjsx
@@ -16,7 +16,7 @@ MultiselectSplitInteractionHandler = require './multiselect-split-interaction-ha
###
Public: MultiselectList wraps {ListTabular} and makes it easy to present a
-{ModelView} with selection support. It adds a checkbox column to the columns
+{ListDataSource} with selection support. It adds a checkbox column to the columns
you provide, and also handles:
- Command-clicking individual items
@@ -98,7 +98,7 @@ class MultiselectList extends React.Component
otherProps = _.omit(@props, _.keys(@constructor.propTypes))
className = @props.className
- if @state.dataView and @state.handler
+ if @state.dataSource and @state.handler
className += " " + @state.handler.cssClass()
@itemPropsProvider ?= (item) =>
@@ -114,7 +114,7 @@ class MultiselectList extends React.Component
if @props.emptyComponent
emptyElement = <@props.emptyComponent
visible={@state.loaded and @state.empty}
- dataView={@state.dataView} />
+ dataSource={@state.dataSource} />
spinnerElement =
@@ -124,7 +124,7 @@ class MultiselectList extends React.Component
ref="list"
columns={@state.computedColumns}
scrollTooltipComponent={@props.scrollTooltipComponent}
- dataView={@state.dataView}
+ dataSource={@state.dataSource}
itemPropsProvider={@itemPropsProvider}
itemHeight={@props.itemHeight}
onSelect={@_onClickItem}
@@ -157,12 +157,12 @@ class MultiselectList extends React.Component
_onSelectAll: =>
return unless @state.handler
- items = @state.dataView.itemsCurrentlyInViewMatching -> true
- @state.dataView.selection.set(items)
+ items = @state.dataSource.itemsCurrentlyInViewMatching -> true
+ @state.dataSource.selection.set(items)
_onDeselect: =>
- return unless @_visible() and @state.dataView
- @state.dataView.selection.clear()
+ return unless @_visible() and @state.dataSource
+ @state.dataSource.selection.clear()
_onShift: (delta, options = {}) =>
return unless @state.handler
@@ -216,7 +216,7 @@ class MultiselectList extends React.Component
else
handler = new MultiselectSplitInteractionHandler(view, props.collection)
- dataView: view
+ dataSource: view
handler: handler
columns: props.columns
computedColumns: computedColumns
diff --git a/src/components/multiselect-split-interaction-handler.coffee b/src/components/multiselect-split-interaction-handler.coffee
index 0b48046f3..a45f50b1c 100644
--- a/src/components/multiselect-split-interaction-handler.coffee
+++ b/src/components/multiselect-split-interaction-handler.coffee
@@ -5,7 +5,7 @@ _ = require 'underscore'
module.exports =
class MultiselectSplitInteractionHandler
- constructor: (@dataView, @collection) ->
+ constructor: (@dataSource, @collection) ->
cssClass: ->
'handler-split'
@@ -14,21 +14,21 @@ class MultiselectSplitInteractionHandler
true
shouldShowKeyboardCursor: ->
- @dataView.selection.count() > 1
+ @dataSource.selection.count() > 1
onClick: (item) ->
Actions.setFocus({collection: @collection, item: item, usingClick: true})
- @dataView.selection.clear()
+ @dataSource.selection.clear()
@_checkSelectionAndFocusConsistency()
onMetaClick: (item) ->
@_turnFocusIntoSelection()
- @dataView.selection.toggle(item)
+ @dataSource.selection.toggle(item)
@_checkSelectionAndFocusConsistency()
onShiftClick: (item) ->
@_turnFocusIntoSelection()
- @dataView.selection.expandTo(item)
+ @dataSource.selection.expandTo(item)
@_checkSelectionAndFocusConsistency()
onEnter: ->
@@ -40,39 +40,39 @@ class MultiselectSplitInteractionHandler
if options.select
@_turnFocusIntoSelection()
- if @dataView.selection.count() > 0
- selection = @dataView.selection
+ if @dataSource.selection.count() > 0
+ selection = @dataSource.selection
keyboardId = FocusedContentStore.keyboardCursorId(@collection)
- id = keyboardId ? @dataView.selection.top().id
+ id = keyboardId ? @dataSource.selection.top().id
action = Actions.setCursorPosition
else
id = FocusedContentStore.focusedId(@collection)
action = Actions.setFocus
- current = @dataView.getById(id)
- index = @dataView.indexOfId(id)
- index = Math.max(0, Math.min(index + delta, @dataView.count() - 1))
- next = @dataView.get(index)
+ current = @dataSource.getById(id)
+ index = @dataSource.indexOfId(id)
+ index = Math.max(0, Math.min(index + delta, @dataSource.count() - 1))
+ next = @dataSource.get(index)
action({collection: @collection, item: next})
if options.select
- @dataView.selection.walk({current, next})
+ @dataSource.selection.walk({current, next})
@_checkSelectionAndFocusConsistency()
_turnFocusIntoSelection: ->
focused = FocusedContentStore.focused(@collection)
Actions.setFocus({collection: @collection, item: null})
- @dataView.selection.add(focused)
+ @dataSource.selection.add(focused)
_checkSelectionAndFocusConsistency: ->
focused = FocusedContentStore.focused(@collection)
- selection = @dataView.selection
+ selection = @dataSource.selection
if focused and selection.count() > 0
- @dataView.selection.add(focused)
+ @dataSource.selection.add(focused)
Actions.setFocus({collection: @collection, item: null})
if selection.count() is 1 and !focused
Actions.setFocus({collection: @collection, item: selection.items()[0]})
- @dataView.selection.clear()
+ @dataSource.selection.clear()
diff --git a/src/flux/stores/list-data-source.coffee b/src/flux/stores/list-data-source.coffee
new file mode 100644
index 000000000..87c6022ae
--- /dev/null
+++ b/src/flux/stores/list-data-source.coffee
@@ -0,0 +1,46 @@
+_ = require 'underscore'
+EventEmitter = require('events').EventEmitter
+ListSelection = require './list-selection'
+
+module.exports =
+class ListDataSource
+
+ constructor: ->
+ @_emitter = new EventEmitter()
+ @selection = new ListSelection(@, @trigger)
+ @
+
+ # Accessing Data
+
+ trigger: (arg) =>
+ @_emitter.emit('trigger', arg)
+
+ listen: (callback, bindContext) ->
+ eventHandler = ->
+ callback.apply(bindContext, arguments)
+ @_emitter.addListener('trigger', eventHandler)
+ return => @_emitter.removeListener('trigger', eventHandler)
+
+ loaded: ->
+ throw new Error("ListDataSource base class does not implement loaded()")
+
+ empty: ->
+ throw new Error("ListDataSource base class does not implement empty()")
+
+ get: (idx) ->
+ throw new Error("ListDataSource base class does not implement get()")
+
+ getById: (id) ->
+ throw new Error("ListDataSource base class does not implement getById()")
+
+ indexOfId: (id) ->
+ throw new Error("ListDataSource base class does not implement indexOfId()")
+
+ count: ->
+ throw new Error("ListDataSource base class does not implement count()")
+
+ itemsCurrentlyInViewMatching: (matchFn) ->
+ throw new Error("ListDataSource base class does not implement itemsCurrentlyInViewMatching()")
+
+ setRetainedRange: ({start, end}) ->
+ throw new Error("ListDataSource base class does not implement setRetainedRange()")
diff --git a/src/flux/stores/model-view-selection.coffee b/src/flux/stores/list-selection.coffee
similarity index 97%
rename from src/flux/stores/model-view-selection.coffee
rename to src/flux/stores/list-selection.coffee
index 06062840e..129504e73 100644
--- a/src/flux/stores/model-view-selection.coffee
+++ b/src/flux/stores/list-selection.coffee
@@ -2,10 +2,10 @@ Model = require '../models/model'
_ = require 'underscore'
module.exports =
-class ModelViewSelection
+class ListSelection
constructor: (@_view, @trigger) ->
- throw new Error("new ModelViewSelection(): You must provide a view.") unless @_view
+ throw new Error("new ListSelection(): You must provide a view.") unless @_view
@_items = []
count: ->
diff --git a/src/flux/stores/model-view.coffee b/src/flux/stores/model-view.coffee
deleted file mode 100644
index 1b2a5cd0e..000000000
--- a/src/flux/stores/model-view.coffee
+++ /dev/null
@@ -1,46 +0,0 @@
-_ = require 'underscore'
-EventEmitter = require('events').EventEmitter
-ModelViewSelection = require './model-view-selection'
-
-module.exports =
-class ModelView
-
- constructor: ->
- @_emitter = new EventEmitter()
- @selection = new ModelViewSelection(@, @trigger)
- @
-
- # Accessing Data
-
- trigger: (arg) =>
- @_emitter.emit('trigger', arg)
-
- listen: (callback, bindContext) ->
- eventHandler = ->
- callback.apply(bindContext, arguments)
- @_emitter.addListener('trigger', eventHandler)
- return => @_emitter.removeListener('trigger', eventHandler)
-
- loaded: ->
- throw new Error("ModelView base class does not implement loaded()")
-
- empty: ->
- throw new Error("ModelView base class does not implement empty()")
-
- get: (idx) ->
- throw new Error("ModelView base class does not implement get()")
-
- getById: (id) ->
- throw new Error("ModelView base class does not implement getById()")
-
- indexOfId: (id) ->
- throw new Error("ModelView base class does not implement indexOfId()")
-
- count: ->
- throw new Error("ModelView base class does not implement count()")
-
- itemsCurrentlyInViewMatching: (matchFn) ->
- throw new Error("ModelView base class does not implement itemsCurrentlyInViewMatching()")
-
- setRetainedRange: ({start, end}) ->
- throw new Error("ModelView base class does not implement setRetainedRange()")
diff --git a/src/flux/stores/query-result-set-view.coffee b/src/flux/stores/observable-list-data-source.coffee
similarity index 89%
rename from src/flux/stores/query-result-set-view.coffee
rename to src/flux/stores/observable-list-data-source.coffee
index a6b52f22d..23ca26b87 100644
--- a/src/flux/stores/query-result-set-view.coffee
+++ b/src/flux/stores/observable-list-data-source.coffee
@@ -5,7 +5,7 @@ Message = require '../models/message'
QuerySubscriptionPool = require '../models/query-subscription-pool'
QuerySubscription = require '../models/query-subscription'
MutableQuerySubscription = require '../models/mutable-query-subscription'
-ModelView = require './model-view'
+ListDataSource = require './list-data-source'
###
This class takes an observable which vends QueryResultSets and adapts it so that
@@ -14,7 +14,7 @@ you can make it the data source of a MultiselectList.
When the MultiselectList is refactored to take an Observable, this class should
go away!
###
-class QueryResultSetView extends ModelView
+class ObservableListDataSource extends ListDataSource
constructor: ($resultSetObservable, @_setRetainedRange) ->
super
@@ -31,6 +31,7 @@ class QueryResultSetView extends ModelView
previousResultSet = @_resultSet
@_resultSet = nextResultSet
+ @selection.updateModelReferences(@_resultSet.models())
@trigger({previous: previousResultSet, next: nextResultSet})
setRetainedRange: ({start, end}) ->
@@ -64,4 +65,4 @@ class QueryResultSetView extends ModelView
@_resultSet.models().filter(matchFn)
-module.exports = QueryResultSetView
+module.exports = ObservableListDataSource
diff --git a/src/global/nylas-exports.coffee b/src/global/nylas-exports.coffee
index 532442b20..fe7aecf6c 100644
--- a/src/global/nylas-exports.coffee
+++ b/src/global/nylas-exports.coffee
@@ -54,7 +54,7 @@ class NylasExports
@load "DatabaseStore", 'flux/stores/database-store'
@load "DatabaseTransaction", 'flux/stores/database-transaction'
@load "QueryResultSet", 'flux/models/query-result-set'
- @load "QueryResultSetView", 'flux/stores/query-result-set-view'
+ @load "ObservableListDataSource", 'flux/stores/observable-list-data-source'
@load "QuerySubscription", 'flux/models/query-subscription'
@load "MutableQuerySubscription", 'flux/models/mutable-query-subscription'
@load "QuerySubscriptionPool", 'flux/models/query-subscription-pool'