Serialize draft (#8175)

Serialize draft (#8175)

  • DEV: allow serializing data for drafts

  • Various fixes

  • added an alias method for ‘serializeToDraft’ to plugin-api

  • fixed linting issues

  • changed single quotes to double quotes to fix linting issue

  • fixed linting issues

  • fixed composer model file via prettier

  • fixed composer controller file via prettier

  • fixed plugin-api file via prettier

diff --git a/app/assets/javascripts/discourse/controllers/composer.js.es6 b/app/assets/javascripts/discourse/controllers/composer.js.es6
index b96051e..cf295cb 100644
--- a/app/assets/javascripts/discourse/controllers/composer.js.es6
+++ b/app/assets/javascripts/discourse/controllers/composer.js.es6
@@ -39,26 +39,21 @@ function loadDraft(store, opts) {
     ((draft.title && draft.title !== "") || (draft.reply && draft.reply !== ""))
   ) {
     const composer = store.createRecord("composer");
+    const serializedFields = Composer.serializedFieldsForDraft();
 
-    composer.open({
+    let attrs = {
       draftKey,
       draftSequence,
-      action: draft.action,
-      title: draft.title,
-      categoryId: draft.categoryId || opts.categoryId,
-      postId: draft.postId,
-      archetypeId: draft.archetypeId,
-      reply: draft.reply,
-      metaData: draft.metaData,
-      usernames: draft.usernames,
       draft: true,
-      composerState: Composer.DRAFT,
-      composerTime: draft.composerTime,
-      typingTime: draft.typingTime,
-      whisper: draft.whisper,
-      tags: draft.tags,
-      noBump: draft.noBump
+      composerState: Composer.DRAFT
+    };
+
+    serializedFields.forEach(f => {
+      attrs[f] = draft[f] || opts[f];
     });
+
+    composer.open(attrs);
+
     return composer;
   }
 }
@@ -753,15 +748,15 @@ export default Ember.Controller.extend({
   },
 
   /**
-    Open the composer view
-
-    @method open
-    @param {Object} opts Options for creating a post
-      @param {String} opts.action The action we're performing: edit, reply or createTopic
-      @param {Discourse.Post} [opts.post] The post we're replying to
-      @param {Discourse.Topic} [opts.topic] The topic we're replying to
-      @param {String} [opts.quote] If we're opening a reply from a quote, the quote we're making
-  **/
+   Open the composer view
+
+   @method open
+   @param {Object} opts Options for creating a post
+   @param {String} opts.action The action we're performing: edit, reply or createTopic
+   @param {Discourse.Post} [opts.post] The post we're replying to
+   @param {Discourse.Topic} [opts.topic] The topic we're replying to
+   @param {String} [opts.quote] If we're opening a reply from a quote, the quote we're making
+   **/
   open(opts) {
     opts = opts || {};
 
diff --git a/app/assets/javascripts/discourse/lib/plugin-api.js.es6 b/app/assets/javascripts/discourse/lib/plugin-api.js.es6
index 4cf670b..76959bd 100644
--- a/app/assets/javascripts/discourse/lib/plugin-api.js.es6
+++ b/app/assets/javascripts/discourse/lib/plugin-api.js.es6
@@ -43,6 +43,7 @@ import Sharing from "discourse/lib/sharing";
 import { addComposerUploadHandler } from "discourse/components/composer-editor";
 import { addCategorySortCriteria } from "discourse/components/edit-category-settings";
 import { queryRegistry } from "discourse/widgets/widget";
+import Composer from "discourse/models/composer";
 
 // If you add any methods to the API ensure you bump up this number
 const PLUGIN_API_VERSION = "0.8.32";
@@ -424,44 +425,44 @@ class PluginApi {
   }
 
   /**
-    Called whenever the "page" changes. This allows us to set up analytics
-    and other tracking.
+   Called whenever the "page" changes. This allows us to set up analytics
+   and other tracking.
 
-    To get notified when the page changes, you can install a hook like so:
+   To get notified when the page changes, you can install a hook like so:
 
-    `‍``javascript
-      api.onPageChange((url, title) => {
+   `‍``javascript
+   api.onPageChange((url, title) => {
         console.log('the page changed to: ' + url + ' and title ' + title);
       });
-    `‍``
-  **/
+   `‍``
+   **/
   onPageChange(fn) {
     this.onAppEvent("page:changed", data => fn(data.url, data.title));
   }
 
   /**
-    Listen for a triggered `AppEvent` from Discourse.
+   Listen for a triggered `AppEvent` from Discourse.
 
-    `‍``javascript
-      api.onAppEvent('inserted-custom-html', () => {
+   `‍``javascript
+   api.onAppEvent('inserted-custom-html', () => {
         console.log('a custom footer was rendered');
       });
-    `‍``
-  **/
+   `‍``
+   **/
   onAppEvent(name, fn) {
     const appEvents = this._lookupContainer("service:app-events");
     appEvents && appEvents.on(name, fn);
   }
 
   /**
-    Registers a function to generate custom avatar CSS classes
-    for a particular user.
+   Registers a function to generate custom avatar CSS classes
+   for a particular user.
 
-    Takes a function that will accept a user as a parameter
-    and return an array of CSS classes to apply.
+   Takes a function that will accept a user as a parameter
+   and return an array of CSS classes to apply.
 
-    `‍``javascript
-    api.customUserAvatarClasses(user => {
+   `‍``javascript
+   api.customUserAvatarClasses(user => {
       if (Ember.get(user, 'primary_group_name') === 'managers') {
         return ['managers'];
       }
@@ -845,6 +846,21 @@ class PluginApi {
   }
 
   /**
+   * Adds a field to draft serializer
+   *
+   * Example:
+   *
+   * api.serializeToDraft('key_set_in_model', 'field_name_in_payload');
+   *
+   * to keep both of them same
+   * api.serializeToDraft('field_name');
+   *
+   */
+  serializeToDraft(fieldName, property) {
+    Composer.serialzeToDraft(fieldName, property);
+  }
+
+  /**
    * Registers a criteria that can be used as default topic order on category
    * pages.
    *
diff --git a/app/assets/javascripts/discourse/models/composer.js.es6 b/app/assets/javascripts/discourse/models/composer.js.es6
index de9d904..9ba0afe 100644
--- a/app/assets/javascripts/discourse/models/composer.js.es6
+++ b/app/assets/javascripts/discourse/models/composer.js.es6
@@ -57,6 +57,20 @@ const CLOSED = "closed",
     tags: "topic.tags",
     featuredLink: "topic.featured_link"
   },
+  _draft_serializer = {
+    reply: "reply",
+    action: "action",
+    title: "title",
+    categoryId: "categoryId",
+    archetypeId: "archetypeId",
+    whisper: "whisper",
+    metaData: "metaData",
+    composerTime: "composerTime",
+    typingTime: "typingTime",
+    postId: "post.id",
+    usernames: "targetUsernames"
+  },
+  _add_draft_fields = {},
   FAST_REPLY_LENGTH_THRESHOLD = 10000;
 
 export const SAVE_LABELS = {
@@ -722,6 +736,11 @@ const Composer = RestModel.extend({
       composer.appEvents.trigger("composer:reply-reloaded", composer);
     }
 
+    // Ensure additional draft fields are set
+    Object.keys(_add_draft_fields).forEach(f => {
+      this.set(_add_draft_fields[f], opts[f]);
+    });
+
     return false;
   },
 
@@ -1019,24 +1038,7 @@ const Composer = RestModel.extend({
       this._clearingStatus = null;
     }
 
-    let data = this.getProperties(
-      "reply",
-      "action",
-      "title",
-      "categoryId",
-      "archetypeId",
-      "whisper",
-      "metaData",
-      "composerTime",
-      "typingTime",
-      "tags",
-      "noBump"
-    );
-
-    data = Object.assign(data, {
-      usernames: this.targetUsernames,
-      postId: this.get("post.id")
-    });
+    let data = this.serialize(_draft_serializer);
 
     if (data.postId && !Ember.isEmpty(this.originalText)) {
       data.originalText = this.originalText;
@@ -1113,6 +1115,18 @@ Composer.reopenClass({
     return Object.keys(_create_serializer);
   },
 
+  serializeToDraft(fieldName, property) {
+    if (!property) {
+      property = fieldName;
+    }
+    _draft_serializer[fieldName] = property;
+    _add_draft_fields[fieldName] = property;
+  },
+
+  serializedFieldsForDraft() {
+    return Object.keys(_draft_serializer);
+  },
+
   // The status the compose view can have
   CLOSED,
   SAVING,

GitHub sha: 8fc0cc9a