mirror of
https://github.com/Foundry376/Mailspring.git
synced 2025-02-14 11:13:06 +08:00
Summary: This diff replaces the participant text fields with ones based on TokenizingTextField, a new core component that handles autocompletion, drag and drop of tokens, etc. Fix large queries overloading SQLite size limits New general purpose tokenized text field with token selection, copy paste, etc Move pre-send logic to the view since DraftStore requests from db, which may not have settled Tests - still a WIP Support for contextual menus instead of X Test Plan: Run new tests. Needs many more, but have higher priority things to fix Reviewers: evan Reviewed By: evan Differential Revision: https://review.inboxapp.com/D1142
104 lines
3.4 KiB
CoffeeScript
104 lines
3.4 KiB
CoffeeScript
{Message, Actions,DraftStore} = require 'inbox-exports'
|
|
EventEmitter = require('events').EventEmitter
|
|
_ = require 'underscore-plus'
|
|
|
|
# As the user interacts with the draft, changes are accumulated in the
|
|
# DraftChangeSet associated with the store proxy. The DraftChangeSet does two things:
|
|
#
|
|
# 1. It debounces changes and calls Actions.saveDraft() at a reasonable interval.
|
|
#
|
|
# 2. It exposes `applyToModel`, which allows you to optimistically apply changes
|
|
# to a draft object. When the proxy vends the draft, it passes it through this
|
|
# function to apply uncommitted changes. This means the Draft provided by the
|
|
# DraftStoreProxy will always relfect recent changes, even though they're
|
|
# written to the database intermittently.
|
|
#
|
|
class DraftChangeSet
|
|
constructor: (@localId, @_onChange) ->
|
|
@_pending = {}
|
|
@_timer = null
|
|
|
|
add: (changes, immediate) =>
|
|
@_pending = _.extend(@_pending, changes)
|
|
@_onChange()
|
|
if immediate
|
|
@commit()
|
|
else
|
|
clearTimeout(@_timer) if @_timer
|
|
@_timer = setTimeout(@commit, 5000)
|
|
|
|
commit: =>
|
|
@_pending.localId = @localId
|
|
if Object.keys(@_pending).length > 1
|
|
Actions.saveDraft(@_pending)
|
|
@_pending = {}
|
|
|
|
applyToModel: (model) =>
|
|
model.fromJSON(@_pending) if model
|
|
model
|
|
|
|
# DraftStoreProxy is a small class that makes it easy to implement components
|
|
# that display Draft objects or allow for interactive editing of Drafts.
|
|
#
|
|
# 1. It synchronously provides an instance of a draft via `draft()`, and
|
|
# triggers whenever that draft instance has changed.
|
|
#
|
|
# 2. It provides an interface for modifying the draft that transparently
|
|
# batches changes, and ensures that the draft provided via `draft()`
|
|
# always has pending changes applied.
|
|
#
|
|
module.exports =
|
|
class DraftStoreProxy
|
|
|
|
constructor: (@draftLocalId) ->
|
|
@unlisteners = []
|
|
@unlisteners.push DraftStore.listen(@_onDraftChanged, @)
|
|
@unlisteners.push Actions.didSwapModel.listen(@_onDraftSwapped, @)
|
|
@_emitter = new EventEmitter()
|
|
@_draft = false
|
|
@_reloadDraft()
|
|
|
|
@changes = new DraftChangeSet @draftLocalId, =>
|
|
@_emitter.emit('trigger')
|
|
|
|
draft: ->
|
|
@changes.applyToModel(@_draft)
|
|
@_draft
|
|
|
|
listen: (callback, bindContext) ->
|
|
eventHandler = (args) ->
|
|
callback.apply(bindContext, args)
|
|
@_emitter.addListener('trigger', eventHandler)
|
|
return =>
|
|
@_emitter.removeListener('trigger', eventHandler)
|
|
if @_emitter.listeners('trigger').length == 0
|
|
# Unlink ourselves from the stores/actions we were listening to
|
|
# so that we can be garbage collected
|
|
unlisten() for unlisten in @unlisteners
|
|
|
|
_onDraftChanged: (change) ->
|
|
# We don't accept changes unless our draft object is loaded
|
|
return unless @_draft
|
|
|
|
# Is this change an update to our draft?
|
|
myDraft = _.find(change.objects, (obj) => obj.id == @_draft.id)
|
|
if myDraft
|
|
@_draft = myDraft
|
|
@_emitter.emit('trigger')
|
|
|
|
_onDraftSwapped: (change) ->
|
|
# A draft was saved with a new ID. Since we use the draft ID to
|
|
# watch for changes to our draft, we need to pull again using our
|
|
# localId.
|
|
if change.oldModel.id is @_draft.id
|
|
@_draft = change.newModel
|
|
@_emitter.emit('trigger')
|
|
|
|
_reloadDraft: ->
|
|
promise = DraftStore.findByLocalId(@draftLocalId)
|
|
promise.catch (err) ->
|
|
console.log(err)
|
|
promise.then (draft) =>
|
|
@_draft = draft
|
|
@_emitter.emit('trigger')
|
|
|