/**
* 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 should be mixed into renderers that wish to be able to either display selected state or that
* can be clicked to change selected state. This is mixed into both the [Selector]{@link module:alfresco/renderers/Selector}
* and [Thumbnail]{@link module:alfresco/renderers/Thumbnail} renderers.
*
* @module alfresco/lists/ItemSelectionMixin
* @author Dave Draper
* @since 1.0.40
*/
define(["dojo/_base/declare",
"alfresco/core/Core",
"alfresco/core/topics",
"alfresco/documentlibrary/_AlfDocumentListTopicMixin",
"dojo/_base/lang",
"dojo/_base/array",
"dojo/dom-class",
"dojo/_base/event"],
function( declare, Core, topics, _AlfDocumentListTopicMixin, lang, array, domClass, event) {
return declare([Core, _AlfDocumentListTopicMixin], {
/**
* The dot-notation property in the currentItem that uniquely idenfities that item. This defaults
* to "nodeRef" as the most likely use case is for working with Nodes but this can be configured
* to a different value.
*
* @instance
* @type {string}
* @default
*/
itemKey: "nodeRef",
/**
* Indicates whether the subscriptions made by
* [createItemSelectionSubscriptions]{@link module:alfresco/lists/ItemSelectionMixin#createItemSelectionSubscriptions}
* and the publications made by [select]{@link module:alfresco/lists/ItemSelectionMixin#select} and
* [deselect]{@link module:alfresco/lists/ItemSelectionMixin#deselect} should be made on the global scope.
*
* @instance
* @type {boolean}
* @default
*/
publishGlobal: null,
/**
* Indicates whether the subscriptions made by
* [createItemSelectionSubscriptions]{@link module:alfresco/lists/ItemSelectionMixin#createItemSelectionSubscriptions}
* and the publications made by [select]{@link module:alfresco/lists/ItemSelectionMixin#select} and
* [deselect]{@link module:alfresco/lists/ItemSelectionMixin#deselect} should be made on the parent scope.
*
* @instance
* @type {boolean}
* @default
*/
publishToParent: null,
/**
* This indicates whether or not the mixing widget should subscribe to item selection events. This
* attribute is inspected by the [createItemSelectionSubscriptions]{@link module:alfresco/lists/ItemSelectionMixin#createItemSelectionSubscriptions}
* function to determine whether to bind the
* [documentSelectionTopic]{@link module:alfresco/documentlibrary/_AlfDocumentListTopicMixin#documentSelectionTopic}
* to the [onItemSelection]{@link module:alfresco/lists/ItemSelectionMixin#onItemSelection} function.
*
* @instance
* @type {boolean}
* @default
*/
updateOnSelection: true,
/**
* The CSS class to apply to the root DOM node of the widget
*
* @instance
* @type {string}
* @default
*/
selectedCssClass: "alfresco-lists-ItemSelectionMixin--selected",
/**
* This indicates whether or not clicking on the widget mixed by this module will trigger it's selection
* (it might be preferred to just update the CSS classes on selection rather than actually enabling
* item selection).
*
* @instance
* @type {boolean}
* @default
*/
selectOnClick: true,
/**
* If [updateOnSelection]{@link module:alfresco/lists/ItemSelectionMixin#updateOnSelection} is configured to be
* true then this will setup the necessary subscriptions for item selection handling. Each time items are selected
* [onItemSelection]{@link module:alfresco/lists/ItemSelectionMixin#onItemSelection} will be called.
*
* @instance
* @listens module:alfresco/documentlibrary/_AlfDocumentListTopicMixin#documentSelectionTopic
*/
createItemSelectionSubscriptions: function alfresco_lists_ItemSelectionMixin__createItemSelectionSubscriptions() {
// Set up a subscription to handle file selection events, these will be along the lines of
// select all, select none, invert, etc. Each individual selector will respond to these
// events...
if (this.updateOnSelection)
{
this.alfSubscribe(this.documentSelectionTopic, lang.hitch(this, this.onItemSelection), this.getSelectionPublishGlobal(), this.getSelectionPublishToParent());
this.alfSubscribe(this.documentDeselectedTopic, lang.hitch(this, this.onIndividualItemSelection, false), this.getSelectionPublishGlobal(), this.getSelectionPublishToParent());
this.alfSubscribe(this.documentSelectedTopic, lang.hitch(this, this.onIndividualItemSelection, true), this.getSelectionPublishGlobal(), this.getSelectionPublishToParent());
}
},
/**
* Returns whether or not selection subscriptions and publications should be made globally. By default
* this returns [publishGlobal]{@link module:alfresco/renderers/_PublishPayloadMixin#publishGlobal}.
*
* @instance
* @overridable
* @return {boolean} A boolean indicating whether or not to publish and subscribe to selection topics globally.
*/
getSelectionPublishGlobal: function alfresco_lists_ItemSelectionMixin__getSelectionPublishGlobal() {
return this.publishGlobal;
},
/**
* Returns whether or not selection subscriptions and publications should be made globally. By default
* this returns [publishToParent]{@link module:alfresco/renderers/_PublishPayloadMixin#publishToParent}.
*
* @instance
* @overridable
* @return {boolean} A boolean indicating whether or not to publish and subscribe to selection topics to the parent scope.
*/
getSelectionPublishToParent: function alfresco_lists_ItemSelectionMixin__getSelectionPublishToParent() {
return this.publishToParent;
},
/**
* Handles the individual selection or deselection of an object.
*
* @instance
* @param {boolean} select Indicates if this is a selection action
* @param {object} payload The payload containing the details of the item selected
* @param {boolean} [payload.selfProcessing=false] Indicates whether or not to only respond to requests initiated from the current instance
* @param {object} [payload.requester=null] The instance that originated this request
* @param {object} [payload.value] The item to be selected or deselected
*/
onIndividualItemSelection: function alfresco_lists_ItemSelectionMixin__onIndividualItemSelection(select, payload) {
if (!payload.selfProcessing || payload.requester === this)
{
var a = lang.getObject(this.itemKey, false, payload.value);
var b = lang.getObject(this.itemKey, false, this.currentItem);
var match = ((a || a === 0) && a === b);
if (match)
{
if (select)
{
domClass.add(this.domNode, this.selectedCssClass);
}
else
{
domClass.remove(this.domNode, this.selectedCssClass);
}
}
}
},
/**
* Handles selection request events for the following values: "selectAll", "selectNone",
* "selectInvert", "selectFolders" & "selectDocuments". All other selection requests are
* ignored.
*
* @instance
* @param {object} payload The details of the selection request.
*/
onItemSelection: function alfresco_lists_ItemSelectionMixin__onItemSelection(payload) {
// jshint maxcomplexity:false
if (payload)
{
if (payload.value === "selectAll")
{
// Select regardless of current status...
this.select();
}
else if (payload.value === "selectNone")
{
// De-select regardless of current status...
this.deselect();
}
else if (payload.value === "selectInvert")
{
// Invert the current status
// See AKU-1093 - it is important to indicate that selection should only be handled by
// if the ultimate subscriber is the same as the publisher, this ensures that invertion
// does not occur multiple times on a single request.
if (domClass.contains(this.domNode, this.selectedCssClass))
{
this.deselect(true);
}
else
{
this.select(true);
}
}
else if (payload.value === "selectFolders" && this.currentItem && this.currentItem.jsNode)
{
// Select if the current item is a container
if (this.currentItem.jsNode.isContainer)
{
this.select();
}
else
{
this.deselect();
}
}
else if (payload.value === "selectDocuments" && this.currentItem && this.currentItem.jsNode)
{
// Select if the current item is NOT a container
if (this.currentItem.jsNode.isContainer)
{
this.deselect();
}
else
{
this.select();
}
}
else if (payload.selectedItems)
{
// Check to see if the list of selected items contains the item that this instance has
// renderered.
array.some(payload.selectedItems, function(item) {
var a = lang.getObject(this.itemKey, false, item);
var b = lang.getObject(this.itemKey, false, this.currentItem);
var match = ((a || a === 0) && a === b);
if (match) {
domClass.add(this.domNode, this.selectedCssClass);
}
return match;
}, this);
}
}
},
/**
* Updates the CSS classes to indicate that the item has been selected and publishes
* [the topic]{@link module:alfresco/documentlibrary/_AlfDocumentListTopicMixin#documentSelectedTopic}
* to indicate that an item has been selected.
*
* @instance
* @param {boolean} [selfProcessing=false] Indicates whether or not the subscriber should only handle publications made by itself
* @fires module:alfresco/documentlibrary/_AlfDocumentListTopicMixin#documentSelectedTopic
*/
select: function alfresco_lists_ItemSelectionMixin__select(selfProcessing) {
domClass.add(this.domNode, this.selectedCssClass);
this.alfPublish(this.documentSelectedTopic, {
value: this.currentItem,
requester: this,
selfProcessing: selfProcessing
}, this.getSelectionPublishGlobal(), this.getSelectionPublishToParent());
},
/**
* Updates the CSS classes to indicate that the item has been de-selected and publishes
* [the topic]{@link module:alfresco/documentlibrary/_AlfDocumentListTopicMixin#documentDeselectedTopic}
* to indicate that an item has been de-selected.
*
* @instance
* @param {boolean} [selfProcessing=false] Indicates whether or not the subscriber should only handle publications made by itself
* @fires module:alfresco/documentlibrary/_AlfDocumentListTopicMixin#documentDeselectedTopic
*/
deselect: function alfresco_lists_ItemSelectionMixin__deselect(selfProcessing) {
domClass.remove(this.domNode, this.selectedCssClass);
this.alfPublish(this.documentDeselectedTopic, {
value: this.currentItem,
requester: this,
selfProcessing: selfProcessing
}, this.getSelectionPublishGlobal(), this.getSelectionPublishToParent());
},
/**
* If [selectOnClick]{@link module:alfresco/lists/ItemSelectionMixin#selectOnClick} is configured to be
* true then this will call either [deselect]{@link module:alfresco/lists/ItemSelectionMixin#deselect}
* or [select]{@link module:alfresco/lists/ItemSelectionMixin#select} (depending upon the current
* state).
*
* @instance
*/
onSelectionClick: function alfresco_lists_ItemSelectionMixin__onSelectionClick(evt) {
if (this.selectOnClick)
{
evt && event.stop(evt);
if (domClass.contains(this.domNode, this.selectedCssClass))
{
// De-select if currently selected...
this.deselect();
}
else
{
// Select if currently not selected...
this.select();
}
}
}
});
});