Source: forms/CrudForm.js

/**
 * Copyright (C) 2005-2016 Alfresco Software Limited.
 *
 * This file is part of Alfresco
 *
 * Alfresco is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Alfresco is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * This module extends the standard [Form widget]{@link module:alfresco/forms/Form} to provide the ability
 * to change the data and buttons displayed based upon topics published relating to various CRUD states.
 * For example the same form can show empty (or default) fields for creating new objects or can be updated
 * with data for existing items. The buttons will vary based on the current form state, e.g. "Delete" and "Update"
 * will be shown for existing data, but will not be displayed when creating new items.
 * 
 * @module alfresco/forms/DynamicForm
 * @extends module:alfresco/forms/Form
 * @author Dave Draper
 */
define(["dojo/_base/declare",
        "alfresco/forms/Form",
        "dojo/_base/lang",
        "dojo/_base/array",
        "alfresco/buttons/AlfButton",
        "dojo/dom-construct",
        "dojo/dom-style",
        "dijit/registry"], 
        function(declare, Form, lang, array, AlfButton, domConstruct, domStyle, registry) {
   
   return declare([Form], {
      
      /**
       * This should be configured to be an object that contains the default data set to use
       * for creating new instances. This object will be passed to the 
       * [setValue]{@link module:alfresco/forms/Form#setValue} function when the "create" form
       * state is entered.
       * 
       * @instance
       * @type {object}
       * @default
       */
      defaultData: null,

      /**
       * This should be configured to be an array of topics that when published will reveal the
       * the information panel. The information panel is expected to be shown after creation, update
       * and deletion events
       *
       * @instance
       * @type {array}
       * @default
       */
      showInfoTopics: null,

      /**
       * This should be configured to be an array of topics that when published will reveal the
       * the form. The form is expected to be shown when an existing item is selected or when a new
       * item should be created.
       *
       * @instance
       * @type {array}
       * @default
       */
      showFormTopics: null,

      /**
       * Subscribes to 
       * @instance
       */
      postMixInProperties: function alfresco_forms_CrudForm__postMixInProperties() {

         // There are two main states for the form - creating new items and updating
         // existing updates...
         this.alfSubscribe("ALF_CRUD_FORM_CREATE", lang.hitch(this, "onShowCreateState"));
         this.alfSubscribe("ALF_CRUD_FORM_UPDATE", lang.hitch(this, "onShowUpdateState"));

         if (this.showInfoTopics)
         {
            array.forEach(this.showInfoTopics, function(topic) {
               this.alfSubscribe(topic, lang.hitch(this, this.onShowInfo));
            }, this);
         }
         if (this.showFormTopics)
         {
            array.forEach(this.showFormTopics, function(topic) {
               this.alfSubscribe(topic, lang.hitch(this, this.onShowForm));
            }, this);
         }
      },

      /**
       * Extends the [inherited function]{@link module:alfresco/forms/Form#postCreate} to 
       * create a new "info" node. This node will be displayed when no item has been selected
       * or when the last viewed item has been updated or deleted.
       * 
       * @instance
       */
      postCreate: function alfresco_forms_CrudForm__postCreate() {
         this.infoNode = domConstruct.create("div", {
            id: this.id + "_INFO_NODE"
         }, this.domNode, "first");
         this.__creatingInfoWidgets = true;
         this.processWidgets(this.widgetsForInfo, this.infoNode);
         this.inherited(arguments);
         this.onShowInfo();
      },

      /**
       * This function is called whenever the form should be displayed and the information panel
       * hidden. The topics that when published will cause this function to be called can be configured
       * via the [showFormTopics]{@link module:alfresco/forms/CrudForm#showFormTopics} attribute.
       * 
       * @instance
       */
      onShowForm: function alfresco_forms_CrudForm__onShowForm() {
         domStyle.set(this.infoNode, "display", "none");
         domStyle.set(this._form.domNode, "display", "block");
         domStyle.set(this.buttonsNode, "display", "block");

      },

      /**
       * This function is called whenever the information panel should be displayed and the form
       * hidden. The topics that when published will cause this function to be called can be configured
       * via the [showFormTopics]{@link module:alfresco/forms/CrudForm#showInfoTopics} attribute.
       * 
       * @instance
       */
      onShowInfo: function alfresco_forms_CrudForm__onShowInfo() {
         domStyle.set(this._form.domNode, "display", "none");
         domStyle.set(this.buttonsNode, "display", "none");
         domStyle.set(this.infoNode, "display", "block");
      },

      /**
       * Extends the default implementation to capture the form fields and update the default
       * data object.
       * 
       * @instance
       * @param {array} widgets The created form controls
       */
      allWidgetsProcessed: function alfresco_forms_CrudForm__allWidgetsProcessed(/*jshint unused:false*/ widgets) {
         /*jshint eqnull:true*/
         if (this.__creatingInfoWidgets === true)
         {
            this.__creatingInfoWidgets = false;
         }
         else if (this.__creatingAdditionalButtons === true)
         {
            this.__creatingAdditionalButtons = false;
            this.additionalButtons = registry.findWidgets(this.buttonsNode);
         }
         else
         {
            this.inherited(arguments);

            // Collect the initial set of form data...
            var startingFormData = {};
            array.forEach(this._form.getChildren(), function(entry) {
               lang.setObject(entry.get("name"), entry.getValue(), startingFormData);
            });

            if (this.defaultData != null)
            {
               // Mix the default data into the starting form data (this overrides what's initialised in the form)
               lang.mixin(startingFormData, this.defaultData);
            }
            else
            {
               // Use the initial form data as the default data set for creating new items...
               this.defaultData = startingFormData;
            }
         }
      },

      /**
       * Overrides the default implementation to creates the "Create", "Update" and "Save" buttons
       * 
       * @instance
       */
      createButtons: function alfresco_forms_CrudForm__createButtons() {
         /*jshint eqnull:true*/
         
         // Clear the default buttonsNode...
         domConstruct.empty(this.buttonsNode);

         // Create the "Create" button...
         // TODO: Should be using "createWidget" helper function
         this.createButtonNode = domConstruct.create("div", null, this.buttonsNode);
         this.createButton = new AlfButton({
            pubSubScope: this.pubSubScope,
            label: this.message(this.createButtonLabel),
            additionalCssClasses: "createButton call-to-action",
            publishTopic: this.createButtonPublishTopic,
            publishPayload: this.createButtonPublishPayload,
            publishGlobal: this.createButtonPublishGlobal
         }, this.createButtonNode);

         // Create the "Update" button...
         // TODO: Should be using "createWidget" helper function
         this.updateButtonNode = domConstruct.create("div", null, this.buttonsNode);
         this.updateButton = new AlfButton({
            pubSubScope: this.pubSubScope,
            label: this.message(this.updateButtonLabel),
            additionalCssClasses: "updateButton call-to-action",
            publishTopic: this.updateButtonPublishTopic,
            publishPayload: this.updateButtonPublishPayload,
            publishGlobal: this.updateButtonPublishGlobal
         }, this.updateButtonNode);

         // Create the "Delete" button...
         // TODO: Should be using "createWidget" helper function
         this.deleteButtonNode = domConstruct.create("div", null, this.buttonsNode);
         this.deleteButton = new AlfButton({
            pubSubScope: this.pubSubScope,
            label: this.message(this.deleteButtonLabel),
            additionalCssClasses: "deleteButton",
            publishTopic: this.deleteButtonPublishTopic,
            publishPayload: this.deleteButtonPublishPayload,
            publishGlobal: this.deleteButtonPublishGlobal
         }, this.deleteButtonNode);
         
         // Copied from original code - might not need the IF condition...
         if (this.widgetsAdditionalButtons != null)
         {
            this.__creatingAdditionalButtons = true;
            this.additionalButtons = [];
            this.processWidgets(this.widgetsAdditionalButtons, this.buttonsNode);
         }
         else
         {
            this.additionalButtons = registry.findWidgets(this.buttonsNode);
         }

         // Initialise to the create state...
         this.onShowCreateState(null);
      },

      /**
       * Hides the "Update" and "Delete" buttons and shows the "Create" button and updates the 
       * form to display the default data.
       *
       * @instance
       * @param {object} payload The details of the create state
       */
      onShowCreateState: function alfresco_forms_CrudForm__onShowCreateState(/*jshint unused:false*/ payload) {
         // Update the form to display the default data.
         this.setValue(this.defaultData);

         // TODO: Change the displayed buttons (show the "Create" button, hide the "Update" & "Delete" buttons)
         domStyle.set(this.createButton.domNode, "display", "");
         domStyle.set(this.updateButton.domNode, "display", "none");
         domStyle.set(this.deleteButton.domNode, "display", "none");

         // Set the "OK" button as the "Create" button and then validate so that it is enabled/disabled appropriately
         this.okButton = this.createButton; 
         this.validate();

         this.onShowForm();
      },

      /**
       * Hides the "Create" button and shows the "Update" and "Delete" buttons. Updates the
       * form with the requested data.
       * 
       * @instance
       * @param {object} payload The details of the create state
       */
      onShowUpdateState: function alfresco_forms_CrudForm__onShowUpdateState(payload) {

         // In the future, this should potentially make an XHR request to get the latest data,
         // but for now just use the data provided in the payload. It is expected that the payload
         // will contain all the relevant data.
         this.setValue(payload);

         domStyle.set(this.createButton.domNode, "display", "none");
         domStyle.set(this.updateButton.domNode, "display", "");
         domStyle.set(this.deleteButton.domNode, "display", "");

         // Set the "OK" button as the "Update" button and then validate so that it is enabled/disabled appropriately
         this.okButton = this.updateButton; 
         this.validate();

         this.onShowForm();
      },

      widgetsForInfo: [
         {
            name: "alfresco/layout/VerticalWidgets",
            config: {
               widgets: [
                  {
                     name: "alfresco/html/Label",
                     config: {
                        label: "Info Page TBD"
                     }
                  }
               ]
            }
         }
      ]
   });
});