Source: forms/controls/DragAndDropTargetControl.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/>.
 */

/**
 * <p>This form control can be used for constructing form data through a drag and drop interface. Include
 * this widget in a [form]{@link module:alfresco/forms/Form} and it will render a 
 * [DragAndDropTarget]{@link module:alfresco/dnd/DragAndDropTarget} that can be used to drop items dragged from a
 * [DragAndDropItems]{@link module:alfresco/dnd/DragAndDropItems} widget.</p>
 * <p>When configured the control you can choose whether or not to [use a modelling service]{@link module:alfresco/form/controls/DragAndDropTargetControl#useModellingService}
 * (recommended for finer control) as well as overriding the 
 * [widget model for wrapping dropped items]{@link module:alfresco/form/controls/DragAndDropTargetControl#widgetsForWrappingDroppedItems}
 * and the [widget model for rendering each dropped item]{@link module:alfresco/form/controls/DragAndDropTargetControl#widgetsForDroppedItems}} (although the latter
 * configuration might get overriden by your modelling service configuration).</p>
 * 
 * @module alfresco/forms/controls/DragAndDropTargetControl
 * @extends module:alfresco/forms/controls/BaseFormControl
 * @mixes module:alfresco/core/CoreWidgetProcessing
 * @author Dave Draper
 */
define(["dojo/_base/declare",
        "alfresco/forms/controls/BaseFormControl",
        "alfresco/core/CoreWidgetProcessing",
        "alfresco/dnd/DragAndDropTarget",
        "dojo/_base/lang",
        "dojo/on",
        "alfresco/dnd/Constants",
        "dijit/registry"], 
        function(declare, BaseFormControl, CoreWidgetProcessing, DragAndDropTarget, lang, on, Constants, registry) {
   
   return declare([BaseFormControl, CoreWidgetProcessing], {
      
      /**
       * Defines a topic to subscribe to that if published on will result in all of the dropped items being
       * deleted. The difference between this topic and the 
       * [clearDroppedItemsTopic]{@link module:alfresco/forms/controls/DragAndDropTargetControl#clearDroppedItemsTopic}
       * is that single-use items that have been used will NOT be returned to the 
       * [DragAndDropItems]{@link module:alfresco/dnd/DragAndDropItems#items} widget from which they were dragged.
       * 
       * @instance
       * @type {string}
       * @default
       */
      clearTopic: null,
      
      /**
       * Defines a topic to subscribe to that if published on will result in all of the dropped items being
       * deleted. The difference between this topic and the 
       * [clearTopic]{@link module:alfresco/forms/controls/DragAndDropTargetControl#clearTopic}
       * is that single-use items that have been used WILL be returned to the 
       * [DragAndDropItems]{@link module:alfresco/dnd/DragAndDropItems#items} widget from which they were dragged.
       * 
       * @instance
       * @type {string}
       * @default
       */
      clearDroppedItemsTopic: null,

      /**
       * Indicates whether or not to use a modelling service to render the dropped items.
       * This will result in publications being made to request the widgets to use for each
       * dropped item based on the value of the dropped item.
       *
       * @instance
       * @type {boolean}
       * @default
       */
      useModellingService: false,

      /**
       * An optional model to override the default widgets used for rendering the wrapper around
       * a dropped item.
       * 
       * @instance
       * @type {array}
       * @default
       */
      widgetsForWrappingDroppedItems: null,

      /**
       * An optional model to override the default widgets used for rendering a dropped item.
       * 
       * @instance
       * @type {array}
       * @default
       */
      widgetsForDroppedItems: null,

      /**
       * Indicates whether or not dragging should be done with handles.
       *
       * @instance
       * @type {boolean}
       * @default
       */
      withHandles: true,

      /**
       * Return the configuration for the widget
       * 
       * @instance
       */
      getWidgetConfig: function alfresco_forms_controls_DragAndDropTargetControl__getWidgetConfig() {
         var config = {
            id : this.generateUuid(),
            name: this.name,
            pubSubScope: this.pubSubScope,
            parentPubSubScope: this.pubSubScope,
            acceptTypes: this.acceptTypes,
            useModellingService: this.useModellingService,
            withHandles: this.withHandles
         };
         if (this.widgetsForWrappingDroppedItems)
         {
            config.widgetsForWrappingDroppedItems = this.widgetsForWrappingDroppedItems;
         }
         if (this.widgetsForDroppedItems)
         {
            config.widgetsForDroppedItems = this.widgetsForDroppedItems;
         }
         return config;
      },
      
      /**
       * Instantiates a new [DragAndDropTarget]{@link module:alfresco/dnd/DragAndDropTarget} widget.
       * 
       * @instance
       * @param {config} config The configuration to instantiate the control with.
       */
      createFormControl: function alfresco_forms_controls_DragAndDropTargetControl__createFormControl(config, /*jshint unused:false*/ domNode) {
         if (this.widgetsForControl && this.widgetsForControl.length && this.widgetsForControl[0].name)
         {
            return this.createWidget({
               name: this.widgetsForControl[0].name,
               config: config
            });
         }
         else
         {
            return new DragAndDropTarget(config);
         }
      },

      /**
       * Creates subscriptions to the [clearTopic]{@link module:alfresco/forms/controls/DragAndDropTargetControl#clearTopic}
       * and [clearDroppedItemsTopic]{@link module:alfresco/forms/controls/DragAndDropTargetControl#clearDroppedItemsTopic}
       * topics (if configured) in order 
       * 
       * @instance
       */
      startup: function alfresco_dnd_DragAndDropFormControlTarget__startup() {
         if(this.clearTopic)
         {
            this.alfSubscribe(this.clearTopic, lang.hitch(this, this.onClear));
         }
         if(this.clearDroppedItemsTopic)
         {
            this.alfSubscribe(this.clearDroppedItemsTopic, lang.hitch(this, this.onClearDroppedItems));
         }
      },

      /**
       * This function wipes the canvas, discarding nodes it contains.
       * 
       * @instance
       */
      onClear: function cmm_forms_controls_DragAndDropTargetControl__onClear() {
         var canvas = lang.getObject("wrappedWidget.previewTarget", false, this);
         if (canvas)
         {
            canvas.selectAll().deleteSelectedNodes();
         }
      },

      /**
       * This function wipes the canvas by running the deletion process of any nodes it contains. The 
       * nodes will therefore return to their palettes of origin if required.
       * 
       * @instance
       */
      onClearDroppedItems: function cmm_forms_controls_DragAndDropTargetControl__onClearDroppedItems() {
         var nodes = lang.getObject("wrappedWidget.previewTarget.map", false, this);
         for (var node in nodes)
         {
            if (nodes.hasOwnProperty(node))
            {
               var widget = registry.byId(node);
               if(widget && typeof widget.onItemDelete === "function")
               {
                  widget.onItemDelete();
               }
            }
         }
      },

      /**
       * This can be set to be an array containing a single widget definition. The array structure is used in order
       * for Surf dynamic-dependency analysis to include the required widget resources on the page. Only the "name"
       * attribute of the first widget in the page will be used, other configuration will be ignored.
       *
       * @instance
       * @type {array}
       * @default
       */
      widgetsForControl: null,
      
      /**
       * Overrides the [inherited function]{@link module:alfresco/forms/controls/BaseFormControl#setupChangeEvents}
       * to listen to update events generated when items are added or removed from the control.
       * 
       * @instance
       */
      setupChangeEvents: function alfresco_forms_controls_DragAndDropTargetControl__setupChangeEvents() {
         this.own(on(this.domNode, Constants.updateItemsEvent, lang.hitch(this, this.onDragAndDropTargetUpdated)));
      },

      /**
       * Handles the change in value for the current form control by publishing the details of the change and calling the
       * validate function to check that the new value is acceptable.
       * 
       * @instance
       * @param {string} name
       * @param {string} oldValue
       * @param {string} value
       */
      onDragAndDropTargetUpdated: function alfresco_forms_controls_DragAndDropTargetControl__onDragAndDropTargetUpdated(evt) {
         if (typeof evt.stopPropagation === "function")
         {
            evt.stopPropagation();
         }
         if (typeof evt.preventDefault === "function")
         {
            evt.preventDefault();
         }
         var updatedValue = this.getValue();
         this.formControlValueChange(name, null, updatedValue);
         this.validate();
      }
   });
});