2627 lines
100 KiB
JavaScript
2627 lines
100 KiB
JavaScript
|
/*****************************************************************************
|
||
|
*
|
||
|
* Copyright (c) 2003-2005 Kupu Contributors. All rights reserved.
|
||
|
*
|
||
|
* This software is distributed under the terms of the Kupu
|
||
|
* License. See LICENSE.txt for license text. For a list of Kupu
|
||
|
* Contributors see CREDITS.txt.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
// $Id: kupusilvatools.js 19933 2005-11-16 14:56:53Z guido $
|
||
|
|
||
|
// a mapping from namespace to field names, here you can configure which
|
||
|
// metadata fields should be editable with the property editor (needs to
|
||
|
// be moved to somewhere in Silva or something?)
|
||
|
EDITABLE_METADATA = {
|
||
|
'http://infrae.com/namespaces/metadata/silva-news':
|
||
|
[['subjects', 'checkbox', 1, 'Subjects'],
|
||
|
['target_audiences', 'checkbox', 1, 'Target audiences'],
|
||
|
['start_datetime', 'datetime', 1, 'Start date/time'],
|
||
|
['end_datetime', 'datetime', 0, 'End date/time'],
|
||
|
['location', 'text', 0, 'Location']
|
||
|
]
|
||
|
}
|
||
|
|
||
|
function SilvaLinkTool() {
|
||
|
/* redefine the contextmenu elements */
|
||
|
};
|
||
|
|
||
|
SilvaLinkTool.prototype = new LinkTool;
|
||
|
|
||
|
SilvaLinkTool.prototype.updateLink = function (linkel, url, type,
|
||
|
name, target, title) {
|
||
|
if (type && type == 'anchor') {
|
||
|
linkel.removeAttribute('href');
|
||
|
linkel.setAttribute('name', name);
|
||
|
} else {
|
||
|
linkel.href = url;
|
||
|
linkel.setAttribute('silva_href', url);
|
||
|
if (linkel.innerHTML == "") {
|
||
|
var doc = this.editor.getInnerDocument();
|
||
|
linkel.appendChild(doc.createTextNode(title || url));
|
||
|
}
|
||
|
if (title) {
|
||
|
linkel.title = title;
|
||
|
} else {
|
||
|
linkel.removeAttribute('title');
|
||
|
}
|
||
|
if (target && target != '') {
|
||
|
linkel.setAttribute('target', target);
|
||
|
}
|
||
|
else {
|
||
|
linkel.removeAttribute('target');
|
||
|
};
|
||
|
linkel.style.color = this.linkcolor;
|
||
|
};
|
||
|
};
|
||
|
|
||
|
SilvaLinkTool.prototype.createContextMenuElements = function(selNode, event) {
|
||
|
/* create the 'Create link' or 'Remove link' menu elements */
|
||
|
var ret = new Array();
|
||
|
var link = this.editor.getNearestParentOfType(selNode, 'a');
|
||
|
if (link) {
|
||
|
ret.push(new ContextMenuElement('Delete link', this.deleteLink, this));
|
||
|
} else {
|
||
|
ret.push(new ContextMenuElement('Create link', getLink, this));
|
||
|
};
|
||
|
return ret;
|
||
|
};
|
||
|
|
||
|
function SilvaLinkToolBox(inputid, targetselectid, targetinputid,
|
||
|
addbuttonid, updatebuttonid, delbuttonid,
|
||
|
toolboxid, plainclass, activeclass) {
|
||
|
/* create and edit links */
|
||
|
|
||
|
this.input = getFromSelector(inputid);
|
||
|
this.targetselect = getFromSelector(targetselectid);
|
||
|
this.targetinput = getFromSelector(targetinputid);
|
||
|
this.addbutton = getFromSelector(addbuttonid);
|
||
|
this.updatebutton = getFromSelector(updatebuttonid);
|
||
|
this.delbutton = getFromSelector(delbuttonid);
|
||
|
this.toolboxel = getFromSelector(toolboxid);
|
||
|
this.plainclass = plainclass;
|
||
|
this.activeclass = activeclass;
|
||
|
};
|
||
|
|
||
|
SilvaLinkToolBox.prototype = new LinkToolBox;
|
||
|
|
||
|
SilvaLinkToolBox.prototype.initialize = function(tool, editor) {
|
||
|
this.tool = tool;
|
||
|
this.editor = editor;
|
||
|
addEventHandler(this.targetselect, 'change', this.selectTargetHandler, this);
|
||
|
addEventHandler(this.targetinput, 'change', this.selectTargetHandler, this);
|
||
|
addEventHandler(this.addbutton, 'click', this.createLinkHandler, this);
|
||
|
addEventHandler(this.updatebutton, 'click', this.createLinkHandler, this);
|
||
|
addEventHandler(this.delbutton, 'click', this.tool.deleteLink, this);
|
||
|
this.targetinput.style.display = 'none';
|
||
|
this.editor.logMessage('Link tool initialized');
|
||
|
};
|
||
|
|
||
|
SilvaLinkToolBox.prototype.selectTargetHandler = function(event) {
|
||
|
var select = this.targetselect;
|
||
|
var input = this.targetinput;
|
||
|
|
||
|
var selvalue = select.options[select.selectedIndex].value;
|
||
|
if (selvalue != 'input') {
|
||
|
input.style.display = 'none';
|
||
|
} else {
|
||
|
input.style.display = 'inline';
|
||
|
};
|
||
|
};
|
||
|
|
||
|
SilvaLinkToolBox.prototype.createLinkHandler = function(event) {
|
||
|
var url = this.input.value;
|
||
|
var target = this.targetselect.options[
|
||
|
this.targetselect.selectedIndex].value;
|
||
|
if (target == 'input') {
|
||
|
target = this.targetinput.value;
|
||
|
};
|
||
|
this.tool.createLink(url, 'link', null, target);
|
||
|
};
|
||
|
|
||
|
SilvaLinkToolBox.prototype.updateState = function(selNode, event) {
|
||
|
var currnode = selNode;
|
||
|
var link = false;
|
||
|
var href = '';
|
||
|
while (currnode) {
|
||
|
if (currnode.nodeName.toLowerCase() == 'a') {
|
||
|
href = currnode.getAttribute('silva_href');
|
||
|
if (!href) {
|
||
|
href = currnode.getAttribute('href');
|
||
|
};
|
||
|
if (href) {
|
||
|
if (this.toolboxel) {
|
||
|
this.toolboxel.className = this.activeclass;
|
||
|
if (this.toolboxel.open_handler) {
|
||
|
this.toolboxel.open_handler();
|
||
|
};
|
||
|
};
|
||
|
this.input.value = href;
|
||
|
var target = currnode.getAttribute('target');
|
||
|
if (!target) {
|
||
|
this.targetselect.selectedIndex = 0;
|
||
|
this.targetinput.style.display = 'none';
|
||
|
} else {
|
||
|
var target_found = false;
|
||
|
for (var i=0; i < this.targetselect.options.length; i++) {
|
||
|
var option = this.targetselect.options[i];
|
||
|
if (option.value == target) {
|
||
|
this.targetselect.selectedIndex = i;
|
||
|
target_found = true;
|
||
|
break;
|
||
|
};
|
||
|
};
|
||
|
if (target_found) {
|
||
|
this.targetinput.value = '';
|
||
|
this.targetinput.style.display = 'none';
|
||
|
} else {
|
||
|
// XXX this is pretty hard-coded...
|
||
|
this.targetselect.selectedIndex =
|
||
|
this.targetselect.options.length - 1;
|
||
|
this.targetinput.value = target;
|
||
|
this.targetinput.style.display = 'inline';
|
||
|
};
|
||
|
};
|
||
|
this.addbutton.style.display = 'none';
|
||
|
this.updatebutton.style.display = 'inline';
|
||
|
this.delbutton.style.display = 'inline';
|
||
|
return;
|
||
|
};
|
||
|
};
|
||
|
currnode = currnode.parentNode;
|
||
|
};
|
||
|
this.targetselect.selectedIndex = 0;
|
||
|
this.targetinput.value = '';
|
||
|
this.targetinput.style.display = 'none';
|
||
|
this.updatebutton.style.display = 'none';
|
||
|
this.delbutton.style.display = 'none';
|
||
|
this.addbutton.style.display = 'inline';
|
||
|
if (this.toolboxel) {
|
||
|
this.toolboxel.className = this.plainclass;
|
||
|
};
|
||
|
this.input.value = '';
|
||
|
};
|
||
|
|
||
|
function SilvaImageTool(editelid, urlinputid, targetselectid, targetinputid,
|
||
|
hireslinkradioid, linklinkradioid, linkinputid,
|
||
|
alignselectid, titleinputid, toolboxid, plainclass,
|
||
|
activeclass) {
|
||
|
/* Silva specific image tool */
|
||
|
this.editel = getFromSelector(editelid);
|
||
|
this.urlinput = getFromSelector(urlinputid);
|
||
|
this.targetselect = getFromSelector(targetselectid);
|
||
|
this.targetinput = getFromSelector(targetinputid);
|
||
|
this.hireslinkradio = getFromSelector(hireslinkradioid);
|
||
|
this.linklinkradio = getFromSelector(linklinkradioid);
|
||
|
this.linkinput = getFromSelector(linkinputid);
|
||
|
this.alignselect = getFromSelector(alignselectid);
|
||
|
this.titleinput = getFromSelector(titleinputid);
|
||
|
this.toolboxel = getFromSelector(toolboxid);
|
||
|
this.plainclass = plainclass;
|
||
|
this.activeclass = activeclass;
|
||
|
}
|
||
|
|
||
|
SilvaImageTool.prototype = new ImageTool;
|
||
|
|
||
|
SilvaImageTool.prototype.initialize = function(editor) {
|
||
|
this.editor = editor;
|
||
|
addEventHandler(this.targetselect, 'change', this.setTarget, this);
|
||
|
addEventHandler(this.targetselect, 'change', this.selectTargetHandler, this);
|
||
|
addEventHandler(this.targetinput, 'change', this.setTarget, this);
|
||
|
addEventHandler(this.urlinput, 'change', this.setSrc, this);
|
||
|
addEventHandler(this.hireslinkradio, 'click', this.setHires, this);
|
||
|
addEventHandler(this.linklinkradio, 'click', this.setNoHires, this);
|
||
|
addEventHandler(this.linkinput, 'keypress', this.setLink, this);
|
||
|
addEventHandler(this.linkinput, 'change', this.setLink, this);
|
||
|
addEventHandler(this.alignselect, 'change', this.setAlign, this);
|
||
|
addEventHandler(this.titleinput, 'change', this.setTitle, this);
|
||
|
this.targetinput.style.display = 'none';
|
||
|
this.editor.logMessage('Image tool initialized');
|
||
|
};
|
||
|
|
||
|
SilvaImageTool.prototype.createContextMenuElements = function(selNode, event) {
|
||
|
return new Array(new ContextMenuElement('Create image', getImage, this));
|
||
|
};
|
||
|
|
||
|
SilvaImageTool.prototype.selectTargetHandler = function(event) {
|
||
|
var select = this.targetselect;
|
||
|
var input = this.targetinput;
|
||
|
|
||
|
var selvalue = select.options[select.selectedIndex].value;
|
||
|
if (selvalue != 'input') {
|
||
|
input.style.display = 'none';
|
||
|
} else {
|
||
|
input.style.display = 'inline';
|
||
|
};
|
||
|
};
|
||
|
|
||
|
SilvaImageTool.prototype.updateState = function(selNode, event) {
|
||
|
var image = this.editor.getNearestParentOfType(selNode, 'img');
|
||
|
if (image) {
|
||
|
this.editel.style.display = 'block';
|
||
|
var src = image.getAttribute('silva_src');
|
||
|
if (!src) {
|
||
|
src = image.getAttribute('src');
|
||
|
};
|
||
|
this.urlinput.value = src;
|
||
|
var target = image.getAttribute('target');
|
||
|
if (!target) {
|
||
|
this.targetselect.selectedIndex = 0;
|
||
|
this.targetinput.style.display = 'none';
|
||
|
} else {
|
||
|
var target_found = false;
|
||
|
for (var i=0; i < this.targetselect.options.length; i++) {
|
||
|
var option = this.targetselect.options[i];
|
||
|
if (option.value == target) {
|
||
|
this.targetselect.selectedIndex = i;
|
||
|
target_found = true;
|
||
|
break;
|
||
|
};
|
||
|
};
|
||
|
if (target_found) {
|
||
|
this.targetinput.value = '';
|
||
|
this.targetinput.style.display = 'none';
|
||
|
} else {
|
||
|
this.targetselect.selectedIndex = this.targetselect.options.length - 1;
|
||
|
this.targetinput.value = target;
|
||
|
this.targetinput.style.display = 'inline';
|
||
|
};
|
||
|
};
|
||
|
var hires = image.getAttribute('link_to_hires') == '1';
|
||
|
if (!hires) {
|
||
|
var link = image.getAttribute('link');
|
||
|
this.linklinkradio.checked = 'selected';
|
||
|
this.linkinput.value = link == null ? '' : link;
|
||
|
} else {
|
||
|
this.hireslinkradio.checked = 'checked';
|
||
|
this.linkinput.value = '';
|
||
|
};
|
||
|
if (this.toolboxel) {
|
||
|
if (this.toolboxel.open_handler) {
|
||
|
this.toolboxel.open_handler();
|
||
|
};
|
||
|
this.toolboxel.className = this.activeclass;
|
||
|
};
|
||
|
var align = image.getAttribute('alignment');
|
||
|
if (!align) {
|
||
|
align = 'left';
|
||
|
};
|
||
|
var title = image.getAttribute('title');
|
||
|
if (!title) {
|
||
|
title = '';
|
||
|
};
|
||
|
this.titleinput.value = title;
|
||
|
selectSelectItem(this.alignselect, align);
|
||
|
} else {
|
||
|
this.editel.style.display = 'none';
|
||
|
this.urlinput.value = '';
|
||
|
this.titleinput.value = '';
|
||
|
if (this.toolboxel) {
|
||
|
this.toolboxel.className = this.plainclass;
|
||
|
};
|
||
|
this.targetselect.selectedIndex = 0;
|
||
|
this.targetinput.value = '';
|
||
|
this.targetinput.style.display = 'none';
|
||
|
};
|
||
|
};
|
||
|
|
||
|
SilvaImageTool.prototype.createImage = function(url, alttext, imgclass) {
|
||
|
/* create an image */
|
||
|
var img = this.editor.getInnerDocument().createElement('img');
|
||
|
img.src = url;
|
||
|
img.setAttribute('silva_src', url);
|
||
|
img.removeAttribute('height');
|
||
|
img.removeAttribute('width');
|
||
|
if (alttext) {
|
||
|
img.alt = alttext;
|
||
|
};
|
||
|
if (imgclass) {
|
||
|
img.className = imgclass;
|
||
|
};
|
||
|
img = this.editor.insertNodeAtSelection(img, 1);
|
||
|
this.editor.logMessage(_('Image inserted'));
|
||
|
this.editor.updateState();
|
||
|
return img;
|
||
|
};
|
||
|
|
||
|
SilvaImageTool.prototype.setTarget = function() {
|
||
|
var target = this.targetselect.options[this.targetselect.selectedIndex].value;
|
||
|
if (target == 'input') {
|
||
|
target = this.targetinput.value;
|
||
|
};
|
||
|
var selNode = this.editor.getSelectedNode();
|
||
|
var image = this.editor.getNearestParentOfType(selNode, 'img');
|
||
|
if (!image) {
|
||
|
this.editor.logMessage('No image selected!', 1);
|
||
|
};
|
||
|
image.setAttribute('target', target);
|
||
|
};
|
||
|
|
||
|
SilvaImageTool.prototype.setSrc = function() {
|
||
|
var selNode = this.editor.getSelectedNode();
|
||
|
var img = this.editor.getNearestParentOfType(selNode, 'img');
|
||
|
if (!img) {
|
||
|
this.editor.logMessage('Not inside an image!', 1);
|
||
|
};
|
||
|
|
||
|
var src = this.urlinput.value;
|
||
|
img.setAttribute('src', src);
|
||
|
img.setAttribute('silva_src', src);
|
||
|
this.editor.logMessage('Image updated');
|
||
|
};
|
||
|
|
||
|
SilvaImageTool.prototype.setHires = function() {
|
||
|
var selNode = this.editor.getSelectedNode();
|
||
|
var image = this.editor.getNearestParentOfType(selNode, 'img');
|
||
|
if (!image) {
|
||
|
this.editor.logMessage('No image selected!', 1);
|
||
|
return;
|
||
|
};
|
||
|
image.setAttribute('link_to_hires', '1');
|
||
|
image.removeAttribute('link');
|
||
|
this.linkinput.value = '';
|
||
|
};
|
||
|
|
||
|
SilvaImageTool.prototype.setNoHires = function() {
|
||
|
var selNode = this.editor.getSelectedNode();
|
||
|
var image = this.editor.getNearestParentOfType(selNode, 'img');
|
||
|
if (!image) {
|
||
|
this.editor.logMessage('Not inside an image!', 1);
|
||
|
return;
|
||
|
};
|
||
|
var link = this.linkinput.value;
|
||
|
image.setAttribute('link_to_hires', '0');
|
||
|
image.setAttribute('link', link);
|
||
|
this.linklinkradio.setAttribute('selected', 'selected');
|
||
|
};
|
||
|
|
||
|
SilvaImageTool.prototype.setLink = function() {
|
||
|
var link = this.linkinput.value;
|
||
|
var selNode = this.editor.getSelectedNode();
|
||
|
var image = this.editor.getNearestParentOfType(selNode, 'img');
|
||
|
if (!image) {
|
||
|
this.editor.logMessage('No image selected!', 1);
|
||
|
return;
|
||
|
};
|
||
|
image.setAttribute('link', link);
|
||
|
image.setAttribute('link_to_hires', '0');
|
||
|
};
|
||
|
|
||
|
SilvaImageTool.prototype.setTitle = function() {
|
||
|
var selNode = this.editor.getSelectedNode();
|
||
|
var image = this.editor.getNearestParentOfType(selNode, 'img');
|
||
|
if (!image) {
|
||
|
this.editor.logMessage('No image selected!', 1);
|
||
|
return;
|
||
|
};
|
||
|
var title = this.titleinput.value;
|
||
|
image.setAttribute('title', title);
|
||
|
};
|
||
|
|
||
|
SilvaImageTool.prototype.setAlign = function() {
|
||
|
var selNode = this.editor.getSelectedNode();
|
||
|
var image = this.editor.getNearestParentOfType(selNode, 'img');
|
||
|
if (!image) {
|
||
|
this.editor.logMessage('Not inside an image', 1);
|
||
|
return;
|
||
|
};
|
||
|
var align = this.alignselect.options[this.alignselect.selectedIndex].value;
|
||
|
image.setAttribute('alignment', align);
|
||
|
};
|
||
|
|
||
|
function SilvaTableTool() {
|
||
|
/* Silva specific table functionality
|
||
|
overrides most of the table functionality, required because Silva requires
|
||
|
a completely different format for tables
|
||
|
*/
|
||
|
|
||
|
this.createTable = function(rows, cols, makeHeader, tableclass) {
|
||
|
/* add a Silvs specific table, with an (optional) header with colspan */
|
||
|
var doc = this.editor.getInnerDocument();
|
||
|
|
||
|
var table = doc.createElement('table');
|
||
|
table.style.width = "100%";
|
||
|
table.className = tableclass;
|
||
|
|
||
|
var tbody = doc.createElement('tbody');
|
||
|
|
||
|
if (makeHeader) {
|
||
|
this._addRowHelper(doc, tbody, 'th', -1, cols);
|
||
|
}
|
||
|
|
||
|
for (var i=0; i < rows; i++) {
|
||
|
this._addRowHelper(doc, tbody, 'td', -1, cols);
|
||
|
}
|
||
|
|
||
|
table.appendChild(tbody);
|
||
|
|
||
|
var iterator = new NodeIterator(table);
|
||
|
var currnode = null;
|
||
|
var contentcell = null;
|
||
|
while (currnode = iterator.next()) {
|
||
|
var nodename = currnode.nodeName.toLowerCase();
|
||
|
if (nodename == 'td' || nodename == 'th') {
|
||
|
contentcell = currnode;
|
||
|
break;
|
||
|
};
|
||
|
};
|
||
|
|
||
|
var selection = this.editor.getSelection();
|
||
|
var docfrag = selection.cloneContents();
|
||
|
var setcursoratend = false;
|
||
|
if (contentcell && docfrag.hasChildNodes()) {
|
||
|
while (contentcell.hasChildNodes()) {
|
||
|
contentcell.removeChild(contentcell.firstChild);
|
||
|
};
|
||
|
|
||
|
while (docfrag.hasChildNodes()) {
|
||
|
contentcell.appendChild(docfrag.firstChild);
|
||
|
setcursoratend = true;
|
||
|
};
|
||
|
};
|
||
|
this.editor.insertNodeAtSelection(table);
|
||
|
|
||
|
this._setTableCellHandlers(table);
|
||
|
|
||
|
this.editor.logMessage('Table added');
|
||
|
};
|
||
|
|
||
|
this.addTableRow = function() {
|
||
|
/* add a table row or header */
|
||
|
var currnode = this.editor.getSelectedNode();
|
||
|
var doc = this.editor.getInnerDocument();
|
||
|
var tbody = this.editor.getNearestParentOfType(currnode, 'tbody');
|
||
|
if (!tbody) {
|
||
|
this.editor.logMessage('No table found!', 1);
|
||
|
return;
|
||
|
}
|
||
|
var cols = this._countCells(tbody);
|
||
|
var currrow = this.editor.getNearestParentOfType(currnode, 'tr');
|
||
|
if (!currrow) {
|
||
|
this.editor.logMessage('Not inside a row!', 1);
|
||
|
return;
|
||
|
};
|
||
|
var index = this._getRowIndex(currrow) + 1;
|
||
|
// should check what to add as well
|
||
|
this._addRowHelper(doc, tbody, 'td', index, cols);
|
||
|
|
||
|
this.editor.logMessage('Table row added');
|
||
|
};
|
||
|
|
||
|
this.delTableRow = function() {
|
||
|
/* delete a table row or header */
|
||
|
var currnode = this.editor.getSelectedNode();
|
||
|
var currtr = this.editor.getNearestParentOfType(currnode, 'tr');
|
||
|
|
||
|
if (!currtr) {
|
||
|
this.editor.logMessage('Not inside a row!', 1);
|
||
|
return;
|
||
|
};
|
||
|
|
||
|
currtr.parentNode.removeChild(currtr);
|
||
|
|
||
|
this.editor.logMessage('Table row removed');
|
||
|
};
|
||
|
|
||
|
this.addTableColumn = function() {
|
||
|
/* add a table column */
|
||
|
var currnode = this.editor.getSelectedNode();
|
||
|
var doc = this.editor.getInnerDocument();
|
||
|
var body = this.editor.getNearestParentOfType(currnode, 'tbody');
|
||
|
if (!body) {
|
||
|
this.editor.logMessage('Not inside a table!');
|
||
|
return;
|
||
|
};
|
||
|
var currcell = this.editor.getNearestParentOfType(currnode, 'td');
|
||
|
if (!currcell) {
|
||
|
var currcell = this.editor.getNearestParentOfType(currnode, 'th');
|
||
|
if (!currcell) {
|
||
|
this.editor.logMessage('Not inside a row!', 1);
|
||
|
return;
|
||
|
} else {
|
||
|
var index = -1;
|
||
|
};
|
||
|
} else {
|
||
|
var index = this._getColIndex(currcell) + 1;
|
||
|
};
|
||
|
var numcells = this._countCells(body);
|
||
|
this._addColHelper(doc, body, index, numcells);
|
||
|
|
||
|
this.editor.logMessage('Column added');
|
||
|
};
|
||
|
|
||
|
this.delTableColumn = function() {
|
||
|
/* delete a column */
|
||
|
var currnode = this.editor.getSelectedNode();
|
||
|
var body = this.editor.getNearestParentOfType(currnode, 'tbody');
|
||
|
if (!body) {
|
||
|
this.editor.logMessage('Not inside a table body!', 1);
|
||
|
return;
|
||
|
}
|
||
|
var currcell = this.editor.getNearestParentOfType(currnode, 'td');
|
||
|
if (!currcell) {
|
||
|
currcell = this.editor.getNearestParentOfType(currnode, 'th');
|
||
|
if (!currcell) {
|
||
|
this.editor.logMessage('Not inside a cell!');
|
||
|
return;
|
||
|
};
|
||
|
var index = -1;
|
||
|
} else {
|
||
|
var index = this._getColIndex(currcell);
|
||
|
};
|
||
|
|
||
|
this._delColHelper(body, index);
|
||
|
|
||
|
this.editor.logMessage('Column deleted');
|
||
|
};
|
||
|
|
||
|
this.setColumnWidths = function(widths) {
|
||
|
/* sets relative column widths */
|
||
|
var selNode = this.editor.getSelectedNode();
|
||
|
var table = this.editor.getNearestParentOfType(selNode, 'table');
|
||
|
|
||
|
// first remove all current width settings from the table
|
||
|
var iterator = new NodeIterator(table);
|
||
|
var currnode = null;
|
||
|
while (currnode = iterator.next()) {
|
||
|
if (currnode.nodeName.toLowerCase() == 'td') {
|
||
|
if (currnode.getAttribute('width')) {
|
||
|
currnode.removeAttribute('width');
|
||
|
} else if (currnode.style.width) {
|
||
|
delete currnode.style.width;
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
|
||
|
var silva_column_info = new Array();
|
||
|
widths = widths.split(',');
|
||
|
for (var i=0; i < widths.length; i++) {
|
||
|
widths[i] = widths[i].strip();
|
||
|
silva_column_info.push('C:' + widths[i]);
|
||
|
var widthint = parseInt(widths[i]);
|
||
|
if (!isNaN(widthint)) {
|
||
|
widths[i] = widthint;
|
||
|
} else if (widths[i] != '*') {
|
||
|
alert(_('Illegal or missing width entry in column info!'));
|
||
|
return;
|
||
|
};
|
||
|
};
|
||
|
silva_column_info = silva_column_info.join(' ');
|
||
|
table.setAttribute('silva_column_info', silva_column_info);
|
||
|
|
||
|
// find the first cell, use its parent as the row
|
||
|
// XXX note that this might potentially go wrong on nested tables!
|
||
|
var firstrow = table.getElementsByTagName('td')[0].parentNode;
|
||
|
|
||
|
// now convert the relative widths to percentages
|
||
|
// first find the first row containing cells
|
||
|
var totalunits = 0;
|
||
|
for (var i=0; i < widths.length; i++) {
|
||
|
if (widths[i] == '*') {
|
||
|
totalunits += 1;
|
||
|
} else {
|
||
|
totalunits += widths[i];
|
||
|
};
|
||
|
};
|
||
|
|
||
|
var percent_per_unit = 100.0 / totalunits;
|
||
|
|
||
|
var children = firstrow.childNodes;
|
||
|
var currcellindex = 0;
|
||
|
for (var i=0; i < children.length; i++) {
|
||
|
var child = children[i];
|
||
|
if (child.nodeType != 1 || child.nodeName.toLowerCase() != 'td') {
|
||
|
continue;
|
||
|
};
|
||
|
var width = widths[currcellindex];
|
||
|
if (width != '*') {
|
||
|
child.setAttribute('width', '' +
|
||
|
(width * percent_per_unit) + '%');
|
||
|
} else {
|
||
|
child.removeAttribute('width');
|
||
|
};
|
||
|
currcellindex++;
|
||
|
};
|
||
|
};
|
||
|
|
||
|
this.getColumnWidths = function(table) {
|
||
|
var silvacolinfo = table.getAttribute('silva_column_info');
|
||
|
var widths = new Array();
|
||
|
if (!silvacolinfo) {
|
||
|
var body = null;
|
||
|
var iterator = new NodeIterator(table);
|
||
|
var body = iterator.next();
|
||
|
while (body.nodeName.toLowerCase() != 'tbody') {
|
||
|
body = iterator.next();
|
||
|
};
|
||
|
var numcols = this._countCells(body);
|
||
|
for (var i=0; i < numcols; i++) {
|
||
|
widths.push(1);
|
||
|
};
|
||
|
} else {
|
||
|
silvacolinfo = silvacolinfo.split(' ');
|
||
|
for (var i=0; i < silvacolinfo.length; i++) {
|
||
|
var pair = silvacolinfo[i].split(':');
|
||
|
if (pair[1] == '*') {
|
||
|
widths.push('*');
|
||
|
} else {
|
||
|
widths.push(parseInt(pair[1]));
|
||
|
};
|
||
|
};
|
||
|
widths = this._factorWidths(widths);
|
||
|
};
|
||
|
return widths;
|
||
|
};
|
||
|
|
||
|
this._factorWidths = function(widths) {
|
||
|
var highest = 0;
|
||
|
for (var i=0; i < widths.length; i++) {
|
||
|
if (widths[i] > highest) {
|
||
|
highest = widths[i];
|
||
|
};
|
||
|
};
|
||
|
var factor = 1;
|
||
|
for (var i=0; i < highest; i++) {
|
||
|
var testnum = highest - i;
|
||
|
var isfactor = true;
|
||
|
for (var j=0; j < widths.length; j++) {
|
||
|
if (widths[j] % testnum != 0) {
|
||
|
isfactor = false;
|
||
|
break;
|
||
|
};
|
||
|
};
|
||
|
if (isfactor) {
|
||
|
factor = testnum;
|
||
|
break;
|
||
|
};
|
||
|
};
|
||
|
if (factor > 1) {
|
||
|
for (var i=0; i < widths.length; i++) {
|
||
|
widths[i] = widths[i] / factor;
|
||
|
};
|
||
|
};
|
||
|
return widths;
|
||
|
};
|
||
|
|
||
|
this._addRowHelper = function(doc, body, celltype, index, numcells) {
|
||
|
/* actually adds a row to the table */
|
||
|
var row = doc.createElement('tr');
|
||
|
|
||
|
// fill the row with cells
|
||
|
if (celltype == 'td') {
|
||
|
for (var i=0; i < numcells; i++) {
|
||
|
var cell = doc.createElement(celltype);
|
||
|
var nbsp = doc.createTextNode("\u00a0");
|
||
|
cell.appendChild(nbsp);
|
||
|
row.appendChild(cell);
|
||
|
}
|
||
|
} else if (celltype == 'th') {
|
||
|
var cell = doc.createElement(celltype);
|
||
|
cell.setAttribute('colSpan', numcells);
|
||
|
var nbsp = doc.createTextNode("\u00a0");
|
||
|
cell.appendChild(nbsp);
|
||
|
row.appendChild(cell);
|
||
|
}
|
||
|
|
||
|
// now append it to the tbody
|
||
|
var rows = this._getAllRows(body);
|
||
|
if (index == -1 || index >= rows.length) {
|
||
|
body.appendChild(row);
|
||
|
} else {
|
||
|
var nextrow = rows[index];
|
||
|
body.insertBefore(row, nextrow);
|
||
|
}
|
||
|
|
||
|
return row;
|
||
|
};
|
||
|
|
||
|
this._addColHelper = function(doc, body, index, numcells) {
|
||
|
/* actually adds a column to a table */
|
||
|
var rows = this._getAllRows(body);
|
||
|
for (var i=0; i < rows.length; i++) {
|
||
|
var row = rows[i];
|
||
|
var cols = this._getAllColumns(row);
|
||
|
var col = cols[0];
|
||
|
if (col.nodeName.toLowerCase() == 'th') {
|
||
|
var colspan = col.getAttribute('colSpan');
|
||
|
if (colspan) {
|
||
|
colspan = parseInt(colspan);
|
||
|
} else {
|
||
|
colspan = 1;
|
||
|
}
|
||
|
col.setAttribute('colSpan', colspan + 1);
|
||
|
} else {
|
||
|
var cell = doc.createElement('td');
|
||
|
var nbsp = doc.createTextNode('\u00a0');
|
||
|
cell.appendChild(nbsp);
|
||
|
if (index == -1 || index >= rows.length) {
|
||
|
row.appendChild(cell);
|
||
|
} else {
|
||
|
row.insertBefore(cell, cols[index]);
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
|
||
|
this._delColHelper = function(body, index) {
|
||
|
/* actually delete all cells in a column */
|
||
|
var rows = this._getAllRows(body);
|
||
|
for (var i=0; i < rows.length; i++) {
|
||
|
var row = rows[i];
|
||
|
var cols = this._getAllColumns(row);
|
||
|
if (cols[0].nodeName.toLowerCase() == 'th') {
|
||
|
// is a table header, so reduce colspan
|
||
|
var th = cols[0];
|
||
|
var colspan = th.getAttribute('colSpan');
|
||
|
if (!colspan || colspan == '1') {
|
||
|
body.removeChild(row);
|
||
|
} else {
|
||
|
colspan = parseInt(colspan);
|
||
|
th.setAttribute('colSpan', colspan - 1);
|
||
|
};
|
||
|
} else {
|
||
|
// is a table cell row, remove one
|
||
|
if (index > -1) {
|
||
|
row.removeChild(cols[index]);
|
||
|
} else {
|
||
|
row.removeChild(cols[cols.length - 1]);
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
};
|
||
|
|
||
|
this._getRowIndex = function(row) {
|
||
|
/* get the current rowindex */
|
||
|
var rowindex = 0;
|
||
|
var prevrow = row.previousSibling;
|
||
|
while (prevrow) {
|
||
|
if (prevrow.nodeName.toLowerCase() == 'tr') {
|
||
|
rowindex++;
|
||
|
};
|
||
|
prevrow = prevrow.previousSibling;
|
||
|
};
|
||
|
return rowindex;
|
||
|
};
|
||
|
|
||
|
this._countCells = function(body) {
|
||
|
/* get the current column index */
|
||
|
var numcols = 0;
|
||
|
var cols = this._getAllColumns(this._getAllRows(body)[0]);
|
||
|
for (var i=0; i < cols.length; i++) {
|
||
|
var node = cols[i];
|
||
|
if (node.nodeName.toLowerCase() == 'th') {
|
||
|
var colspan = node.getAttribute('colSpan');
|
||
|
if (colspan) {
|
||
|
colspan = parseInt(colspan);
|
||
|
} else {
|
||
|
colspan = 1;
|
||
|
};
|
||
|
numcols += colspan;
|
||
|
} else {
|
||
|
numcols++;
|
||
|
};
|
||
|
};
|
||
|
return numcols;
|
||
|
};
|
||
|
|
||
|
this._getAllRows = function(body) {
|
||
|
/* returns an Array of all available rows */
|
||
|
var rows = new Array();
|
||
|
for (var i=0; i < body.childNodes.length; i++) {
|
||
|
var node = body.childNodes[i];
|
||
|
if (node.nodeName.toLowerCase() == 'tr') {
|
||
|
rows.push(node);
|
||
|
};
|
||
|
};
|
||
|
return rows;
|
||
|
};
|
||
|
|
||
|
this._getAllColumns = function(row) {
|
||
|
/* returns an Array of all columns in a row */
|
||
|
var cols = new Array();
|
||
|
for (var i=0; i < row.childNodes.length; i++) {
|
||
|
var node = row.childNodes[i];
|
||
|
if (node.nodeName.toLowerCase() == 'td' ||
|
||
|
node.nodeName.toLowerCase() == 'th') {
|
||
|
cols.push(node);
|
||
|
};
|
||
|
};
|
||
|
return cols;
|
||
|
};
|
||
|
}
|
||
|
|
||
|
SilvaTableTool.prototype = new TableTool;
|
||
|
|
||
|
function SilvaTableToolBox(addtabledivid, edittabledivid, newrowsinputid,
|
||
|
newcolsinputid, makeheaderinputid, classselectid, alignselectid, widthinputid,
|
||
|
addtablebuttonid, addrowbuttonid, delrowbuttonid, addcolbuttonid, delcolbuttonid,
|
||
|
fixbuttonid, delbuttonid, toolboxid, plainclass, activeclass) {
|
||
|
/* Silva specific table functionality
|
||
|
overrides most of the table functionality, required because Silva requires
|
||
|
a completely different format for tables
|
||
|
*/
|
||
|
|
||
|
this.addtablediv = getFromSelector(addtabledivid);
|
||
|
this.edittablediv = getFromSelector(edittabledivid);
|
||
|
this.newrowsinput = getFromSelector(newrowsinputid);
|
||
|
this.newcolsinput = getFromSelector(newcolsinputid);
|
||
|
this.makeheaderinput = getFromSelector(makeheaderinputid);
|
||
|
this.classselect = getFromSelector(classselectid);
|
||
|
this.alignselect = getFromSelector(alignselectid);
|
||
|
this.widthinput = getFromSelector(widthinputid);
|
||
|
this.addtablebutton = getFromSelector(addtablebuttonid);
|
||
|
this.addrowbutton = getFromSelector(addrowbuttonid);
|
||
|
this.delrowbutton = getFromSelector(delrowbuttonid);
|
||
|
this.addcolbutton = getFromSelector(addcolbuttonid);
|
||
|
this.delcolbutton = getFromSelector(delcolbuttonid);
|
||
|
this.fixbutton = getFromSelector(fixbuttonid);
|
||
|
this.delbutton = getFromSelector(delbuttonid);
|
||
|
this.toolboxel = getFromSelector(toolboxid);
|
||
|
this.plainclass = plainclass;
|
||
|
this.activeclass = activeclass;
|
||
|
|
||
|
this.initialize = function(tool, editor) {
|
||
|
/* attach the event handlers */
|
||
|
this.tool = tool;
|
||
|
this.editor = editor;
|
||
|
addEventHandler(this.addtablebutton, "click", this.addTable, this);
|
||
|
addEventHandler(this.addrowbutton, "click", this.tool.addTableRow, this.tool);
|
||
|
addEventHandler(this.delrowbutton, "click", this.tool.delTableRow, this.tool);
|
||
|
addEventHandler(this.addcolbutton, "click", this.tool.addTableColumn, this.tool);
|
||
|
addEventHandler(this.delcolbutton, "click", this.tool.delTableColumn, this.tool);
|
||
|
addEventHandler(this.fixbutton, "click", this.fixTable, this);
|
||
|
addEventHandler(this.delbutton, "click", this.tool.delTable, this);
|
||
|
addEventHandler(this.alignselect, "change", this.setColumnAlign, this);
|
||
|
addEventHandler(this.classselect, "change", this.setTableClass, this);
|
||
|
addEventHandler(this.widthinput, "change", this.setColumnWidths, this);
|
||
|
this.addtablediv.style.display = "block";
|
||
|
this.edittablediv.style.display = "none";
|
||
|
this.editor.logMessage('Table tool initialized');
|
||
|
};
|
||
|
|
||
|
this.updateState = function(selNode) {
|
||
|
/* update the state (add/edit) and update the pulldowns (if required) */
|
||
|
var table = this.editor.getNearestParentOfType(selNode, 'table');
|
||
|
if (table) {
|
||
|
this.addtablediv.style.display = "none";
|
||
|
this.edittablediv.style.display = "block";
|
||
|
var td = this.editor.getNearestParentOfType(selNode, 'td');
|
||
|
if (!td) {
|
||
|
td = this.editor.getNearestParentOfType(selNode, 'th');
|
||
|
this.widthinput.value = '';
|
||
|
} else {
|
||
|
this.widthinput.value = this.tool.getColumnWidths(table);
|
||
|
};
|
||
|
if (td) {
|
||
|
var align = td.getAttribute('align');
|
||
|
if (this.editor.config.use_css) {
|
||
|
align = td.style.textAlign;
|
||
|
};
|
||
|
selectSelectItem(this.alignselect, align);
|
||
|
};
|
||
|
selectSelectItem(this.classselect, table.className);
|
||
|
if (this.toolboxel) {
|
||
|
if (this.toolboxel.open_handler) {
|
||
|
this.toolboxel.open_handler();
|
||
|
};
|
||
|
this.toolboxel.className = this.activeclass;
|
||
|
};
|
||
|
} else {
|
||
|
this.edittablediv.style.display = "none";
|
||
|
this.addtablediv.style.display = "block";
|
||
|
this.alignselect.selectedIndex = 0;
|
||
|
this.classselect.selectedIndex = 0;
|
||
|
if (this.toolboxel) {
|
||
|
this.toolboxel.className = this.plainclass;
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
|
||
|
this.addTable = function() {
|
||
|
/* add a Silvs specific table, with an (optional) header with colspan */
|
||
|
var rows = parseInt(this.newrowsinput.value);
|
||
|
var cols = parseInt(this.newcolsinput.value);
|
||
|
var makeHeader = this.makeheaderinput.checked;
|
||
|
var classchooser = getFromSelector("kupu-table-classchooser-add");
|
||
|
var tableclass = this.classselect.options[this.classselect.selectedIndex].value;
|
||
|
this.tool.createTable(rows, cols, makeHeader, tableclass);
|
||
|
};
|
||
|
|
||
|
this.setTableClass = function() {
|
||
|
var cls = this.classselect.options[this.classselect.selectedIndex].value;
|
||
|
this.tool.setTableClass(cls);
|
||
|
};
|
||
|
|
||
|
this.setColumnWidths = function() {
|
||
|
var widths = this.widthinput.value;
|
||
|
this.tool.setColumnWidths(widths);
|
||
|
};
|
||
|
|
||
|
this.fixTable = function(event) {
|
||
|
/* fix the table so it is Silva (and this tool) compliant */
|
||
|
// since this can be quite a nasty creature we can't just use the
|
||
|
// helper methods
|
||
|
|
||
|
// first we create a new tbody element
|
||
|
var currnode = this.editor.getSelectedNode();
|
||
|
var table = this.editor.getNearestParentOfType(currnode, 'TABLE');
|
||
|
if (!table) {
|
||
|
this.editor.logMessage('Not inside a table!');
|
||
|
return;
|
||
|
};
|
||
|
var doc = this.editor.getInnerDocument();
|
||
|
var tbody = doc.createElement('tbody');
|
||
|
|
||
|
var allowed_classes = new Array('plain', 'grid', 'list', 'listing', 'data');
|
||
|
if (!allowed_classes.contains(table.getAttribute('class'))) {
|
||
|
table.setAttribute('class', 'plain');
|
||
|
};
|
||
|
|
||
|
table.setAttribute('cellpadding', '0');
|
||
|
table.setAttribute('cellspacing', '0');
|
||
|
|
||
|
// now get all the rows of the table, the rows can either be
|
||
|
// direct descendants of the table or inside a 'tbody', 'thead'
|
||
|
// or 'tfoot' element
|
||
|
var rows = new Array();
|
||
|
var parents = new Array('thead', 'tbody', 'tfoot');
|
||
|
for (var i=0; i < table.childNodes.length; i++) {
|
||
|
var node = table.childNodes[i];
|
||
|
if (node.nodeName.toLowerCase() == 'tr') {
|
||
|
rows.push(node);
|
||
|
} else if (parents.contains(node.nodeName.toLowerCase())) {
|
||
|
for (var j=0; j < node.childNodes.length; j++) {
|
||
|
var inode = node.childNodes[j];
|
||
|
if (inode.nodeName.toLowerCase() == 'tr') {
|
||
|
rows.push(inode);
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
|
||
|
// now find out how many cells our rows should have
|
||
|
var numcols = 0;
|
||
|
for (var i=0; i < rows.length; i++) {
|
||
|
var row = rows[i];
|
||
|
var currnumcols = 0;
|
||
|
for (var j=0; j < row.childNodes.length; j++) {
|
||
|
var node = row.childNodes[j];
|
||
|
if (node.nodeName.toLowerCase() == 'td' ||
|
||
|
node.nodeName.toLowerCase() == 'th') {
|
||
|
var colspan = 1;
|
||
|
if (node.getAttribute('colSpan')) {
|
||
|
colspan = parseInt(node.getAttribute('colSpan'));
|
||
|
};
|
||
|
currnumcols += colspan;
|
||
|
};
|
||
|
};
|
||
|
if (currnumcols > numcols) {
|
||
|
numcols = currnumcols;
|
||
|
};
|
||
|
};
|
||
|
|
||
|
// now walk through all rows to clean them up
|
||
|
for (var i=0; i < rows.length; i++) {
|
||
|
var row = rows[i];
|
||
|
var newrow = doc.createElement('tr');
|
||
|
var currcolnum = 0;
|
||
|
var inhead = -1;
|
||
|
while (row.childNodes.length > 0) {
|
||
|
var node = row.childNodes[0];
|
||
|
if (node.nodeName.toLowerCase() == 'td') {
|
||
|
if (inhead == -1) {
|
||
|
inhead = 0;
|
||
|
node.setAttribute('colSpan', '1');
|
||
|
};
|
||
|
} else if (node.nodeName.toLowerCase() == 'th') {
|
||
|
if (inhead == -1) {
|
||
|
inhead = 1;
|
||
|
newrow.appendChild(node);
|
||
|
node.setAttribute('colSpan', '1');
|
||
|
node.setAttribute('rowSpan', '1');
|
||
|
continue;
|
||
|
} else if (inhead == 0) {
|
||
|
var td = doc.createElement('td');
|
||
|
while (node.childNodes.length) {
|
||
|
td.appendChild(node.childNodes[0]);
|
||
|
};
|
||
|
row.removeChild(node);
|
||
|
node = td;
|
||
|
};
|
||
|
} else {
|
||
|
row.removeChild(node);
|
||
|
continue;
|
||
|
};
|
||
|
node.setAttribute('rowspan', '1');
|
||
|
if (inhead) {
|
||
|
while (node.childNodes.length) {
|
||
|
newrow.childNodes[0].appendChild(node.childNodes[0]);
|
||
|
};
|
||
|
var colspan = node.getAttribute('colSpan');
|
||
|
if (colspan) {
|
||
|
colspan = parseInt(colspan);
|
||
|
} else {
|
||
|
colspan = 1;
|
||
|
}
|
||
|
var current_colspan = parseInt(newrow.childNodes[0].getAttribute('colSpan'));
|
||
|
newrow.childNodes[0].setAttribute('colSpan', (current_colspan + colspan).toString());
|
||
|
row.removeChild(node);
|
||
|
} else {
|
||
|
node.setAttribute('colSpan', 1);
|
||
|
node.setAttribute('rowSpan', 1);
|
||
|
newrow.appendChild(node);
|
||
|
};
|
||
|
};
|
||
|
if (newrow.childNodes.length) {
|
||
|
tbody.appendChild(newrow);
|
||
|
};
|
||
|
};
|
||
|
|
||
|
// now make sure all rows have the correct length
|
||
|
for (var i=0; i < tbody.childNodes.length; i++) {
|
||
|
var row = tbody.childNodes[i];
|
||
|
if (row.childNodes.length && row.childNodes[0].nodeName.toLowerCase() == 'th') {
|
||
|
row.childNodes[0].setAttribute('colSpan', numcols);
|
||
|
} else {
|
||
|
while (row.childNodes.length < numcols) {
|
||
|
var td = doc.createElement('td');
|
||
|
var nbsp = doc.createTextNode('\u00a0');
|
||
|
td.appendChild(nbsp);
|
||
|
row.appendChild(td);
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
|
||
|
// now remove all the old stuff from the table and add the new tbody
|
||
|
var tlength = table.childNodes.length;
|
||
|
for (var i=0; i < tlength; i++) {
|
||
|
table.removeChild(table.childNodes[0]);
|
||
|
};
|
||
|
table.appendChild(tbody);
|
||
|
|
||
|
this.editor.getDocument().getWindow().focus();
|
||
|
|
||
|
this.editor.logMessage('Table cleaned up');
|
||
|
};
|
||
|
|
||
|
this._fixAllTables = function() {
|
||
|
/* fix all the tables in the document at once */
|
||
|
return;
|
||
|
var tables = this.editor.getInnerDocument().getElementsByTagName('table');
|
||
|
for (var i=0; i < tables.length; i++) {
|
||
|
this.fixTable(tables[i]);
|
||
|
};
|
||
|
};
|
||
|
}
|
||
|
|
||
|
SilvaTableToolBox.prototype = new TableToolBox;
|
||
|
|
||
|
function SilvaIndexTool(inputid, addbuttonid, updatebuttonid, deletebuttonid, toolboxid, plainclass, activeclass) {
|
||
|
/* a tool to manage index items (named anchors) for Silva */
|
||
|
this.input = getFromSelector(inputid);
|
||
|
this.addbutton = getFromSelector(addbuttonid);
|
||
|
this.updatebutton = getFromSelector(updatebuttonid);
|
||
|
this.deletebutton = getFromSelector(deletebuttonid);
|
||
|
this.toolboxel = getFromSelector(toolboxid);
|
||
|
this.plainclass = plainclass;
|
||
|
this.activeclass = activeclass;
|
||
|
|
||
|
this.initialize = function(editor) {
|
||
|
/* attach the event handlers */
|
||
|
this.editor = editor;
|
||
|
addEventHandler(this.input, 'blur', this.updateIndex, this);
|
||
|
addEventHandler(this.addbutton, 'click', this.addIndex, this);
|
||
|
addEventHandler(this.updatebutton, 'click', this.updateIndex, this);
|
||
|
addEventHandler(this.deletebutton, 'click', this.deleteIndex, this);
|
||
|
if (this.editor.getBrowserName() == 'IE') {
|
||
|
// need to catch some additional events for IE
|
||
|
addEventHandler(editor.getInnerDocument(), 'keyup', this.handleKeyPressOnIndex, this);
|
||
|
addEventHandler(editor.getInnerDocument(), 'keydown', this.handleKeyPressOnIndex, this);
|
||
|
};
|
||
|
addEventHandler(editor.getInnerDocument(), 'keypress', this.handleKeyPressOnIndex, this);
|
||
|
this.updatebutton.style.display = 'none';
|
||
|
this.deletebutton.style.display = 'none';
|
||
|
};
|
||
|
|
||
|
this.addIndex = function(event) {
|
||
|
/* create an index */
|
||
|
var name = this.input.value;
|
||
|
var currnode = this.editor.getSelectedNode();
|
||
|
var indexel = this.editor.getNearestParentOfType(currnode, 'A');
|
||
|
|
||
|
if (indexel && indexel.getAttribute('href')) {
|
||
|
this.editor.logMessage('Can not add index items in anchors');
|
||
|
return;
|
||
|
};
|
||
|
|
||
|
if (!indexel) {
|
||
|
var doc = this.editor.getDocument();
|
||
|
if (!name) {
|
||
|
var selection = this.editor.getSelection();
|
||
|
var cloned = selection.cloneContents();
|
||
|
var iterator = new NodeIterator(cloned);
|
||
|
var name = '';
|
||
|
var currnode = null;
|
||
|
while (currnode = iterator.next()) {
|
||
|
if (currnode.nodeValue) {
|
||
|
name += currnode.nodeValue;
|
||
|
};
|
||
|
};
|
||
|
if (name) {
|
||
|
this.input.value = name;
|
||
|
};
|
||
|
};
|
||
|
var docel = doc.getDocument();
|
||
|
indexel = docel.createElement('a');
|
||
|
var text = docel.createTextNode('[' + name + ']');
|
||
|
indexel.appendChild(text);
|
||
|
indexel = this.editor.insertNodeAtSelection(indexel, true);
|
||
|
indexel.className = 'index';
|
||
|
};
|
||
|
|
||
|
indexel.setAttribute('name', name);
|
||
|
var sel = this.editor.getSelection();
|
||
|
sel.collapse(true);
|
||
|
this.editor.logMessage('Index added');
|
||
|
};
|
||
|
|
||
|
this.updateIndex = function(event) {
|
||
|
/* update an existing index */
|
||
|
var currnode = this.editor.getSelectedNode();
|
||
|
var indexel = this.editor.getNearestParentOfType(currnode, 'A');
|
||
|
if (!indexel) {
|
||
|
return;
|
||
|
};
|
||
|
|
||
|
if (indexel && indexel.getAttribute('href')) {
|
||
|
this.editor.logMessage('Can not add an index element inside a link!');
|
||
|
return;
|
||
|
};
|
||
|
|
||
|
var name = this.input.value;
|
||
|
indexel.setAttribute('name', name);
|
||
|
while (indexel.hasChildNodes()) {
|
||
|
indexel.removeChild(indexel.firstChild);
|
||
|
};
|
||
|
var text = this.editor.getInnerDocument().createTextNode('[' + name + ']')
|
||
|
indexel.appendChild(text);
|
||
|
this.editor.logMessage('Index modified');
|
||
|
};
|
||
|
|
||
|
this.deleteIndex = function() {
|
||
|
var selNode = this.editor.getSelectedNode();
|
||
|
var a = this.editor.getNearestParentOfType(selNode, 'a');
|
||
|
if (!a || a.getAttribute('href')) {
|
||
|
this.editor.logMessage('Not inside an index element!');
|
||
|
return;
|
||
|
};
|
||
|
a.parentNode.removeChild(a);
|
||
|
this.editor.logMessage('Index element removed');
|
||
|
};
|
||
|
|
||
|
this.handleKeyPressOnIndex = function(event) {
|
||
|
var selNode = this.editor.getSelectedNode();
|
||
|
var a = this.editor.getNearestParentOfType(selNode, 'a');
|
||
|
if (!a || a.getAttribute('href')) {
|
||
|
return;
|
||
|
};
|
||
|
var keyCode = event.keyCode;
|
||
|
if (keyCode == 8 || keyCode == 46) {
|
||
|
a.parentNode.removeChild(a);
|
||
|
} else if (keyCode == 9 || keyCode == 39) {
|
||
|
var next = a.nextSibling;
|
||
|
while (next && next.nodeName.toLowerCase() == 'br') {
|
||
|
next = next.nextSibling;
|
||
|
};
|
||
|
if (!next) {
|
||
|
var doc = this.editor.getInnerDocument();
|
||
|
next = doc.createTextNode('\xa0');
|
||
|
a.parentNode.appendChild(next);
|
||
|
};
|
||
|
var selection = this.editor.getSelection();
|
||
|
// XXX I fear I'm working around bugs here... because of a bug in
|
||
|
// selection.moveStart() I can't use the same codepath in IE as in Moz
|
||
|
if (this.editor.getBrowserName() == 'IE') {
|
||
|
selection.selectNodeContents(a);
|
||
|
// XXX are we depending on a bug here? shouldn't we move the
|
||
|
// selection one place to get out of the anchor? it works,
|
||
|
// but seems wrong...
|
||
|
selection.collapse(true);
|
||
|
} else {
|
||
|
selection.selectNodeContents(next);
|
||
|
selection.collapse();
|
||
|
var selection = this.editor.getSelection();
|
||
|
};
|
||
|
this.editor.updateState();
|
||
|
};
|
||
|
if (event.preventDefault) {
|
||
|
event.preventDefault();
|
||
|
} else {
|
||
|
event.returnValue = false;
|
||
|
};
|
||
|
return false;
|
||
|
};
|
||
|
|
||
|
this.updateState = function(selNode) {
|
||
|
var indexel = this.editor.getNearestParentOfType(selNode, 'A');
|
||
|
if (indexel && !indexel.getAttribute('href')) {
|
||
|
if (this.toolboxel) {
|
||
|
if (this.toolboxel.open_handler) {
|
||
|
this.toolboxel.open_handler();
|
||
|
};
|
||
|
this.toolboxel.className = this.activeclass;
|
||
|
};
|
||
|
this.input.value = indexel.getAttribute('name');
|
||
|
this.addbutton.style.display = 'none';
|
||
|
this.updatebutton.style.display = 'inline';
|
||
|
this.deletebutton.style.display = 'inline';
|
||
|
} else {
|
||
|
if (this.toolboxel) {
|
||
|
this.toolboxel.className = this.plainclass;
|
||
|
};
|
||
|
this.input.value = '';
|
||
|
this.updatebutton.style.display = 'none';
|
||
|
this.deletebutton.style.display = 'none';
|
||
|
this.addbutton.style.display = 'inline';
|
||
|
};
|
||
|
};
|
||
|
|
||
|
this.createContextMenuElements = function(selNode, event) {
|
||
|
var indexel = this.editor.getNearestParentOfType(selNode, 'A');
|
||
|
if (indexel && !indexel.getAttribute('href')) {
|
||
|
return new Array(new ContextMenuElement('Delete index', this.deleteIndex, this));
|
||
|
} else {
|
||
|
return new Array();
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
|
||
|
SilvaIndexTool.prototype = new KupuTool;
|
||
|
|
||
|
function SilvaTocTool(depthselectid, addbuttonid, delbuttonid, toolboxid, plainclass, activeclass) {
|
||
|
this.depthselect = getFromSelector(depthselectid);
|
||
|
this.addbutton = getFromSelector(addbuttonid);
|
||
|
this.delbutton = getFromSelector(delbuttonid);
|
||
|
this.toolbox = getFromSelector(toolboxid);
|
||
|
this.plainclass = plainclass;
|
||
|
this.activeclass = activeclass;
|
||
|
this._inside_toc = false;
|
||
|
|
||
|
this.initialize = function(editor) {
|
||
|
this.editor = editor;
|
||
|
addEventHandler(this.addbutton, 'click', this.addOrUpdateToc, this);
|
||
|
addEventHandler(this.depthselect, 'change', this.updateToc, this);
|
||
|
addEventHandler(this.delbutton, 'click', this.deleteToc, this);
|
||
|
addEventHandler(editor.getInnerDocument(), 'keypress', this.handleKeyPressOnToc, this);
|
||
|
if (this.editor.getBrowserName() == 'IE') {
|
||
|
addEventHandler(editor.getInnerDocument(), 'keydown', this.handleKeyPressOnToc, this);
|
||
|
addEventHandler(editor.getInnerDocument(), 'keyup', this.handleKeyPressOnToc, this);
|
||
|
};
|
||
|
};
|
||
|
|
||
|
this.handleKeyPressOnToc = function(event) {
|
||
|
if (!this._inside_toc) {
|
||
|
return;
|
||
|
};
|
||
|
var keyCode = event.keyCode;
|
||
|
if (keyCode == 8 || keyCode == 46) {
|
||
|
var selNode = this.editor.getSelectedNode();
|
||
|
var toc = this.getNearestToc(selNode);
|
||
|
toc.parentNode.removeChild(toc);
|
||
|
};
|
||
|
if (keyCode == 13 || keyCode == 9 || keyCode == 39) {
|
||
|
var selNode = this.editor.getSelectedNode();
|
||
|
var toc = this.getNearestToc(selNode);
|
||
|
var doc = this.editor.getInnerDocument();
|
||
|
var selection = this.editor.getSelection();
|
||
|
if (toc.nextSibling) {
|
||
|
var sibling = toc.nextSibling;
|
||
|
selection.selectNodeContents(toc.nextSibling);
|
||
|
selection.collapse();
|
||
|
} else {
|
||
|
var parent = toc.parentNode;
|
||
|
var p = doc.createElement('p');
|
||
|
parent.appendChild(p);
|
||
|
var text = doc.createTextNode('\xa0');
|
||
|
p.appendChild(text);
|
||
|
selection.selectNodeContents(p);
|
||
|
};
|
||
|
this._inside_toc = false;
|
||
|
};
|
||
|
if (event.preventDefault) {
|
||
|
event.preventDefault();
|
||
|
} else {
|
||
|
event.returnValue = false;
|
||
|
};
|
||
|
};
|
||
|
|
||
|
this.updateState = function(selNode, event) {
|
||
|
var toc = this.getNearestToc(selNode);
|
||
|
if (toc) {
|
||
|
var depth = toc.getAttribute('toc_depth');
|
||
|
selectSelectItem(this.depthselect, depth);
|
||
|
this.addbutton.style.display = 'none';
|
||
|
this.delbutton.style.display = 'inline';
|
||
|
this._inside_toc = true;
|
||
|
if (this.toolbox) {
|
||
|
if (this.toolbox.open_handler) {
|
||
|
this.toolbox.open_handler();
|
||
|
};
|
||
|
this.toolbox.className = this.activeclass;
|
||
|
};
|
||
|
} else {
|
||
|
this.depthselect.selectedIndex = 0;
|
||
|
this.delbutton.style.display = 'none';
|
||
|
this.addbutton.style.display = 'inline';
|
||
|
this._inside_toc = false;
|
||
|
if (this.toolbox) {
|
||
|
this.toolbox.className = this.plainclass;
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
|
||
|
this.addOrUpdateToc = function(event, depth) {
|
||
|
var selNode = this.editor.getSelectedNode();
|
||
|
var depth = depth ? depth : this.depthselect.options[this.depthselect.selectedIndex].value;
|
||
|
var toc = this.getNearestToc(selNode);
|
||
|
var doc = this.editor.getInnerDocument();
|
||
|
var toctext = this.getTocText(depth);
|
||
|
if (toc) {
|
||
|
// there's already a toc, just update the depth
|
||
|
toc.setAttribute('toc_depth', depth);
|
||
|
while (toc.hasChildNodes()) {
|
||
|
toc.removeChild(toc.firstChild);
|
||
|
};
|
||
|
toc.appendChild(doc.createTextNode(toctext));
|
||
|
} else {
|
||
|
// create a new toc
|
||
|
var div = doc.createElement('div');
|
||
|
div.setAttribute('toc_depth', depth);
|
||
|
div.setAttribute('is_toc', 1);
|
||
|
div.className = 'toc';
|
||
|
var text = doc.createTextNode(toctext);
|
||
|
div.appendChild(text);
|
||
|
this.editor.insertNodeAtSelection(div);
|
||
|
};
|
||
|
};
|
||
|
|
||
|
this.createDefaultToc = function() {
|
||
|
// XXX nasty workaround, entering null as the event...
|
||
|
this.addOrUpdateToc(null, '-1');
|
||
|
};
|
||
|
|
||
|
this.updateToc = function() {
|
||
|
var selNode = this.editor.getSelectedNode();
|
||
|
var toc = this.getNearestToc(selNode);
|
||
|
if (toc) {
|
||
|
var depth = this.depthselect.options[this.depthselect.selectedIndex].value;
|
||
|
var toctext = this.getTocText(depth);
|
||
|
toc.setAttribute('toc_depth', depth);
|
||
|
while (toc.hasChildNodes()) {
|
||
|
toc.removeChild(toc.firstChild);
|
||
|
};
|
||
|
doc = this.editor.getInnerDocument();
|
||
|
toc.appendChild(doc.createTextNode(toctext));
|
||
|
};
|
||
|
};
|
||
|
|
||
|
this.deleteToc = function() {
|
||
|
var selNode = this.editor.getSelectedNode();
|
||
|
var toc = this.getNearestToc(selNode);
|
||
|
if (!toc) {
|
||
|
this.editor.logMessage('Not inside a toc!', 1);
|
||
|
return;
|
||
|
};
|
||
|
toc.parentNode.removeChild(toc);
|
||
|
};
|
||
|
|
||
|
this.getNearestToc = function(selNode) {
|
||
|
var currnode = selNode;
|
||
|
while (currnode) {
|
||
|
if (currnode.nodeName.toLowerCase() == 'div' &&
|
||
|
currnode.getAttribute('is_toc')) {
|
||
|
return currnode;
|
||
|
};
|
||
|
currnode = currnode.parentNode;
|
||
|
};
|
||
|
return false;
|
||
|
};
|
||
|
|
||
|
this.createContextMenuElements = function(selNode, event) {
|
||
|
/* create the 'Delete TOC' menu elements */
|
||
|
var ret = new Array();
|
||
|
if (this.getNearestToc(selNode)) {
|
||
|
ret.push(new ContextMenuElement('Delete TOC', this.deleteToc, this));
|
||
|
} else {
|
||
|
ret.push(new ContextMenuElement('Create TOC', this.createDefaultToc, this));
|
||
|
};
|
||
|
return ret;
|
||
|
};
|
||
|
|
||
|
this.getTocText = function(depth) {
|
||
|
var toctext = 'Table of Contents ';
|
||
|
switch (depth) {
|
||
|
case '-1':
|
||
|
toctext += '(unlimited levels)';
|
||
|
break;
|
||
|
case '1':
|
||
|
toctext += '(1 level)';
|
||
|
break;
|
||
|
default:
|
||
|
toctext += '(' + depth + ' levels)';
|
||
|
break;
|
||
|
};
|
||
|
return toctext;
|
||
|
};
|
||
|
};
|
||
|
|
||
|
SilvaTocTool.prototype = new KupuTool;
|
||
|
|
||
|
function SilvaAbbrTool(abbrradioid, acronymradioid, radiocontainerid, titleinputid,
|
||
|
addbuttonid, updatebuttonid, delbuttonid,
|
||
|
toolboxid, plainclass, activeclass) {
|
||
|
/* tool to manage citation elements */
|
||
|
this.abbrradio = getFromSelector(abbrradioid);
|
||
|
this.acronymradio = getFromSelector(acronymradioid);
|
||
|
this.radiocontainer = getFromSelector(radiocontainerid);
|
||
|
this.titleinput = getFromSelector(titleinputid);
|
||
|
this.addbutton = getFromSelector(addbuttonid);
|
||
|
this.updatebutton = getFromSelector(updatebuttonid);
|
||
|
this.delbutton = getFromSelector(delbuttonid);
|
||
|
this.toolbox = getFromSelector(toolboxid);
|
||
|
this.plainclass = plainclass;
|
||
|
this.activeclass = activeclass;
|
||
|
|
||
|
this.initialize = function(editor) {
|
||
|
this.editor = editor;
|
||
|
addEventHandler(this.addbutton, 'click', this.addElement, this);
|
||
|
addEventHandler(this.updatebutton, 'click', this.updateElement, this);
|
||
|
addEventHandler(this.delbutton, 'click', this.deleteElement, this);
|
||
|
|
||
|
this.updatebutton.style.display = 'none';
|
||
|
this.delbutton.style.display = 'none';
|
||
|
};
|
||
|
|
||
|
this.updateState = function(selNode, event) {
|
||
|
var element = this.getNearestAbbrAcronym(selNode);
|
||
|
if (element) {
|
||
|
this.addbutton.style.display = 'none';
|
||
|
this.updatebutton.style.display = 'inline';
|
||
|
this.delbutton.style.display = 'inline';
|
||
|
this.titleinput.value = element.getAttribute('title');
|
||
|
this.radiocontainer.style.display = 'none';
|
||
|
if (this.toolbox) {
|
||
|
if (this.toolbox.open_handler) {
|
||
|
this.toolbox.open_handler();
|
||
|
};
|
||
|
this.toolbox.className = this.activeclass;
|
||
|
};
|
||
|
} else {
|
||
|
this.addbutton.style.display = 'inline';
|
||
|
this.updatebutton.style.display = 'none';
|
||
|
this.delbutton.style.display = 'none';
|
||
|
this.titleinput.value = '';
|
||
|
if (this.editor.getBrowserName() == 'IE' || this.radiocontainer.nodeName.toLowerCase() != 'tr') {
|
||
|
this.radiocontainer.style.display = 'block';
|
||
|
} else {
|
||
|
this.radiocontainer.style.display = 'table-row';
|
||
|
};
|
||
|
if (this.toolbox) {
|
||
|
this.toolbox.className = this.plainclass;
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
|
||
|
this.getNearestAbbrAcronym = function(selNode) {
|
||
|
var current = selNode;
|
||
|
while (current && current.nodeType != 9) {
|
||
|
if (current.nodeType == 1) {
|
||
|
var nodeName = current.nodeName.toLowerCase();
|
||
|
if (nodeName == 'abbr' || nodeName == 'acronym') {
|
||
|
return current;
|
||
|
};
|
||
|
};
|
||
|
current = current.parentNode;
|
||
|
};
|
||
|
};
|
||
|
|
||
|
this.addElement = function() {
|
||
|
var type = this.abbrradio.checked ? 'abbr' : 'acronym';
|
||
|
var doc = this.editor.getInnerDocument();
|
||
|
var selNode = this.editor.getSelectedNode();
|
||
|
if (this.getNearestAbbrAcronym(selNode)) {
|
||
|
this.editor.logMessage('Can not nest abbr and acronym elements');
|
||
|
return;
|
||
|
};
|
||
|
var element = doc.createElement(type);
|
||
|
element.setAttribute('title', this.titleinput.value);
|
||
|
|
||
|
var selection = this.editor.getSelection();
|
||
|
var docfrag = selection.cloneContents();
|
||
|
var placecursoratend = false;
|
||
|
if (docfrag.hasChildNodes()) {
|
||
|
for (var i=0; i < docfrag.childNodes.length; i++) {
|
||
|
element.appendChild(docfrag.childNodes[i]);
|
||
|
};
|
||
|
placecursoratend = true;
|
||
|
} else {
|
||
|
var text = doc.createTextNode('\xa0');
|
||
|
element.appendChild(text);
|
||
|
};
|
||
|
this.editor.insertNodeAtSelection(element, 1);
|
||
|
var selection = this.editor.getSelection();
|
||
|
selection.collapse(placecursoratend);
|
||
|
this.editor.getDocument().getWindow().focus();
|
||
|
var selNode = selection.getSelectedNode();
|
||
|
this.editor.updateState(selNode);
|
||
|
this.editor.logMessage('Element ' + type + ' added');
|
||
|
};
|
||
|
|
||
|
this.updateElement = function() {
|
||
|
var selNode = this.editor.getSelectedNode();
|
||
|
var element = this.getNearestAbbrAcronym(selNode);
|
||
|
if (!element) {
|
||
|
this.editor.logMessage('Not inside an abbr or acronym element!', 1);
|
||
|
return;
|
||
|
};
|
||
|
var title = this.titleinput.value;
|
||
|
element.setAttribute('title', title);
|
||
|
this.editor.logMessage('Updated ' + element.nodeName.toLowerCase() + ' element');
|
||
|
};
|
||
|
|
||
|
this.deleteElement = function() {
|
||
|
var selNode = this.editor.getSelectedNode();
|
||
|
var element = this.getNearestAbbrAcronym(selNode);
|
||
|
if (!element) {
|
||
|
this.editor.logMessage('Not inside an abbr or acronym element!', 1);
|
||
|
return;
|
||
|
};
|
||
|
element.parentNode.removeChild(element);
|
||
|
this.editor.logMessage('Deleted ' + element.nodeName.toLowerCase() + ' deleted');
|
||
|
};
|
||
|
};
|
||
|
|
||
|
SilvaAbbrTool.prototype = new KupuTool;
|
||
|
|
||
|
function SilvaCitationTool(authorinputid, sourceinputid, addbuttonid, updatebuttonid, delbuttonid,
|
||
|
toolboxid, plainclass, activeclass) {
|
||
|
/* tool to manage citation elements */
|
||
|
this.authorinput = getFromSelector(authorinputid);
|
||
|
this.sourceinput = getFromSelector(sourceinputid);
|
||
|
this.addbutton = getFromSelector(addbuttonid);
|
||
|
this.updatebutton = getFromSelector(updatebuttonid);
|
||
|
this.delbutton = getFromSelector(delbuttonid);
|
||
|
this.toolbox = getFromSelector(toolboxid);
|
||
|
this.plainclass = plainclass;
|
||
|
this.activeclass = activeclass;
|
||
|
this._inside_citation = false;
|
||
|
|
||
|
this.initialize = function(editor) {
|
||
|
this.editor = editor;
|
||
|
addEventHandler(this.addbutton, 'click', this.addCitation, this);
|
||
|
addEventHandler(this.updatebutton, 'click', this.updateCitation, this);
|
||
|
addEventHandler(this.delbutton, 'click', this.deleteCitation, this);
|
||
|
if (editor.getBrowserName() == 'IE') {
|
||
|
addEventHandler(editor.getInnerDocument(), 'keyup', this.cancelEnterPress, this);
|
||
|
addEventHandler(editor.getInnerDocument(), 'keydown', this.handleKeyPressOnCitation, this);
|
||
|
} else {
|
||
|
addEventHandler(editor.getInnerDocument(), 'keypress', this.handleKeyPressOnCitation, this);
|
||
|
};
|
||
|
|
||
|
this.updatebutton.style.display = 'none';
|
||
|
this.delbutton.style.display = 'none';
|
||
|
};
|
||
|
|
||
|
this.cancelEnterPress = function(event) {
|
||
|
if (!this._inside_citation || (event.keyCode != 13 && event.keyCode != 9)) {
|
||
|
return;
|
||
|
};
|
||
|
if (event.preventDefault) {
|
||
|
event.preventDefault();
|
||
|
} else {
|
||
|
event.returnValue = false;
|
||
|
};
|
||
|
};
|
||
|
|
||
|
this.handleKeyPressOnCitation = function(event) {
|
||
|
if (!this._inside_citation) {
|
||
|
return;
|
||
|
};
|
||
|
var keyCode = event.keyCode;
|
||
|
var citation = this.getNearestCitation(this.editor.getSelectedNode());
|
||
|
var doc = this.editor.getInnerDocument();
|
||
|
var selection = this.editor.getSelection();
|
||
|
if (keyCode == 13 && this.editor.getBrowserName() == 'IE') {
|
||
|
var br = doc.createElement('br');
|
||
|
var currnode = selection.getSelectedNode();
|
||
|
selection.replaceWithNode(br);
|
||
|
selection.selectNodeContents(br);
|
||
|
selection.collapse(true);
|
||
|
event.returnValue = false;
|
||
|
} else if (keyCode == 9) {
|
||
|
var next = citation.nextSibling;
|
||
|
if (!next) {
|
||
|
next = doc.createElement('p');
|
||
|
next.appendChild(doc.createTextNode('\xa0'));
|
||
|
citation.parentNode.appendChild(next);
|
||
|
};
|
||
|
selection.selectNodeContents(next);
|
||
|
selection.collapse();
|
||
|
if (event.preventDefault) {
|
||
|
event.preventDefault();
|
||
|
};
|
||
|
event.returnValue = false;
|
||
|
this._inside_citation = false;
|
||
|
};
|
||
|
};
|
||
|
|
||
|
this.updateState = function(selNode, event) {
|
||
|
var citation = this.getNearestCitation(selNode);
|
||
|
if (citation) {
|
||
|
this.addbutton.style.display = 'none';
|
||
|
this.updatebutton.style.display = 'inline';
|
||
|
this.delbutton.style.display = 'inline';
|
||
|
this.authorinput.value = citation.getAttribute('author');
|
||
|
this.sourceinput.value = citation.getAttribute('source');
|
||
|
this._inside_citation = true;
|
||
|
if (this.toolbox) {
|
||
|
if (this.toolbox.open_handler) {
|
||
|
this.toolbox.open_handler();
|
||
|
};
|
||
|
this.toolbox.className = this.activeclass;
|
||
|
};
|
||
|
} else {
|
||
|
this.addbutton.style.display = 'inline';
|
||
|
this.updatebutton.style.display = 'none';
|
||
|
this.delbutton.style.display = 'none';
|
||
|
this.authorinput.value = '';
|
||
|
this.sourceinput.value = '';
|
||
|
this._inside_citation = false;
|
||
|
if (this.toolbox) {
|
||
|
this.toolbox.className = this.plainclass;
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
|
||
|
this.addCitation = function() {
|
||
|
var selNode = this.editor.getSelectedNode();
|
||
|
var citation = this.getNearestCitation(selNode);
|
||
|
if (citation) {
|
||
|
this.editor.logMessage('Nested citations are not allowed!');
|
||
|
return;
|
||
|
};
|
||
|
var author = this.authorinput.value;
|
||
|
var source = this.sourceinput.value;
|
||
|
var doc = this.editor.getInnerDocument();
|
||
|
var div = doc.createElement('div');
|
||
|
div.className = 'citation';
|
||
|
div.setAttribute('author', author);
|
||
|
div.setAttribute('source', source);
|
||
|
div.setAttribute('is_citation', '1');
|
||
|
var selection = this.editor.getSelection();
|
||
|
var docfrag = selection.cloneContents();
|
||
|
var placecursoratend = false;
|
||
|
if (docfrag.hasChildNodes()) {
|
||
|
for (var i=0; i < docfrag.childNodes.length; i++) {
|
||
|
div.appendChild(docfrag.childNodes[i]);
|
||
|
};
|
||
|
placecursoratend = true;
|
||
|
} else {
|
||
|
var text = doc.createTextNode('\xa0');
|
||
|
div.appendChild(text);
|
||
|
};
|
||
|
this.editor.insertNodeAtSelection(div, 1);
|
||
|
var selection = this.editor.getSelection();
|
||
|
selection.collapse(placecursoratend);
|
||
|
this.editor.getDocument().getWindow().focus();
|
||
|
var selNode = selection.getSelectedNode();
|
||
|
this.editor.updateState(selNode);
|
||
|
};
|
||
|
|
||
|
this.updateCitation = function() {
|
||
|
var selNode = this.editor.getSelectedNode();
|
||
|
var citation = this.getNearestCitation(selNode);
|
||
|
if (!citation) {
|
||
|
this.editor.logMessage('Not inside a citation element!');
|
||
|
return;
|
||
|
};
|
||
|
citation.setAttribute('author', this.authorinput.value);
|
||
|
citation.setAttribute('source', this.sourceinput.value);
|
||
|
};
|
||
|
|
||
|
this.deleteCitation = function() {
|
||
|
var selNode = this.editor.getSelectedNode();
|
||
|
var citation = this.getNearestCitation(selNode);
|
||
|
if (!citation) {
|
||
|
this.editor.logMessage('Not inside citation element!');
|
||
|
return;
|
||
|
};
|
||
|
citation.parentNode.removeChild(citation);
|
||
|
};
|
||
|
|
||
|
this.getNearestCitation = function(selNode) {
|
||
|
var currnode = selNode;
|
||
|
while (currnode) {
|
||
|
if (currnode.nodeName.toLowerCase() == 'div' &&
|
||
|
currnode.getAttribute('is_citation')) {
|
||
|
return currnode;
|
||
|
};
|
||
|
currnode = currnode.parentNode;
|
||
|
};
|
||
|
return false;
|
||
|
};
|
||
|
|
||
|
this.createContextMenuElements = function(selNode, event) {
|
||
|
/* create the 'Delete citation' menu elements */
|
||
|
var ret = new Array();
|
||
|
if (this.getNearestCitation(selNode)) {
|
||
|
ret.push(new ContextMenuElement('Delete cite', this.deleteCitation, this));
|
||
|
};
|
||
|
return ret;
|
||
|
};
|
||
|
};
|
||
|
|
||
|
SilvaCitationTool.prototype = new KupuTool;
|
||
|
|
||
|
function SilvaExternalSourceTool(idselectid, formcontainerid, addbuttonid, cancelbuttonid,
|
||
|
updatebuttonid, delbuttonid, toolboxid, plainclass, activeclass) {
|
||
|
this.idselect = getFromSelector(idselectid);
|
||
|
this.formcontainer = getFromSelector(formcontainerid);
|
||
|
this.addbutton = getFromSelector(addbuttonid);
|
||
|
this.cancelbutton = getFromSelector(cancelbuttonid);
|
||
|
this.updatebutton = getFromSelector(updatebuttonid);
|
||
|
this.delbutton = getFromSelector(delbuttonid);
|
||
|
this.toolbox = getFromSelector(toolboxid);
|
||
|
this.plainclass = plainclass;
|
||
|
this.activeclass = activeclass;
|
||
|
|
||
|
this._editing = false;
|
||
|
this._url = null;
|
||
|
this._id = null;
|
||
|
this._form = null;
|
||
|
this._insideExternalSource = false;
|
||
|
|
||
|
// store the base url, this will be prepended to the id to form the url to
|
||
|
// get the codesource from (Zope's acquisition will make sure it ends up on
|
||
|
// the right object)
|
||
|
var urlparts = document.location.pathname.toString().split('/')
|
||
|
var urlparts_to_use = [];
|
||
|
for (var i=0; i < urlparts.length; i++) {
|
||
|
var part = urlparts[i];
|
||
|
if (part == 'edit') {
|
||
|
break;
|
||
|
};
|
||
|
urlparts_to_use.push(part);
|
||
|
};
|
||
|
this._baseurl = urlparts_to_use.join('/');
|
||
|
|
||
|
this.initialize = function(editor) {
|
||
|
this.editor = editor;
|
||
|
addEventHandler(this.addbutton, 'click', this.startExternalSourceAddEdit, this);
|
||
|
addEventHandler(this.cancelbutton, 'click', this.resetTool, this);
|
||
|
addEventHandler(this.updatebutton, 'click', this.startExternalSourceAddEdit, this);
|
||
|
addEventHandler(this.delbutton, 'click', this.delExternalSource, this);
|
||
|
addEventHandler(editor.getInnerDocument(), 'keypress', this.handleKeyPressOnExternalSource, this);
|
||
|
if (this.editor.getBrowserName() == 'IE') {
|
||
|
addEventHandler(editor.getInnerDocument(), 'keydown', this.handleKeyPressOnExternalSource, this);
|
||
|
addEventHandler(editor.getInnerDocument(), 'keyup', this.handleKeyPressOnExternalSource, this);
|
||
|
};
|
||
|
|
||
|
// search for a special serialized identifier of the current document
|
||
|
// which is used to send to the ExternalSource element when sending
|
||
|
// requests so the ExternalSources know their context
|
||
|
this.docref = null;
|
||
|
var metas = this.editor.getInnerDocument().getElementsByTagName('meta');
|
||
|
for (var i=0; i < metas.length; i++) {
|
||
|
var meta = metas[i];
|
||
|
if (meta.getAttribute('name') == 'docref') {
|
||
|
this.docref = meta.getAttribute('content');
|
||
|
};
|
||
|
};
|
||
|
|
||
|
this.updatebutton.style.display = 'none';
|
||
|
this.delbutton.style.display = 'none';
|
||
|
this.cancelbutton.style.display = 'none';
|
||
|
};
|
||
|
|
||
|
this.updateState = function(selNode) {
|
||
|
var extsource = this.getNearestExternalSource(selNode);
|
||
|
if (extsource) {
|
||
|
this._insideExternalSource = true;
|
||
|
selectSelectItem(this.idselect, extsource.getAttribute('source_id'));
|
||
|
this.addbutton.style.display = 'none';
|
||
|
this.cancelbutton.style.display = 'none';
|
||
|
this.updatebutton.style.display = 'inline';
|
||
|
this.delbutton.style.display = 'inline';
|
||
|
this.startExternalSourceUpdate(extsource);
|
||
|
if (this.toolbox) {
|
||
|
this.toolbox.className = this.activeclass;
|
||
|
};
|
||
|
} else {
|
||
|
this._insideExternalSource = false;
|
||
|
this.resetTool();
|
||
|
if (this.toolbox) {
|
||
|
this.toolbox.className = this.plainclass;
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
|
||
|
this.handleKeyPressOnExternalSource = function(event) {
|
||
|
if (!this._insideExternalSource) {
|
||
|
return;
|
||
|
};
|
||
|
var keyCode = event.keyCode;
|
||
|
var selNode = this.editor.getSelectedNode();
|
||
|
var div = this.getNearestExternalSource(selNode);
|
||
|
var doc = this.editor.getInnerDocument();
|
||
|
if (keyCode == 13 || keyCode == 9 || keyCode == 39) {
|
||
|
if (div.nextSibling) {
|
||
|
var selection = this.editor.getSelection();
|
||
|
selection.selectNodeContents(div.nextSibling);
|
||
|
selection.collapse();
|
||
|
} else {
|
||
|
var p = doc.createElement('p');
|
||
|
var nbsp = doc.createTextNode('\xa0');
|
||
|
p.appendChild(nbsp);
|
||
|
div.parentNode.appendChild(p);
|
||
|
var selection = this.editor.getSelection();
|
||
|
selection.selectNodeContents(p);
|
||
|
selection.collapse();
|
||
|
};
|
||
|
this._insideExternalSource = false;
|
||
|
} else if (keyCode == 8) {
|
||
|
var selectnode = div.nextSibling;
|
||
|
if (!selectnode) {
|
||
|
selectnode = doc.createElement('p');
|
||
|
selectnode.appendChild(doc.createTextNode('\xa0'));
|
||
|
doc.appendChild(selectnode);
|
||
|
};
|
||
|
var selection = this.editor.getSelection();
|
||
|
selection.selectNodeContents(selectnode);
|
||
|
div.parentNode.removeChild(div);
|
||
|
selection.collapse();
|
||
|
};
|
||
|
if (event.preventDefault) {
|
||
|
event.preventDefault();
|
||
|
} else {
|
||
|
event.returnValue = false;
|
||
|
};
|
||
|
};
|
||
|
|
||
|
this.getUrlAndContinue = function(id, handler) {
|
||
|
if (id == this._id) {
|
||
|
// return cached
|
||
|
handler.call(this, this._url);
|
||
|
return;
|
||
|
};
|
||
|
var request = new XMLHttpRequest();
|
||
|
request.open('GET',
|
||
|
this._baseurl + '/edit/get_extsource_url?id=' + id, true);
|
||
|
var callback = new ContextFixer(function() {
|
||
|
if (request.readyState == 4) {
|
||
|
var url = request.responseText;
|
||
|
this._id = id;
|
||
|
this._url = url;
|
||
|
handler.call(this, url);
|
||
|
};
|
||
|
}, this);
|
||
|
request.onreadystatechange = callback.execute;
|
||
|
request.send('');
|
||
|
};
|
||
|
|
||
|
this.startExternalSourceAddEdit = function() {
|
||
|
// get the appropriate form and display it
|
||
|
if (!this._editing) {
|
||
|
var id = this.idselect.options[this.idselect.selectedIndex].value;
|
||
|
this.getUrlAndContinue(id, this._continueStartExternalSourceEdit);
|
||
|
} else {
|
||
|
// validate the data and take further actions
|
||
|
var formdata = this._gatherFormData();
|
||
|
var doc = window.document;
|
||
|
var request = new XMLHttpRequest();
|
||
|
request.open('POST', this._url + '/validate_form_to_request', true);
|
||
|
var callback = new ContextFixer(this._addExternalSourceIfValidated, request, this);
|
||
|
request.onreadystatechange = callback.execute;
|
||
|
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
||
|
request.send(formdata);
|
||
|
};
|
||
|
};
|
||
|
|
||
|
this._continueStartExternalSourceEdit = function(url) {
|
||
|
url = url + '/get_rendered_form_for_editor?docref=' + this.docref;
|
||
|
var request = new XMLHttpRequest();
|
||
|
request.open('GET', url, true);
|
||
|
var callback = new ContextFixer(this._addFormToTool, request, this);
|
||
|
request.onreadystatechange = callback.execute;
|
||
|
request.send(null);
|
||
|
while (this.formcontainer.hasChildNodes()) {
|
||
|
this.formcontainer.removeChild(this.formcontainer.firstChild);
|
||
|
};
|
||
|
var text = document.createTextNode('Loading...');
|
||
|
this.formcontainer.appendChild(text);
|
||
|
this.updatebutton.style.display = 'none';
|
||
|
this.cancelbutton.style.display = 'inline';
|
||
|
this.addbutton.style.display = 'inline';
|
||
|
this._editing = true;
|
||
|
};
|
||
|
|
||
|
this.startExternalSourceUpdate = function(extsource) {
|
||
|
var id = extsource.getAttribute('source_id');
|
||
|
this.getUrlAndContinue(id, this._continueStartExternalSourceUpdate);
|
||
|
};
|
||
|
|
||
|
this._continueStartExternalSourceUpdate = function(url) {
|
||
|
url = url + '/get_rendered_form_for_editor';
|
||
|
var formdata = this._gatherFormDataFromElement();
|
||
|
formdata += '&docref=' + this.docref;
|
||
|
var request = new XMLHttpRequest();
|
||
|
request.open('POST', url, true);
|
||
|
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
||
|
var callback = new ContextFixer(this._addFormToTool, request, this);
|
||
|
request.onreadystatechange = callback.execute;
|
||
|
request.send(formdata);
|
||
|
this._editing = true;
|
||
|
while (this.formcontainer.hasChildNodes()) {
|
||
|
this.formcontainer.removeChild(this.formcontainer.firstChild);
|
||
|
};
|
||
|
var text = document.createTextNode('Loading...');
|
||
|
this.formcontainer.appendChild(text);
|
||
|
};
|
||
|
|
||
|
this._addFormToTool = function(object) {
|
||
|
if (this.readyState == 4) {
|
||
|
if (this.status != '200') {
|
||
|
// element not found, return without doing anythink
|
||
|
object.resetTool();
|
||
|
return;
|
||
|
};
|
||
|
while (object.formcontainer.hasChildNodes()) {
|
||
|
object.formcontainer.removeChild(object.formcontainer.firstChild);
|
||
|
};
|
||
|
// XXX Somehow appending the XML to the form using DOM doesn't
|
||
|
// work correctly, it looks like the elements aren't HTMLElements
|
||
|
// but XML elements, don't know how to fix now so I'll use string
|
||
|
// insertion for now, needless to say it should be changed to DOM
|
||
|
// manipulation asap...
|
||
|
// XXX why is this.responseXML.documentElement.xml sometimes 'undefined'?
|
||
|
object.formcontainer.innerHTML = this.responseText;
|
||
|
object.idselect.style.display = 'none';
|
||
|
// the formcontainer will contain a table with a form
|
||
|
var form = null;
|
||
|
var iterator = new NodeIterator(object.formcontainer);
|
||
|
while (form == null) {
|
||
|
var next = iterator.next();
|
||
|
if (next.nodeName.toLowerCase() == 'form') {
|
||
|
form = next;
|
||
|
};
|
||
|
};
|
||
|
object._form = form;
|
||
|
};
|
||
|
};
|
||
|
|
||
|
this._addExternalSourceIfValidated = function(object) {
|
||
|
if (this.readyState == 4) {
|
||
|
if (this.status == '200') {
|
||
|
// success, add the external source element to the document
|
||
|
var selNode = object.editor.getSelectedNode();
|
||
|
var currsource = object.getNearestExternalSource(selNode);
|
||
|
var doc = object.editor.getInnerDocument();
|
||
|
|
||
|
var extsource = doc.createElement('div');
|
||
|
extsource.setAttribute('source_id', object._id);
|
||
|
var header = doc.createElement('h4');
|
||
|
extsource.appendChild(header);
|
||
|
extsource.className = 'externalsource';
|
||
|
var metatype = 'Silva Code Source'; // a default just in case
|
||
|
for (var i=0; i < this.responseXML.documentElement.childNodes.length; i++) {
|
||
|
var child = this.responseXML.documentElement.childNodes[i];
|
||
|
if (child.nodeName.toLowerCase() == 'parameter') {
|
||
|
var key = child.getAttribute('key');
|
||
|
var value = '';
|
||
|
for (var j=0; j < child.childNodes.length; j++) {
|
||
|
value += child.childNodes[j].nodeValue;
|
||
|
};
|
||
|
if (key == 'metatype') {
|
||
|
metatype = value;
|
||
|
continue;
|
||
|
};
|
||
|
extsource.setAttribute(key, value);
|
||
|
var textel = doc.createTextNode('Key: ' + key + ', value: ' + value.toString());
|
||
|
extsource.appendChild(textel);
|
||
|
extsource.appendChild(doc.createElement('br'));
|
||
|
};
|
||
|
};
|
||
|
var htext = doc.createTextNode(metatype + ' \xab' + object._id + '\xbb');
|
||
|
header.insertBefore(htext, header.firstChild);
|
||
|
extsource.appendChild(doc.createElement('br'));
|
||
|
if (!currsource) {
|
||
|
object.editor.insertNodeAtSelection(extsource);
|
||
|
} else {
|
||
|
currsource.parentNode.replaceChild(extsource, currsource);
|
||
|
var selection = object.editor.getSelection();
|
||
|
selection.selectNodeContents(extsource);
|
||
|
selection.collapse(true);
|
||
|
};
|
||
|
object.resetTool();
|
||
|
object.editor.updateState();
|
||
|
} else if (this.status == '400') {
|
||
|
// failure, provide some feedback and return to the form
|
||
|
alert('Form could not be validated, error message: ' + this.responseText);
|
||
|
} else {
|
||
|
alert('POST failed with unhandled status ' + this.status);
|
||
|
throw('Error handling POST, server returned ' + this.status + ' HTTP status code');
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
|
||
|
this.delExternalSource = function() {
|
||
|
var selNode = this.editor.getSelectedNode();
|
||
|
var source = this.getNearestExternalSource(selNode);
|
||
|
if (!source) {
|
||
|
this.editor.logMessage('Not inside external source!', 1);
|
||
|
return;
|
||
|
};
|
||
|
var nextsibling = source.nextSibling;
|
||
|
source.parentNode.removeChild(source);
|
||
|
if (nextsibling) {
|
||
|
var selection = this.editor.getSelection();
|
||
|
selection.selectNodeContents(nextsibling);
|
||
|
selection.collapse();
|
||
|
};
|
||
|
};
|
||
|
|
||
|
this.resetTool = function() {
|
||
|
while (this.formcontainer.hasChildNodes()) {
|
||
|
this.formcontainer.removeChild(this.formcontainer.firstChild);
|
||
|
};
|
||
|
this.idselect.style.display = 'inline';
|
||
|
this.addbutton.style.display = 'inline';
|
||
|
this.cancelbutton.style.display = 'none';
|
||
|
this.updatebutton.style.display = 'none';
|
||
|
this.delbutton.style.display = 'none';
|
||
|
//this.editor.updateState();
|
||
|
this._editing = false;
|
||
|
};
|
||
|
|
||
|
this._gatherFormData = function() {
|
||
|
/* walks through the form and creates a POST body */
|
||
|
// XXX we may want to turn this into a helper function, since it's
|
||
|
// quite useful outside of this object I reckon
|
||
|
var form = this._form;
|
||
|
if (!form) {
|
||
|
this.editor.logMessage('Not currently editing');
|
||
|
return;
|
||
|
};
|
||
|
// first place all data into a dict, convert to a string later on
|
||
|
var data = {};
|
||
|
for (var i=0; i < form.elements.length; i++) {
|
||
|
var child = form.elements[i];
|
||
|
var elname = child.nodeName.toLowerCase();
|
||
|
if (elname == 'input') {
|
||
|
var name = child.getAttribute('name');
|
||
|
var type = child.getAttribute('type');
|
||
|
if (!type || type == 'text' || type == 'hidden' || type == 'password') {
|
||
|
data[name] = child.value;
|
||
|
} else if (type == 'checkbox' || type == 'radio') {
|
||
|
if (child.checked) {
|
||
|
if (data[name]) {
|
||
|
if (typeof data[name] == typeof('')) {
|
||
|
var value = new Array(data[name]);
|
||
|
value.push(child.value);
|
||
|
data[name] = value;
|
||
|
} else {
|
||
|
data[name].push(child.value);
|
||
|
};
|
||
|
} else {
|
||
|
data[name] = child.value;
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
} else if (elname == 'textarea') {
|
||
|
data[child.getAttribute('name')] = child.value;
|
||
|
} else if (elname == 'select') {
|
||
|
var name = child.getAttribute('name');
|
||
|
var multiple = child.getAttribute('multiple');
|
||
|
if (!multiple) {
|
||
|
data[name] = child.options[child.selectedIndex].value;
|
||
|
} else {
|
||
|
var value = new Array();
|
||
|
for (var i=0; i < child.options.length; i++) {
|
||
|
if (child.options[i].checked) {
|
||
|
value.push(options[i].value);
|
||
|
};
|
||
|
if (value.length > 1) {
|
||
|
data[name] = value;
|
||
|
} else if (value.length) {
|
||
|
data[name] = value[0];
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
|
||
|
// now we should turn it into a query string
|
||
|
var ret = new Array();
|
||
|
for (var key in data) {
|
||
|
var value = data[key];
|
||
|
// XXX does IE5 support encodeURIComponent?
|
||
|
ret.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
|
||
|
};
|
||
|
|
||
|
return ret.join("&");
|
||
|
};
|
||
|
|
||
|
this._gatherFormDataFromElement = function() {
|
||
|
var selNode = this.editor.getSelectedNode();
|
||
|
var source = this.getNearestExternalSource(selNode);
|
||
|
if (!source) {
|
||
|
return '';
|
||
|
};
|
||
|
var ret = new Array();
|
||
|
for (var i=0; i < source.attributes.length; i++) {
|
||
|
var attr = source.attributes[i];
|
||
|
var name = attr.nodeName;
|
||
|
var value = attr.nodeValue;
|
||
|
if (name != 'class' && name != 'source_id' && name != 'id') {
|
||
|
ret.push(encodeURIComponent(name) + '=' + encodeURIComponent(value));
|
||
|
};
|
||
|
};
|
||
|
return ret.join('&');
|
||
|
};
|
||
|
|
||
|
this.getNearestExternalSource = function(selNode) {
|
||
|
|
||
|
var currnode = selNode;
|
||
|
while (currnode) {
|
||
|
if (currnode.nodeName.toLowerCase() == 'div' && currnode.className == 'externalsource') {
|
||
|
return currnode;
|
||
|
};
|
||
|
currnode = currnode.parentNode;
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
|
||
|
SilvaExternalSourceTool.prototype = new KupuTool;
|
||
|
|
||
|
function SilvaKupuUI(textstyleselectid) {
|
||
|
this.tsselect = getFromSelector(textstyleselectid);
|
||
|
|
||
|
this.updateState = function(selNode) {
|
||
|
/* set the text-style pulldown */
|
||
|
|
||
|
// first get the nearest style
|
||
|
var styles = {}; // use an object here so we can use the 'in' operator later on
|
||
|
for (var i=0; i < this.tsselect.options.length; i++) {
|
||
|
// XXX we should cache this
|
||
|
styles[this.tsselect.options[i].value] = i;
|
||
|
}
|
||
|
|
||
|
// search the list of nodes like in the original one, break if we encounter a match,
|
||
|
// this method does some more than the original one since it can handle commands in
|
||
|
// the form of '<style>|<classname>' next to the plain '<style>' commands
|
||
|
var currnode = selNode;
|
||
|
var index = -1;
|
||
|
while (index==-1 && currnode) {
|
||
|
var nodename = currnode.nodeName.toLowerCase();
|
||
|
for (var style in styles) {
|
||
|
if (style.indexOf('|') < 0) {
|
||
|
// simple command
|
||
|
if (nodename == style.toLowerCase() && !currnode.className) {
|
||
|
index = styles[style];
|
||
|
break;
|
||
|
};
|
||
|
} else {
|
||
|
// command + classname
|
||
|
var tuple = style.split('|');
|
||
|
if (nodename == tuple[0].toLowerCase() && currnode.className == tuple[1]) {
|
||
|
index = styles[style];
|
||
|
break;
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
currnode = currnode.parentNode;
|
||
|
}
|
||
|
this.tsselect.selectedIndex = Math.max(index,0);
|
||
|
};
|
||
|
|
||
|
this.setTextStyle = function(style) {
|
||
|
/* parse the argument into a type and classname part
|
||
|
|
||
|
generate a block element accordingly
|
||
|
*/
|
||
|
// XXX somehow this method always gets called twice... I would
|
||
|
// really like to know why, but can't find it right now and don't
|
||
|
// have time for a full investigation, so fiddle-fixed it this
|
||
|
// way. Needless to say this needs some investigation at some point...
|
||
|
if (this._cancel_update) {
|
||
|
this._cancel_update = false;
|
||
|
return;
|
||
|
};
|
||
|
|
||
|
var classname = "";
|
||
|
var eltype = style;
|
||
|
if (style.indexOf('|') > -1) {
|
||
|
style = style.split('|');
|
||
|
eltype = style[0];
|
||
|
classname = style[1];
|
||
|
};
|
||
|
|
||
|
var command = eltype;
|
||
|
// first create the element, then find it and set the classname
|
||
|
if (this.editor.getBrowserName() == 'IE') {
|
||
|
command = '<' + eltype + '>';
|
||
|
};
|
||
|
this.editor.getDocument().execCommand('formatblock', command);
|
||
|
|
||
|
// now get a reference to the element just added
|
||
|
var selNode = this.editor.getSelectedNode();
|
||
|
var el = this.editor.getNearestParentOfType(selNode, eltype);
|
||
|
|
||
|
// now set the classname
|
||
|
if (classname) {
|
||
|
el.className = classname;
|
||
|
el.setAttribute('silva_type', classname);
|
||
|
};
|
||
|
this._cancel_update = true;
|
||
|
this.editor.updateState();
|
||
|
this.editor.getDocument().getWindow().focus();
|
||
|
};
|
||
|
};
|
||
|
|
||
|
SilvaKupuUI.prototype = new KupuUI;
|
||
|
|
||
|
function SilvaPropertyTool(tablerowid, formid) {
|
||
|
/* a simple tool to edit metadata fields
|
||
|
|
||
|
the fields' contents are stored in Silva's metadata sets
|
||
|
*/
|
||
|
this.tablerow = document.getElementById(tablerowid);
|
||
|
this.form = document.getElementById(formid);
|
||
|
this.table = this.tablerow.parentNode;
|
||
|
while (!this.table.nodeName.toLowerCase() == 'table') {
|
||
|
this.table = this.table.parentNode;
|
||
|
};
|
||
|
// remove current content from the fields
|
||
|
var tds = this.tablerow.getElementsByTagName('td');
|
||
|
for (var i=0; i < tds.length; i++) {
|
||
|
while (tds[i].hasChildNodes()) {
|
||
|
tds[i].removeChild(tds[i].childNodes[0]);
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
|
||
|
SilvaPropertyTool.prototype = new KupuTool;
|
||
|
|
||
|
SilvaPropertyTool.prototype.initialize = function(editor) {
|
||
|
this.editor = editor;
|
||
|
|
||
|
// walk through all metadata fields and expose them to the user
|
||
|
var metas = this.editor.getInnerDocument().getElementsByTagName('meta');
|
||
|
for (var i=0; i < metas.length; i++) {
|
||
|
var meta = metas[i];
|
||
|
var name = meta.getAttribute('name');
|
||
|
if (!name) {
|
||
|
// http-equiv type
|
||
|
continue;
|
||
|
};
|
||
|
var rowcopy = this.tablerow.cloneNode(true);
|
||
|
this.tablerow.parentNode.appendChild(rowcopy);
|
||
|
// create the form elements, pass in the rowcopy so the row can be
|
||
|
// rendered real-time, this because IE doesn't select checkboxes that
|
||
|
// arent' visible(!!)
|
||
|
this.parseFormElIntoRow(meta, rowcopy);
|
||
|
/*
|
||
|
if (tag) {
|
||
|
this.tablerow.parentNode.appendChild(tag);
|
||
|
};
|
||
|
*/
|
||
|
};
|
||
|
// throw away the original row: we don't need it anymore...
|
||
|
this.tablerow.parentNode.removeChild(this.tablerow);
|
||
|
};
|
||
|
|
||
|
SilvaPropertyTool.prototype.parseFormElIntoRow = function(metatag, tablerow) {
|
||
|
/* render a field in the properties tool according to a metadata tag
|
||
|
|
||
|
returns some false value if the meta tag should not be editable
|
||
|
*/
|
||
|
var scheme = metatag.getAttribute('scheme');
|
||
|
if (!scheme || !(scheme in EDITABLE_METADATA)) {
|
||
|
return;
|
||
|
};
|
||
|
var name = metatag.getAttribute('name');
|
||
|
var namespace = metatag.getAttribute('scheme');
|
||
|
var nametypes = EDITABLE_METADATA[scheme];
|
||
|
var type = 'text';
|
||
|
var mandatory = false;
|
||
|
var namefound = false;
|
||
|
var fieldtitle = '';
|
||
|
for (var i=0; i < nametypes.length; i++) {
|
||
|
var nametype = nametypes[i];
|
||
|
var elname = nametype[0];
|
||
|
var type = nametype[1];
|
||
|
var mandatory = nametype[2];
|
||
|
var fieldtitle = nametype[3];
|
||
|
if (elname == name) {
|
||
|
namefound = true;
|
||
|
break;
|
||
|
};
|
||
|
};
|
||
|
if (!namefound) {
|
||
|
return;
|
||
|
};
|
||
|
|
||
|
var titlefield = document.createElement('span');
|
||
|
var title = document.createTextNode(fieldtitle);
|
||
|
titlefield.appendChild(title);
|
||
|
tablerow.getElementsByTagName('td')[0].appendChild(titlefield);
|
||
|
titlefield.className = 'metadata-field';
|
||
|
|
||
|
var value = metatag.getAttribute('content');
|
||
|
var parentvalue = metatag.getAttribute('parentcontent');
|
||
|
var td = tablerow.getElementsByTagName('td')[1]
|
||
|
if (type == 'text' || type == 'textarea' || type == 'datetime') {
|
||
|
this._createSimpleItemHTML(type, value, name,
|
||
|
namespace, mandatory, td);
|
||
|
} else if (type == 'checkbox') {
|
||
|
var titlecell = tablerow.getElementsByTagName('td')[0];
|
||
|
this._createCheckboxItemHTML(titlecell, value, name, namespace,
|
||
|
mandatory, td);
|
||
|
};
|
||
|
if (parentvalue && parentvalue != '') {
|
||
|
td.appendChild(document.createElement('br'));
|
||
|
td.appendChild(document.createTextNode('acquired value:'));
|
||
|
td.appendChild(document.createElement('br'));
|
||
|
td.appendChild(document.createTextNode(parentvalue));
|
||
|
};
|
||
|
|
||
|
return tablerow;
|
||
|
};
|
||
|
|
||
|
// just to make the above method a bit more readable
|
||
|
SilvaPropertyTool.prototype._createSimpleItemHTML = function(type, value,
|
||
|
name, namespace,
|
||
|
mandatory, td) {
|
||
|
var input = null;
|
||
|
if (type == 'text' || type == 'datetime') {
|
||
|
input = document.createElement('input');
|
||
|
input.setAttribute('type', 'text');
|
||
|
input.value = value;
|
||
|
if (type == 'datetime') {
|
||
|
input.setAttribute('widget:type', 'datetime');
|
||
|
};
|
||
|
} else if (type == 'textarea') {
|
||
|
input = document.createElement('textarea');
|
||
|
var content = document.createTextNode(value);
|
||
|
input.appendChild(content);
|
||
|
};
|
||
|
input.setAttribute('name', name);
|
||
|
input.setAttribute('namespace', namespace);
|
||
|
input.className = 'metadata-input';
|
||
|
if (mandatory) {
|
||
|
input.setAttribute('mandatory', 'true');
|
||
|
};
|
||
|
td.appendChild(input);
|
||
|
};
|
||
|
|
||
|
SilvaPropertyTool.prototype._createCheckboxItemHTML = function(titlecell,
|
||
|
value, name, namespace,
|
||
|
mandatory, td) {
|
||
|
// elements are seperated by ||
|
||
|
var infos = value.split('||');
|
||
|
|
||
|
// messy stuff coming up, that make the checkboxes appear in some
|
||
|
// 'foldable' div
|
||
|
var outerdiv = document.createElement('div');
|
||
|
outerdiv.className = 'kupu-properties-checkbox-outerdiv';
|
||
|
|
||
|
// the arrow and 'items' label
|
||
|
var itemsdiv = document.createElement('div');
|
||
|
outerdiv.appendChild(itemsdiv);
|
||
|
var img = document.createElement('img');
|
||
|
// XXX would be nice if this would be absolute...
|
||
|
img.src = 'kupu_silva/closed_arrow.gif';
|
||
|
outerdiv.image = img; // XXX memory leak!!
|
||
|
itemsdiv.appendChild(img);
|
||
|
itemsdiv.appendChild(document.createTextNode(_('items')));
|
||
|
itemsdiv.setAttribute('title', _('click to unfold'));
|
||
|
|
||
|
// handler for showing/hiding the checkbox divs
|
||
|
var handler = function(evt) {
|
||
|
if (this.lastChild.style.display == 'none') {
|
||
|
this.image.src = 'kupu_silva/opened_arrow.gif';
|
||
|
this.image.setAttribute('title', _('click to fold'));
|
||
|
this.lastChild.style.display = 'block';
|
||
|
} else {
|
||
|
this.image.src = 'kupu_silva/closed_arrow.gif';
|
||
|
this.image.setAttribute('title', _('click to unfold'));
|
||
|
this.lastChild.style.display = 'none';
|
||
|
}
|
||
|
};
|
||
|
addEventHandler(itemsdiv, 'click', handler, outerdiv);
|
||
|
addEventHandler(titlecell, 'click', handler, outerdiv);
|
||
|
|
||
|
// innerdiv is where the actual checkboxes are displayed in, and what
|
||
|
// is collapsed/uncollapsed
|
||
|
var innerdiv = document.createElement('div');
|
||
|
innerdiv.className = 'kupu-properties-checkbox-innerdiv';
|
||
|
outerdiv.appendChild(innerdiv);
|
||
|
td.appendChild(outerdiv);
|
||
|
|
||
|
for (var i=0; i < infos.length; i++) {
|
||
|
// in certain cases the value you want to display is different
|
||
|
// from that you want to store, in that case seperate id from
|
||
|
// value with a |, there should always be a value|checked, but
|
||
|
// in some cases you may want a value|title|checked set...
|
||
|
var info = infos[i].split('|');
|
||
|
var itemvalue = info[0];
|
||
|
var title = info[0];
|
||
|
var checked = (info[1] == 'true' || info[1] == 'yes');
|
||
|
if (info.length == 3) {
|
||
|
title = info[1];
|
||
|
checked = (info[2] == 'true' || info[2] == 'yes');
|
||
|
};
|
||
|
var div = document.createElement('div');
|
||
|
div.className = 'kupu-properties-checkbox-line';
|
||
|
innerdiv.appendChild(div);
|
||
|
|
||
|
var cbdiv = document.createElement('div');
|
||
|
cbdiv.className = 'kupu-properties-checkbox-input';
|
||
|
div.appendChild(cbdiv);
|
||
|
|
||
|
var checkbox = document.createElement('input');
|
||
|
checkbox.setAttribute('name', name);
|
||
|
checkbox.setAttribute('namespace', namespace);
|
||
|
checkbox.type = 'checkbox';
|
||
|
checkbox.value = itemvalue;
|
||
|
cbdiv.appendChild(checkbox);
|
||
|
if (checked) {
|
||
|
checkbox.checked = 'checked';
|
||
|
};
|
||
|
checkbox.className = 'metadata-checkbox';
|
||
|
// XXX a bit awkward to set this on all checkboxes
|
||
|
if (mandatory) {
|
||
|
checkbox.setAttribute('mandatory', 'true');
|
||
|
};
|
||
|
var textdiv = document.createElement('div');
|
||
|
textdiv.className = 'kupu-properties-checkbox-item-title';
|
||
|
textdiv.appendChild(document.createTextNode(title));
|
||
|
div.appendChild(textdiv);
|
||
|
};
|
||
|
// we can not hide the checkboxes earlier because IE requires them
|
||
|
// to be *visible* in order to check them from code :(
|
||
|
innerdiv.style.display = 'none';
|
||
|
};
|
||
|
|
||
|
SilvaPropertyTool.prototype.beforeSave = function() {
|
||
|
/* save the metadata to the document */
|
||
|
if (window.widgeteer) {
|
||
|
widgeteer.widget_registry.prepareForm(this.form);
|
||
|
};
|
||
|
var doc = this.editor.getInnerDocument();
|
||
|
var inputs = this.table.getElementsByTagName('input');
|
||
|
var textareas = this.table.getElementsByTagName('textarea');
|
||
|
var checkboxdata = {}; // name: value for all checkboxes checked
|
||
|
var errors = [];
|
||
|
var okay = [];
|
||
|
for (var i=0; i < inputs.length; i++) {
|
||
|
var input = inputs[i];
|
||
|
if (!input.getAttribute('namespace')) {
|
||
|
continue;
|
||
|
};
|
||
|
var name = input.getAttribute('name');
|
||
|
var scheme = input.getAttribute('namespace');
|
||
|
if (input.getAttribute('type') == 'text') {
|
||
|
var value = input.value;
|
||
|
if (input.getAttribute('mandatory') && value.strip() == '') {
|
||
|
errors.push(name);
|
||
|
continue;
|
||
|
};
|
||
|
okay.push([name, scheme, value]);
|
||
|
} else if (input.getAttribute('type') == 'checkbox') {
|
||
|
if (checkboxdata[name] === undefined) {
|
||
|
checkboxdata[name] = [];
|
||
|
// XXX yuck!!
|
||
|
checkboxdata[name].namespace = scheme;
|
||
|
checkboxdata[name].mandatory =
|
||
|
input.getAttribute('mandatory') ? true : false;
|
||
|
};
|
||
|
if (input.checked) {
|
||
|
checkboxdata[name].push(
|
||
|
input.value.replace('|', '&pipe;', 'g'));
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
for (var i=0; i < textareas.length; i++) {
|
||
|
var textarea = textareas[i];
|
||
|
var name = textarea.getAttribute('name');
|
||
|
var scheme = textarea.getAttribute('namespace');
|
||
|
var value = textarea.value;
|
||
|
if (textarea.getAttribute('mandatory') && value.strip() == '') {
|
||
|
errors.push(name);
|
||
|
continue;
|
||
|
};
|
||
|
okay.push([name, scheme, value]);
|
||
|
};
|
||
|
for (var name in checkboxdata) {
|
||
|
if (checkboxdata[name].mandatory && checkboxdata[name].length == 0) {
|
||
|
errors.push(name);
|
||
|
} else {
|
||
|
var data = checkboxdata[name];
|
||
|
okay.push([name, data.namespace, data.join('|')]);
|
||
|
};
|
||
|
};
|
||
|
if (errors.length) {
|
||
|
throw('Error in properties: fields ' + errors.join(', ') +
|
||
|
' are required but not filled in');
|
||
|
};
|
||
|
for (var i=0; i < okay.length; i++) {
|
||
|
this._addMetaTag(doc, okay[i][0], okay[i][1], okay[i][2]);
|
||
|
};
|
||
|
};
|
||
|
|
||
|
SilvaPropertyTool.prototype._addMetaTag = function(doc, name, scheme,
|
||
|
value, parentvalue) {
|
||
|
var head = doc.getElementsByTagName('head')[0];
|
||
|
if (!head) {
|
||
|
throw('The editable document *must* have a <head> element!');
|
||
|
};
|
||
|
// first find and delete the old one
|
||
|
// XXX if only we'd have XPath...
|
||
|
var metas = doc.getElementsByTagName('meta');
|
||
|
for (var i=0; i < metas.length; i++) {
|
||
|
var meta = metas[i];
|
||
|
if (meta.getAttribute('name') == name &&
|
||
|
meta.getAttribute('scheme') == scheme) {
|
||
|
meta.parentNode.removeChild(meta);
|
||
|
};
|
||
|
};
|
||
|
var tag = doc.createElement('meta');
|
||
|
tag.setAttribute('name', name);
|
||
|
tag.setAttribute('scheme', scheme);
|
||
|
tag.setAttribute('content', value);
|
||
|
|
||
|
head.appendChild(tag);
|
||
|
};
|
||
|
|
||
|
function SilvaCharactersTool(charselectid) {
|
||
|
/* a tool to add non-standard characters */
|
||
|
this._charselect = document.getElementById(charselectid);
|
||
|
};
|
||
|
|
||
|
SilvaCharactersTool.prototype = new KupuTool;
|
||
|
|
||
|
SilvaCharactersTool.prototype.initialize = function(editor) {
|
||
|
this.editor = editor;
|
||
|
addEventHandler(this._charselect, 'change', this.addCharacter, this);
|
||
|
var chars = this.editor.config.nonstandard_chars.split(' ');
|
||
|
for (var i=0; i < chars.length; i++) {
|
||
|
var option = document.createElement('option');
|
||
|
option.value = chars[i];
|
||
|
var text = document.createTextNode(chars[i]);
|
||
|
option.appendChild(text);
|
||
|
this._charselect.appendChild(option);
|
||
|
};
|
||
|
};
|
||
|
|
||
|
SilvaCharactersTool.prototype.addCharacter = function() {
|
||
|
var select = this._charselect;
|
||
|
var c = select.options[select.selectedIndex].value;
|
||
|
if (!c.strip()) {
|
||
|
return;
|
||
|
};
|
||
|
var selection = this.editor.getSelection();
|
||
|
var textnode = this.editor.getInnerDocument().createTextNode(c);
|
||
|
var span = this.editor.getInnerDocument().createElement('span');
|
||
|
span.appendChild(textnode);
|
||
|
selection.replaceWithNode(span);
|
||
|
var selection = this.editor.getSelection();
|
||
|
selection.selectNodeContents(span);
|
||
|
selection.moveEnd(1);
|
||
|
selection.collapse(true);
|
||
|
this.editor.logMessage('Character ' + c + ' inserted');
|
||
|
this.editor.getDocument().getWindow().focus();
|
||
|
select.selectedIndex = 0;
|
||
|
};
|