discourse-legacysite-perl/site/forum.slowtwitch.com/www/static/editor/editor.js
2024-06-17 22:27:49 +10:00

917 lines
35 KiB
JavaScript

/*
* =================================================================
* HTML Editor - A WYSIWYG web based editor for IE5.5+ and Mozilla v1.4+
*
* Website : http://gossamer-threads.com/
* Support : http://gossamer-threads.com/scripts/support/
* Revision : $Id: editor.js,v 1.12 2009/05/09 05:52:50 brewt Exp $
*
* Copyright (c) 2005 Gossamer Threads Inc. All Rights Reserved.
* Redistribution in part or in whole strictly prohibited. Please
* see LICENSE file for full details.
* =================================================================
*/
var dialogWindow = {};
function advancedEditor() {
this.config = {
imageURL : 'images',
imageDialogURL : '',
defaultFont : 'Arial',
defaultFontSize : '3',
defaultForeground : '#000000',
defaultBackground : '#FFFFFF',
focusOnload : false
};
this.id = {
editorFrame : 'editor_iframe',
toolbarArea : 'toolbar_area',
editableFrame : 'editable_iframe',
editableContent : 'editable_content',
editableSource : 'editable_source',
form : '',
content : ''
};
// command, image, title, updateType(0 = don't update, 1 = queryCommandState, 2 = queryCommandEnabled, 3 = customQueryCommandState, 4 = customQueryCommandEnabled), customCommand, customStateCommand, useCSS (mozilla)
this.toolbar = [
{
buttons : {
copy : ['Copy', 'copy.gif', 'Copy', 2],
cut : ['Cut', 'cut.gif', 'Cut', 2],
paste : ['Paste', 'paste.gif', 'Paste', 2]
},
num_buttons : 3,
hidden : isIE ? 0 : 1
},
// The undo/redo buttons don't work too reliably and the buffer is lost after
// doing things like resizing (changing any properties of the contenteditable
// area will wipe it), or custom commands.
/*
{
buttons : {
undo : ['Undo', 'undo.gif', 'Undo', 2],
redo : ['Redo', 'redo.gif', 'Redo', 2]
},
num_buttons : 2
},
*/
{
buttons : {
bold : ['Bold', 'bold.gif', 'Bold', 1],
italic : ['Italic', 'italic.gif', 'Italic', 1],
underline : ['Underline', 'underline.gif', 'Underline', 1]
},
num_buttons : 3
},
{
buttons : {
quote : ['', 'quote.gif', 'Quote', 0, 'this.insertQuote()']
/*
reply : ['', 'reply.gif', 'Reply', 0, 'this.insertReply()'],
code : ['', 'code.gif', 'Code', 0, 'this.insertCode()']
*/
},
num_buttons : 1
},
{
buttons : {
alignleft : ['JustifyLeft', 'alignleft.gif', 'Align Left', 1],
center : ['JustifyCenter', 'center.gif', 'Center', 1],
alignright : ['JustifyRight', 'alignright.gif', 'Align Right', 1]
},
num_buttons : 3
},
{
buttons : {
numlist : ['InsertOrderedList', 'numlist.gif', 'Numbering', 1],
bullist : ['InsertUnorderedList', 'bullist.gif', 'Bullets', 1],
outdent : ['Outdent', 'outdent.gif', 'Decrease Indent', 0],
indent : ['Indent', 'indent.gif', 'Increase Indent', 0]
},
num_buttons : 4
},
{
buttons : {
font : ['FontName', 'font.gif', 'Font', 0, 'this.fontDialog()'],
color : ['', 'color.gif', 'Color', 0, 'this.colorDialog("foreground")']
},
num_buttons : 2
},
{
buttons : {
hr : ['InsertHorizontalRule', 'hr.gif', 'Horizontal Rule', 0],
image : ['', 'image.gif', 'Insert Image', 0, 'this.imageDialog()'],
link : ['', 'link.gif', 'Create Link', 4, 'this.linkDialog()', 'this.selectionMade()']
},
num_buttons : 3
},
{
buttons : {
source : ['', 'source.gif', 'Toggle HTML Source', 3, 'this.toggleSource()', 'this.sourceMode']
},
num_buttons : 1
}
];
/* not allowed to have upload image for some forum */
if (!this.canAttach()) {
this.toolbar[6] = {
buttons : {
hr : ['InsertHorizontalRule', 'hr.gif', 'Horizontal Rule', 0],
link : ['', 'link.gif', 'Create Link', 4, 'this.linkDialog()', 'this.selectionMade()']
},
num_buttons : 2
};
}
this.toolbarMapping = {};
this.toolbarQueryCommandState = {};
this.toolbarQueryCommandEnabled = {};
this.objects = {};
this.loadingInterval = 0;
this.initCount = 0;
this.toolbarInterval = 0;
this.selection = null;
this.loaded = false;
this.sourceMode = false;
// TODO remove this and get values from currentStyle
// Dimensions of various objects
// *Extra are padding/border/margin widths that need to be added to properly
// calculate object total widths
this.editorFrameExtra = 2;
this.editableContentExtra = 10;
this.toolbarExtra = 2;
this.toolbarHeight = 26;
this.buttonWidth = 25;
this.separatorWidth = 8;
}
advancedEditor.prototype.load = function (form, content) {
var self = this;
if (form)
this.id.form = form;
if (content)
this.id.content = content;
this.loadingInterval = setInterval(function () { self.init() }, 100);
}
advancedEditor.prototype.init = function () {
if (this.initCount++ > 100) {
clearInterval(this.loadingInterval);
return;
}
var self = this;
this.objects.editorFrame = document.getElementById(this.id.editorFrame);
if (!this.objects.editorFrame)
return;
this.objects.editorFrameDoc = this.objects.editorFrame.contentWindow.document;
this.objects.editableSource = this.objects.editorFrameDoc.getElementById(this.id.editableSource);
this.objects.editableFrame = this.objects.editorFrameDoc.getElementById(this.id.editableFrame);
if (!this.objects.editableFrame)
return;
if (!this.objects.editableSource)
this.deleteButton('source');
this.objects.editableFrameDoc = this.objects.editableFrame.contentWindow.document;
this.objects.editableContent = this.objects.editableFrameDoc.getElementById(this.id.editableContent);
if (!this.objects.editableContent)
return;
this.objects.toolbarArea = this.objects.editorFrameDoc.getElementById(this.id.toolbarArea);
if (!this.objects.toolbarArea)
return;
clearInterval(this.loadingInterval);
this.objects.form = document.getElementById(this.id.form);
this.objects.content = document.getElementById(this.id.content);
this.objects.editableContent.innerHTML = this.objects.content.value;
registerEvent(this.objects.form, 'submit', function () {
self.objects.content.value = self.getContent();
});
// Before leaving the page, make sure the content is put back into the input so that the content isn't lost if the user goes back to the page
registerEvent(window, 'beforeunload', function () {
self.objects.content.value = self.getContent();
});
// Tabbing from the subject takes you to the iframe in IE, but the document in Mozilla
registerEvent(this.objects.editorFrame, 'focus', function () { self.focus() });
registerEvent(this.objects.editorFrameDoc, 'focus', function () { self.focus() });
var width = this.objects.editorFrame.offsetWidth - this.editorFrameExtra;
var toolbar;
for (var i = 0; i < this.toolbar.length; i++) {
if (this.toolbar[i].hidden || this.toolbar[i].num_buttons <= 0)
continue;
var group = this.objects.editorFrameDoc.createElement('div');
group.aewidth = this.buttonWidth * this.toolbar[i].num_buttons;
if (!toolbar || toolbar.aewidth + this.toolbarExtra + this.separatorWidth + group.aewidth > width)
toolbar = this.addToolbar();
else
this.addSeparator(toolbar);
this.addButtonGroup(toolbar, group);
for (var item in this.toolbar[i].buttons) {
var button = this.objects.editorFrameDoc.createElement('div');
group.appendChild(button);
button.id = item;
button.enabled = true;
button.className = 'button';
button.style.backgroundImage = 'url(' + this.config.imageURL + '/' + this.toolbar[i].buttons[item][1] + ')';
button.title = this.toolbar[i].buttons[item][2];
button.setAttribute('unselectable', 'on');
registerEvent(button, 'mouseover', function (e) { self.mouseHandler(e) });
registerEvent(button, 'mouseout', function (e) { self.mouseHandler(e) });
registerEvent(button, 'mousedown', function (e) { self.mouseHandler(e) });
registerEvent(button, 'click', function (e) { self.mouseHandler(e) });
this.toolbarMapping[item] = i;
if (this.toolbar[i].buttons[item][3] == 1 || this.toolbar[i].buttons[item][3] == 3)
this.toolbarQueryCommandState[item] = i;
else if (this.toolbar[i].buttons[item][3] == 2 || this.toolbar[i].buttons[item][3] == 4)
this.toolbarQueryCommandEnabled[item] = i;
}
}
this.objects.editableContent.style.fontFamily = this.config.defaultFont;
var fontsize = {
1 : 'xx-small',
2 : 'x-small',
3 : 'small',
4 : 'medium',
5 : 'large',
6 : 'x-large',
7 : 'xx-large'
};
this.objects.editableContent.style.fontSize = fontsize[parseInt(this.config.defaultFontSize) + (isIE ? 0 : 1)];
this.objects.editableContent.style.backgroundColor = this.config.defaultBackground;
this.objects.editableFrameDoc.body.contentEditable = true;
if (!isIE)
this.objects.editableFrameDoc.designMode = 'on';
// This actually turns *off* the usage of css
if (isMozilla)
this.execCommand("useCSS", true);
this.toolbarInterval = setInterval(function () { self.updateButtonStatus(); }, 250);
registerEvent(this.objects.editableContent, 'dblclick', function (e) {
if (!e) e = self.objects.editableFrame.contentWindow.event;
var target = e.target ? e.target : e.srcElement;
if (target.tagName == 'IMG')
self.imageDialog();
});
registerEvent(self.objects.editorFrame.contentWindow, 'resize', function () { self.resize(); });
if (this.config.focusOnload)
this.focus();
this.loaded = true;
}
advancedEditor.prototype.getContent = function (bodyOnly) {
var content = this.objects.editableContent.innerHTML;
if (content) {
// Perform some clean up on the editor generated HTML
if (isIE)
content = content.replace(/<P>/g, '').replace(/<\/P>/g, '<BR>').replace(/\r?\n/g, '');
else
content = content.replace(/<br><(ol|ul)>/g, "<$1>");
if (content.match(/^(?:&nbsp;)?<br>\n*$/i))
content = '';
if (bodyOnly)
return content;
else {
var bgcolor = advancedEditor.getHexColor(this.objects.editableContent.style.backgroundColor);
var html = '<html><body';
if (bgcolor)
html += ' bgcolor="' + bgcolor + '"';
html += '>' + content + '</body></html>';
return html;
}
}
return '';
}
advancedEditor.prototype.setContent = function (html) {
this.objects.editableContent.innerHTML = html;
}
advancedEditor.prototype.enable = function () {
this.changeButtonState(true);
}
advancedEditor.prototype.disable = function () {
this.changeButtonState(false);
}
advancedEditor.prototype.deleteButton = function () {
var args = advancedEditor.prototype.deleteButton.arguments;
if (this.loaded || !args.length) {
alert("Can't call deleteButton() after the editor has loaded!");
return;
}
var del = {};
for (var i = 0; i < args.length; i++)
del[args[i]] = 1;
for (var i = 0; i < this.toolbar.length; i++) {
for (var button in this.toolbar[i].buttons) {
if (del[button]) {
delete this.toolbar[i].buttons[button];
delete del[button];
this.toolbar[i].num_buttons--;
if (!del) break;
}
}
}
}
advancedEditor.prototype.changeButtonState = function (enabled) {
var args = advancedEditor.prototype.changeButtonState.arguments;
var leave = {};
for (var i = 0; i < args.length; i++)
leave[args[i]] = 1;
for (var id in this.toolbarMapping) {
if (leave[id])
continue;
var button = this.objects.editorFrameDoc.getElementById(id);
if (enabled) {
button.enabled = button.previousState;
button.className = button.previousClass;
button.noUpdates = false;
}
else {
button.noUpdates = true;
button.previousState = button.enabled;
button.enabled = false;
button.previousClass = button.className;
button.className = 'button button-disabled';
}
}
}
advancedEditor.prototype.addToolbar = function () {
var toolbar = this.objects.editorFrameDoc.createElement('div');
this.objects.toolbarArea.appendChild(toolbar);
toolbar.aewidth = 0;
toolbar.className = 'toolbar';
toolbar.setAttribute('unselectable', 'on');
this.objects.editableFrame.style.height = this.objects.editorFrame.offsetHeight - this.editorFrameExtra - this.toolbarHeight * this.objects.toolbarArea.childNodes.length + 'px';
return toolbar;
}
advancedEditor.prototype.addButtonGroup = function (toolbar, group, beforeElement) {
if (beforeElement)
toolbar.insertBefore(group, beforeElement);
else
toolbar.appendChild(group);
toolbar.aewidth += group.aewidth;
}
advancedEditor.prototype.addSeparator = function (toolbar, beforeElement) {
var separator = this.objects.editorFrameDoc.createElement('div');
separator.className = 'separator';
separator.setAttribute('unselectable', 'on');
if (beforeElement)
toolbar.insertBefore(separator, beforeElement);
else
toolbar.appendChild(separator);
toolbar.aewidth += this.separatorWidth;
}
advancedEditor.prototype.updateButtonStatus = function () {
for (var item in this.toolbarQueryCommandState) {
var buttonConfig = this.toolbar[this.toolbarQueryCommandState[item]].buttons[item];
var command = buttonConfig[0];
var button = this.objects.editorFrameDoc.getElementById(item);
if (button.mousedown || button.noUpdates)
continue;
var previousState = button.pressed;
if (buttonConfig[3] == 3)
button.pressed = eval(buttonConfig[5]);
else
button.pressed = this.objects.editableFrameDoc.queryCommandState(command);
if (previousState == button.pressed)
continue;
if (button.pressed)
button.className = 'button button-pressed' + (button.mouseover ? ' button-pressed-mouse-over' : '');
else
button.className = 'button' + (button.mouseover ? ' button-mouse-over' : '');
}
for (var item in this.toolbarQueryCommandEnabled) {
var buttonConfig = this.toolbar[this.toolbarQueryCommandEnabled[item]].buttons[item];
var command = buttonConfig[0];
var button = this.objects.editorFrameDoc.getElementById(item);
if (button.noUpdates)
continue;
var enable;
if (buttonConfig[3] == 4)
enable = eval(buttonConfig[5]);
else
enable = this.objects.editableFrameDoc.queryCommandEnabled(command);
if (button.enabled == enable)
continue;
if (enable) {
button.enabled = true;
// mozilla bug loses mouseout event after changing applying the alpha transparency
button.className = 'button' + (button.mouseover && !isMozilla ? ' button-mouse-over' : '');
}
else {
button.enabled = false;
button.className = 'button button-disabled';
}
}
}
advancedEditor.prototype.mouseHandler = function (e) {
if (!e) e = this.objects.editorFrame.contentWindow.event;
var target = e.target ? e.target : e.srcElement;
switch (e.type) {
case 'mouseover':
target.mouseover = true;
break;
case 'mouseout':
target.mouseover = false;
break;
case 'mousedown':
target.mousedown = true;
break;
case 'click':
target.mousedown = false;
break;
}
if (!target.enabled)
return;
switch (e.type) {
case 'mouseover':
if (target.pressed)
target.className = 'button button-pressed button-pressed-mouse-over';
else
target.className = 'button button-mouse-over';
break;
case 'mouseout':
if (target.pressed)
target.className = 'button button-pressed';
else
target.className = 'button';
break;
case 'mousedown':
if (!target.pressed)
target.className = 'button button-pressed button-pressed-mouse-over';
break;
case 'click':
// Only do something on a left click
if ((e.which && e.which != 1) || (e.button && e.button != 1))
return;
var button = this.toolbar[this.toolbarMapping[target.id]].buttons[target.id];
if (button[4])
eval(button[4]);
else
this.execCommand(button[0], null, button[6]);
if (button[3] == 1)
target.pressed = this.objects.editableFrameDoc.queryCommandState(button[0]);
else if (button[3] == 3)
target.pressed = eval(button[5]);
if (target.pressed)
target.className = 'button button-pressed' + (target.mouseover ? ' button-pressed-mouse-over' : '');
else
target.className = 'button' + (target.mouseover ? ' button-mouse-over' : '');
break;
}
}
advancedEditor.prototype.resize = function () {
var width = this.objects.editorFrame.offsetWidth - this.editorFrameExtra;
var height = this.objects.editorFrame.offsetHeight - this.editorFrameExtra;
var toolbarCount = this.objects.toolbarArea.childNodes.length;
for (var i = 0; i < this.objects.toolbarArea.childNodes.length; i++) {
var toolbar = this.objects.toolbarArea.childNodes[i];
// Window has shrunk, move overflowing buttons down to next toolbar
while (toolbar.aewidth + this.toolbarExtra > width && toolbar.childNodes.length > 2) {
var group = toolbar.removeChild(toolbar.lastChild);
toolbar.removeChild(toolbar.lastChild);
toolbar.aewidth -= group.aewidth + this.separatorWidth;
var nextToolbar;
if (nextToolbar = toolbar.nextSibling) {
this.addSeparator(nextToolbar, nextToolbar.firstChild);
this.addButtonGroup(nextToolbar, group, nextToolbar.firstChild);
}
else
this.addButtonGroup(this.addToolbar(), group);
}
// Window has grown, fill up empty space
var nextToolbar;
if (nextToolbar = toolbar.nextSibling) {
var group = nextToolbar.firstChild;
while (nextToolbar && group && toolbar.aewidth + this.toolbarExtra + this.separatorWidth + group.aewidth <= width) {
nextToolbar.removeChild(group);
nextToolbar.aewidth -= group.aewidth;
if (nextToolbar.hasChildNodes()) {
nextToolbar.removeChild(nextToolbar.firstChild);
nextToolbar.aewidth -= this.separatorWidth;
}
else {
this.objects.toolbarArea.removeChild(nextToolbar);
nextToolbar = toolbar.nextSibling;
}
this.addSeparator(toolbar);
this.addButtonGroup(toolbar, group);
group = nextToolbar ? nextToolbar.firstChild : null;
}
}
}
if (toolbarCount != this.objects.toolbarArea.childNodes.length) {
var contentHeight = height - this.toolbarHeight * this.objects.toolbarArea.childNodes.length;
if (this.sourceMode) {
this.objects.editableSource.style.top = this.toolbarHeight * this.objects.toolbarArea.childNodes.length + 'px';
this.objects.editableSource.style.height = contentHeight + 'px';
// Reset height back to 0px, since addToolbar() sets it
this.objects.editableFrame.style.height = '0px';
}
else
this.objects.editableFrame.style.height = contentHeight + 'px';
}
}
// Set focus on the editor content area
advancedEditor.prototype.focus = function (focusWindow) {
if (focusWindow)
window.focus();
this.objects.editableFrame.contentWindow.focus();
}
advancedEditor.prototype.execCommand = function (cmd, value, useCSS) {
if (isMozilla && useCSS)
this.objects.editableFrameDoc.execCommand("useCSS", false, false);
// For some commands (eg. indent, lists), without focusing it ends up running the
// command in the toolbar area. If you comment out the focus code, then in IE
// click in the editor, click outside the editor, then click indent, you'll see
// the problem.
if (isIE || isWebkit)
this.focus();
var res;
try {
res = this.objects.editableFrameDoc.execCommand(cmd, false, value);
}
catch (err) {
// debug("execCommand failed (" + cmd + " => " + value + ")" + err);
}
// debug("execCommand(" + cmd + ", " + value + ") => " + res + (useCSS ? ' (css)' : ''));
if (isMozilla && useCSS)
this.objects.editableFrameDoc.execCommand("useCSS", false, true);
}
advancedEditor.prototype.queryCommandValue = function (cmd, useCSS) {
if (isMozilla && useCSS)
this.objects.editableFrameDoc.execCommand("useCSS", false, false);
var value = this.objects.editableFrameDoc.queryCommandValue(cmd);
if (isMozilla && useCSS)
this.objects.editableFrameDoc.execCommand("useCSS", false, true);
// debug("queryCommandValue(" + cmd + ") => " + value + (useCSS ? ' (css)' : ''));
cmd = cmd.toLowerCase();
if (cmd == 'forecolor' || cmd == 'backcolor' || cmd == 'hilitecolor')
return advancedEditor.getHexColor(value);
return value;
}
advancedEditor.prototype.setColor = function () {
this.focus(1);
if (dialogWindow.values._type == 'foreground')
this.execCommand('ForeColor', dialogWindow.values.hexcolor);
else if (dialogWindow.values._type == 'background')
this.objects.editableContent.style.backgroundColor = dialogWindow.values.hexcolor;
else if (dialogWindow.values._type == 'highlight')
this.execCommand(isIE ? 'BackColor' : 'HiliteColor', dialogWindow.values.hexcolor, true);
}
advancedEditor.prototype.setFont = function () {
this.focus(1);
if (dialogWindow.values.size)
this.execCommand('FontSize', dialogWindow.values.size);
if (dialogWindow.values.font)
this.execCommand('FontName', dialogWindow.values.font);
if (dialogWindow.values.hexcolor)
this.execCommand('ForeColor', dialogWindow.values.hexcolor);
if ((dialogWindow.values.style.indexOf('b') != -1) != dialogWindow.values._bold)
this.execCommand('Bold');
if ((dialogWindow.values.style.indexOf('i') != -1) != dialogWindow.values._italic)
this.execCommand('Italic');
if ((dialogWindow.values.underline == 'on') != dialogWindow.values._underline)
this.execCommand('Underline');
}
advancedEditor.prototype.insertImage = function () {
this.focus(1);
var img = this.objects.editableFrameDoc.createElement('img');
var values = dialogWindow.values;
img.src = values['src-url-input'];
if (values['src-inline'])
img.setAttribute('gforuminline', values['src-inline-input']);
var currentSelection = new advancedEditorSelection(isIE ? this.objects.editableFrameDoc : this.objects.editableFrame.contentWindow);
currentSelection.replaceSelection(img);
}
advancedEditor.prototype.insertLink = function () {
this.focus(1);
if (dialogWindow.values.url)
this.execCommand('CreateLink', dialogWindow.values.url);
}
advancedEditor.prototype.colorDialog = function (type) {
var values = {
hexcolor : null,
_type : type,
_foreground : null,
_background : null,
_highlight : null
};
values._selection = new advancedEditorSelection(isIE ? this.objects.editableFrameDoc : this.objects.editableFrame.contentWindow);
var selectionObjects = values._selection.getSelection();
values._foreground = this.queryCommandValue('ForeColor') || this.config.defaultForeground;
values._background = advancedEditor.getHexColor(this.objects.editableContent.style.backgroundColor) || this.config.defaultBackground;
values._highlight = this.queryCommandValue(isIE ? 'BackColor' : 'HiliteColor', true);
if (type == 'foreground')
values.hexcolor = values._foreground;
else if (type == 'background')
values.hexcolor = values._background;
else if (type == 'highlight')
values.hexcolor = values._highlight;
this.showDialog('editor_color.html', isSafari ? 375 : 358, 200, values, 'opener.dialogWindow.editor.setColor()');
}
advancedEditor.prototype.fontDialog = function () {
var values = {
font : null,
style : null,
size : null,
underline : null,
hexcolor : null,
_type : 'foreground',
_foreground : null,
_background : null,
_highlight : null
};
values._selection = new advancedEditorSelection(isIE ? this.objects.editableFrameDoc : this.objects.editableFrame.contentWindow);
var selectionObjects = values._selection.getSelection();
values.font = this.queryCommandValue('FontName') || this.config.defaultFont;
values.size = this.queryCommandValue('FontSize') || this.config.defaultFontSize;
values.underline = this.objects.editableFrameDoc.queryCommandState('Underline');
values._underline = values.underline;
values._bold = this.objects.editableFrameDoc.queryCommandState('Bold');
values._italic = this.objects.editableFrameDoc.queryCommandState('Italic');
values.style = (values._bold && values._italic ? 'bi' : values._bold ? 'b' : values._italic ? 'i' : 'r');
values._foreground = this.queryCommandValue('ForeColor') || this.config.defaultForeground;
values._background = advancedEditor.getHexColor(this.objects.editableContent.style.backgroundColor) || this.config.defaultBackground;
values._highlight = this.queryCommandValue(isIE ? 'BackColor' : 'HiliteColor', true);
values.hexcolor = values._foreground;
this.showDialog('editor_font.html', 447, 250, values, 'opener.dialogWindow.editor.setFont()');
}
advancedEditor.prototype.imageDialog = function () {
var values = {
'src-inline' : null,
'src-inline-input' : null,
'src-url-input' : null
};
var url = 'editor_image.html';
if (this.config.imageDialogURL && this.config.imageDialogURL.match(/^https?:/i))
url = this.config.imageDialogURL;
else
url = parent.location.protocol + '//' + parent.location.host +
parent.location.pathname.substr(0, parent.location.pathname.lastIndexOf('/') + 1) +
this.config.imageDialogURL;
this.showDialog(url, 550, 800, values, 'opener.dialogWindow.editor.insertImage()');
}
advancedEditor.prototype.linkDialog = function () {
var values = {
protocol : null,
url : null,
title : null
};
values._selection = new advancedEditorSelection(isIE ? this.objects.editableFrameDoc : this.objects.editableFrame.contentWindow);
var selectionObjects = values._selection.getSelection();
if (selectionObjects.length == 1 && selectionObjects[0].tagName == 'A') {
values.url = selectionObjects[0].href;
values.protocol = values.url.replace(/^(\w+:(?:\/\/)?).*$/, "$1");
values.title = selectionObjects[0].title;
}
this.showDialog('editor_link.html', 390, 100, values, 'opener.dialogWindow.editor.insertLink()');
}
advancedEditor.prototype.showDialog = function (url, width, height, values, returnCall) {
if (dialogWindow.win && !dialogWindow.win.closed)
dialogWindow.win.close();
if (url.match(/^https?:/i))
dialogWindow.url = url;
else
dialogWindow.url = this.objects.editorFrame.contentWindow.location.href.replace(/editor_iframe\.html$/, '') + url;
dialogWindow.width = width;
dialogWindow.height = height;
dialogWindow.name = Math.random().toString().replace(/\./, "");
dialogWindow.left = (screen.width - width) / 2;
dialogWindow.top = (screen.height - height) / 2;
dialogWindow.attribs = 'popup=1,left=' + dialogWindow.left + ',top=' + dialogWindow.top +
'location=0,menubar=0,resizable=1,scrollbars=0,status=0,toolbar=0,width=' + dialogWindow.width +
',height=' + dialogWindow.height;
dialogWindow.editor = this;
dialogWindow.values = values;
dialogWindow.returnCall = returnCall;
try {
dialogWindow.win = window.open(dialogWindow.url, dialogWindow.name, dialogWindow.attribs);
dialogWindow.win.focus();
}
catch (e) {
// FIXME should we alert?
}
}
advancedEditor.prototype.toggleSource = function () {
if (!this.objects.editableSource)
return;
this.sourceMode = !this.sourceMode;
if (this.sourceMode) {
this.changeButtonState(false, 'source');
this.objects.editableSource.value = this.getContent();
this.objects.editableSource.style.top = this.toolbarHeight * this.objects.toolbarArea.childNodes.length + 'px';
this.objects.editableSource.style.height = this.objects.editableFrame.offsetHeight + 'px';
this.objects.editableSource.style.visibility = 'visible';
this.objects.editableFrame.style.visibility = 'hidden';
// Without setting this to 0px, mozilla loses the cursor in the source textarea
this.objects.editableFrame.style.height = '0px';
this.objects.editableSource.focus();
}
else {
this.changeButtonState(true, 'source');
this.objects.editableContent.innerHTML = this.objects.editableSource.value;
this.objects.editableSource.style.visibility = 'hidden';
this.objects.editableFrame.style.height = this.objects.editableSource.style.height;
this.objects.editableFrame.style.visibility = 'visible';
this.focus();
}
}
advancedEditor.prototype.selectionMade = function () {
if (this.objects.editableFrameDoc.selection)
return this.objects.editableFrameDoc.selection.type != 'None';
// Don't use advancedEditorSelection because in Gecko, range.cloneContents()
// tries to re-fetch broken images, and since this gets called on a timer,
// floods the server with requests.
if (this.objects.editableFrame.contentWindow.getSelection)
return this.objects.editableFrame.contentWindow.getSelection().toString().length > 0;
}
advancedEditor.getHexColor = function (color) {
function intToHex(i) {
i = parseInt(i);
return (i < 16 ? '0' : '') + i.toString(16).toUpperCase();
}
if (typeof(color) == 'number')
return '#' + intToHex(color & 0xff) + intToHex((color >> 8) & 0xff) + intToHex((color >> 16) & 0xff);
else if (typeof(color) != 'string')
return;
if (color.match(/rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/i))
return '#' + intToHex(RegExp.$1) + intToHex(RegExp.$2) + intToHex(RegExp.$3);
if (color == 'transparent')
return;
return color.toUpperCase();
}
function advancedEditorSelection(documentWindow) {
if (documentWindow.selection)
this.document = documentWindow;
else
this.window = documentWindow;
}
advancedEditorSelection.prototype.getSelection = function () {
if (this.document) {
this.document.parentWindow.focus();
this.selection = this.document.selection;
this.range = this.selection.createRange();
this.nodes = [];
if (this.selection.type == 'Control') {
for (var i = 0; i < this.range.length; i++)
this.nodes[i] = this.range(i);
}
else if (this.selection.type == 'Text') {
this.nodesContainer = this.document.createElement('span');
this.nodesContainer.innerHTML = this.range.htmlText;
this.nodes = this.nodesContainer.childNodes;
}
}
else {
this.selection = this.window.getSelection();
this.nodes = [];
if (this.selection && this.selection.getRangeAt) {
// Safari triggers an exception when there's nothing selected
try {
this.range = this.selection.getRangeAt(0);
this.documentFragment = this.range.cloneContents();
this.nodes = this.documentFragment.childNodes;
if (this.nodes.length == 1 && this.nodes[0].nodeType == 3 && this.nodes[0].nodeValue == '')
this.nodes = [];
}
catch (e) {}
}
}
return this.nodes;
}
advancedEditorSelection.prototype.getSelectionHTML = function () {
if (!this.selection)
this.getSelection();
if (this.document)
return this.range.htmlText;
else {
var div = document.createElement('div');
div.appendChild(this.documentFragment);
return div.innerHTML;
}
}
advancedEditorSelection.prototype.replaceSelection = function (node) {
if (!this.selection)
this.getSelection();
if (this.document) {
if (this.selection.type == 'Control') {
this.selection.clear();
this.range = this.selection.createRange();
}
this.range.pasteHTML(node.outerHTML);
}
else {
this.range.deleteContents();
this.range.insertNode(node);
}
}