/*
* 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.
*/
/**
* This class controls a ribbon button representing the consistency state of a content
* @private
*/
Ext.define('Ametys.plugins.cms.content.controller.ConsistencyController', {
extend: 'Ametys.ribbon.element.ui.button.OpenToolButtonController',
statics: {
/**
* @private
* @readonly
* @property {Number} CACHE_DURATION=60000 Duration in milliseconds of the consistency cache by the client
*/
CACHE_DURATION: 60000,
/**
* @private
* @property {Object} cache Caching results to avoid too many requests
* cache keys are content ids
* cache values are an object with "date" that is the last results date for this content ; "type" contains the key (fully-ok-contents, mainly-ok-contents or not-ok-contents) and "result" that is the results object
*/
cache: {}
},
/**
* @cfg {String} consistency-ok-icon-decorator The CSS glass for icon decorator when the consistency of selected contents is ok
*/
/**
* @property {String} _okIconDecorator See #cfg-consistency-ok-icon-decorator
* @private
*/
/**
* @cfg {String} consistency-warning-icon-decorator The CSS glass for icon decorator when the consistency check has failed for at least one of selected contents.
*/
/**
* @property {String} _warnIconDecorator See #cfg-consistency-warning-icon-decorator
* @private
*/
/**
* @cfg {String} consistency-error-icon-decorator The CSS glass for icon decorator when the consistency check has failed for all selected contents.
*/
/**
* @property {String} _errorIconDecorator See #cfg-consistency-error-icon-decorator
* @private
*/
/**
* @cfg {String} consistency-okbut-icon-decorator The CSS glass for icon decoratorwhen the consistency check succeed but some links can not be checked.
*/
/**
* @property {String} _okButIconDecorator See #cfg-consistency-okbut-icon-decorator
* @private
*/
constructor: function(config)
{
this.callParent(arguments);
this._okIconDecorator = this.getInitialConfig("consistency-ok-icon-decorator");
this._warnIconDecorator = this.getInitialConfig("consistency-warning-icon-decorator");
this._errorIconDecorator = this.getInitialConfig("consistency-error-icon-decorator");
this._okButIconDecorator = this.getInitialConfig("consistency-okbut-icon-decorator");
Ametys.message.MessageBus.on(Ametys.message.Message.MODIFIED, this._onEdited, this);
Ametys.message.MessageBus.on(Ametys.message.Message.DELETED, this._onDeleted, this);
},
/**
* Listener when the content has changed.
* Will update the lock state of the buttons effectively upon the current selection.
* Will remove contents modified from cache
* @param {Ametys.message.Message} message The MODIFIED message.
* @protected
*/
_onEdited: function (message)
{
if (this.updateTargetsInCurrentSelectionTargets (message))
{
this.refresh();
}
this._removeFromCache(message);
},
/**
* Listener when the contet was removed.
* Will remove contents modified from cache
* @param {Ametys.message.Message} message The DELETED message.
* @protected
*/
_onDeleted: function(message)
{
this._removeFromCache(message);
},
/**
* @private
* Remove contents corresponding to the message from cache
* @param {Ametys.message.Message} message A bus message
*/
_removeFromCache: function(message)
{
var targets = this._getMatchingSelectionTargets(message);
for (var i = 0; i < targets.length; i++)
{
var contentId = targets[i].getParameters().id;
Ametys.plugins.cms.content.controller.ConsistencyController.cache[contentId] = null;
}
},
updateState: function()
{
this.enable();
this._checkConsistency(this.getMatchingTargets());
},
/**
* Get the lock state of given targets
* @param {Ametys.message.MessageTarget[]} targets The content targets
* @private
*/
_checkConsistency: function (targets)
{
var now = new Date().getTime()
var contentIds = [];
var cachedContentIds = [];
for (var i=0; i < targets.length; i++)
{
var contentId = targets[i].getParameters().id;
// Avoid cached
if (!Ametys.plugins.cms.content.controller.ConsistencyController.cache[contentId]
|| Ametys.plugins.cms.content.controller.ConsistencyController.cache[contentId].date + Ametys.plugins.cms.content.controller.ConsistencyController.CACHE_DURATION < now)
{
contentIds.push(contentId);
}
else
{
cachedContentIds.push(contentId);
}
}
if (contentIds.length > 0)
{
this.serverCall ('checkConsistency', [contentIds, true], Ext.bind(this._checkConsistencyCb, this, [cachedContentIds], 1), { priority: Ametys.data.ServerComm.PRIORITY_LONG_REQUEST, errorMessage: true, refreshing: true });
}
else
{
this._checkConsistencyCb(null, cachedContentIds);
}
},
/**
* @private
* Callback function called after checking consistency of content targets
* @param {Object} params The JSON result
* @param {Object} options The cb options
* @param {String[]} options.cachedContentIds The id of the contents that are to handle and that already are in the cache
*/
_checkConsistencyCb: function (params, cachedContentIds)
{
// Put params in cache
var now = new Date().getTime()
Ext.Object.each(params || {}, function(key, value) {
for (var i = 0; i < value.length; i++)
{
var contentId = value[i].id;
Ametys.plugins.cms.content.controller.ConsistencyController.cache[contentId] = {
"date": now,
"type": key,
"result": Ext.clone(value[i])
}
}
})
// Merge cached infos
var mergedParams = Ext.clone(params || { "mainly-ok-contents": [], "not-ok-contents": [], "fully-ok-contents": [], "no-right-contents": []});
var oldestInfo = 0;
for (var i = 0; i < cachedContentIds.length; i++)
{
var contentId = cachedContentIds[i];
// Test to ensure that cache entry was not removed in the meanwhile
if (Ametys.plugins.cms.content.controller.ConsistencyController.cache[contentId])
{
mergedParams[Ametys.plugins.cms.content.controller.ConsistencyController.cache[contentId].type].push(Ext.clone(Ametys.plugins.cms.content.controller.ConsistencyController.cache[contentId].result))
if (oldestInfo == 0 || oldestInfo > Ametys.plugins.cms.content.controller.ConsistencyController.cache[contentId].date)
{
oldestInfo = Ametys.plugins.cms.content.controller.ConsistencyController.cache[contentId].date
}
}
}
// Apply result
this._updateTooltipDescription("", mergedParams, oldestInfo);
this._updateIcon (mergedParams);
},
/**
* @private
* Update the tooltip description after checking consistency of content targets
* @param {String} description The initial description
* @param {Object} params The JSON result
* @param {Number} oldestInfo The oldest information taken from cache
*/
_updateTooltipDescription: function (description, params, oldestInfo)
{
var fullyOkContents = params["fully-ok-contents"];
var mainlyOkContents = params["mainly-ok-contents"];
var notOkContents = params["not-ok-contents"];
var noRightContents = params["no-right-contents"];
if (fullyOkContents.length > 0)
{
description = this._getContentsDescription(description, fullyOkContents, "ok");
}
if (mainlyOkContents.length > 0)
{
description = this._getContentsDescription(description, mainlyOkContents, "okbut");
}
if (notOkContents.length > 0)
{
description = this._getContentsDescription(description, notOkContents, "error");
}
if (noRightContents.length > 0)
{
description = this._getContentsDescription(description, noRightContents, "no-right");
}
if (oldestInfo != 0)
{
description += "<br/><br/>{{i18n CONTENT_CONSISTENCY_DESCRIPTION_FROMCACHE}}".replace(/\{0\}/g, Ext.Date.format(new Date(oldestInfo), Ext.Date.patterns.ShortTime));
}
this.setDescription (description);
},
/**
* Completes the contents description
* @param {String} description The starting description
* @param {Object} contents The contents in a JSON object
* @param {String} type The type
* @returns {String} The completed description
* @private
*/
_getContentsDescription : function (description, contents, type)
{
if (description != "")
{
description += "<br/><br/>";
}
description += this.getInitialConfig("consistency-" + type + "-content-start-description");
for (var i=0; i < contents.length; i++)
{
if (i != 0)
{
description += ", ";
}
description += contents[i].title
+ ((contents[i].description != contents[i].title) ? " (" + contents[i].description + ")" : "");
}
description += this.getInitialConfig("consistency-" + type + "-content-end-description");
return description;
},
/**
* @private
* Update the icons after checking consistency of content targets
* @param {Object} params The JSON result
*/
_updateIcon: function (params)
{
var fullyOkContents = params["fully-ok-contents"];
var mainlyOkContents = params["mainly-ok-contents"];
var notOkContents = params["not-ok-contents"];
if (notOkContents.length > 0 && fullyOkContents.length == 0)
{
this.setIconDecorator(this._errorIconDecorator);
}
else if (notOkContents.length > 0 && fullyOkContents.length > 0)
{
this.setIconDecorator(this._warnIconDecorator);
}
else if (mainlyOkContents.length > 0)
{
this.setIconDecorator(this._okButIconDecorator);
}
else if (fullyOkContents.length > 0)
{
this.setIconDecorator(this._okIconDecorator);
}
},
disable:function()
{
this.setIconDecorator();
this.setDescription(this.getInitialConfig('description'));
this.callParent(arguments);
}
});