/*
* 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.
*/
/**
* HTML Expert singleton class.
* @private
*/
Ext.define('Ametys.plugins.cms.editor.HTMLExpert', {
singleton: true,
/**
* @private
* @property {Ametys.window.DialogBox} _box The HTML expert edition dialog box containing the script editor.
*/
/**
* @private
* @property {Ametys.form.field.Code} _scriptEditor the script editor which is a {@link Ext.form.field.TextArea} managing a CodeMirror instance.
*/
/**
* @private
* @property {HTMLElement} _currentNode the current HTML expert node to edit.
*/
/**
* Action function for the 'insert html expert' button controller.
* @param {Ametys.cms.editor.EditorButtonController} controller The controller calling this function
*/
insert: function(controller)
{
var id = Ext.id();
if (controller.getCurrentField())
{
var editor = controller.getCurrentField().getEditor();
editor.focus();
editor.execCommand('mceBeginUndoLevel');
editor.execCommand('mceInsertContent', false, Ametys.plugins.cms.editor.htmlexpert.HTMLExpertConvertor.createHTML(id, '', null, true));
editor.execCommand('mceEndUndoLevel');
var elt = editor.dom.doc.getElementById(id);
editor.execCommand('mceSelectNode', false, elt);
elt.removeAttribute('id');
}
},
/**
* Enable/disable controller and set input value according the selected image
* @param {Ametys.ribbon.element.ui.ButtonController} controller The controller
* @param {Ametys.cms.form.widget.RichText} field The current field. Can be null
* @param {HTMLElement} node The current selected node. Can be null.
*/
selectionListener: function(controller, field, node)
{
if (node)
{
var value = decodeURIComponent(node.getAttribute('htmlexpert').substring(1));
controller.setValue(value);
}
else
{
controller.setValue('');
}
this._currentNode = node;
},
/**
* Set the HTML expert code when pressing ENTER or ESC key.
* @param {Ext.form.field.TextArea} input The textearea
* @param {Ext.event.Event} e The event object
*/
setHtmlExpertOnSpecialKey: function (input, e)
{
if (e.getKey() == e.ENTER)
{
e.preventDefault();
e.stopPropagation();
this.setHtmlExpert(input.getValue());
}
else if (e.getKey() == e.ESC)
{
e.preventDefault();
e.stopPropagation();
this.setHtmlExpert(this._currentNode != null ? decodeURIComponent(this._currentNode.getAttribute("htmlexpert").substring(1)) : "");
}
},
/**
* Set the HTML expert code when the input loses the focus
* @param {Ext.form.field.TextArea} input The text area
*/
setHtmlExpertOnBlur: function (input)
{
var htmlExpertNode = this._currentNode;
var htmlExpertValue = decodeURIComponent(htmlExpertNode.getAttribute("htmlexpert").substring(1));
var inputValue = input.getValue();
if (htmlExpertValue != inputValue)
{
this.setHtmlExpert(inputValue);
}
},
/**
* Set the HTML expert code
* @param {String} value The raw value
*/
setHtmlExpert: function (value)
{
var htmlexpert = encodeURIComponent(value);
this._currentNode.setAttribute("htmlexpert", "-" + htmlexpert);
// FIXME "tinyMCE.activeEditor" a better method is to use the field.getEditor()
tinyMCE.activeEditor.execCommand('mceAddUndoLevel');
},
/**
* Edit the source HTML code
* @param {Ametys.ribbon.element.RibbonUIController} controller The UI controller holding this function
*/
edit: function (controller)
{
this._createBoxIfRequired(controller);
this._controller = controller;
// Show the box before setting the value because the ribbon has to be blurred in order to update its value
this._box.show();
var htmlexpert = this._currentNode;
if (htmlexpert)
{
var htmlexpert = decodeURIComponent(htmlexpert.getAttribute("htmlexpert").substring(1));
this._scriptEditor.setValue(htmlexpert);
this._scriptEditor.focus(1);
}
},
/**
* Create the {@link #_box} window if needed.
* @param {Ametys.ribbon.element.RibbonUIController} controller The UI controller holding the #edit function
*/
_createBoxIfRequired: function (controller)
{
if (this._box == null)
{
var northItems = [{
xtype: 'component',
cls: 'hint',
html: "{{i18n CONTENT_EDITION_HTMLEXPERT_DIALOGBOX_HINT}}"
}]
this._toolbar = this._getToolbar (controller);
if (this._toolbar != null)
{
northItems.push(this._toolbar);
}
var ratio = 0.80;
var width = window.innerWidth * ratio;
var height = window.innerHeight * ratio;
this._scriptEditor = Ext.create ("Ametys.form.field.Code", {
mode: 'htmlmixed',
scrollable: true,
flex: 1
});
this._box = Ext.create('Ametys.window.DialogBox', {
title: "{{i18n CONTENT_EDITION_HTMLEXPERT_DIALOGBOX_TITLE}}",
iconCls: 'ametysicon-computing10',
layout: {
type: 'vbox',
align: 'stretch'
},
border: false,
scrollable: false,
cls: 'ametys-dialogbox htmlexpert-dialog',
width: width,
height: height,
defaultType: 'container',
defaults: {
cls: 'ametys'
},
items: [{
layout: 'anchor',
items: northItems
},
this._scriptEditor,
{
xtype: 'component',
cls: 'hint',
html: Ext.String.format("{{i18n CONTENT_EDITION_HTMLEXPERT_DIALOGBOX_HINT2}}", controller.helpURL)
}
],
defaultFocus: 'htmlexpert-popup-source',
closeAction: 'hide',
buttons : [{
text :"{{i18n CONTENT_EDITION_HTMLEXPERT_DIALOGBOX_OK}}",
handler : Ext.bind(this._saveHtmlExpert, this)
}, {
text :"{{i18n CONTENT_EDITION_HTMLEXPERT_DIALOGBOX_CANCEL}}",
handler: Ext.bind(function() { this._box.hide(); tinyMCE.activeEditor.focus(); }, this)
}]
});
}
},
/**
* Get the toolbar
* @param {Ametys.ribbon.element.RibbonUIController} controller The UI controller holding the #edit function
* @return {Object} The toolbar configuration object or null.
* @private
*/
_getToolbar : function (controller)
{
var toolbarBtnCfg = controller.getInitialConfig("toolbar-buttons");
if (toolbarBtnCfg && toolbarBtnCfg.length > 0)
{
var toolbarBtn = [];
for (var i = 0; i < toolbarBtnCfg.length ; i++)
{
var btn = Ametys.createObjectByName(toolbarBtnCfg[i].classname, null, Ext.apply(toolbarBtnCfg[i].config, {id: toolbarBtnCfg[i].id, pluginName: toolbarBtnCfg[i].pluginName}));
toolbarBtn.push(btn.createUI());
}
return {
xtype: 'toolbar',
items: toolbarBtn
}
}
else
{
return null;
}
},
/**
* This function is called when pressing 'ok' button of dialog box #_box
* Saves the HTML expert code
* @private
*/
_saveHtmlExpert: function()
{
var htmlexpertNode = this._currentNode;
if (htmlexpertNode)
{
var value = this._scriptEditor.getValue();
var htmlexpert = encodeURIComponent(value);
htmlexpertNode.setAttribute("htmlexpert", "-" + htmlexpert);
// Set controller field value
if (this._controller)
{
this._controller.setValue(value)
}
this._box.hide();
// FIXME "tinyMCE.activeEditor" a better method is to use the field.getEditor()
tinyMCE.activeEditor.focus();
// Trigger cache update
tinyMCE.activeEditor.execCommand('mceAddUndoLevel');
}
},
// FIXME refactor? HTMLExpert button might have a similar method
insertAtCaret: function(text)
{
this._scriptEditor.getCM().replaceSelection(text);
}
});