/*
* 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 handles the access to content properties. See {@link Ametys.cms.content.Content}
*/
Ext.define(
"Ametys.cms.content.ContentDAO",
{
singleton: true,
/**
* @private
* @property {String} _contentDAOClassName The java class name for contents DAO.
*/
_contentDAOClassname: 'org.ametys.cms.repository.ContentDAO',
/**
* Retrieve a content by its id
* @param {String} id The content identifier. Cannot be null.
* @param {Function} callback The callback function called when the content is retrieved. Can be null for synchronous mode (not recommended!). Parameters are
* @param {Ametys.cms.content.Content} callback.content The content retrieved. Can be null if content does not exist.
* @param {String} [workspaceName] The JCR workspace name
* @param {Object} [errorMessage] The error message
* @return {Ametys.cms.content.Content} The content retrieved if no callback function is specified or null otherwise.
*/
getContent: function (id, callback, workspaceName, errorMessage)
{
if (Ext.isEmpty(id))
{
callback(null);
return;
}
this._sendRequest ([id], Ext.bind(this._getContentCb, this, [callback], 1), workspaceName, errorMessage);
},
/**
* @private
* Callback function called after #getContent is processed
* @param {Ametys.cms.content.Content[]} contents The contents retrieved
* @param {Function} callback The callback function called
*/
_getContentCb: function (contents, callback)
{
callback((contents.length == 0) ? null : contents[0]);
},
/**
* Retrieve contents by their ids
* @param {String[]} ids The contents identifiers. Cannot be null.
* @param {Function} callback The callback function called when the content is retrieved. Can be null for synchronous mode (not recommended!). Parameters are
* @param {Ametys.cms.content.Content} callback.content The content retrieved. Can be null if content does not exist.
* @param {String} [workspaceName] The JCR workspace name
* @param {Object} [errorMessage] The error message
* @return {Ametys.cms.content.Content} The content retrieved if no callback function is specified or null otherwise.
*/
getContents: function (ids, callback, workspaceName, errorMessage)
{
if (Ext.isEmpty(ids))
{
callback([]);
return;
}
this._sendRequest (ids, Ext.bind(this._getContentsCb, this, [callback], 1), workspaceName, errorMessage);
},
/**
* @private
* Callback function called after #getContents is processed
* @param {Ametys.cms.content.Content[]} contents The contents retrieved
* @param {Function} callback The callback function called
*/
_getContentsCb: function (contents, callback)
{
callback(contents);
},
/**
* @private
* Send request to server to retrieved contents
* @param {String[]} ids The id of contents to retrieve
* @param {Function} callback The callback function to be called after server process
* @param {String} [workspaceName] The JCR workspace name
* @param {Object} [errorMessage] The error message to use
*/
_sendRequest: function (ids, callback, workspaceName, errorMessage)
{
if (errorMessage === undefined)
{
errorMessage = "{{i18n DAOS_CONTENT_ERROR}}";
}
Ametys.data.ServerComm.callMethod({
role: this._contentDAOClassname,
methodName: "getContentsProperties",
parameters: [ids, workspaceName],
callback: {
scope: this,
handler: this._getContentsCB,
arguments: [callback, errorMessage === false]
},
errorMessage: errorMessage
});
},
/**
* @private
* Callback function called after #_sendRequest is processed
* @param {Object} result The server response
* @param {String[]} result.contents Contents ids that were found
* @param {String[]} result.contentsNotFound Contents ids that were not found
* @param {Array} arguments The callback arguments.
*/
_getContentsCB: function (result, arguments)
{
var contents = [];
var contentsCfg = result.contents;
if (this.getLogger().isDebugEnabled())
{
this.getLogger().debug(contentsCfg.length + " content(s) get from server and " + result.contentsNotFound.length + " content(s) where not found");
}
for (var i=0; i < contentsCfg.length; i++)
{
contents.push(Ext.create ('Ametys.cms.content.Content', contentsCfg[i]));
}
var contentsNotFound = result.contentsNotFound;
if (contentsNotFound.length > 0
&& !arguments[1]) // skip error message
{
Ametys.log.ErrorDialog.display({
title: "{{i18n DAOS_CONTENT_NOT_FOUND}}",
text: "{{i18n DAOS_CONTENT_NOT_FOUND_HINT}}",
details: contentsNotFound.join(", "),
category: this.self.getName()
});
}
if (typeof arguments[0] == 'function')
{
arguments[0] (contents);
}
},
/**
* Create a content
* @param {Object} config Parameters for content creation.
* @param {String} config.contentType (required) The type of the content to create.
* @param {String} config.contentTitle (required) The title of the content to create.
* @param {String} [config.contentName] The name of the content to create. If null #config.contentTitle will be used.
* @param {String} config.contentLanguage The language of the content to create.
* @param {Number} [config.initWorkflowActionId=1] The id of the workflow initialization action.
* @param {Number} [config.initAndEditWorkflowActionId=11] The id of the workflow initialization action followed by edition.
* @param {Number} [config.editWorkflowActionId=2] The id of the workflow edit action if creation is followed by edition.
* @param {String} [config.workflowName] The content workflow name. If empty the content type default worflow name will be used.
* @param {String} [config.rootContentPath] When creating a content under a specific root contents.
* @param {Object} [config.additionalWorkflowParameters] Additional workflow parameters to be added to the server request. All request parameters will be prefixed by "workflow-".
* @param {String} [config.viewName=creation] The view to use for content creation.
* @param {Function} callback The callback function invoked when the content has been created. The callback function will received the following parameters:
* @param {String/Ametys.cms.content.Content} callback.content The created content as an id or a {@link Ametys.cms.content.Content}. See #config.fullContents
* @param {Object} [scope=window] The callback scope, default to window.
* @param {Boolean} [fullContents=false] If `true`, the callback function receives a Content object as argument. If `false`, only the content id is provided.
* @param {String} [contentMessageTargetType=Ametys.message.MessageTarget#CONTENT] The message target factory role to use for the event of the bus thrown after content creation
* @param {String} [parentContentMessageTargetType=Ametys.message.MessageTarget#CONTENT] The message target factory role to use for the event of the bus thrown after parent content modification if applyable
* @param {Ext.Component} [waitMsgCmp] The component that will be masked by the wait message
* @param {Boolean} [auto] True if it is an automatic creation (ie. user did not choose the values of the content fields)
*/
createContent: function (config, callback, scope, fullContents, contentMessageTargetType, parentContentMessageTargetType, waitMsgCmp, auto)
{
// type, name and language are mandatory.
if (!config.contentType || !config.contentLanguage || !config.contentTitle || (Ext.isObject(config.contentTitle) && !config.contentTitle[config.contentLanguage]))
{
Ametys.log.ErrorDialog.display({
title: "{{i18n DAOS_CONTENT_CREATE_CONFIGURATION_ERROR_TITLE}}",
text: "{{i18n DAOS_CONTENT_CREATE_CONFIGURATION_ERROR_MSG}}",
category: Ext.getClassName(this) + '.createContent'
});
// Call the callback with a null argument.
return (callback || Ext.emptyFn).call(scope || window, null);
}
var params = {
'workflow-org.ametys.cms.workflow.CreateContentFunction$contentLanguage': config.contentLanguage,
'workflow-org.ametys.cms.workflow.CreateContentFunction$contentType': config.contentType,
};
if (config.workflowName)
{
params['workflow-workflowName'] = config.workflowName;
}
if (Ext.isObject(config.contentTitle))
{
params['workflow-org.ametys.cms.workflow.CreateContentFunction$contentTitleVariants'] = Ext.JSON.encode(config.contentTitle);
params['workflow-org.ametys.cms.workflow.CreateContentFunction$contentName'] = config.contentName || config.contentTitle[config.contentLanguage];
}
else
{
params['workflow-org.ametys.cms.workflow.CreateContentFunction$contentTitle'] = config.contentTitle;
params['workflow-org.ametys.cms.workflow.CreateContentFunction$contentName'] = config.contentName || config.contentTitle;
}
if (config.rootContentPath)
{
params['workflow-org.ametys.cms.workflow.CreateContentFunction$rootContentPath'] = config.rootContentPath;
}
Ext.Object.each(config.additionalWorkflowParameters, function(key, value) {
params['workflow-' + key] = value;
});
var actionId = config.initWorkflowActionId || 1;
var createContentCb = this._createContentCb;
if (config.editFormValues && !Ext.Object.isEmpty(config.editFormValues))
{
actionId = config.initAndEditWorkflowActionId || 11;
var editParams = {};
editParams.values = config.editFormValues;
editParams.quit = true;
editParams['content.view'] = (config.viewName !== undefined ? config.viewName : 'creation'); // config.viewName can be null so a view will be created using the values
// FIXME CMS-9700 Single workflow action for initialization and edition (for the future)
Ext.applyIf(params, editParams);
params.values = config.editFormValues;
params.quit = true;
params['content.view'] = (config.viewName !== undefined ? config.viewName : 'creation'); // config.viewName can be null so a view will be created using the values
var editActionId = config.editWorkflowActionId || 2;
createContentCb = Ext.bind(this._createContentCb2, this, [editActionId, editParams, waitMsgCmp], true);
}
Ametys.data.ServerComm.send({
plugin: 'cms',
url: 'init-workflow/' + actionId,
parameters: params,
priority: Ametys.data.ServerComm.PRIORITY_MAJOR,
waitMessage: {msg: "{{i18n DAOS_CONTENT_CREATE_REQUEST_WAIT}}", target: waitMsgCmp},
errorMessage: {
msg: "{{i18n DAOS_CONTENT_CREATE_REQUEST_ERROR}}",
category: Ext.getClassName(this) + '.createContent'
},
callback: {
scope: this,
handler: createContentCb,
arguments: {
callback: callback || Ext.emptyFn,
scope: scope || window,
fullContents: fullContents || false,
contentMessageTargetType: contentMessageTargetType || Ametys.message.MessageTarget.CONTENT,
parentContentMessageTargetType: parentContentMessageTargetType || Ametys.message.MessageTarget.CONTENT,
parentContentId: config.parentContentId,
auto: auto
}
}
});
},
/**
* @private
* Callback function called after #createContent server request is processed
* @param {HTMLElement} response The XML document.
* @param {Object} params The callback arguments (see #createContent documentation).
*/
_createContentCb: function (response, params)
{
var success = Ext.dom.Query.selectValue ('> ActionResult > success', response) == "true";
// Handle workflow errors
var workflowErrors = Ext.dom.Query.select ('> ActionResult > workflowValidation > error', response);
if (!success && workflowErrors.length > 0)
{
var detailedMsg = '<ul>';
for (var i=0; i < workflowErrors.length; i++)
{
var errorMsg = Ext.dom.Query.selectValue("", workflowErrors[i]);
detailedMsg += '<li>' + errorMsg + '</li>';
}
detailedMsg += '</ul>';
Ametys.Msg.show({
title: "{{i18n DAOS_CONTENT_CREATE_REQUEST_ERROR}}",
msg: "{{i18n DAOS_CONTENT_CREATE_REQUEST_ERROR}}" + detailedMsg,
buttons: Ext.Msg.OK,
icon: Ext.Msg.ERROR
});
return;
}
var contentId = Ext.dom.Query.selectValue("> ActionResult > contentId", response);
if (params.parentContentId)
{
Ext.create("Ametys.message.Message", {
type: Ametys.message.Message.MODIFIED,
targets: {
id: params.parentContentMessageTargetType,
parameters: { ids: [params.parentContentId] }
}
});
}
var me = this;
Ametys.cms.content.ContentDAO.getContent(contentId, function(content) {
// content notification
me._notifyContentCreation(content);
Ext.create("Ametys.message.Message", {
parameters: params.auto ? {auto: params.auto} : null,
type: Ametys.message.Message.CREATED,
targets: {
id: params.contentMessageTargetType,
parameters: { contents: [content] }
}
});
if (Ext.isFunction (params.callback))
{
params.callback.call(params.scope, params.fullContents ? content : content.getId());
}
});
},
/**
* @private
* Callback function called after #createContent server request is processed in case of a creation followed by a edition
* @param {HTMLElement} response The XML document.
* @param {Object} params The callback arguments (see #createContent documentation)
* @param {Number} editActionId The edit workflow action id
* @param {Object} editParams The parameters for edition
* @param {Ext.Component} [waitMsgCmp] The component that will be masked by the wait message
*/
_createContentCb2: function (response, params, editActionId, editParams, waitMsgCmp)
{
var success = Ext.dom.Query.selectValue ('> ActionResult > success', response) == "true";
// Handle workflow errors
var workflowErrors = Ext.dom.Query.select ('> ActionResult > workflowValidation > error', response);
if (!success && workflowErrors.length > 0)
{
var detailedMsg = '<ul>';
for (var i=0; i < workflowErrors.length; i++)
{
var errorMsg = Ext.dom.Query.selectValue("", workflowErrors[i]);
detailedMsg += '<li>' + errorMsg + '</li>';
}
detailedMsg += '</ul>';
Ametys.Msg.show({
title: "{{i18n plugin.cms:DAOS_CONTENT_CREATE_REQUEST_ERROR}}",
msg: "{{i18n plugin.cms:DAOS_CONTENT_CREATE_REQUEST_ERROR}}" + detailedMsg,
buttons: Ext.Msg.OK,
icon: Ext.Msg.ERROR
});
return;
}
var contentId = Ext.dom.Query.selectValue("> ActionResult > contentId", response);
editParams.contentId = contentId;
Ametys.data.ServerComm.send({
plugin: 'cms',
url: 'do-action/' + editActionId,
parameters: editParams,
waitMessage: {msg: "{{i18n DAOS_CONTENT_CREATE_REQUEST_WAIT}}", target: waitMsgCmp},
errorMessage: {
msg: "{{i18n DAOS_CONTENT_CREATE_REQUEST_ERROR}}",
category: Ext.getClassName(this) + '.createContent'
},
priority: Ametys.data.ServerComm.PRIORITY_MAJOR,
callback: {
scope: this,
handler: this._editContentCb,
arguments: {
callback: params.callback || Ext.emptyFn,
scope: params.scope || window,
contentId: contentId,
fullContents: params.fullContents || false,
contentMessageTargetType: params.contentMessageTargetType || Ametys.message.MessageTarget.CONTENT,
parentContentMessageTargetType: params.parentContentMessageTargetType || Ametys.message.MessageTarget.CONTENT,
parentContentId: params.parentContentId
}
}
});
},
/**
* @private
* Callback function called after edit content server request is processed
* @param {HTMLElement} response The XML document.
* @param {Object} params The callback arguments (see #createContent documentation).
*/
_editContentCb: function (response, params)
{
var contentId = params.contentId;
var workflowMsgErrors = [];
var fieldsInError = {};
var workflowErrors = Ext.dom.Query.select ('> ActionResult > workflowValidation > error', response);
var errors = Ext.dom.Query.select ('> ActionResult > * > fieldResult > error', response);
if (errors.length > 0 || workflowErrors.length > 0)
{
// The content edition failed. Get the fields in error and/or the workflow errors
for (var i=0; i < workflowErrors.length; i++)
{
workflowMsgErrors.push(Ext.dom.Query.selectValue("", workflowErrors[i]));
}
for (var i=0; i < errors.length; i++)
{
var fieldData = errors[i].parentNode.parentNode;
var errorMsg = Ext.dom.Query.selectValue("", errors[i]);
var fieldPath = fieldData.tagName == '_global' ? fieldData.tagName : Ext.dom.Query.selectValue ('> fieldPath', fieldData);
fieldsInError[fieldPath] = errorMsg;
}
// Delete quietly content
Ametys.cms.content.ContentDAO.trashContentsQuietly ([contentId]);
if (Ext.isFunction (params.callback))
{
// Call the callback function with content null
params.callback.call(params.scope, null, fieldsInError, workflowMsgErrors);
}
}
else
{
// The content edition succeeded
if (params.parentContentId)
{
Ext.create("Ametys.message.Message", {
type: Ametys.message.Message.MODIFIED,
targets: {
id: params.parentContentMessageTargetType,
parameters: { ids: [params.parentContentId] }
}
});
}
var me = this;
Ametys.cms.content.ContentDAO.getContent(contentId, function(content) {
// content notification
me._notifyContentCreation(content);
Ext.create("Ametys.message.Message", {
type: Ametys.message.Message.CREATED,
targets: {
id: params.contentMessageTargetType,
parameters: { contents: [content] }
}
});
if (Ext.isFunction (params.callback))
{
params.callback.call(params.scope, params.fullContents ? content : content.getId());
}
});
}
},
/**
* @protected
* Throw a {@link Ametys.ui.fluent.ribbon.Ribbon.Notificator.Notification} to indicate that a content has been created.
*/
_notifyContentCreation: function(content)
{
if (content.getIsSimple())
{
var cType = content.getTypes()[0];
Ametys.notify({
type: 'info',
title: "{{i18n PLUGINS_CMS_NOTIFICATION_CREATE_CONTENT_TITLE}}",
iconGlyph: 'ametysicon-text70',
description: Ext.String.format("{{i18n PLUGINS_CMS_NOTIFICATION_CREATE_CONTENT_DESCRIPTION}}", Ext.String.escapeHtml(content.getTitle())),
action: Ext.bind(Ametys.tool.ToolsManager.openTool, Ametys.tool.ToolsManager, ['uitool-reference-tables', {id: 'reference-table-search-ui.' + cType, contentType: cType}], false)
});
}
else
{
Ametys.notify({
type: 'info',
title: "{{i18n PLUGINS_CMS_NOTIFICATION_CREATE_CONTENT_TITLE}}",
iconGlyph: 'ametysicon-text70',
description: Ext.String.format("{{i18n PLUGINS_CMS_NOTIFICATION_CREATE_CONTENT_DESCRIPTION}}", Ext.String.escapeHtml(content.getTitle())),
action: Ext.bind(Ametys.tool.ToolsManager.openTool, Ametys.tool.ToolsManager, ['uitool-content', {id: content.getId()}], false)
});
}
},
/**
* Edit a content
* @param {Object} config Parameters for content edition.
* @param {String} config.contentId (required) The id of content to edit
* @param {Object} config.values (required) The values to edit.
* @param {Object} [config.unlock=true] Set to 'false' to keep content locked after edition.
* @param {String} [config.viewName] The view to edit.
* @param {String} [config.fallbackViewName] The fallback view to edit if the requested view does not exist.
* @param {Number} [config.editWorkflowActionId=2] The id of the workflow edit action
* @param {Object} [config.bypassedWarnings] the warnings that have already been bypassed
* @param {Boolean} [config.ignoreWarnings=false] True to ignore warnings
* @param {Function} callback The callback function invoked when the content has been edited. The callback function will received the following parameters:
* @param {Boolean} callback.success True if the edition ended successfully, false otherwise
* @param {String/Ametys.cms.content.Content} callback.content The edited content as an id or a {@link Ametys.cms.content.Content}. See #config.fullContents
* @param {String[]} callback.workflowErrors The workflow errors
* @param {Object} callback.fieldsInError The fields in errors
* @param {Object} callback.fieldsWithWarning The fields with warnings
* @param {Object} callback.ingoreWarnings True to ignore warnings
* @param {Object} [scope=window] The callback scope, default to window.
* @param {Boolean} [fullContents=false] If `true`, the callback function receives a Content object as argument. If `false`, only the content id is provided.
* @param {String} [contentMessageTargetType=Ametys.message.MessageTarget#CONTENT] The message target factory role to use for the event of the bus thrown after content creation
* @param {String} [parentContentMessageTargetType=Ametys.message.MessageTarget#CONTENT] The message target factory role to use for the event of the bus thrown after parent content modification if applyable
* @param {Ext.Component} [waitMsgCmp] The component that will be masked by the wait message
*/
editContent: function (config, callback, scope, fullContents, contentMessageTargetType, parentContentMessageTargetType, waitMsgCmp)
{
contentMessageTargetType = contentMessageTargetType || Ametys.message.MessageTarget.CONTENT;
Ext.create("Ametys.message.Message", {
type: Ametys.message.Message.WORKFLOW_CHANGING,
targets: {
id: contentMessageTargetType,
parameters: { ids: [config.contentId] }
}
});
var params = {
values: config.values,
contentId: config.contentId,
quit: config.unlock !== false,
'content.view': config.viewName,
'content.fallback.view': config.fallbackViewName,
'ignore.warnings': config.ignoreWarnings !== false
};
Ametys.data.ServerComm.send({
plugin: 'cms',
url: 'do-action/' + (config.editWorkflowActionId || 2),
parameters: params,
waitMessage: {msg: "{{i18n CONTENT_EDITION_SAVING}}", target: waitMsgCmp},
errorMessage: {
msg: "{{i18n PLUGINS_CMS_SAVE_ACTION_ERROR}}",
category: Ext.getClassName(this) + '.editContent'
},
priority: Ametys.data.ServerComm.PRIORITY_MAJOR,
callback: {
scope: this,
handler: this._editContentCb2,
arguments: {
callback: callback || Ext.emptyFn,
scope: scope || window,
contentId: config.contentId,
fullContents: fullContents || false,
contentMessageTargetType: contentMessageTargetType,
unlock: config.unlock !== false,
bypassedWarnings: config.bypassedWarnings,
ignoreWarnings: config.ignoreWarnings !== false
}
}
});
},
/**
* @private
* Callback function called after edit content server request is processed
* @param {HTMLElement} response The XML document.
* @param {Object} params The callback arguments (see #createContent documentation).
*/
_editContentCb2: function (response, params)
{
var contentId = params.contentId;
if (Ametys.data.ServerComm.isBadResponse(response))
{
// fail
Ametys.cms.content.ContentDAO.getContent(contentId, function(content) {
// Workflow did not really changed, but WORKFLOW_CHANGING has been sent, elements could be waiting for update
Ext.create("Ametys.message.Message", {
type: Ametys.message.Message.WORKFLOW_CHANGED,
targets: {
id: params.contentMessageTargetType,
parameters: { contents: [content] }
}
});
if (Ext.isFunction (params.callback))
{
params.callback.call(params.scope, false, contentId, [], {}, {}, false);
}
});
return;
}
let me = this;
let additionalFns = {
successFn: function(contentId, params)
{
Ametys.cms.content.ContentDAO.getContent(contentId, function(content) {
Ext.create("Ametys.message.Message", {
type: Ametys.message.Message.MODIFIED,
targets: {
id: params.contentMessageTargetType,
parameters: { contents: [content] }
}
});
if (params.unlock)
{
Ext.create("Ametys.message.Message", {
type: Ametys.message.Message.LOCK_CHANGED,
targets: {
id: params.contentMessageTargetType,
parameters: { contents: [content] }
}
});
}
Ext.create("Ametys.message.Message", {
type: Ametys.message.Message.WORKFLOW_CHANGED,
targets: {
id: params.contentMessageTargetType,
parameters: { contents: [content] }
}
});
if (Ext.isFunction (params.callback))
{
params.callback.call(params.scope, true, params.fullContents ? content : contentId, [], {}, {}, false);
}
});
},
workflowValidationErrorFn: function(contentId, msg, detailedMsg, workflowMsgErrors, params) {
Ametys.form.SaveHelper.SaveErrorDialog.showErrorDialog (null, msg, detailedMsg);
Ametys.cms.content.ContentDAO.getContent(contentId, function(content) {
// Workflow did not really changed, but WORKFLOW_CHANGING has been sent, elements could be waiting for update
Ext.create("Ametys.message.Message", {
type: Ametys.message.Message.WORKFLOW_CHANGED,
targets: {
id: params.contentMessageTargetType,
parameters: { contents: [content] }
}
});
if (Ext.isFunction (params.callback))
{
// Call the callback function with success false and content null
params.callback.call(params.scope, false, contentId, workflowMsgErrors, {}, {}, false);
}
});
},
fieldResultErrorFn: function(contentId, msg, detailedMsg, fieldsInError, params) {
Ametys.form.SaveHelper.SaveErrorDialog.showErrorDialog (null, msg, detailedMsg);
Ametys.cms.content.ContentDAO.getContent(contentId, function(content) {
// Workflow did not really changed, but WORKFLOW_CHANGING has been sent, elements could be waiting for update
Ext.create("Ametys.message.Message", {
type: Ametys.message.Message.WORKFLOW_CHANGED,
targets: {
id: params.contentMessageTargetType,
parameters: { contents: [content] }
}
});
if (Ext.isFunction (params.callback))
{
// Call the callback function with success false and content null
params.callback.call(params.scope, false, contentId, [], fieldsInError, {}, false);
}
});
},
fieldResultWarningFn: function(contentId, msg, detailedMsg, question, fieldsWithWarning, params) {
if (msg)
{
Ametys.form.SaveHelper.SaveErrorDialog.showWarningDialog (null, msg, detailedMsg, question, Ext.bind(me._showWarningsCb, me, [fieldsWithWarning, params], 1));
}
else
{
me._showWarningsCb(true, fieldsWithWarning, params);
}
},
fieldResultInfoFn: function(contentId, msg, detailedMsg, fieldsWithInfo, params) {
Ametys.notify({
title: "{{i18n PLUGINS_CMS_SAVE_ACTION_CONTENT_MODIFICATION}}",
description: detailedMsg
});
},
messageFn: function(contentId, messages, globalLevel, params) {
var popupItems = [];
for (var i=0; i < messages.length; i++)
{
var message = messages[i];
var cls = message.level == 'warning' ? 'x-message-box-warning' : 'x-message-box-info';
popupItems.push({
xtype: 'container',
layout : {
type : "hbox",
},
anchor: "100%",
items:[{
xtype: "component",
cls: cls,
width: 48,
style: {
'text-align': 'center'
}
},
{
xtype: 'component',
cls: 'text',
html: message.msg,
flex: 1
}]
});
if (i != messages.length-1)
{
popupItems.push({
xtype: 'component',
cls: 'text',
html: '<hr>',
flex: 1
});
}
}
var iconCls = globalLevel == 'warning' ? 'ametysicon-sign-caution' : 'ametysicon-sign-info';
var title = globalLevel == 'warning' ? "{{i18n PLUGINS_CMS_DUPLICATE_CONTENTS_SAVE_REPORT_MESSAGE_WARNING}}" : "{{i18n PLUGINS_CMS_DUPLICATE_CONTENTS_SAVE_REPORT_MESSAGE_INFO}}";
var reportBox = Ext.create('Ametys.window.DialogBox', {
layout: 'anchor',
autoShow: true,
autoScroll: true,
maxWidth: 580,
maxHeight: 700,
iconCls: iconCls,
title: title,
items: popupItems,
closeAction: 'destroy',
defaultButton: 'buttonOk',
buttons: [{
itemId: 'button-ok',
reference: 'buttonOk',
text: "{{i18n PLUGINS_CMS_DUPLICATE_CONTENTS_SAVE_REPORT_BUTTON_OK}}",
handler: function() {
reportBox.close();
}
}
]
});
}
};
Ametys.cms.content.ContentErrorHelper.handleContentEditError(response, contentId, params, additionalFns)
},
/**
* @private
* Callback function called after user chose to ignore warnings or not
* @param {Boolean} ignoreWarnings true if the user choose to ignore warnings and save anyway, false otherwise
* @param {Object} fieldsWithWarnings the fields with warnings
* @param {Object} params The callback arguments (see #createContent documentation).
*/
_showWarningsCb: function (ignoreWarnings, fieldsWithWarnings, params)
{
var contentId = params.contentId;
if (!ignoreWarnings)
{
Ametys.cms.content.ContentDAO.getContent(contentId, function(content) {
// Workflow did not really changed, but WORKFLOW_CHANGING has been sent, elements could be waiting for update
Ext.create("Ametys.message.Message", {
type: Ametys.message.Message.WORKFLOW_CHANGED,
targets: {
id: params.contentMessageTargetType,
parameters: { contents: [content] }
}
});
});
}
if (Ext.isFunction (params.callback))
{
// Call the callback function with success false and content null
params.callback.call(params.scope, false, contentId, [], {}, fieldsWithWarnings, ignoreWarnings);
}
},
/**
* Delete contents
* @param {String[]} contentIds The id of contents to delete
* @param {Ametys.message.MessageTarget[]} contentTargets The content's targets
* @param {Function} [callback] The function to call when the java process is over.
* @param {Object} callback.deleted-contents The deleted contents
* @param {Object} callback.referenced-contents The undeleted contents because they are referenced
* @param {Object} callback.undeleted-contents The undeleted contents
* @param {Object} [scope=window] The callback scope, default to window.
*/
trashContents: function (contentIds, contentTargets, callback, scope)
{
Ametys.data.ServerComm.callMethod({
role: this._contentDAOClassname,
methodName: "trashContents",
parameters: [contentIds],
callback: {
scope: this,
handler: this._trashContentsCb,
arguments: {
callback: callback,
scope: scope,
targets: contentTargets
}
},
waitMessage: true,
errorMessage: "{{i18n DAOS_CONTENT_DELETE_ERROR}}"
});
},
/**
* Force delete contents even if it has references. If the content has references, these references will be deleted too and the referenced contents will be modified.
* @param {String[]} contentIds The id of contents to delete
* @param {Ametys.message.MessageTarget[]} contentTargets The content's targets
* @param {Function} [callback] The function to call when the java process is over.
* @param {Object} callback.deleted-contents The deleted contents
* @param {Object} callback.undeleted-contents The undeleted contents
* @param {Object} [scope=window] The callback scope, default to window.
*/
forceTrashContents: function (contentIds, contentTargets, callback, scope)
{
Ametys.data.ServerComm.callMethod({
role: this._contentDAOClassname,
methodName: "forceTrashContents",
parameters: [contentIds],
callback: {
scope: this,
handler: this._trashContentsCb,
arguments: {
callback: callback,
scope: scope,
targets: contentTargets
}
},
waitMessage: true,
errorMessage: "{{i18n DAOS_CONTENT_DELETE_ERROR}}"
});
},
/**
* Delete contents quietly, ie. without sending bus message or displaying the result of deletion
* @param {String[]} contentIds The id of contents to delete
* @param {Ametys.message.MessageTarget[]} contentTargets The content's targets
*/
trashContentsQuietly: function (contentIds, contentTargets)
{
Ametys.data.ServerComm.callMethod({
role: this._contentDAOClassname,
methodName: "trashContents",
parameters: [contentIds],
errorMessage: false
});
},
/**
* @private
* Callback function called after contents were removed
* @param {Object} response The server result
* @param {Object} args The callback arguments :
* @param {Ametys.message.MessageTarget[]} args.targets The content's targets
* @param {Ametys.message.MessageTarget[]} [args.callback] The callback function
*/
_trashContentsCb: function (response, args)
{
var targets = args.targets;
var deletedContents = response['deleted-contents'];
if (deletedContents.length > 0)
{
var deletedContentTargets = [];
for (var i=0; i < deletedContents.length; i++)
{
for (var j=0; j < targets.length; j++)
{
if (targets[j].getParameters().id == deletedContents[i].id)
{
deletedContentTargets.push(targets[j]);
}
}
// Remove content from navigation history
Ametys.navhistory.HistoryDAO.removeEntry (deletedContents[i].id);
// Notify content deletion
Ametys.notify({
type: 'info',
iconGlyph: 'ametysicon-text70',
title: "{{i18n PLUGINS_CMS_NOTIFICATION_DELETE_CONTENT_TITLE}}",
description: Ext.String.format("{{i18n PLUGINS_CMS_NOTIFICATION_DELETE_CONTENT_DESCRIPTION}}", Ext.String.escapeHtml(deletedContents[i].title))
});
}
// Fires deleted event
Ext.create("Ametys.message.Message", {
type: Ametys.message.Message.DELETED,
// we assume that everything is trashed. The only case
// of actual deletion should be shared content but we will ignore it
// for simplicity
parameters : {trashed: true},
targets: deletedContentTargets
});
}
var undeletedContents = response['undeleted-contents'];
var referencedContents = response['referenced-contents'];
var lockedContents = response['locked-contents'];
var unauthorizedContents = response['unauthorized-contents'];
if (undeletedContents.length > 0 || referencedContents.length > 0 || lockedContents.length > 0 || unauthorizedContents.length > 0)
{
var message = '';
var message = this._buildErrorMessage(message, undeletedContents, "{{i18n CONTENT_DELETE_FAILED_CONTENTS}}");
message = this._buildErrorMessage(message, referencedContents, "{{i18n CONTENT_DELETE_REFERENCED_CONTENTS}}", ".<br/>{{i18n CONTENT_DELETE_REFERENCED_CONTENTS_END}}");
message = this._buildErrorMessage(message, lockedContents, "{{i18n CONTENT_DELETE_LOCKED_CONTENTS}}");
message = this._buildErrorMessage(message, unauthorizedContents, "{{i18n CONTENT_DELETE_UNAUTHORIZED_CONTENTS}}");
Ametys.Msg.show({
title: "{{i18n CONTENT_DELETE_LABEL}}",
msg: message,
buttons: Ext.Msg.OK,
icon: Ext.MessageBox.ERROR
});
}
if (Ext.isFunction (args.callback))
{
args.callback.call(args.scope, response);
}
},
/**
* @private
* Build error message
* @param {String} message The initial error message
* @param {Object[]} contentsInError The contents in error
* @param {String} startDesc The start description
* @param {String} endDesc The end description
*/
_buildErrorMessage: function(message, contentsInError, startDesc, endDesc)
{
message = message || '';
if (contentsInError.length > 0)
{
if (message.length > 0)
{
message += '<br/><br/>';
}
message += startDesc || '';
for (var i=0; i < contentsInError.length; i++)
{
message += (i > 0 ? ', ' : '') + Ext.String.escapeHtml(contentsInError[i].title);
}
message += endDesc || '';
}
return message;
},
/**
* Lock the content
* @param {String} id the id of content
* @param {String} contentTarget the content target
* @param {Function} [callback] Callback function to invoke after locking the content
*/
lockContent: function(id, contentTarget, callback)
{
var content = Ext.create("Ametys.cms.content.Content", {
id: id,
locked: false,
messageTarget: contentTarget
});
content.lock(callback);
},
/**
* Unlock the content
* @param {String} id the id of content
* @param {String} contentTarget the content target
* @param {Function} [callback] Callback function to invoke after unlocking the content
*/
unlockContent: function(id, contentTarget, callback)
{
var content = Ext.create("Ametys.cms.content.Content", {
id: id,
locked: true,
messageTarget: contentTarget
});
content.unlock(callback);
}
}
);