/*
* Copyright 2015 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.
*/
/**
* Class handling the forms of a rich text
*/
Ext.define('Ametys.plugins.forms.content.Forms', {
singleton: true,
/**
* @private
* @property {HTMLElement} _currentNode the node that is currently selected
*/
/**
* @private
* @property {HTMLElement} _currentFormNameNode the form node that is currently selected
*/
/**
* @private
* @property {String} _currentWorkflowValue the current value of the workflow
*/
/**
* @private
* @property {String} _currentWorkflowNode the current node for the workflow
*/
/**
* @private
* @property {HTMLElement} _currentFormProcessingEmailsNode the form node processing emails that is currently selected
*/
/**
* @private
* @property {HTMLElement} _currentFormOINWNode the form node for the open in new window feature
*/
/**
* @private
* @property {HTMLElement} _currentURLNode the current node for the external form's url
*/
/**
* @private
* @property {HTMLElement} _currentFormReceiptNode the current node for the email processing
*/
/**
* @private
* @property {HTMLElement} _currentFormRedirectNode the current node for the page redirection
*/
/**
* @private
* @property {HTMLElement} _currentFormConvertToCMSNode the current node for conversion from cms to external
*/
/**
* @private
* @property {HTMLElement} _currentFormConvertToExternalNode the current node for conversion from external to cms
*/
/**
* @private
* @property {HTMLElement} _currentRemovableForm the removable form currently selected
*/
/**
* @private
* @property {HTMLElement} _currentFormLimitNode the current node for the entry limit processing
*/
/**
* Enable/disable the button according to the selection
* @param {Ametys.cms.editor.EditorButtonController} controller The controller
* @param {Ametys.cms.form.widget.RichText} field The current field. Can be null
* @param {HTMLElement} node The currently selected node. Can be null.
*/
insertListener: function(controller, field, node)
{
var form = (field != null && node != null) ? this._getForm(field.getEditor(), node) : null;
controller.setDisabled(field == null || node == null || form != null);
},
/**
* Insert a CMS form
*/
insertCMS: function()
{
var layoutCSSClassName = Ametys.plugins.forms.content.Layout._handledLayoutClass[Ext.Object.getKeys(Ametys.plugins.forms.content.Layout._layoutActions).indexOf(Ametys.form.widget.RichText.RichTextConfiguration.getTag("div", tinyMCE.activeEditor.getParam('category')).getAttribute("layout").defaultValue)];
this._insertForm(' class="form cmsForm ' + layoutCSSClassName + '" type="cms" _mce_ribbon_select="1" form_name="' + this._findName() + '" ');
},
/**
* Insert an external form
*/
insertExternal: function()
{
var layoutCSSClassName = Ametys.plugins.forms.content.Layout._handledLayoutClass[Ext.Object.getKeys(Ametys.plugins.forms.content.Layout._layoutActions).indexOf(Ametys.form.widget.RichText.RichTextConfiguration.getTag("div", tinyMCE.activeEditor.getParam('category')).getAttribute("layout").defaultValue)];
this._insertForm(' class="form ' + layoutCSSClassName + '" target="_blank" ');
},
/**
* @private
* Insert a form with the given attributes
* @param {String} attrs the attributes of the form
*/
_insertForm: function(attrs)
{
// Generate 15-digit random number
var id = 'form_' + Math.round((Math.random() * 0.9 + 0.1) * Math.pow(10, 15));
var html = '<div form="form"';
html += ' id="' + id + '"';
html += ' layout="' + Ametys.form.widget.RichText.RichTextConfiguration.getTag("div", tinyMCE.activeEditor.getParam('category')).getAttribute("layout").defaultValue + '" ';
html += attrs;
html += '>';
html += "</div>";
// FIXME "tinyMCE.activeEditor" a better method is to use the field.getEditor()
tinyMCE.activeEditor.focus();
tinyMCE.activeEditor.execCommand('mceBeginUndoLevel');
tinyMCE.insertHTMLAtRoot(html);
this._currentNode = tinyMCE.activeEditor.dom.doc.getElementById(id);
tinyMCE.activeEditor.execCommand('mceSelectNode', false, this._currentNode);
var layout = Ametys.plugins.forms.content.Layout._getCurrentLayout(this._currentNode);
var layoutFunctionName = Ametys.plugins.forms.content.Layout._layoutActions[layout];
eval(layoutFunctionName + "();");
tinyMCE.activeEditor.execCommand('mceEndUndoLevel');
var element = this._currentNode;
while (element.childNodes && element.childNodes.length > 0)
{
element = element.childNodes[0];
}
tinyMCE.activeEditor.execCommand('mceSelectNode', false, element);
},
/**
* Listener function invoked when the form name text input changes
* @param {Ext.form.Field} input the input field
*/
setFormNameOnBlur: function (input)
{
if (this._setFormName(input.getValue()) === false)
{
input.setValue(this._getFormName());
}
},
/**
* Listener function invoked when a special key was stroke in the form name input field
* @param {Ext.form.Field} input the input field
* @param {Ext.event.Event} event the specialkey event
*/
setFormNameOnSpecialKey: function (input, event)
{
if (event.getKey() == event.ENTER)
{
event.preventDefault();
event.stopPropagation();
if (this._setFormName(input.getValue()) === false)
{
input.setValue(this._getFormName());
}
// FIXME "tinyMCE.activeEditor" a better method is to use the field.getEditor()
tinyMCE.activeEditor.focus();
}
else if (event.getKey() == event.ESC)
{
event.preventDefault();
event.stopPropagation();
input.setValue(this._getFormName());
// FIXME "tinyMCE.activeEditor" a better method is to use the field.getEditor()
tinyMCE.activeEditor.focus();
}
},
/**
* Listener for the form name input field
* @param {Ametys.cms.editor.EditorFieldController} controller The controller
* @param {Ametys.cms.form.widget.RichText} field The current field. Can be null
* @param {HTMLElement} node The currently selected node. Can be null.
*/
formNameListener: function (controller, field, node)
{
var form = (field != null && node != null && field.getEditor() != null) ? this._getForm(field.getEditor(), field.getEditor().selection.getNode()) : null;
if (form != null && form.getAttribute("type") != "cms")
{
form = null;
}
this._currentFormNameNode = form;
if (!form)
{
controller.disable();
controller.setValue("");
}
else
{
controller.enable();
controller.setValue(this._getFormName());
}
},
/**
* @private
* Get the name of the form
* @return the name of the form
*/
_getFormName: function ()
{
var formName = this._currentFormNameNode.getAttribute("form_name");
return (this._currentFormNameNode == null || formName == null) ? "" : decodeURIComponent(formName);
},
/**
* @private
* Set the name of the form with the provided value
* @param value the name to set to the form
* @return false if an error occurred
*/
_setFormName: function (value)
{
if (this._getFormName() != value)
{
if (value == '' && this._getFormProcessingEmails() == '')
{
Ametys.Msg.show({
title: "{{i18n PLUGINS_FORMS_FORMS_EDITOR_CMS_FORMNAME_EMPTYERROR_TITLE}}",
msg: "{{i18n PLUGINS_FORMS_FORMS_EDITOR_CMS_FORMNAME_EMPTYERROR_DESCRIPTION}} <br />"
+ "{{i18n PLUGINS_FORMS_FORMS_EDITOR_CMS_FORMNAME_EMPTYERROR_DETAILS}}",
buttons: Ext.Msg.OK,
icon: Ext.MessageBox.ERROR
});
return false;
}
var form = this._currentFormNameNode;
if (form != null)
{
if ((value != '') && (!this._isFreeCMSFormName(form.id, value)))
{
Ametys.Msg.show({
title: "{{i18n PLUGINS_FORMS_FORMS_EDITOR_CMS_FORMNAME_ERROR_TITLE}}",
msg: "{{i18n PLUGINS_FORMS_FORMS_EDITOR_CMS_FORMNAME_ERROR_DESCRIPTION}} <br />"
+ "{{i18n PLUGINS_FORMS_FORMS_EDITOR_CMS_FORMNAME_ERROR_DETAILS}}",
buttons: Ext.Msg.OK,
icon: Ext.MessageBox.ERROR
});
return false;
}
form.setAttribute("form_name", encodeURIComponent(value));
// FIXME "tinyMCE.activeEditor" a better method is to use the field.getEditor()
tinyMCE.activeEditor.execCommand('mceAddUndoLevel');
}
}
},
/**
* Listener when the selection changes in the editor
* @param {Ametys.cms.editor.EditorFieldController} controller the button's controller
* @param {Ext.form.Field} field the target field
* @param {HTMLElement} node the node
*/
workflowSelectionListener: function(controller, field, node)
{
var off = field == null || node == null;
if (off)
{
controller.disable();
return;
}
var formNode = Ametys.plugins.forms.content.Forms._getForm(field.getEditor(), node);
if (formNode != null)
{
this._currentWorkflowNode = formNode;
controller.enable();
var formWorkflow = formNode.getAttribute("form_workflow");
var value = formWorkflow != null ? formWorkflow : controller.getStore().getRange()[0].data.value;
formNode.setAttribute("form_workflow", value);
controller.setValue(value);
this._currentWorkflowValue = value;
}
},
/**
* Listener when the selection changes in the editor
* @param {Ametys.cms.editor.EditorFieldController} controller the button's controller
* @param {Ext.data.Record} record the selected record
*/
applyWorkflow: function (controller, record)
{
var newValue = record.data.value;
var oldValue = this._currentWorkflowValue;
// Never display the warning message when there initially was no workflow on the form,
// nor when going back to the form's initial workflow
var initialValue = this._currentWorkflowNode.getAttribute("initial_form_workflow");
this._currentWorkflowNode.setAttribute("form_workflow", newValue);
this._currentWorkflowValue = newValue;
if (oldValue != newValue && initialValue != "" && initialValue != null && newValue != initialValue)
{
Ametys.Msg.confirm(
"{{i18n PLUGINS_FORMS_FORMS_EDITOR_WORKFLOW_CHANGE_DIALOG_TITLE}}",
newValue == "" ? "{{i18n PLUGINS_FORMS_FORMS_EDITOR_WORKFLOW_DELETE_DIALOG_TEXT}}"
: "{{i18n PLUGINS_FORMS_FORMS_EDITOR_WORKFLOW_CHANGE_DIALOG_TEXT}}",
function (answer) {
if (answer != 'yes')
{
controller.setValue(oldValue);
this._currentWorkflowValue = oldValue;
this._currentWorkflowNode.setAttribute("form_workflow", oldValue);
}
},
this
);
}
tinyMCE.activeEditor.focus();
},
/**
* Listener for the open in new window checkbox field
* @param {Ametys.cms.editor.EditorFieldController} controller The controller
* @param {Ametys.cms.form.widget.RichText} field The current field. Can be null
* @param {HTMLElement} node The currently selected node. Can be null.
*/
openInNewWindowListener: function(controller, field, node)
{
var form = (field != null && node != null) ? this._getForm(field.getEditor(), node) : null;
this._currentFormOINWNode = form;
if (!form)
{
controller.disable();
}
else
{
controller.enable();
controller.setValue(this._getOpenInNewWindow());
}
},
/**
* Function invoked when the open in new window field changes
* @param {Ext.form.Field} input the checkbox field
*/
setOpenInNewWindow: function(input)
{
var form = this._currentFormOINWNode;
var newValue = input.getValue();
if (form && newValue != this._getOpenInNewWindow())
{
form.setAttribute("target", input.getValue() ? "_blank" : "");
// FIXME "tinyMCE.activeEditor" a better method is to use the field.getEditor()
tinyMCE.activeEditor.execCommand('mceAddUndoLevel');
}
tinyMCE.activeEditor.focus();
},
/**
* @private
* Is the open in new window option activated ?
*/
_getOpenInNewWindow: function()
{
var form = this._currentFormOINWNode;
if (form)
{
return form.getAttribute("target") != null && form.getAttribute("target") == "_blank";
}
},
/**
* Function invoked when a special key is stroke in the form's url field
* @param {Ext.form.Field} input the field
* @param {Ext.event.Event} event the event
*/
setURLOnSpecialKey: function (input, event)
{
if (event.getKey() == event.ENTER)
{
event.preventDefault();
event.stopPropagation();
if (this._setURL(input.getValue()) === false)
{
input.setValue(this._getURL());
}
}
else if (event.getKey() == event.ESC)
{
event.preventDefault();
event.stopPropagation();
input.setValue(this._getURL());
// FIXME "tinyMCE.activeEditor" a better method is to use the field.getEditor()
tinyMCE.activeEditor.focus();
}
},
/**
* Function invoked when the url input field changes
* @param {Ext.form.Field} input the url input field
*/
setURLOnBlur: function (input)
{
if (this._setURL(input.getValue()) === false)
{
input.setValue(this._getURL());
}
},
/**
* Listener controlling the state of the url field
* @param {Ametys.cms.editor.EditorFieldController} controller The controller
* @param {Ametys.cms.form.widget.RichText} field The current field. Can be null
* @param {HTMLElement} node The currently selected node. Can be null.
*/
urlListener: function (controller, field, node)
{
var form = (field != null && node != null && field.getEditor() != null) ? this._getForm(field.getEditor(), field.getEditor().selection.getNode()) : null;
if (form != null && form.getAttribute("type") == "cms")
{
form = null;
}
this._currentURLNode = form;
if (!form)
{
controller.setValue("");
controller.disable();
}
else
{
controller.setValue(this._getURL());
controller.enable();
}
},
/**
* @private
* Get the url of the form
*/
_getURL: function()
{
if (this._currentURLNode == null || this._currentURLNode.getAttribute("form_action") == null)
{
return "";
}
else
{
return decodeURIComponent(this._currentURLNode.getAttribute("form_action"));
}
},
/**
* @private
* Set the url of the form
* @param {String} value the value to set on the url field
*/
_setURL: function (value)
{
if (this._getURL() != value)
{
if (/^https?:\/\/.+$/.test(value) == false)
{
Ametys.Msg.show({
title: "{{i18n PLUGINS_FORMS_FORMS_EDITOR_EXTERNAL_URL_ERROR_TITLE}}",
msg: "{{i18n PLUGINS_FORMS_FORMS_EDITOR_EXTERNAL_URL_ERROR_DESCRIPTION}} <br />"
+ "{{i18n PLUGINS_FORMS_FORMS_EDITOR_EXTERNAL_URL_ERROR_DETAILS}}<br/>^https?://.+$",
buttons: Ext.Msg.OK,
icon: Ext.MessageBox.ERROR,
fn: function () { tinyMCE.activeEditor.focus(); }
});
return false;
}
var form = this._currentURLNode;
if (form != null)
{
form.setAttribute("form_action", encodeURIComponent(value));
// FIXME "tinyMCE.activeEditor" a better method is to use the field.getEditor()
tinyMCE.activeEditor.execCommand('mceAddUndoLevel');
}
}
tinyMCE.activeEditor.focus();
},
/**
* Function invoked when the email processing field has changed
* @param {Ext.form.Field} input the email processing field
*/
setFormProcessingEmailsOnBlur: function (input)
{
if (this._setFormProcessingEmails(input.getValue()) === false)
{
input.setValue(this._getFormProcessingEmails());
}
},
/**
* @private
* Set the form processing emails value
* @param value the value
* @return false if an error occurred
*/
_setFormProcessingEmails: function (value)
{
if (this._getFormProcessingEmails() != value)
{
if (value == '' && this._getFormName() == '')
{
Ametys.Msg.show({
title: "{{i18n PLUGINS_FORMS_FORMS_EDITOR_CMS_EMAILPROCESSING_EMPTYERROR_TITLE}}",
msg: "{{i18n PLUGINS_FORMS_FORMS_EDITOR_CMS_EMAILPROCESSING_EMPTYERROR_DESCRIPTION}} <br />"
+ "{{i18n PLUGINS_FORMS_FORMS_EDITOR_CMS_EMAILPROCESSING_EMPTYERROR_DETAILS}}",
buttons: Ext.Msg.OK,
icon: Ext.MessageBox.ERROR
});
return false;
}
var form = this._currentFormProcessingEmailsNode;
if (form != null)
{
if (value == '' || /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,})([ ,;\r\n]*([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,}))*$/.test(value))
{
form.setAttribute("form_processing_emails", encodeURIComponent(value));
// FIXME "tinyMCE.activeEditor" a better method is to use the field.getEditor()
tinyMCE.activeEditor.execCommand('mceAddUndoLevel');
}
else
{
Ametys.Msg.show({
title: "{{i18n PLUGINS_FORMS_FORMS_EDITOR_CMS_EMAILPROCESSING_ERROR_TITLE}}",
msg: "{{i18n PLUGINS_FORMS_FORMS_EDITOR_CMS_EMAILPROCESSING_ERROR_DESCRIPTION}} <br />"
+ "{{i18n PLUGINS_FORMS_FORMS_EDITOR_CMS_EMAILPROCESSING_ERROR_DETAILS}}",
buttons: Ext.Msg.OK,
icon: Ext.MessageBox.ERROR
});
return false;
}
}
}
},
/**
* @private
* Get the form processing emails
*/
_getFormProcessingEmails: function ()
{
if (this._currentFormProcessingEmailsNode == null || this._currentFormProcessingEmailsNode.getAttribute("form_processing_emails") == null)
{
return "";
}
else
{
return decodeURIComponent(this._currentFormProcessingEmailsNode.getAttribute("form_processing_emails"));
}
},
/**
* Listener controlling the state of the form processing field
* @param {Ametys.cms.editor.EditorButtonController} controller The controller
* @param {Ametys.cms.form.widget.RichText} field The current field. Can be null
* @param {HTMLElement} node The currently selected node. Can be null.
*/
formProcessingEmailsListener: function (controller, field, node)
{
var form = (field != null && node != null && field.getEditor() != null) ? this._getForm(field.getEditor(), field.getEditor().selection.getNode()) : null;
if (form != null && form.getAttribute("type") != "cms")
{
form = null;
}
this._currentFormProcessingEmailsNode = form;
if (!form)
{
controller.setValue('');
controller.disable();
}
else
{
controller.setValue(this._getFormProcessingEmails());
controller.enable();
}
},
/**
* Send to the visitor an email when its request is received
* @param {Ametys.cms.editor.EditorButtonController} controller the button controller
*/
receiptAction: function(controller)
{
var form = this._currentFormReceiptNode;
var emailIds = this._receiptGetEmailFields();
var atLeastOne = emailIds.length > 0
// test if there is at least a field
if (!atLeastOne)
{
// no one
Ametys.Msg.show({
title: "{{i18n PLUGINS_FORMS_FORMS_EDITOR_MAILRECEIPT_NO_TITLE}}",
msg: "{{i18n PLUGINS_FORMS_FORMS_EDITOR_MAILRECEIPT_NO_DESCRIPTION}}",
buttons: Ext.Msg.OK,
icon: Ext.MessageBox.ERROR,
fn: function () { tinyMCE.activeEditor.focus(); }
});
return;
}
// display receipt dialog box
var from = form.getAttribute("form_receipt_from");
var to = form.getAttribute("form_receipt_to");
var subject = form.getAttribute("form_receipt_subject");
var body = form.getAttribute("form_receipt_body");
Ametys.plugins.forms.content.ReceiptBox.create(from,
to,
subject != null ? decodeURIComponent(subject) : null,
body != null ? decodeURIComponent(body) : null,
emailIds,
Ext.bind(this._setFormReceiptAttributes, this, [controller], 5));
},
/**
* @private
* Set the form attributes for the receipt
* @param {String} from the sender
* @param {String} to the receiver
* @param {String} subject the subject of the email
* @param {String} body the body of the email
* @param {Ametys.cms.editor.EditorButtonController} controller the button's controller
* @return true
*/
_setFormReceiptAttributes: function(from, to, subject, body, controller)
{
var form = this._currentFormReceiptNode;
if (from != null)
{
form.setAttribute("form_receipt_from", from);
form.setAttribute("form_receipt_to", to);
form.setAttribute("form_receipt_subject", subject != null ? encodeURIComponent(subject) : null);
form.setAttribute("form_receipt_body", body != null ? encodeURIComponent(body) : null);
// FIXME "tinyMCE.activeEditor" a better method is to use the field.getEditor()
tinyMCE.activeEditor.execCommand('mceAddUndoLevel');
controller.toggle(true);
controller.enable();
}
else
{
form.removeAttribute("form_receipt_from");
form.removeAttribute("form_receipt_to");
form.removeAttribute("form_receipt_subject");
form.removeAttribute("form_receipt_body");
// FIXME "tinyMCE.activeEditor" a better method is to use the field.getEditor()
tinyMCE.activeEditor.execCommand('mceAddUndoLevel');
controller.toggle(false);
controller.enable();
}
tinyMCE.activeEditor.focus();
return true;
},
/**
* Get the email ids form the form
*/
_receiptGetEmailFields: function()
{
var emailIds = [];
function trimee(s)
{
if (s.substring(s.length - 1) == ":")
{
return s.substring(0, s.length - 1).trim();
}
else
{
return s;
}
}
var currentForm = this._currentFormReceiptNode;
var imgs = currentForm.getElementsByTagName("img");
for (var i = 0; i < imgs.length; i++)
{
if (imgs[i].getAttribute("marker") == "marker"
&& imgs[i].getAttribute("form") == "form"
&& imgs[i].getAttribute("input_text") == "input_text"
&& imgs[i].getAttribute("form_regexptype") == "email")
{
// found one
var label = Ametys.plugins.forms.content.Components._getLabel(imgs[i]);
emailIds.push([imgs[i].id, label != null ? trimee(label.innerHTML) : imgs[i].id]);
}
}
return emailIds;
},
/**
* Listener controlling the state of the receipt button
* @param {Ametys.cms.editor.EditorButtonController} controller The controller
* @param {Ametys.cms.form.widget.RichText} field The current field. Can be null
* @param {HTMLElement} node The currently selected node. Can be null.
*/
receiptListener: function(controller, field, node)
{
var form = (field != null && node != null && field.getEditor() != null) ? this._getForm(field.getEditor(), field.getEditor().selection.getNode()) : null;
if (form != null && form.getAttribute("type") != "cms")
{
form = null;
}
this._currentFormReceiptNode = form;
if (!form)
{
controller.toggle(false);
controller.disable();
}
else
{
var to = this._currentFormReceiptNode.getAttribute("form_receipt_to") || "";
if (to != "")
{
// repairing
var input = field.getEditor().dom.doc.getElementById(to);
if (input == null || input.getAttribute("input_text") != "input_text" || input.getAttribute("form_regexptype") != "email")
{
input.setAttribute("form_receipt_to", null);
to = "";
}
}
controller.toggle(to != '');
controller.enable();
}
},
/**
* Limit the entries of a form
* @param {Ametys.cms.editor.EditorButtonController} controller the button controller
*/
limitAction: function(controller)
{
var form = this._currentFormLimitNode;
// display receipt dialog box
var limit = form.getAttribute("form_limit");
var places = form.getAttribute("form_places");
var noPlaces = form.getAttribute("form_no_places");
Ametys.plugins.forms.content.LimitBox.create(limit, places, noPlaces,
Ext.bind(this._setFormLimitAttributes, this, [controller, controller.getCurrentField()], 4));
},
/**
* @private
* Set the form attributes for the limit of entries
* @param {Number} limit the limit of entries
* @param {String} places the message to display if there are remaining places.
* @param {String} noPlaces the message to display if there are no remaining places left.
* @param {Ametys.cms.editor.EditorButtonController} controller the button's controller
* @return true
*/
_setFormLimitAttributes: function(limit, places, noPlaces, controller, field)
{
var form = this._currentFormLimitNode;
if (limit != null)
{
form.setAttribute("form_limit", limit);
form.setAttribute("form_places", places);
form.setAttribute("form_no_places", noPlaces);
field.getEditor().execCommand('mceAddUndoLevel');
controller.toggle(true);
controller.enable();
}
else
{
form.removeAttribute("form_limit");
form.removeAttribute("form_places");
form.removeAttribute("form_no_places");
field.getEditor().execCommand('mceAddUndoLevel');
controller.toggle(false);
controller.enable();
}
tinyMCE.activeEditor.focus();
return true;
},
/**
* Listener controlling the state of the limit button
* @param {Ametys.cms.editor.EditorButtonController} controller The controller
* @param {Ametys.cms.form.widget.RichText} field The current field. Can be null
* @param {HTMLElement} node The currently selected node. Can be null.
*/
limitListener: function(controller, field, node)
{
var form = (field != null && node != null && field.getEditor() != null) ? this._getForm(field.getEditor(), field.getEditor().selection.getNode()) : null;
if (form != null && form.getAttribute("type") != "cms")
{
form = null;
}
this._currentFormLimitNode = form;
if (!form)
{
controller.toggle(false);
controller.disable();
}
else
{
var places = this._currentFormReceiptNode.getAttribute("form_places") || "";
controller.toggle(places != '');
controller.enable();
}
},
/**
* Choose a page to redirect the user to when the form is submitted
* @param {Ametys.cms.editor.EditorButtonController} controller the button's controller
*/
redirectionAction: function(controller)
{
var value = this._currentFormRedirectNode.getAttribute("form_redirect");
Ametys.web.helper.ChoosePage.open({
iconCls: 'ametysicon-website38 decorator-ametysicon-check34',
title: "{{i18n PLUGINS_FORMS_FORMS_EDITOR_REDIRECTION_DIALOG_TITLE}}",
helpMessage: "{{i18n PLUGINS_FORMS_FORMS_EDITOR_REDIRECTION_DIALOG_DESCRIPTION}}",
values: Ext.Array.from(value),
defaultSitemapName: Ametys.cms.language.LanguageDAO.getCurrentLanguage(),
allowCreation: true,
allowDeletion: true,
callback: Ext.bind(this._redirectionAction, this, [controller], 1)
});
},
/**
* @private
* Set the redirection attribute on the form
* @param {String} pageId the id of the selected page. Can be null if no page is selected
* @param {Ametys.cms.editor.EditorButtonController} controller the button's controller
*/
_redirectionAction: function(pageId, controller)
{
if (pageId !== undefined)
{
if (pageId != null)
{
this._currentFormRedirectNode.setAttribute("form_redirect", pageId);
// FIXME "tinyMCE.activeEditor" a better method is to use the field.getEditor()
tinyMCE.activeEditor.execCommand('mceAddUndoLevel');
controller.toggle(true);
}
else
{
this._currentFormRedirectNode.removeAttribute("form_redirect");
tinyMCE.activeEditor.execCommand('mceAddUndoLevel');
controller.toggle(false);
}
controller.enable();
tinyMCE.activeEditor.focus();
}
},
/**
* Listener controlling the state of the redirection button
* @param {Ametys.cms.editor.EditorButtonController} controller The controller
* @param {Ametys.cms.form.widget.RichText} field The current field. Can be null
* @param {HTMLElement} node The currently selected node. Can be null.
*/
redirectionListener: function(controller, field, node)
{
var form = (field != null && node != null && field.getEditor() != null) ? this._getForm(field.getEditor(), field.getEditor().selection.getNode()) : null;
if (form != null && form.getAttribute("type") != "cms")
{
form = null;
}
this._currentFormRedirectNode = form;
if (!form)
{
controller.toggle(false);
controller.disable();
controller.setDescription(controller.getInitialConfig("description"));
}
else
{
var to = this._currentFormRedirectNode.getAttribute("form_redirect") || "";
controller.toggle(to != '');
controller.enable();
if (to != '')
{
Ametys.web.page.PageDAO.getPage(to, Ext.bind(this._getPageCb, this, [controller], 1));
}
else
{
var description = controller.getInitialConfig("description");
description += controller.getInitialConfig("redirection-description-no") || '';
controller.setDescription(description);
}
}
},
/**
* @private
* Callback invoked after getting the redirection page. Update the tooltip of controller.
* @param {Ametys.web.page.Page} page the page
* @param {Ametys.cms.editor.EditorButtonController} controller The controller
*/
_getPageCb: function (page, controller)
{
if (page)
{
var description = controller.getInitialConfig("description");
description += Ext.String.format("{{i18n PLUGINS_FORMS_FORMS_EDITOR_REDIRECTION_PAGE_DESCRIPTION}}", page.getTitle());
controller.setDescription(description);
}
},
/**
* Convert the selected form to an external form
* @param {Ametys.cms.editor.EditorButtonController} controller the button controller
*/
convertFormToExternal: function(controller)
{
// FIXME "tinyMCE.activeEditor" a better method is to use the field.getEditor()
tinyMCE.activeEditor.dom.removeClass(this._currentFormConvertToExternalNode, 'cmsForm');
this._currentFormConvertToExternalNode.removeAttribute("type");
this._currentFormConvertToExternalNode.removeAttribute("form_name");
this._currentFormConvertToExternalNode.removeAttribute("form_processing_emails");
this._currentFormConvertToExternalNode.removeAttribute("form_receipt_to");
this._currentFormConvertToExternalNode.removeAttribute("form_receipt_from");
this._currentFormConvertToExternalNode.removeAttribute("form_receipt_subject");
this._currentFormConvertToExternalNode.removeAttribute("form_receipt_body");
this._currentFormConvertToExternalNode.removeAttribute("form_redirect");
this._currentFormConvertToExternalNode.removeAttribute("form_limit");
this._currentFormConvertToExternalNode.removeAttribute("form_places");
this._currentFormConvertToExternalNode.removeAttribute("form_no_places");
tinyMCE.activeEditor.execCommand('mceAddUndoLevel');
tinyMCE.activeEditor.execCommand('mceSelectNode', false, this._currentFormConvertToExternalNode);
tinyMCE.activeEditor.focus();
},
/**
* Listener controlling the state of the conversion button from a CMS form to an external form
* @param {Ametys.cms.editor.EditorButtonController} controller The controller
* @param {Ametys.cms.form.widget.RichText} field The current field. Can be null
* @param {HTMLElement} node The currently selected node. Can be null.
*/
convertFormToExternalListener: function(controller, field, node)
{
var form = (field != null && node != null && field.getEditor() != null) ? this._getForm(field.getEditor(), field.getEditor().selection.getNode()) : null;
if (form == null || form.getAttribute("type") == null)
{
form = null;
}
this._currentFormConvertToExternalNode = form;
controller.setDisabled(form == null);
},
/**
* Convert the selected form to a cms form
* @param {Ametys.cms.editor.EditorButtonController} controller the button controller
*/
convertFormToCMS: function(controller)
{
// FIXME "tinyMCE.activeEditor" a better method is to use the field.getEditor()
tinyMCE.activeEditor.dom.addClass(this._currentFormConvertToCMSNode, 'cmsForm');
this._currentFormConvertToCMSNode.setAttribute("type", "cms");
this._currentFormConvertToCMSNode.setAttribute("form_name", this._findName());
tinyMCE.activeEditor.execCommand('mceAddUndoLevel');
tinyMCE.activeEditor.execCommand('mceSelectNode', false, this._currentFormConvertToCMSNode);
tinyMCE.activeEditor.focus();
},
/**
* Listener controlling the state of the conversion button from a CMS form to an external form
* @param {Ametys.cms.editor.EditorButtonController} controller The controller
* @param {Ametys.cms.form.widget.RichText} field The current field. Can be null
* @param {HTMLElement} node The currently selected node. Can be null.
*/
convertFormToCMSListener: function(controller, field, node)
{
var form = (field != null && node != null && tinyMCE.activeEditor != null) ? this._getForm(field.getEditor(), field.getEditor().selection.getNode()) : null;
if (form == null || form.getAttribute("type") == "cms")
{
form = null;
}
this._currentFormConvertToCMSNode = form;
controller.setDisabled(form == null);
},
/**
* Remove form
* @param {Ametys.cms.editor.EditorButtonController} controller the button controller
*/
removeForm: function(controller)
{
Ext.MessageBox.confirm("{{i18n PLUGINS_FORMS_FORMS_EDITOR_REMOVEFORM_CONFIRM_TITLE}}",
"{{i18n PLUGINS_FORMS_FORMS_EDITOR_REMOVEFORM_CONFIRM_TEXT}}",
Ext.bind(this._removeForm, this));
},
/**
* Actual form removal process if the user clicked 'Ok'
* @param {String} answer the user's answer
*/
_removeForm: function(answer)
{
if (answer == 'yes')
{
// FIXME "tinyMCE.activeEditor" a better method is to use the field.getEditor()
tinyMCE.activeEditor.execCommand('mceBeginUndoLevel');
var form = this._currentRemovableForm;
tinyMCE.activeEditor.execCommand('mceSelectNode', false, form);
form.parentNode.removeChild(form);
tinyMCE.activeEditor.execCommand('mceInsertContent', false, '<p><br _moz_dirty=""/></p>');
tinyMCE.activeEditor.execCommand('mceEndUndoLevel');
}
tinyMCE.activeEditor.focus();
},
/**
* Listener controlling the state of the form removal button
* @param {Ametys.cms.editor.EditorButtonController} controller The controller
* @param {Ametys.cms.form.widget.RichText} field The current field. Can be null
* @param {HTMLElement} node The currently selected node. Can be null.
*/
canRemoveForm: function(controller, field, node)
{
var form = (field != null && node != null && field.getEditor() != null) ? this._getForm(field.getEditor(), field.getEditor().selection.getNode()) : null;
controller.setDisabled(form == null);
this._currentRemovableForm = form;
},
/**
* @private
* Get the form in the editor above the given dom node
* @param {Object} editor The active editor
* @param {HTMLElement} node The currently selected node. Can be null.
* @return the dom node of the form
*/
_getForm: function(editor, node)
{
while (true)
{
var specificNode = editor && editor.dom && editor.dom.getParent(node, 'div');
if (specificNode == null)
{
return null;
}
else if (specificNode != null && specificNode.getAttribute('form') == 'form')
{
return specificNode;
}
node = specificNode.parentNode;
}
},
/**
* Compute the name of the form, comparing with possible existing form names
* @return the name of the form
*/
_findName: function()
{
var formName = "{{i18n PLUGINS_FORMS_FORMS_EDITOR_CMS_FORMNAME_DEFAULTVALUE}}";
var i = 0;
var found = false;
do
{
i++;
found = this._isFreeCMSFormName(null, formName + " " + i);
} while (!found);
return encodeURIComponent(formName + ' ' + i);
},
/**
* @private
* Is the name of the cms form available ?
* @param {String} id the id of the form
* @param {String} name the wished name for the form
* @return true if the form name is available, false otherwise
*/
_isFreeCMSFormName: function(id, name)
{
// FIXME "tinyMCE.activeEditor" a better method is to use the field.getEditor()
var forms = tinyMCE.activeEditor.dom.doc.getElementsByTagName("div");
Ext.Array.each(forms, function(form) {
if (form.getAttribute("form") == "form" && form.getAttribute("type") == "cms" && (id == null || form.id != id)
&& encodeURIComponent(name) == form.getAttribute("form_name"))
{
return false;
}
});
return true;
}
});