summaryrefslogtreecommitdiffstats
path: root/client/lib/unsavedEdits.js
diff options
context:
space:
mode:
authorMaxime Quandalle <maxime@quandalle.com>2015-08-31 15:09:53 +0200
committerMaxime Quandalle <maxime@quandalle.com>2015-08-31 15:52:16 +0200
commitd644cba38ff06369cc43c1ebd08d344fd1d248ea (patch)
treebad4bcef1f549132792301cf134b3c8234ad1d13 /client/lib/unsavedEdits.js
parentcc88e78483d2f39048d3558193f0c82b711c12c8 (diff)
downloadwekan-d644cba38ff06369cc43c1ebd08d344fd1d248ea.tar.gz
wekan-d644cba38ff06369cc43c1ebd08d344fd1d248ea.tar.bz2
wekan-d644cba38ff06369cc43c1ebd08d344fd1d248ea.zip
Replace the component bounded `cachedValue` by a global `UnsavedEdits`
This new draft saving system is currently only implemented for the card description and comment. We need better a component inheritance/composition model to support this for all editable fields. Fixes #186
Diffstat (limited to 'client/lib/unsavedEdits.js')
-rw-r--r--client/lib/unsavedEdits.js82
1 files changed, 82 insertions, 0 deletions
diff --git a/client/lib/unsavedEdits.js b/client/lib/unsavedEdits.js
new file mode 100644
index 00000000..55ea2529
--- /dev/null
+++ b/client/lib/unsavedEdits.js
@@ -0,0 +1,82 @@
+Meteor.subscribe('unsaved-edits');
+
+// `UnsavedEdits` is a global key-value store used to save drafts of user
+// inputs. We used to have the notion of a `cachedValue` that was local to a
+// component but the global store has multiple advantages:
+// 1. When the component is unmounted (ie, destroyed) the draft isn't lost
+// 2. The drafts are synced across multiple computers
+// 3. The drafts are synced across multiple browser tabs
+// XXX This currently doesn't work in purely offline mode since the sync is
+// handled with the DDP connection to the server. To solve this, we could use
+// something like GroundDB that syncs using localstorage.
+//
+// The key is a dictionary composed of two fields:
+// * a `fieldName` which identifies the particular field. Since this is a global
+// identifier a good practice would be to compose it with the collection name
+// and the document field, eg. `boardTitle`, `cardDescription`.
+// * a `docId` which identifies the appropriate document. In general we use
+// MongoDB `_id` field.
+//
+// The value is a string containing the draft.
+
+UnsavedEdits = {
+ // XXX Wanted to have the collection has an instance variable, but
+ // unfortunately the collection isn't defined yet at this point. We need ES6
+ // modules to solve the file order issue!
+ //
+ // _collection: UnsavedEditCollection,
+
+ get({ fieldName, docId }, defaultTo = '') {
+ let unsavedValue = this._getCollectionDocument(fieldName, docId);
+ if (unsavedValue) {
+ return unsavedValue.value
+ } else {
+ return defaultTo;
+ }
+ },
+
+ has({ fieldName, docId }) {
+ return Boolean(this.get({fieldName, docId}));
+ },
+
+ set({ fieldName, docId }, value) {
+ let currentDoc = this._getCollectionDocument(fieldName, docId);
+ if (currentDoc) {
+ UnsavedEditCollection.update(currentDoc._id, {
+ $set: {
+ value: value
+ }
+ });
+ } else {
+ UnsavedEditCollection.insert({
+ fieldName,
+ docId,
+ value,
+ });
+ }
+ },
+
+ reset({ fieldName, docId }) {
+ let currentDoc = this._getCollectionDocument(fieldName, docId);
+ if (currentDoc) {
+ UnsavedEditCollection.remove(currentDoc._id);
+ }
+ },
+
+ _getCollectionDocument(fieldName, docId) {
+ return UnsavedEditCollection.findOne({fieldName, docId});
+ }
+}
+
+Blaze.registerHelper('getUnsavedValue', (fieldName, docId, defaultTo) => {
+ // Workaround some blaze feature that ass a list of keywords arguments as the
+ // last parameter (even if the caller didn't specify any).
+ if (! _.isString(defaultTo)) {
+ defaultTo = '';
+ }
+ return UnsavedEdits.get({ fieldName, docId }, defaultTo);
+});
+
+Blaze.registerHelper('hasUnsavedValue', (fieldName, docId) => {
+ return UnsavedEdits.has({ fieldName, docId });
+});