Third pass at adding key files
This commit is contained in:
916
site/forum.slowtwitch.com/www/static/editor/editor.js
Normal file
916
site/forum.slowtwitch.com/www/static/editor/editor.js
Normal file
@ -0,0 +1,916 @@
|
||||
/*
|
||||
* =================================================================
|
||||
* 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(/^(?: )?<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);
|
||||
}
|
||||
}
|
57
site/forum.slowtwitch.com/www/static/editor/editor_dialog.js
Normal file
57
site/forum.slowtwitch.com/www/static/editor/editor_dialog.js
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* =================================================================
|
||||
* 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_dialog.js,v 1.2 2009/04/08 20:13:20 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.
|
||||
* =================================================================
|
||||
*/
|
||||
|
||||
function initForm() {
|
||||
for (var item in opener.dialogWindow.values) {
|
||||
if (opener.dialogWindow.values[item] == null)
|
||||
continue;
|
||||
var obj;
|
||||
if (obj = document.getElementById(item)) {
|
||||
if (obj.type == 'radio' || obj.type == 'checkbox')
|
||||
obj.checked = opener.dialogWindow.values[item];
|
||||
else {
|
||||
obj.value = opener.dialogWindow.values[item];
|
||||
if (isWebkit && item == 'font') {
|
||||
obj.value = opener.dialogWindow.values[item].replace(/'/g, '');
|
||||
}
|
||||
if (isWebkit && item == 'size') {
|
||||
var fontsize = {
|
||||
'8px' : 0, // not used
|
||||
'10px' : 1,
|
||||
'13px' : 2,
|
||||
'16px' : 3,
|
||||
'18px' : 4,
|
||||
'24px' : 5,
|
||||
'32px' : 6,
|
||||
'48px' : 7
|
||||
};
|
||||
obj.value = fontsize[opener.dialogWindow.values[item]];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function submitForm() {
|
||||
for (var item in opener.dialogWindow.values) {
|
||||
var obj;
|
||||
if (obj = document.getElementById(item))
|
||||
opener.dialogWindow.values[item] = (obj.type == 'radio' || obj.type == 'checkbox') ? obj.checked : obj.value;
|
||||
}
|
||||
if (typeof(opener.dialogWindow.returnCall) == 'function')
|
||||
opener.dialogWindow.returnCall();
|
||||
else if (opener.dialogWindow.returnCall)
|
||||
eval(opener.dialogWindow.returnCall);
|
||||
window.close();
|
||||
}
|
Reference in New Issue
Block a user