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'