/*
* 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.
*/
/**
* The table layout with 2 columns.
*/
Ext.define('Ametys.plugins.forms.content.layout.Table2Cols', {
singleton: true,
/**
* Unlock the table 2 columns layout : invisible table with 2 columns, left one for field names and right one for the corresponding field
* @param {Ametys.ribbon.element.ui.ButtonController} controller the controller calling this function
*/
act: function(controller)
{
if (!Ametys.plugins.forms.content.Layout._setLayoutOnNode(controller.getInitialConfig('value'), controller.getInitialConfig('css-class')))
{
return;
}
controller.getCurrentField().getEditor().execCommand('mceBeginUndoLevel');
var me = this;
Ametys.plugins.forms.content.Layout._cleanLayout();
// then rebuild
function macrorefactor(parentNode)
{
me.create(parentNode);
var table = parentNode.childNodes[parentNode.childNodes.length - 1];
while (true)
{
var element = parentNode.childNodes[0];
if (/^table$/i.test(element.tagName))
{
if (table.rows.length > 1)
{
tinyMCE.activeEditor.execCommand('mceSelectNode', false, table.rows[0].cells[0]);
Ametys.plugins.cms.editor.Tables.deleteRow();
}
break;
}
// refactor
else if (/^label$/i.test(element.tagName))
{
// does not handle now, but ensure it will be
var id = element.htmlFor;
var input = null;
if (id != null)
{
input = tinyMCE.activeEditor.dom.get(id);
if (input != null)
{
var inputform = Ametys.plugins.forms.content.Forms._getForm(controller.getCurrentField().getEditor(), input);
var labelform = Ametys.plugins.forms.content.Forms._getForm(controller.getCurrentField().getEditor(), element);
if (inputform != labelform)
{
input = null;
}
else
{
// move label after input
input.parentNode.appendChild(element);
}
}
}
if (input == null)
{
element.parentNode.removeChild(element);
}
}
else if (/^fieldset$/i.test(element.tagName))
{
me._insertRowDown(table);
tinyMCE.activeEditor.execCommand('mceSelectNode', false, table.rows[table.rows.length - 1].cells[0]);
tinyMCE.activeEditor.dom.setAttrib(tinyMCE.activeEditor.dom.select('td[data-mce-selected=\"1\"],th[data-mce-selected=\"1\"]'), 'data-mce-selected', null);
tinyMCE.activeEditor.dom.setAttrib(table.rows[table.rows.length - 1].cells[0], 'data-mce-selected', '1');
tinyMCE.activeEditor.dom.setAttrib(table.rows[table.rows.length - 1].cells[1], 'data-mce-selected', '1');
Ametys.plugins.cms.editor.Tables.mergeCells(false);
tinyMCE.activeEditor.dom.setAttrib(tinyMCE.activeEditor.dom.select('td[data-mce-selected=\"1\"],th[data-mce-selected=\"1\"]'), 'data-mce-selected', null);
table.rows[table.rows.length - 1].cells[0].appendChild(element);
macrorefactor(element);
}
else if (/^legend$/i.test(element.tagName))
{
element.parentNode.appendChild(element);
}
else if (/^img$/i.test(element.tagName))
{
var label = Ametys.plugins.forms.content.Components._getLabel(element);
me._refactor(table, label, element);
}
else
{
Ametys.Msg.show({
title: "{{i18n PLUGINS_FORMS_FORMS_EDITOR_LAYOUT_GALLERY_TABLE2COLS_ERROR_TITLE}}",
msg: "{{i18n PLUGINS_FORMS_FORMS_EDITOR_LAYOUT_GALLERY_TABLE2COLS_ERROR_DESCRIPTION}} <br />"
+ "{{i18n PLUGINS_FORMS_FORMS_EDITOR_LAYOUT_GALLERY_TABLE2COLS_ERROR_DETAILS}}<" + element.tagName + ">",
buttons: Ext.Msg.OK,
icon: Ext.MessageBox.ERROR
});
throw "Unsupported element " + element.tagName + " during refactor"
}
}
}
macrorefactor(Ametys.plugins.forms.content.Forms._currentNode);
if (Ametys.plugins.forms.content.Forms._currentNode.childNodes.length == 0)
{
this.create();
}
tinyMCE.activeEditor.execCommand('mceEndUndoLevel');
tinyMCE.activeEditor.focus();
},
/**
* Create the layout
* @param {HTMLElement} node the node where to begin the layout
*/
create: function(node)
{
node = node || Ametys.plugins.forms.content.Forms._currentNode;
var html = Ametys.plugins.cms.editor.Tables._createHTMLForTable(2, 1, "invisible", null, true);
// FIXME "tinyMCE.activeEditor" a better method is to use the field.getEditor()
var br = tinyMCE.activeEditor.dom.doc.createElement("br");
br.className = "_mce_marker";
node.appendChild(br);
tinyMCE.activeEditor.dom.setOuterHTML(br, html);
tinymce.each(tinyMCE.activeEditor.dom.select('table[_mce_new]'), function(node) {
tinyMCE.activeEditor.dom.setAttrib(node, '_mce_new', '');
});
tinyMCE.activeEditor.addVisual();
},
/**
* Insert an input text in the layout
* @param {String} name the name of the input
* @param {String} id the id of the input
* @param {String} inputHTML the html for the input
* @param {String} labelHTML the html for the label
* @param {String} more additional html
*/
insertInputText: function(name, id, inputHTML, labelHTML, more)
{
// 1 find table
// FIXME "tinyMCE.activeEditor" a better method is to use the field.getEditor()
var table = tinyMCE.activeEditor.dom.getParent(tinyMCE.activeEditor.selection.getNode(), 'table');
var form = Ametys.plugins.forms.content.Forms._getForm(tinymce.activeEditor, table);
if (form == null || table == null)
{
Ametys.Msg.show({
title: "{{i18n PLUGINS_FORMS_FORMS_EDITOR_LAYOUT_GALLERY_TABLE2COLS_INSERT_ERROR_TITLE}}",
msg: "{{i18n PLUGINS_FORMS_FORMS_EDITOR_LAYOUT_GALLERY_TABLE2COLS_INSERT_ERROR_DESCRIPTION}} <br />"
+ "{{i18n PLUGINS_FORMS_FORMS_EDITOR_LAYOUT_GALLERY_TABLE2COLS_INSERT_ERROR_DETAILS}}",
buttons: Ext.Msg.OK,
icon: Ext.MessageBox.ERROR
});
return;
}
// 2 find the row
var row = tinyMCE.activeEditor.dom.getParent(tinyMCE.activeEditor.selection.getNode(), "tr");
if (table.rows[row.rowIndex] != row)
{
row = null;
}
tinyMCE.activeEditor.execCommand('mceBeginUndoLevel');
// 3 insert a new row if needed
function isEmpty(row)
{
for (var i = 0; i < row.cells.length; i++)
{
if (row.cells[i].childNodes.length > 1)
{
return false;
}
if (row.cells[i].childNodes.length == 1)
{
if (row.cells[i].childNodes[0].innerHTML.replace(/<p>/gi, '').replace(/<\/p>/gi, '').replace(/<br _mce_bogus="1">/gi, '').replace(/ /gi, '') != '')
{
return false;
}
}
}
return true;
}
var index = row != null ? row.rowIndex : table.rows.length - 1;
if (index != 0 || !isEmpty(table.rows[index]))
{
this._insertRowDown(table, index);
index++;
}
// 4 insert the labels
if (labelHTML != null && labelHTML != "")
{
// FIXME "tinyMCE.activeEditor" a better method is to use the field.getEditor()
tinyMCE.activeEditor.dom.setAttrib(tinyMCE.activeEditor.dom.select('td[data-mce-selected=\"1\"],th[data-mce-selected=\"1\"]'), 'data-mce-selected', null);
tinyMCE.activeEditor.execCommand('mceSelectNode', false, table.rows[index].cells[0].childNodes[0]);
Ametys.plugins.cms.editor.Tables.alignTable("right", "top");
tinyMCE.activeEditor.execCommand('mceSelectNode', false, table.rows[index].cells[1].childNodes[0]);
table.rows[index].cells[0].innerHTML = Ametys.plugins.cms.editor.Tables._createInnerHTML(labelHTML);
table.rows[index].cells[1].innerHTML = Ametys.plugins.cms.editor.Tables._createInnerHTML(inputHTML);
}
else
{
// FIXME "tinyMCE.activeEditor" a better method is to use the field.getEditor()
tinyMCE.activeEditor.execCommand('mceSelectNode', false, table.rows[index].cells[0]);
tinyMCE.activeEditor.dom.setAttrib(tinyMCE.activeEditor.dom.select('td[data-mce-selected=\"1\"],th[data-mce-selected=\"1\"]'), 'data-mce-selected', null);
tinyMCE.activeEditor.dom.setAttrib(table.rows[index].cells[0], 'data-mce-selected', '1');
tinyMCE.activeEditor.dom.setAttrib(table.rows[index].cells[0], 'data-mce-first-selected', '1');
tinyMCE.activeEditor.dom.setAttrib(table.rows[index].cells[1], 'data-mce-selected', '1');
tinyMCE.activeEditor.dom.setAttrib(table.rows[index].cells[1], 'data-mce-last-selected', '1');
Ametys.plugins.cms.editor.Tables.mergeCells(true);
tinyMCE.activeEditor.dom.setAttrib(tinyMCE.activeEditor.dom.select('td[data-mce-selected=\"1\"],th[data-mce-selected=\"1\"]'), 'data-mce-first-selected', null);
tinyMCE.activeEditor.dom.setAttrib(tinyMCE.activeEditor.dom.select('td[data-mce-selected=\"1\"],th[data-mce-selected=\"1\"]'), 'data-mce-last-selected', null);
tinyMCE.activeEditor.dom.setAttrib(tinyMCE.activeEditor.dom.select('td[data-mce-selected=\"1\"],th[data-mce-selected=\"1\"]'), 'data-mce-selected', null);
tinyMCE.activeEditor.execCommand('mceSelectNode', false, table.rows[index].cells[0].childNodes[0].childNodes[0]);
table.rows[index].cells[0].innerHTML = Ametys.plugins.cms.editor.Tables._createInnerHTML(inputHTML);
Ametys.plugins.cms.editor.Tables.alignTable("center", "middle");
}
tinyMCE.activeEditor.execCommand('mceEndUndoLevel');
},
/**
* Insert a text area in the layout
* @param {String} name the name of the input
* @param {String} id the id of the input
* @param {String} inputHTML the html for the input
* @param {String} labelHTML the html for the label
* @param {String} more additional html
*/
insertTextarea: function(name, id, inputHTML, labelHTML, more)
{
this.insertInputText(name, id, inputHTML, labelHTML, more);
},
/**
* Insert a select input in the layout
* @param {String} name the name of the input
* @param {String} id the id of the input
* @param {String} inputHTML the html for the input
* @param {String} labelHTML the html for the label
* @param {String} more additional html
*/
insertSelect: function(name, id, inputHTML, labelHTML, more)
{
this.insertInputText(name, id, inputHTML, labelHTML, more);
},
/**
* Insert a select input in the layout
* @param {String} name the name of the input
* @param {String} id the id of the input
* @param {String} inputHTML the html for the input
* @param {String} labelHTML the html for the label
* @param {String} more additional html
*/
insertCaptcha: function(name, id, inputHTML, labelHTML, more)
{
this.insertInputText(name, id, inputHTML, labelHTML, more);
},
/**
* Insert a select input in the layout
* @param {String} name the name of the input
* @param {String} id the id of the input
* @param {String} inputHTML the html for the input
* @param {String} labelHTML the html for the label
* @param {String} more additional html
*/
insertInputCheckbox: function(name, id, inputHTML, labelHTML, more)
{
this.insertInputText(name, id, inputHTML, labelHTML, more);
},
/**
* Insert a select input in the layout
* @param {String} name the name of the input
* @param {String} id the id of the input
* @param {String} inputHTML the html for the input
* @param {String} labelHTML the html for the label
* @param {String} more additional html
*/
insertInputRadio: function(name, id, inputHTML, labelHTML, more)
{
this.insertInputText(name, id, inputHTML, labelHTML, more);
},
/**
* Insert a password input in the layout
* @param {String} name the name of the input
* @param {String} id the id of the input
* @param {String} inputHTML the html for the input
* @param {String} labelHTML the html for the label
* @param {String} more additional html
*/
insertInputPassword: function(name, id, inputHTML, labelHTML, more)
{
this.insertInputText(name, id, inputHTML, labelHTML, more);
},
/**
* Insert a cost field in the layout
* @param {String} name the name of the input
* @param {String} id the id of the input
* @param {String} inputHTML the html for the input
* @param {String} labelHTML the html for the label
* @param {String} more additional html
*/
insertInputCost: function(name, id, inputHTML, labelHTML, more)
{
this.insertInputText(name, id, inputHTML, labelHTML, more);
},
/**
* Insert a select input in the layout
* @param {String} name the name of the input
* @param {String} id the id of the input
* @param {String} inputHTML the html for the input
* @param {String} labelHTML the html for the label
* @param {String} more additional html
*/
insertInputFile: function(name, id, inputHTML, labelHTML, more)
{
this.insertInputText(name, id, inputHTML, labelHTML, more);
},
/**
* Insert a select input in the layout
* @param {String} name the name of the input
* @param {String} id the id of the input
* @param {String} inputHTML the html for the input
*/
insertInputHidden: function(name, id, inputHTML)
{
// FIXME "tinyMCE.activeEditor" a better method is to use the field.getEditor()
tinyMCE.activeEditor.execCommand('mceBeginUndoLevel');
tinyMCE.activeEditor.selection.collapse();
tinyMCE.activeEditor.execCommand('mceInsertContent', false, inputHTML);
tinyMCE.activeEditor.execCommand('mceEndUndoLevel');
tinyMCE.activeEditor.execCommand('mceSelectNode', false, tinyMCE.activeEditor.dom.doc.getElementById(id));
},
/**
* Insert a select input in the layout
* @param {String} id the id of the fieldset
* @param {String} inputHTML the html for the fieldset
*/
insertFieldset: function(id, inputHTML)
{
this.insertInputText(null, id, inputHTML, null);
// FIXME "tinyMCE.activeEditor" a better method is to use the field.getEditor()
var fieldset = tinyMCE.activeEditor.dom.doc.getElementById(id);
fieldset.removeChild(fieldset.childNodes[fieldset.childNodes.length - 1]); // to remove the p included in the html
this.create(fieldset);
tinyMCE.activeEditor.execCommand('mceSelectNode', false, fieldset.childNodes[fieldset.childNodes.length - 1].rows[0].cells[0]);
},
/**
* Insert a select input in the layout
* @param {String} name the name of the input
* @param {String} id the id of the input
* @param {String} inputHTML the html for the input
* @param {String} labelHTML the html for the label
* @param {String} more additional html
*/
insertInputSubmit: function(name, id, inputHTML, labelHTML, more)
{
this.insertInputText(name, id, inputHTML, labelHTML, more);
},
/**
* Insert a select input in the layout
* @param {String} name the name of the input
* @param {String} id the id of the input
* @param {String} inputHTML the html for the input
* @param {String} labelHTML the html for the label
* @param {String} more additional html
*/
insertInputReset: function(name, id, inputHTML, labelHTML, more)
{
this.insertInputText(name, id, inputHTML, labelHTML, more);
},
/**
* Move the selected input up
* @param {HTMLElement} input the input to move
*/
moveUp: function(input)
{
// FIXME "tinyMCE.activeEditor" a better method is to use the field.getEditor()
var rowToMove = tinyMCE.activeEditor.dom.getParent(input, "tr");
var rowToMoveIsInside = false;
var currentRow = rowToMove;
while (true)
{
if (currentRow == null)
{
break;
}
else
{
var where = rowToMoveIsInside ? currentRow : currentRow.previousSibling;
if (where == null)
{
// goes up
currentRow = tinyMCE.activeEditor.dom.getParent(currentRow.parentNode, "tr");
rowToMoveIsInside = true;
}
else
{
var wherePreceding = rowToMoveIsInside ? where.previousSibling : where;
if (wherePreceding != null)
{
var fieldsets = tinyMCE.activeEditor.dom.select("fieldset table", wherePreceding);
if (fieldsets.length == 0)
{
where.parentNode.insertBefore(rowToMove, where);
}
else
{
while (true)
{
var fieldsets = tinyMCE.activeEditor.dom.select("fieldset table", wherePreceding);
if (fieldsets.length == 0)
{
wherePreceding.parentNode.insertBefore(rowToMove, null);
break;
}
else
{
// goes down
wherePreceding = fieldsets[0].rows[fieldsets[0].rows.length - 1];
}
}
}
}
break;
}
}
}
},
/**
* Move the selected input down
* @param {HTMLElement} input the input to move
*/
moveDown: function(input)
{
// FIXME "tinyMCE.activeEditor" a better method is to use the field.getEditor()
var rowToMove = tinyMCE.activeEditor.dom.getParent(input, "tr");
var rowToMoveIsInside = false;
var currentRow = rowToMove;
while (true)
{
if (currentRow == null)
{
break;
}
else
{
var where = rowToMoveIsInside ? currentRow : currentRow.nextSibling;
if (where == null)
{
// goes up
currentRow = tinyMCE.activeEditor.dom.getParent(currentRow.parentNode, "tr");
rowToMoveIsInside = true;
}
else
{
var whereFollowing = rowToMoveIsInside ? where.nextSibling : where;
if (whereFollowing != null)
{
var fieldsets = tinyMCE.activeEditor.dom.select("fieldset table", whereFollowing);
if (fieldsets.length == 0)
{
where.parentNode.insertBefore(rowToMove, where.nextSibling);
}
else
{
while (true)
{
var fieldsets = tinyMCE.activeEditor.dom.select("fieldset table", whereFollowing);
if (fieldsets.length == 0)
{
whereFollowing.parentNode.insertBefore(rowToMove, whereFollowing.parentNode.childNodes[0]);
break;
}
else
{
// goes down
whereFollowing = fieldsets[0].rows[0];
}
}
}
}
break;
}
}
}
},
/**
* Remove the selected input
* @param {HTMLElement} input the input
*/
remove: function(input)
{
// FIXME "tinyMCE.activeEditor" a better method is to use the field.getEditor()
var cell = tinyMCE.activeEditor.dom.getParent(input, "td,th");
if (cell != null)
{
var table = tinyMCE.activeEditor.dom.getParent(input, "table");
if (table.rows.length == 1)
{
tinyMCE.activeEditor.execCommand('mceSelectNode', false, cell);
this._insertRowDown(table);
}
tinyMCE.activeEditor.execCommand('mceSelectNode', false, cell);
Ametys.plugins.cms.editor.Tables.deleteRow();
}
},
/**
* Insert a new line to the table and set the label and input
* @param {HTMLElement} table the dom node of the table
* @param {String} label label the label
* @param {HTMLElement} input the input
* @param {Number} index the index
*/
_refactor: function (table, label, input, index)
{
index = index != null ? index : table.rows.length - 1;
this._insertRowDown(table, index);
index++;
if (label)
{
table.rows[index].cells[0].insertBefore(label, table.rows[index].cells[0].childNodes[0]);
table.rows[index].cells[1].insertBefore(input, table.rows[index].cells[1].childNodes[0]);
// FIXME "tinyMCE.activeEditor" a better method is to use the field.getEditor()
tinyMCE.activeEditor.dom.setAttrib(tinyMCE.activeEditor.dom.select('td[data-mce-selected=\"1\"],th[data-mce-selected=\"1\"]'), 'data-mce-selected', null);
tinyMCE.activeEditor.execCommand('mceSelectNode', false, table.rows[index].cells[0].childNodes[0]);
Ametys.plugins.cms.editor.Tables.alignTable("right", "top");
}
else
{
// FIXME "tinyMCE.activeEditor" a better method is to use the field.getEditor()
tinyMCE.activeEditor.execCommand('mceSelectNode', false, table.rows[index].cells[0]);
tinyMCE.activeEditor.dom.setAttrib(tinyMCE.activeEditor.dom.select('td[data-mce-selected=\"1\"],th[data-mce-selected=\"1\"]'), 'data-mce-selected', null);
tinyMCE.activeEditor.dom.setAttrib(table.rows[index].cells[0], 'data-mce-selected', '1');
tinyMCE.activeEditor.dom.setAttrib(table.rows[index].cells[0], 'data-mce-first-selected', '1');
tinyMCE.activeEditor.dom.setAttrib(table.rows[index].cells[1], 'data-mce-selected', '1');
tinyMCE.activeEditor.dom.setAttrib(table.rows[index].cells[1], 'data-mce-last-selected', '1');
Ametys.plugins.cms.editor.Tables.mergeCells(true);
tinyMCE.activeEditor.dom.setAttrib(tinyMCE.activeEditor.dom.select('td[data-mce-selected=\"1\"],th[data-mce-selected=\"1\"]'), 'data-mce-first-selected', null);
tinyMCE.activeEditor.dom.setAttrib(tinyMCE.activeEditor.dom.select('td[data-mce-selected=\"1\"],th[data-mce-selected=\"1\"]'), 'data-mce-last-selected', null);
tinyMCE.activeEditor.dom.setAttrib(tinyMCE.activeEditor.dom.select('td[data-mce-selected=\"1\"],th[data-mce-selected=\"1\"]'), 'data-mce-selected', null);
Ametys.plugins.cms.editor.Tables.alignTable("center", "middle");
table.rows[index].cells[0].insertBefore(input, table.rows[index].cells[0].childNodes[0]);
}
},
/**
* Insert a row down the selected row
* @param {HTMLElement} table the dom node of the table
* @param {Number} index the index at which insert the table. Can be null to insert at the bottom of the table
*/
_insertRowDown: function(table, index)
{
index = index == null ? table.rows.length - 1 : index;
tinyMCE.activeEditor.execCommand('mceSelectNode', false, table.rows[index].cells[0]);
Ametys.plugins.cms.editor.Tables.insertRowDown(true, table);
index++;
tinyMCE.activeEditor.dom.setAttrib(tinyMCE.activeEditor.dom.select('td[data-mce-selected=\"1\"],th[data-mce-selected=\"1\"]'), 'data-mce-selected', null);
tinyMCE.activeEditor.execCommand('mceSelectNode', false, table.rows[index].cells[0]);
for (var i = 0; i < table.rows[index].cells.length; i++)
{
tinyMCE.activeEditor.dom.setAttrib(table.rows[index].cells[i], 'data-mce-selected', '1');
}
Ametys.plugins.cms.editor.Tables.splitCells(false);
tinyMCE.activeEditor.dom.setAttrib(tinyMCE.activeEditor.dom.select('td[data-mce-selected=\"1\"],th[data-mce-selected=\"1\"]'), 'data-mce-selected', null);
table.rows[index].cells[0].innerHTML = Ametys.plugins.cms.editor.Tables._createInnerHTML();
}
});