unsavedEdits.js 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. Meteor.subscribe('unsaved-edits');
  2. // `UnsavedEdits` is a global key-value store used to save drafts of user
  3. // inputs. We used to have the notion of a `cachedValue` that was local to a
  4. // component but the global store has multiple advantages:
  5. // 1. When the component is unmounted (ie, destroyed) the draft isn't lost
  6. // 2. The drafts are synced across multiple computers
  7. // 3. The drafts are synced across multiple browser tabs
  8. // XXX This currently doesn't work in purely offline mode since the sync is
  9. // handled with the DDP connection to the server. To solve this, we could use
  10. // something like GroundDB that syncs using localstorage.
  11. //
  12. // The key is a dictionary composed of two fields:
  13. // * a `fieldName` which identifies the particular field. Since this is a global
  14. // identifier a good practice would be to compose it with the collection name
  15. // and the document field, eg. `boardTitle`, `cardDescription`.
  16. // * a `docId` which identifies the appropriate document. In general we use
  17. // MongoDB `_id` field.
  18. //
  19. // The value is a string containing the draft.
  20. UnsavedEdits = {
  21. // XXX Wanted to have the collection has an instance variable, but
  22. // unfortunately the collection isn't defined yet at this point. We need ES6
  23. // modules to solve the file order issue!
  24. //
  25. // _collection: UnsavedEditCollection,
  26. get({ fieldName, docId }, defaultTo = '') {
  27. let unsavedValue = this._getCollectionDocument(fieldName, docId);
  28. if (unsavedValue) {
  29. return unsavedValue.value
  30. } else {
  31. return defaultTo;
  32. }
  33. },
  34. has({ fieldName, docId }) {
  35. return Boolean(this.get({fieldName, docId}));
  36. },
  37. set({ fieldName, docId }, value) {
  38. let currentDoc = this._getCollectionDocument(fieldName, docId);
  39. if (currentDoc) {
  40. UnsavedEditCollection.update(currentDoc._id, {
  41. $set: {
  42. value: value
  43. }
  44. });
  45. } else {
  46. UnsavedEditCollection.insert({
  47. fieldName,
  48. docId,
  49. value,
  50. });
  51. }
  52. },
  53. reset({ fieldName, docId }) {
  54. let currentDoc = this._getCollectionDocument(fieldName, docId);
  55. if (currentDoc) {
  56. UnsavedEditCollection.remove(currentDoc._id);
  57. }
  58. },
  59. _getCollectionDocument(fieldName, docId) {
  60. return UnsavedEditCollection.findOne({fieldName, docId});
  61. }
  62. }
  63. Blaze.registerHelper('getUnsavedValue', (fieldName, docId, defaultTo) => {
  64. // Workaround some blaze feature that ass a list of keywords arguments as the
  65. // last parameter (even if the caller didn't specify any).
  66. if (! _.isString(defaultTo)) {
  67. defaultTo = '';
  68. }
  69. return UnsavedEdits.get({ fieldName, docId }, defaultTo);
  70. });
  71. Blaze.registerHelper('hasUnsavedValue', (fieldName, docId) => {
  72. return UnsavedEdits.has({ fieldName, docId });
  73. });