/*
* Copyright 2010 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 tool displays the consistency report for a content
* @private
*/
Ext.define('Ametys.plugins.cms.content.tool.ConsistencyTool', {
extend: "Ametys.tool.SelectionTool",
statics: {
/**
* @property
* @private
* @static {Object} The tips
*/
_tips: {
'unknown': "{{i18n UITOOL_CONSISTENCY_TOOLTIP_UNKNOWN}}",
'success': "{{i18n UITOOL_CONSISTENCY_TOOLTIP_SUCCESS}}",
'unauthorized': "{{i18n UITOOL_CONSISTENCY_TOOLTIP_UNAUTHORIZED}}",
'not-found': "{{i18n UITOOL_CONSISTENCY_TOOLTIP_NOT_FOUND}}",
'server-error': "{{i18n UITOOL_CONSISTENCY_TOOLTIP_SERVER_ERROR}}",
'detail-message': "{{i18n UITOOL_CONSISTENCY_TOOLTIP_MESSAGE_DETAILS}}"
}
},
/**
* @property {Ext.Template} pathTpl The template used to display the metadata path for each group of consistencies. Defaults to '<h2>{0}</h2>'
*/
pathTpl: Ext.create('Ext.XTemplate', '<p class="metadata-path"><strong>{0}</strong></p>'),
/**
* @property {Ext.Template} linkTpl The template used for displaying link. Defaults to '<p><img title="{type}" src="{icon}"/>{link}</p>'
*/
linkTpl: Ext.create('Ext.XTemplate', '<p><span class="{iconCls}" title="{type}<tpl if="message">.\n{message}</tpl>"></span>{link}</p>'),
/**
* @private
* @property {Boolean} _showAllLinks true to show only broken links
*/
_showAllLinks: false,
/**
* @cfg {String} showAllLinksButtonIconCls The separated CSS classes to apply to button to show all links
*/
showAllLinksButtonIconCls: 'ametysicon-code-html-link',
/**
* @cfg {String} showAllLinksButtonTooltip Tooltip of the button to show all links
*/
showAllLinksButtonTooltip: "{{i18n UITOOL_CONSITENCY_SHOW_ALL_LINKS}}",
/**
* @cfg {String} showOnlyBrokenLinksButtonIconCls The separated CSS classes to apply to button to hide sucessful links
*/
showOnlyBrokenLinksButtonIconCls: 'ametysicon-code-html-link-broken',
/**
* @cfg {String} showOnlyBrokenLinksButtonTooltip Tooltip of the button to hide empty sucessful links
*/
showOnlyBrokenLinksButtonTooltip: "{{i18n UITOOL_CONSITENCY_SHOW_ONLY_BROKEN_LINKS}}",
constructor: function(config)
{
this.callParent(arguments);
Ametys.message.MessageBus.on(Ametys.message.Message.WORKFLOW_CHANGED, this._onEdited, this);
Ametys.message.MessageBus.on(Ametys.message.Message.DELETED, this._onDeleted, this);
},
createPanel: function()
{
return Ext.create('Ext.Panel', {
border: false,
scrollable: false,
cls: 'consistency-tool',
layout: 'card',
activeItem: 0,
items: [{
xtype: 'component',
cls: 'a-panel-text-empty',
html: '',
hidden: true
},
{
flex: 1,
border: false,
scrollable: true,
xtype: 'panel',
itemId: 'content-links',
html: '',
bodyStyle: {
padding: '5px'
},
dockedItems: this._getTopPanel()
}
]
});
},
/**
* @protected
* Get the top panel for hint and actions
* @return {Ext.Panel} the top panel
*/
_getTopPanel: function ()
{
return Ext.create({
dock: 'top',
xtype: 'container',
layout: {
type: 'hbox',
align: 'middle'
},
cls: 'top',
items: [
{
// hint
xtype: 'component',
itemId: 'content-info',
cls: 'hint',
html: '',
flex: 1
},
{
// show only broken links
xtype: 'button',
iconCls: this.showAllLinksButtonIconCls,
tooltip: this.showAllLinksButtonTooltip,
scope: this,
enableToggle: true,
toggleHandler: this.showAllLinks,
cls: 'a-btn-light'
}
]
});
},
showAllLinks: function(btn, state)
{
this._showAllLinks = state;
if (this._showAllLinks)
{
btn.setIconCls(this.showOnlyBrokenLinksButtonIconCls);
btn.setTooltip(this.showOnlyBrokenLinksButtonTooltip)
}
else
{
btn.setIconCls(this.showAllLinksButtonIconCls);
btn.setTooltip(this.showAllLinksButtonTooltip);
}
this.refresh();
},
setParams: function (params)
{
this.callParent(arguments);
this.refresh();
},
refresh: function (manual)
{
this.showRefreshing();
var contentTarget = this.getCurrentSelectionTargets().length > 0 ? this.getCurrentSelectionTargets()[0] : null;
if (contentTarget != null)
{
this._contentId = contentTarget.getParameters().id;
var params = {contentsId: [this._contentId]};
Ametys.data.ServerComm.send({
plugin: 'cms',
url: 'consistency/check.xml',
parameters: params,
priority: Ametys.data.ServerComm.PRIORITY_LONG_REQUEST,
callback: {
handler: this._refreshCallback,
scope: this,
arguments: [this._contentId]
}
});
}
else
{
// Nothing to do.
// Do not use the noSelectionMatch method to avoid erasing the current message
this.showRefreshed();
}
},
/**
* @private
* This function is called after check links is processed. Update the tool.
*/
_refreshCallback : function (response, args)
{
var contentId = args[0];
var currentTarget = this.getCurrentSelectionTargets().length > 0 ? this.getCurrentSelectionTargets()[0] : null;
if (currentTarget == null || currentTarget.getParameters().id != contentId)
{
// too late => discard (another content has been selected)
return;
}
if (Ametys.data.ServerComm.handleBadResponse("{{i18n UITOOL_CONSISTENCY_ERROR}} '" + contentId + "'", response, 'Ametys.plugins.cms.content.tool.ConsistencyTool'))
{
this.showRefreshed();
return;
}
var html = '';
// If we only want to see the broken links, then set the "sucessType" to an empty string in order to not get the valid links
var successTypeOrEmpty = "";
if (this._showAllLinks)
{
// If we want all the links, set the sucessType to "sucess" in order to retrieve the valid links
successTypeOrEmpty = "> success";
}
var contents = Ext.dom.Query.select("contents/content", response);
for (var i = 0; i < contents.length; i++)
{
var content = contents[i];
if (Ext.dom.Query.selectDirectElements("no-right", content).length != 0)
{
var panel = this.getContentPanel().items.get(0);
panel.update(this.getInitialConfig("selection-description-noright"));
this.getContentPanel().getLayout().setActiveItem(0);
}
else
{
this.getContentPanel().down("#content-info").update((this._showAllLinks ? "{{i18n UITOOL_CONSISTENCY_HINT_TEXT}}" : "{{i18n UITOOL_CONSISTENCY_HINT_TEXT2}}") + '<b>' + Ext.String.escapeHtml(content.getAttribute("title")) + '</b>');
// Preparing metadata definition labels
var metadataDef2Labels = {};
var metadataDefinitions = Ext.dom.Query.select("> metadata-definition", content),
metadataDefinition;
for (var j = 0; j < metadataDefinitions.length; j++)
{
metadataDefinition = metadataDefinitions[j];
metadataDef2Labels[Ext.dom.Query.selectValue('@path', metadataDefinition)] = {
label: Ext.dom.Query.selectValue('', metadataDefinition),
isRepeater: Ext.dom.Query.selectValue('@is-repeater', metadataDefinition) == 'true'
};
}
var consistenciesArray = Ext.Array.merge(Ext.dom.Query.select("> unknown", content),
Ext.dom.Query.select("> not-found", content),
Ext.dom.Query.select("> unauthorized", content),
Ext.dom.Query.select("> server-error", content));
if (successTypeOrEmpty != "")
{
consistenciesArray = Ext.Array.merge(Ext.dom.Query.select(successTypeOrEmpty, content),
consistenciesArray)
}
var consistencies = consistenciesArray, consistency, path, consistenciesByPath = {};
for (var j = 0; j < consistencies.length; j++)
{
consistency = consistencies[j];
path = Ext.dom.Query.selectValue('@path', consistency);
consistenciesByPath[path] = consistenciesByPath[path] || [];
consistenciesByPath[path].push(consistency);
}
// Loop on consistency grouped by path;
var type, parts, currentPath, fullLabel, labelInfo, label;
Ext.Object.each(consistenciesByPath, function(path, consistencies) {
// Evaluate metadata path label.
parts = path.split('/'), currentPath = '', fullLabel = [];
Ext.Array.forEach(parts, function(part) {
currentPath += (currentPath ? '/' : '') + part;
labelInfo = metadataDef2Labels[currentPath] || {};
fullLabel.push(labelInfo.label || '');
});
html += this.pathTpl.applyTemplate([fullLabel.join(' > ')]);
Ext.Array.forEach(consistencies, function(consistency) {
type = consistency.nodeName;
var values = {
link: Ext.dom.Query.selectValue("> label", consistency),
type: Ametys.plugins.cms.content.tool.ConsistencyTool._tips[type],
iconCls: this._getIconCls(type)
};
if (type == "server-error")
{
var message = Ext.dom.Query.selectValue("> message", consistency);
if (message)
{
values['message'] = Ametys.plugins.cms.content.tool.ConsistencyTool._tips['detail-message'] + message;
}
}
html += this.linkTpl.applyTemplate(values);
}, this);
}, this);
if (html == '')
{
html = this._showAllLinks ? "{{i18n UITOOL_CONSISTENCY_NOLINKS}}" : "{{i18n UITOOL_CONSISTENCY_NOBROKENLINKS}}";
}
this.getContentPanel().down("#content-links").update(html);
this.getContentPanel().getLayout().setActiveItem(1);
}
}
this.showRefreshed();
},
/**
* @private
* Get the separated CSS classes to apply to the link
* @param {String} type The type of the link
* @return {String} The CSS classes
*/
_getIconCls: function (type)
{
switch (type)
{
case "success":
return "ametysicon-check34 link-glyph link-ok";
case "unknown":
return "ametysicon-question13 link-glyph link-warn";
case "server-error":
return "ametysicon-letter-x5 link-glyph link-error";
case "not-found":
return "ametysicon-alert9 link-glyph link-error";
case "unauthorized":
return "ametysicon-forbidden1 link-glyph link-error";
default:
return "";
}
},
setNoSelectionMatchState: function (message)
{
this.callParent(arguments);
var panel = this.getContentPanel().items.get(0);
panel.update(message);
this.getContentPanel().getLayout().setActiveItem(0);
this._contentId = null;
},
/**
* Listener on {@link Ametys.message.Message#WORKFLOW_CHANGED} message. If the current
* content is concerned, the tool will be out-of-date.
*
* @param {Ametys.message.Message} message The workflow changed message.
* @protected
*/
_onEdited: function (message)
{
if (this.getTargetsInCurrentSelectionTargets(message).length > 0)
{
this.showOutOfDate();
}
},
/**
* Listener on {@link Ametys.message.Message#DELETED} message. If the current content is concerned, the tool will be set in no selection mode.
* @param {Ametys.message.Message} message The deleted message.
* @protected
*/
_onDeleted: function (message)
{
if (this.getTargetsInCurrentSelectionTargets(message).length > 0)
{
this.setNoSelectionMatchState("{{i18n UITOOL_CONSISTENCY_SELECT_CONTENT}}");
}
}
});