/*
* Copyright 2013 Anyware Services
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @private
* This class control a ribbon menu representing the workflow state.
* It HAS to be used in conjunction with the java org.ametys.cms.clientsideelement.WorkflowStepsClientSideElement
*/
Ext.define('Ametys.plugins.cms.content.controller.WorkflowMenu', {
extend: 'Ametys.ribbon.element.ui.ButtonController',
/**
* @property {String} workflowItems The name of items concerned by this workflow
*/
workflowItems: 'contents',
/**
* @property {Boolean} _visible The current visible state for the menu
* @private
*/
constructor: function (config)
{
config['toggle-enabled'] = true;
this.callParent(arguments);
this._visible = true;
Ametys.message.MessageBus.on(Ametys.message.Message.WORKFLOW_CHANGING, this._onWorkflowChanging, this);
Ametys.message.MessageBus.on(Ametys.message.Message.LOCK_CHANGED, this.refreshIfMatchingMessage, this);
Ametys.message.MessageBus.on(Ametys.message.Message.WORKFLOW_CHANGED, this._onWorkflowChanged, this);
},
/**
* @private
* Listener on workflow changing. Set buttons in refreshing state
* @param {Ametys.message.Message} message The bus message
*/
_onWorkflowChanging: function (message)
{
if (this.updateTargetsInCurrentSelectionTargets (message))
{
this.refreshing();
}
},
/**
* @private
* Listener on workflow changed. Stop the refreshing state and refresh
* @param {Ametys.message.Message} message The bus message
*/
_onWorkflowChanged: function (message)
{
if (this.updateTargetsInCurrentSelectionTargets (message))
{
this.stopRefreshing();
this.refresh(true);
}
},
updateState: function()
{
this.stopRefreshing(true);
this._getWorkflowState(this.getMatchingTargets());
},
/**
* Get the lock state of given targets
* @param targets The content targets
* @private
*/
_getWorkflowState: function (targets)
{
var workflowName = this.getInitialConfig("workflow-name");
// Avoid workflow button to be updated if the content is not of the concerned workflow
var matchingTargets = Ext.Array.filter(targets, function (target) {
return !target.getParameters().workflowName || target.getParameters().workflowName == workflowName;
}, this);
if (matchingTargets.length > 0)
{
this.disable();
var result = this._calculateStatus(targets);
this._getWorkflowStateCb(result);
}
else
{
// There is no target matching the concerned workflow, hide button
this._hide();
}
},
/**
* @protected
* Simulation of getStatus server side, done only client-side.
* In cases where the server side still needs to be called, see Ametys.plugins.cms.content.controller.SmartContentController#_getStatus
* @param {Object[]} targets see Ametys.ribbon.element.ui.CommonController#getMatchingTargets
* @return {Object} a map of arrays representing contents in different states. default is unmodifiable-contents, locked-contents, noright-contents, invalidworkflowaction-contents,invalidworkflowstep-contents, allright-contents
*/
_calculateStatus: function(targets)
{
var result = {};
result["contents"] = [];
var invalidWorkflowForAllContents = true;
Ext.Array.each(targets, function(matchingTarget)
{
var parameters = matchingTarget.getParameters();
if (parameters && parameters.content)
{
var content = parameters.content;
if (this.getInitialConfig("workflow-name") == content.getWorkflowName())
{
invalidWorkflowForAllContents = false;
if (content.getWorkflowSteps() != null && content.getWorkflowSteps().indexOf(this.getInitialConfig("workflow-step")) >= 0)
{
var contentParams = {};
contentParams["id"] = content.getId();
contentParams["title"] = content.getTitle();
var description;
if (content.getLocked() && !this._isLockOwner(content))
{
var i18nStr = "{{i18n plugin.cms:CONTENT_WORKFLOW_LOCKED_DESCRIPTION}}";
var lockOwner = content.getLockOwner();
var fullName = lockOwner != null ? lockOwner.fullname : "";
var login = lockOwner != null ? lockOwner.login : "Anonymous";
description = Ext.String.format(i18nStr, content.getTitle(), fullName, login);
}
else
{
var i18nStr = "{{i18n plugin.cms:CONTENT_WORKFLOW_DESCRIPTION}}";
description = Ext.String.format(i18nStr, content.getTitle());
}
contentParams["description"] = description;
contentParams["locked"] = content.getLocked();
var availableActions = content.getAvailableActions();
contentParams["actions"] = availableActions;
result["contents"].push(contentParams);
}
}
}
}, this);
if (invalidWorkflowForAllContents)
{
result["invalidWorkflow"] = true;
}
return result;
},
/**
* @private
* Is the given locked content, locked by the current user?
* @param {Ametys.cms.content.Content} content A locked content
* @return {Boolean} true is the current user is the locker.
*/
_isLockOwner: function (content)
{
var currentUser = Ametys.getAppParameter('user');
var lockOwner = content.getLockOwner();
return currentUser.login === lockOwner.login && currentUser.population === lockOwner.populationId;
},
/**
* @private
* Callback function called after retrieving the workflow state of content targets
* @param params The JSON result
*/
_getWorkflowStateCb: function (params)
{
if (params && params[this.workflowItems].length > 0)
{
// Workflow actions of menu items
var hasActionEnabled = false;
var menuitems = this.getInitialConfig("menu-items") ? this.getInitialConfig("menu-items") : [];
if (menuitems.length > 0)
{
var menuActions = {};
for (var i=0; i < menuitems.length; i++)
{
var item = Ametys.ribbon.RibbonManager.getUI(menuitems[i]);
var actionId = item.getInitialConfig("workflow-action-id");
menuActions[actionId] = [];
}
var contents = params[this.workflowItems];
for (var i=0; i < contents.length; i++)
{
var actions = contents[i].actions;
for (var actionId in menuActions)
{
if (Ext.Array.contains (actions, parseInt(actionId)))
{
menuActions[actionId].push(contents[i].id);
}
}
}
for (var i=0; i < menuitems.length; i++)
{
var item = Ametys.ribbon.RibbonManager.getUI(menuitems[i]);
var actionId = item.getInitialConfig("workflow-action-id");
var multiSelectionEnabled = item.getInitialConfig("selection-enable-multiselection") != "false";
if (menuActions[actionId].length > 0 && (multiSelectionEnabled || contents.length == 1))
{
item.enable();
item[this.workflowItems] = menuActions[actionId];
hasActionEnabled = true;
}
else
{
item.contents = [];
item.disable()
}
}
}
var description = this._getTooltipDescription (this.getInitialConfig("description"), params);
if (!hasActionEnabled && menuitems.length > 0)
{
description += '<br/><br/>';
description += this.getInitialConfig("noaction-available-description");
}
this.setDescription (description);
this.toggle(true);
this._show();
this[hasActionEnabled || menuitems.length == 0 ? 'enable' : 'disable'](); // enable or disable
}
else
{
this.setDescription (this.getInitialConfig("description") + '<br/><br/>' + this.getInitialConfig("selection-description-nomatch"));
this.toggle(false);
this.disable();
this[params.invalidWorkflow ? '_hide' : '_show'](); // hide or show
}
},
/**
* Show all controlled ui
*/
_show: function()
{
if (!this._visible)
{
this._visible = true;
this.getUIControls().each(function (controller) {
controller.show();
});
}
},
/**
* Hide all controlled ui
*/
_hide: function()
{
if (this._visible)
{
this._visible = false;
this.getUIControls().each(function (controller) {
controller.hide();
});
}
},
/**
* @private
* Get the tooltip description according to workflow state of the current selection
* @return The description
*/
_getTooltipDescription: function (description, params)
{
var contents = params["contents"];
if (contents.length > 0)
{
if (description != "")
{
description += "<br/><br/>";
}
description += this.getInitialConfig("contentselected-start-description");
for (var i=0; i < contents.length; i++)
{
if (i != 0)
{
description += ", ";
}
description += contents[i].description;
}
description += this.getInitialConfig("contentselected-end-description");
}
return description;
}
});