
fitnesse.resources.wysiwyg.wysiwyg.js Maven / Gradle / Ivy
Show all versions of fitnesse Show documentation
"use strict";
/*jslint devel: true, undef: true, browser: true, continue: true, sloppy: true, stupid: true, vars: true, plusplus: true, regexp: true, maxerr: 50, indent: 4 */
/****
vim:sw=4:et:ai
Wysiwyg editor for FitNesse, based on the Trac Wysiwyg editor written by
OpenGroove and Ciklone, BSD licensed.
General rules are:
- text is rendered to a Fragment node
- div elements separate nested blocks e.g. collapsible sections
****/
var Wysiwyg = function (textarea, options) {
CodeMirror.commands.autocomplete = function(cm) {
cm.showHint({hint: CodeMirror.hint.fitnesse_anyword});
};
CodeMirror.commands.save = function(cm) {
$(document.f).submit();
return false;
};
this.codeMirrorEditor = CodeMirror.fromTextArea(textarea, {
mode: "fitnesse",
lineNumbers: true,
foldGutter: true,
showCursorWhenSelecting: true,
viewportMargin: Infinity,
gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"],
extraKeys: {
"Ctrl-Space": "autocomplete"
}
});
var self = this;
var editorMode = Wysiwyg.getEditorMode();
this.textarea = textarea;
this.options = options || {};
this.frame = this.createEditable(document, textarea);
this.contentWindow = window;
this.contentDocument = this.contentWindow.document;
this.wysiwygToolbar = this.createWysiwygToolbar(document);
this.textareaToolbar = this.createTextareaToolbar(document);
this.styleMenu = this.createStyleMenu(document);
this.menus = [ this.styleMenu ];
this.toolbarButtons = this.setupWysiwygMenuEvents();
this.setupTextareaMenuEvents();
this.toggleEditorButtons = null;
this.savedWysiwygHTML = null;
this.setupToggleEditorButtons();
// Hide both editors, so the current one gets properly shown:
this.codeMirrorEditor.getWrapperElement().style.display = this.frame.style.display = "none";
textarea.parentNode.insertBefore(this.toggleEditorButtons, textarea);
textarea.parentNode.insertBefore(this.textareaToolbar, textarea);
textarea.parentNode.insertBefore(this.wysiwygToolbar, textarea);
document.getElementById("wt-style").parentNode.appendChild(this.menus[0]);
this.listenerToggleEditor(editorMode)({ initializing: true });
// disable firefox table resizing
try { this.contentDocument.execCommand("enableObjectResizing", false, false); } catch (e) {}
try { this.contentDocument.execCommand("enableInlineTableEditing", false, false); } catch (e) {}
var exception;
try { self.execCommand("useCSS", false); } catch (e1) { }
try { self.execCommand("styleWithCSS", false); } catch (e2) { }
if (editorMode === "wysiwyg") {
try { self.loadWysiwygDocument(); } catch (e3) { exception = e3; }
}
self.setupEditorEvents();
self.setupFormEvent();
if (exception) {
self.codeMirrorEditor.getWrapperElement().style.display = self.textareaToolbar.style.display = "";
self.frame.style.display = self.wysiwygToolbar.style.display = "none";
alert("Failed to activate the wysiwyg editor.");
throw exception;
}
};
Wysiwyg.getBooleanFromCookie = function(fieldName, defaultValue) {
var result = defaultValue;
var cookies = (document.cookie || "").split(";");
var length = cookies.length;
var i;
for (i = 0; i < length; i++) {
var regex = new RegExp("^\\s*" + fieldName + "=(\\S*)");
var match = regex.exec(cookies[i]);
if (match) {
return (match[1] === "true");
}
}
return result;
};
Wysiwyg.getWrapOn = function () {
return Wysiwyg.getBooleanFromCookie('textwrapon', false);
};
Wysiwyg.getAutoformat = function () {
return Wysiwyg.getBooleanFromCookie('textautoformat', false);
};
Wysiwyg.prototype.listenerToggleEditor = function (type) {
var self = this;
var setEditorMode = function (mode) {
if (mode !== "wysiwyg") {
mode = "textarea";
}
Wysiwyg.editorMode = mode;
Wysiwyg.setCookie("wysiwyg", mode);
};
switch (type) {
case "textarea":
return function (event) {
var wrappedElement = self.codeMirrorEditor.getWrapperElement();
if (wrappedElement.style.display === "none") {
self.hideAllMenus();
if (event && !event.initializing) { self.loadWikiText(); }
wrappedElement.style.display = "";
wrappedElement.setAttribute("tabIndex", "");
self.syncTextAreaHeight();
self.frame.style.display = self.wysiwygToolbar.style.display = "none";
self.frame.setAttribute("tabIndex", "-1");
self.textareaToolbar.style.display = "";
self.codeMirrorEditor.refresh();
setEditorMode(type);
}
self.focusTextarea();
};
case "wysiwyg":
return function (event) {
var frame = self.frame;
var wrappedElement = self.codeMirrorEditor.getWrapperElement();
if (frame.style.display === "none") {
try {
self.loadWysiwygDocument();
} catch (e) {
Wysiwyg.stopEvent(event || window.event);
alert("Failed to activate the wysiwyg editor.");
throw e;
}
wrappedElement.style.display = "none";
wrappedElement.setAttribute("tabIndex", "-1");
frame.style.display = self.wysiwygToolbar.style.display = "";
frame.setAttribute("tabIndex", "");
self.textareaToolbar.style.display = "none";
setEditorMode(type);
}
self.focusWysiwyg();
};
}
};
Wysiwyg.prototype.activeEditor = function () {
return this.codeMirrorEditor.getWrapperElement().style.display === "none" ? "wysiwyg" : "textarea";
};
Wysiwyg.prototype.isModified = function () {
return this.savedWysiwygHTML !== null && this.frame.innerHTML !== this.savedWysiwygHTML;
};
Wysiwyg.prototype.setupFormEvent = function () {
var self = this;
$(this.textarea.form).submit(function (event) {
try {
if (self.activeEditor() === "wysiwyg") {
var body = self.frame;
if (self.isModified()) {
self.codeMirrorEditor.setValue(self.domToWikitext(body, self.options));
self.codeMirrorEditor.save();
}
}
if (Wysiwyg.getAutoformat()) {
var formatter = new WikiFormatter();
self.codeMirrorEditor.setValue(formatter.format(self.codeMirrorEditor.getValue()));
self.codeMirrorEditor.save();
}
} catch (e) {
Wysiwyg.stopEvent(event);
}
});
};
Wysiwyg.prototype.createEditable = function (d, textarea) {
var frame = d.createElement("div");
frame.setAttribute("class", "wysiwyg");
frame.setAttribute("contenteditable", "true");
textarea.parentNode.insertBefore(frame, textarea.nextSibling);
return frame;
};
Wysiwyg.prototype.createWysiwygToolbar = function (d) {
var html = [
'',
'
',
' ',
'',
'',
'',
'',
'',
''];
var div = d.createElement("div");
div.className = "wysiwyg-toolbar";
div.innerHTML = html.join("").replace(/ href="#">/g, ' href="#" onmousedown="return false" tabindex="-1">');
return div;
};
Wysiwyg.prototype.createStyleMenu = function (d) {
var html = [
'',
'Header 1
',
'Header 2
',
'Header 3
',
'Header 4
',
'Header 5
',
'Header 6
',
'Code block
' ];
var menu = d.createElement("div");
menu.className = "wysiwyg-menu";
Wysiwyg.setStyle(menu, { display: "none" });
menu.innerHTML = html.join("").replace(/ href="#">/g, ' href="#" onmousedown="return false" tabindex="-1">');
return menu;
};
Wysiwyg.prototype.setupWysiwygMenuEvents = function () {
function addToolbarEvent(element, self, args) {
var method = args.shift();
$(element).click(function (event) {
Wysiwyg.stopEvent(event);
var keepMenus = false, exception;
try { keepMenus = method.apply(self, args); } catch (e) { exception = e; }
if (!keepMenus) {
self.hideAllMenus();
}
element.blur();
self.frame.focus();
if (exception) {
throw exception;
}
});
}
function argsByType(self, name, element) {
switch (name) {
case "style":
return [ self.toggleMenu, self.styleMenu, element ];
case "strong":
return [ self.execDecorate, "bold" ];
case "em":
return [ self.execDecorate, "italic" ];
case "underline":
return [ self.execDecorate, "underline" ];
case "strike":
return [ self.execDecorate, "strikethrough" ];
case "sub":
return [ self.execDecorate, "subscript" ];
case "sup":
return [ self.execDecorate, "superscript" ];
case "escape":
return [ self.execDecorate, "escape" ];
case "remove":
return [ self.execCommand, "removeformat" ];
case "paragraph":
return [ self.formatParagraph ];
case "heading1":
return [ self.formatHeaderBlock, "h1" ];
case "heading2":
return [ self.formatHeaderBlock, "h2" ];
case "heading3":
return [ self.formatHeaderBlock, "h3" ];
case "heading4":
return [ self.formatHeaderBlock, "h4" ];
case "heading5":
return [ self.formatHeaderBlock, "h5" ];
case "heading6":
return [ self.formatHeaderBlock, "h6" ];
case "link":
return [ self.createLink ];
case "unlink":
return [ self.execCommand, "unlink" ];
case "ol":
return [ self.insertOrderedList ];
case "ul":
return [ self.insertUnorderedList ];
case "outdent":
return [ self.outdent ];
case "indent":
return [ self.indent ];
case "image":
return [ self.insertImage ];
case "table":
case "table-in-table":
return [ self.insertTable ];
case "hash-table":
return [ self.insertHashTable ];
case "insert-cell-before":
return [ self.ui_insertTableCell, false ];
case "insert-cell-after":
return [ self.ui_insertTableCell, true ];
case "insert-row-before":
return [ self.insertTableRow, false ];
case "insert-row-after":
return [ self.insertTableRow, true ];
case "insert-col-before":
return [ self.insertTableColumn, false ];
case "insert-col-after":
return [ self.insertTableColumn, true ];
case "delete-cell":
return [ self.deleteTableCell ];
case "delete-row":
return [ self.deleteTableRow ];
case "delete-col":
return [ self.deleteTableColumn ];
case "remove-table":
return [ self.deleteTable ];
case "code":
return [ self.formatCodeBlock ];
case "hr":
return [ self.insertHorizontalRule ];
case "br":
return [ self.insertLineBreak ];
case "collapsible-closed":
return [ self.insertCollapsibleSection, "closed" ];
case "collapsible-open":
return [ self.insertCollapsibleSection ];
case "collapsible-hidden":
return [ self.insertCollapsibleSection, "hidden" ];
case "remove-collapsible":
return [ self.deleteCollapsibleSection ];
}
return null;
}
function setup(container) {
var elements = container.getElementsByTagName("a");
var length = elements.length;
var i;
for (i = 0; i < length; i++) {
var element = elements[i];
var name = element.id.replace(/^wt-/, "");
var args = argsByType(this, name, element);
if (args) {
addToolbarEvent(element, this, args);
buttons[name] = element;
}
}
}
var buttons = {}, i;
setup.call(this, this.wysiwygToolbar);
for (i = 0; i < this.menus.length; i++) {
setup.call(this, this.menus[i]);
}
return buttons;
};
Wysiwyg.prototype.createTextareaToolbar = function (d) {
var html = [
'',
'',
'',
'',
'',
'',
''];
var div = d.createElement("div");
div.className = "textarea-toolbar";
div.innerHTML = html.join(" ");
return div;
};
Wysiwyg.prototype.setupTextareaMenuEvents = function () {
var codeMirror = this.codeMirrorEditor;
var container = this.textareaToolbar;
$('#tt-spreadsheet-to-wiki', container).click(function () {
var translator = new SpreadsheetTranslator();
translator.parseExcelTable(codeMirror.getValue());
codeMirror.setValue(translator.getFitNesseTables());
codeMirror.focus();
});
$('#tt-wiki-to-spreadsheet', container).click(function () {
var selection = codeMirror.getValue();
selection = selection.replace(/\r\n/g, '\n');
selection = selection.replace(/\r/g, '\n');
// remove the last | at the end of the line
selection = selection.replace(/\|\n/g, '\n');
// replace all remaining | with \t
selection = selection.replace(/\|/g, '\t');
codeMirror.setValue(selection);
codeMirror.focus();
});
$('#tt-format-wiki', container).click(function () {
var formatter = new WikiFormatter();
var scrollInfo = codeMirror.getScrollInfo();
var cursorInfo = codeMirror.getDoc().getCursor();
codeMirror.setValue(formatter.format(codeMirror.getValue()));
codeMirror.scrollTo(scrollInfo.left, scrollInfo.top);
codeMirror.getDoc().setCursor(cursorInfo.line, cursorInfo.ch);
codeMirror.focus();
});
$('#tt-insert-template', container).click(function () {
var selectedValue = $('#tt-template-map').val();
var inserter = new TemplateInserter();
inserter.insertInto(selectedValue, codeMirror);
codeMirror.focus();
});
function setWrap(wrap) {
if (wrap) {
codeMirror.setOption("lineWrapping", true);
Wysiwyg.setCookie("textwrapon", "true");
} else {
codeMirror.setOption("lineWrapping", false);
Wysiwyg.setCookie("textwrapon", "false");
}
}
function setAutoformat(autoformat) {
if (autoformat) {
Wysiwyg.setCookie("textautoformat", "true");
} else {
Wysiwyg.setCookie("textautoformat", "false");
}
}
$('#tt-wrap-text', container)
.change(function () {
setWrap($(this).is(':checked'));
})
.prop('checked', Wysiwyg.getWrapOn())
.change();
$('#tt-autoformat', container)
.change(function () {
setAutoformat($(this).is(':checked'));
})
.prop('checked', Wysiwyg.getAutoformat())
.change();
};
Wysiwyg.prototype.toggleMenu = function (menu) {
if (menu.style.display === "none") {
this.hideAllMenus(menu);
Wysiwyg.setStyle(menu, { display: "" });
} else {
this.hideAllMenus();
}
return true;
};
Wysiwyg.prototype.hideAllMenus = function (except) {
var menus = this.menus;
var length = menus.length;
var i;
for (i = 0; i < length; i++) {
if (menus[i] !== except) {
Wysiwyg.setStyle(menus[i], { display: "none" });
}
}
};
Wysiwyg.prototype.execDecorate = function (name) {
if (this.selectionContainsTagName("pre")) {
return;
}
var getSelfOrAncestor = Wysiwyg.getSelfOrAncestor;
var position = this.getSelectionPosition();
var ancestor = {};
ancestor.start = getSelfOrAncestor(position.start, /^(?:a|tt)$/);
ancestor.end = getSelfOrAncestor(position.end, /^(?:a|tt)$/);
this.expandSelectionToElement(ancestor);
if (name !== "escape") {
this.execCommand(name);
} else {
this.execDecorateMonospace();
}
this.selectionChanged();
};
Wysiwyg.prototype.execDecorateMonospace = function () {
var html = this.getSelectionHTML();
if (/^/i.test(html) && /<\/tt>$/i.test(html)) {
html = html.replace(/|<\/tt>/gi, "");
} else {
html = '' + html.replace(/<[a-z]+.*?>|<\/[a-z]+>/gi, "") + "";
}
this.insertHTML(html);
var node = this.contentDocument.getElementById(id);
if (node) {
this.selectNode(node);
}
};
Wysiwyg.prototype.execCommand = function (name, arg, selectionRange) {
this.frame.focus();
if (selectionRange) {
this.selectRange(selectionRange.startContainer, selectionRange.startOffset, selectionRange.endContainer, selectionRange.endOffset);
this.selectionChanged();
}
return this.contentDocument.execCommand(name, false, arg);
};
Wysiwyg.prototype.isHashTable = function (node) {
return node.tagName === "TABLE" && /hashtable/.test(node.className);
};
Wysiwyg.prototype.setupEditorEvents = function () {
var getSelfOrAncestor = Wysiwyg.getSelfOrAncestor;
var self = this;
var frame = this.frame;
var ime = false;
var inPasteAction = false;
$(frame).keydown(function (event) {
var method = null;
var args = null;
var keyCode = event.keyCode;
switch (keyCode) {
case 0x09: // TAB
var range = self.getSelectionRange();
var stop = false;
var element = getSelfOrAncestor(range.startContainer, /^(?:li|pre|table)$/);
if (element) {
switch (element.tagName.toLowerCase()) {
case "li":
self.execCommand(event.shiftKey ? "outdent" : "indent");
self.selectionChanged();
stop = true;
break;
case "pre":
self.insertHTML("\t");
stop = true;
break;
case "table":
if (getSelfOrAncestor(range.endContainer, "table") === element) {
self.moveFocusInTable(!event.shiftKey);
self.selectionChanged();
stop = true;
}
break;
}
}
if (stop) {
Wysiwyg.stopEvent(event);
}
return;
case 0xe5:
ime = true;
break;
}
switch ((keyCode & 0x00fffff) | (event.ctrlKey ? 0x40000000 : 0)
| (event.shiftKey ? 0x20000000 : 0) | (event.altKey ? 0x10000000 : 0)) {
case 0x40000042: // C-b
method = self.execDecorate;
args = [ "bold" ];
break;
case 0x40000049: // C-i
method = self.execDecorate;
args = [ "italic" ];
break;
case 0x40000055: // C-u
method = self.execDecorate;
args = [ "underline" ];
break;
case 0x40000059: // C-y
method = self.execCommand;
args = [ "redo" ];
break;
case 0x4000005a: // C-z
method = self.execCommand;
args = [ "undo" ];
break;
}
if (method !== null) {
Wysiwyg.stopEvent(event);
method.apply(self, args);
self.selectionChanged();
} else if (keyCode && !inPasteAction) {
var focus = self.getFocusNode();
if (!getSelfOrAncestor(focus, /^(?:p|li|h[1-6]|t[dh]|d[td]|pre|blockquote)$/)) {
self.execCommand("formatblock", "");
}
}
});
//noinspection JSUnresolvedFunction
$(frame).keypress(function (event) {
var modifier = (event.ctrlKey ? 0x40000000 : 0)
| (event.shiftKey ? 0x20000000 : 0) | (event.altKey ? 0x10000000 : 0);
switch (event.charCode || event.keyCode) {
case 0x20: // SPACE
self.detectLink(event);
return;
case 0x3e: // ">"
self.detectLink(event);
return;
case 0x0d: // ENTER
self.detectLink(event);
switch (modifier) {
case 0:
var focus = self._getFocusForTable();
if (focus.table && focus.cell) {
self.insertTableRow(true);
Wysiwyg.stopEvent(event);
} else if (self.insertParagraphOnEnter) {
self.insertParagraphOnEnter(event);
}
break;
case 0x20000000: // Shift
if (self.insertLineBreakOnShiftEnter) {
self.insertLineBreakOnShiftEnter(event);
}
break;
}
return;
case 0x7c: // "|"
case 28: // ctrl-"|"
var range = self.getSelectionRange();
var element = getSelfOrAncestor(range.startContainer, "table");
if (element && !self.isHashTable(element) &&
getSelfOrAncestor(range.endContainer, "table") === element &&
!getSelfOrAncestor(range.endContainer, /^(?:tt)/)) {
if (event.ctrlKey) {
self.deleteTableCell();
} else {
self.ui_insertTableCell(true);
}
Wysiwyg.stopEvent(event);
}
return;
}
});
//noinspection JSUnresolvedFunction
$(frame).keyup(function (event) {
var keyCode = event.keyCode;
if (ime) {
switch (keyCode) {
case 0x20: // SPACE
self.detectLink(event);
break;
}
ime = false;
}
if (self.getSelectionRange()) {
self.updateElementClassName(self.getSelectionRange().startContainer);
}
self.selectionChanged();
});
//noinspection JSUnresolvedFunction
$(frame).mouseup(function () {
self.selectionChanged();
});
$(frame).click(function () {
self.hideAllMenus();
self.selectionChanged();
});
$(frame).on('touchstart click', 'div.collapsible > p.title', function (event) {
var x = event.pageX - $(this).offset().left;
if (x < parseInt($(this).css('padding-left'))) {
var e = $(this.parentNode);
if (e.hasClass('closed')) {
e.removeClass('closed').addClass('hidden');
} else if (e.hasClass('hidden')) {
e.removeClass('hidden');
} else {
e.addClass('closed');
}
}
// Avoid default open/close handling from being called
event.stopPropagation();
});
$(frame).on('click', 'a', function () {
return false;
});
/* Pasting data is forced in a specific div: pasteddata. In there, the
* raw data is collected and fed to the wikiToDom parser.
*/
$(frame).on('paste', 'body', function () {
function tagNode(node) { while (node.nodeType === 3 /* TextNode */) { node = node.parentNode; } return node; }
// Clone state is change in Firefox, need to extract the fields
var range = self.getSelectionRange();
var position = {
startContainer: range.startContainer,
endContainer: range.startContainer === range.endContainer ? range.startContainer.nextSibling : range.endContainer,
sameContainer: range.startContainer === range.endContainer,
atStart: range.startOffset === 0,
atEnd: range.endOffset === range.endContainer.length
};
inPasteAction = true;
// Move tables up to the table they're pasted in
function flattenTable(td) {
var nestedRows = $('tr', td);
if (nestedRows.length) {
var parentTr = getSelfOrAncestor(td, 'tr');
nestedRows.each(function(j, elem) {
$(parentTr).after(elem);
parentTr = $(parentTr).next();
});
self.spanTableColumns(getSelfOrAncestor(parentTr, 'table'));
}
}
function wikitextToOnelinerFragment (wikitext, contentDocument) {
var source = this.wikitextToFragment(wikitext, contentDocument);
var fragment = contentDocument.createDocumentFragment();
this.collectChildNodes(fragment, source.firstChild);
return fragment;
}
// Post processing:
setTimeout(function () {
inPasteAction = false;
var parentTd = getSelfOrAncestor(position.startContainer, 'td');
var wikiText, fragment;
if (parentTd) {
flattenTable(parentTd);
// Make a one-liner for the content pasted in the table cell
wikiText = self.domToWikitext(parentTd, self.options);
fragment = wikitextToOnelinerFragment(wikiText.replace('\n', ' '), self.contentDocument, self.options);
while (parentTd.firstChild) { parentTd.removeChild(parentTd.firstChild); }
parentTd.appendChild(fragment);
flattenTable(parentTd);
} else if (position.sameContainer) {
var c = tagNode(position.startContainer);
wikiText = self.domToWikitext(c, { retainNewLines: true });
fragment = self.wikitextToFragment(wikiText, self.contentDocument);
c.parentNode.insertBefore(fragment, c);
c.parentNode.removeChild(c);
// NOTE: At this point the position object is invalid/not useful.
}
}, 20);
});
};
Wysiwyg.prototype.loadWysiwygDocument = function () {
var container = this.frame;
if (!container) { return; }
var tmp = container.lastChild;
while (tmp) {
container.removeChild(tmp);
tmp = container.lastChild;
}
var fragment = this.wikitextToFragment(this.codeMirrorEditor.getValue(), this.contentDocument, this.options);
container.appendChild(fragment);
this.savedWysiwygHTML = container.innerHTML;
};
Wysiwyg.prototype.focusWysiwyg = function () {
var self = this;
function lazy() {
self.frame.focus();
try { self.execCommand("useCSS", false); } catch (e1) { }
try { self.execCommand("styleWithCSS", false); } catch (e2) { }
self.selectionChanged();
$(window).resize();
}
setTimeout(lazy, 10);
};
Wysiwyg.prototype.loadWikiText = function () {
this.codeMirrorEditor.setValue(this.domToWikitext(this.frame, this.options));
this.codeMirrorEditor.save();
this.savedWysiwygHTML = null;
};
Wysiwyg.prototype.focusTextarea = function () {
this.codeMirrorEditor.focus();
$(window).resize();
};
Wysiwyg.prototype.setupToggleEditorButtons = function () {
var div = document.createElement("div");
var mode = Wysiwyg.editorMode;
var html = ' '
+ ' '
+ ' ';
var buttons;
var i;
div.className = "editor-toggle";
//noinspection JSCheckFunctionSignatures,JSCheckFunctionSignatures
div.innerHTML = html.replace(/@/g, ++Wysiwyg.count);
this.toggleEditorButtons = div;
buttons = div.getElementsByTagName("input");
for (i = 0; i < buttons.length; i++) {
var button = buttons[i];
var token = button.id.replace(/[0-9]+$/, "@");
switch (token) {
case "editor-wysiwyg-@":
case "editor-textarea-@":
$(button).click(this.listenerToggleEditor(button.value));
break;
}
}
};
Wysiwyg.prototype.syncTextAreaHeight = function () {
var height = this.textarea.offsetHeight;
var frame = this.frame;
if (height > 0 && frame.height !== height) {
frame.height = height;
}
};
Wysiwyg.prototype.normalizeLink = function (link) {
if (/^[\/.#]/.test(link)) {
link = encodeURIComponent(link);
}
if (/^[^"']/.test(link) && /\s/.test(link)) {
if (link.indexOf('"') === -1) {
link = '"' + link + '"';
} else if (link.indexOf("'") === -1) {
link = "'" + link + "'";
} else {
link = '"' + link.replace(/"/g, "%22") + '"';
}
}
return link;
};
Wysiwyg.prototype.detectLink = function (event) {
var range = this.getSelectionRange();
var node = range.startContainer;
if (!node || !range.collapsed) {
return;
}
var getSelfOrAncestor = Wysiwyg.getSelfOrAncestor;
if (getSelfOrAncestor(node, /^(?:a|tt|pre)$/)) {
return;
}
var offset = range.startOffset;
if (node.nodeType !== 3) {
node = node.childNodes[offset];
while (node && node.nodeType !== 3) {
node = node.lastChild;
}
if (!node) {
return;
}
offset = node.nodeValue.length;
} else if (offset === 0) {
node = node.previousSibling;
if (!node || node.nodeType === 1) {
return;
}
offset = node.nodeValue.length;
}
//noinspection JSUnusedAssignment
var startContainer = node;
var endContainer = node;
var text = [ node.nodeValue.substring(0, offset) ];
while (true) {
if (/[ \t\r\n\f\v]/.test(text[text.length - 1])) {
break;
}
node = node.previousSibling;
if (!node || node.nodeType === 1) {
break;
}
text.push(node.nodeValue);
startContainer = node;
}
text.reverse();
var linkText = text.join("");
if (!linkText) {
return;
}
var pattern = this.wikiDetectLinkPattern;
pattern.lastIndex = /[^ \t\r\n\f\v]*$/.exec(linkText).index;
var match, tmp;
for (tmp = pattern.exec(linkText); tmp; tmp = pattern.exec(linkText)) {
match = tmp;
}
if (!match) {
return;
}
var label = match[0];
var link = this.normalizeLink(label);
var id = this.generateDomId();
var anchor = this.createAnchor(link, label, { id: id, "data-wysiwyg-autolink": "true" });
var anonymous = this.contentDocument.createElement("div");
anonymous.appendChild(anchor);
var html = anonymous.innerHTML;
node = endContainer;
var startOffset = match.index;
while (startContainer !== node && startOffset >= startContainer.nodeValue.length) {
startOffset -= startContainer.nodeValue.length;
startContainer = startContainer.nextSibling;
}
var endOffset = startOffset + label.length;
endContainer = startContainer;
while (endContainer !== node && endOffset >= endContainer.nodeValue.length) {
endOffset -= endContainer.nodeValue.length;
endContainer = endContainer.nextSibling;
}
this.selectRange(startContainer, startOffset, endContainer, endOffset);
offset = linkText.length - match.index - label.length;
if (offset === 0) {
switch (event.keyCode) {
case 0x20: // SPACE
this.insertHTML(html + "\u00a0");
Wysiwyg.stopEvent(event);
return;
case 0x0d: // ENTER
if (event.shiftKey) {
if (window.opera || !anonymous.addEventListener) {
this.insertHTML(html + "
");
if (window.opera) {
anchor = this.contentDocument.getElementById(id);
node = anchor.parentNode;
offset = node.childNodes.length;
this.selectRange(node, offset, node, offset);
}
Wysiwyg.stopEvent(event);
return;
}
}
this.insertHTML(html);
anchor = this.contentDocument.getElementById(id);
node = event.shiftKey ? anchor.parentNode : anchor;
offset = node.childNodes.length;
this.selectRange(node, offset, node, offset);
return;
}
}
this.insertHTML(html);
anchor = this.contentDocument.getElementById(id);
node = anchor.nextSibling;
if (!node) {
node = anchor.parentNode;
offset = node.childNodes.length;
}
this.selectRange(node, offset, node, offset);
};
Wysiwyg.prototype.outdent = function () {
if (this.selectionContainsTagName("table") || this.selectionContainsTagName("pre")) {
return;
}
this.execCommand("outdent");
};
Wysiwyg.prototype.indent = function () {
if (this.selectionContainsTagName("table") || this.selectionContainsTagName("pre")) {
return;
}
this.execCommand("indent");
};
Wysiwyg.prototype.formatParagraph = function () {
if (this.selectionContainsTagName("table")) {
return;
}
this.execCommand("formatblock", "
");
this.selectionChanged();
};
Wysiwyg.prototype.formatHeaderBlock = function (name) {
if (this.selectionContainsTagName("table")) {
return;
}
this.execCommand("formatblock", "<" + name + ">");
this.selectionChanged();
};
Wysiwyg.prototype.insertOrderedList = function () {
if (this.selectionContainsTagName("table") || this.selectionContainsTagName("pre")) {
return;
}
this.execCommand("insertorderedlist");
this.selectionChanged();
};
Wysiwyg.prototype.insertUnorderedList = function () {
if (this.selectionContainsTagName("table") || this.selectionContainsTagName("pre")) {
return;
}
this.execCommand("insertunorderedlist");
this.selectionChanged();
};
Wysiwyg.prototype.insertImage = function () {
var self = this;
var insertImage = 'insert-image';
var path = ['files'];
var filesList = $('#' + insertImage + ' ul');
var pathName = $('#' + insertImage + ' pre');
var selectionRange = self.getSelectionRange();
loadFiles();
var insertImageBox = $('#' + insertImage + " > div");
insertImageBox
.on('click', 'span', function () {
path = Array.prototype.slice.call($(this).data());
loadFiles();
})
.on('click', 'li.directory', function () {
path.push($(this).data().name);
loadFiles();
})
.on('click', 'li.file', function () {
window.location.hash = "";
insertImageBox.off();
self.execCommand("insertimage", pathStr() + $(this).data().name, selectionRange);
})
.on('click', 'button', function () {
var url = $('#' + insertImage + ' input').val();
window.location.hash = "";
insertImageBox.off();
self.execCommand("insertimage", url, selectionRange);
});
window.location.hash = insertImage;
function loadFiles() {
$.getJSON(pathStr(), {responder: 'files', format: 'json'}, function (data) {
breadcrumbHtml();
filesList.empty();
$(data).each(function (i, e) {
var h = $("
" + e.name + (e.directory ? '/' : '') + " ").attr('class', e.directory ? 'directory' : 'file').data(e);
filesList.append(h);
});
});
}
function pathStr() {
var s = "";
for (var i in path) {
s = s + path[i] + '/';
}
return s;
}
function breadcrumbHtml() {
var s = [];
pathName.empty();
for (var i in path) {
s.push(path[i]);
var d = $.extend({}, s);
d.length = s.length;
pathName.append(" / ");
pathName.append($("" + path[i] + "").data(d));
}
}
};
Wysiwyg.prototype.insertTable = function () {
if (this.selectionContainsTagName("pre")) {
return;
}
var self = this;
function nest(html) {
if (self.selectionContainsTagName("table")) {
return '' + html + "";
}
return html;
}
var id = this.generateDomId();
this.insertHTML(nest(this.tableHTML(id, 2, 2, "wiki")));
var element = this.contentDocument.getElementById(id);
if (element) {
this.selectNodeContents(element);
}
this.selectionChanged();
};
Wysiwyg.prototype.insertHashTable = function () {
if (this.selectionContainsTagName("pre")) {
return;
}
var id = this.generateDomId();
this.insertHTML(this.tableHTML(id, 2, 2, "hashtable"));
var element = this.contentDocument.getElementById(id);
if (element) {
element.setAttribute('class', 'hashtable');
this.selectNodeContents(element);
}
this.selectionChanged();
};
Wysiwyg.prototype._tableHTML = function (row, col, className) {
var tr = "" + ((1 << col) - 1).toString(2).replace(/1/g, " ") + " ";
var html = [
'', '',
((1 << row) - 1).toString(2).replace(/1/g, tr),
'', '
' ];
return html.join("");
};
Wysiwyg.prototype._getFocusForTable = function () {
var hash = { node: null, cell: null, row: null, table: null };
hash.node = this.getFocusNode();
hash.cell = hash.node ? Wysiwyg.getSelfOrAncestor(hash.node, /^t[dh]$/) : null;
hash.row = hash.cell ? Wysiwyg.getSelfOrAncestor(hash.cell, "tr") : null;
hash.table = hash.row ? Wysiwyg.getSelfOrAncestor(hash.row, "table") : null;
return hash;
};
Wysiwyg.prototype.ui_insertTableCell = function (after) {
var focus = this._getFocusForTable();
if (focus.table && focus.cell) {
var row = focus.table.rows[focus.row.rowIndex];
var cellIndex = focus.cell.cellIndex + (after ? 1 : 0);
$(focus.cell).removeAttr('colspan');
var cell = this.insertTableCell(row, Math.min(cellIndex, row.cells.length));
this.spanTableColumns(focus.table);
this.selectNodeContents(cell);
this.selectionChanged();
cell.focus();
}
};
Wysiwyg.prototype.insertTableRow = function (after) {
var focus = this._getFocusForTable();
if (focus.table && focus.row) {
var cells = focus.row.getElementsByTagName("td");
var row = focus.table.insertRow(focus.row.rowIndex + (after ? 1 : 0));
var cell;
var j;
for (j = 0; j < cells.length; j++) {
cell = this.insertTableCell(row, 0);
}
this.spanTableColumns(focus.table);
this.selectNodeContents(cell);
this.selectionChanged();
cell.focus();
return row;
}
};
Wysiwyg.prototype.insertTableColumn = function (after) {
var focus = this._getFocusForTable();
if (focus.table && focus.cell) {
var rows = focus.table.rows;
var length = rows.length;
var cellIndex = focus.cell.cellIndex + (after ? 1 : 0);
var i;
for (i = 1; i < length; i++) {
var row = rows[i];
this.insertTableCell(row, Math.min(cellIndex, row.cells.length));
}
this.spanTableColumns(focus.table);
}
};
Wysiwyg.prototype.deleteTableCell = function () {
var focus = this._getFocusForTable();
if (focus.table && focus.cell) {
var row = focus.table.rows[focus.row.rowIndex];
var cellIndex = focus.cell.cellIndex;
if (cellIndex < row.cells.length) {
row.deleteCell(cellIndex);
}
this.spanTableColumns(focus.table);
//this.selectNode(row.cells[cellIndex < row.cells.length ? cellIndex : row.cells.length - 1].firstChild);
this.moveFocusInTable(false);
}
};
Wysiwyg.prototype.deleteTableRow = function () {
var focus = this._getFocusForTable();
if (focus.table && focus.row) {
focus.table.deleteRow(focus.row.rowIndex);
this.spanTableColumns(focus.table);
}
};
Wysiwyg.prototype.deleteTableColumn = function () {
var focus = this._getFocusForTable();
if (focus.table && focus.cell) {
var rows = focus.table.rows;
var length = rows.length;
var cellIndex = focus.cell.cellIndex;
var i;
for (i = 1; i < length; i++) {
var row = rows[i];
if (cellIndex < row.cells.length) {
row.deleteCell(cellIndex);
}
}
this.spanTableColumns(focus.table);
}
};
Wysiwyg.prototype.deleteTable = function () {
var focus = this._getFocusForTable();
if (focus.table) {
$(focus.table).remove();
}
};
Wysiwyg.prototype.spanTableColumns = function (table) {
// Spanning columns fitnesse style.
var rows = $('> tbody > tr', table);
var maxCells = Math.max.apply(Math, $.map(rows, function (e) {
var tds = $('> td', e);
tds.removeAttr('colspan');
return tds.length;
}));
rows.each(function () {
var s = $('> td', this).length;
if (s < maxCells) {
$('td:last', this).attr('colspan', maxCells - s + 1);
}
});
};
Wysiwyg.prototype.moveFocusInTable = function (forward) {
var getSelfOrAncestor = Wysiwyg.getSelfOrAncestor;
var focus = this.getFocusNode();
var element = getSelfOrAncestor(focus, /^(?:t[dhr]|table)$/);
var target, table, rows, cells;
switch (element.tagName.toLowerCase()) {
case "td":
case "th":
focus = element;
var row = getSelfOrAncestor(element, "tr");
cells = row.cells;
if (forward) {
if (focus.cellIndex + 1 < cells.length) {
target = cells[focus.cellIndex + 1];
} else {
table = getSelfOrAncestor(row, /^(?:tbody|table)$/);
rows = table.rows;
target = row.rowIndex + 1 < rows.length ? rows[row.rowIndex + 1].cells[0] : null;
}
} else {
if (focus.cellIndex > 0) {
target = cells[focus.cellIndex - 1];
} else {
table = getSelfOrAncestor(row, /^(?:tbody|table)$/);
rows = table.rows;
if (row.rowIndex > 0) {
cells = rows[row.rowIndex - 1].cells;
target = cells[cells.length - 1];
} else {
target = null;
}
}
}
break;
case "tr":
cells = element.cells;
target = cells[forward ? 0 : cells.length - 1];
break;
case "tbody":
case "table":
rows = element.rows;
cells = rows[forward ? 0 : rows.length - 1].cells;
target = cells[forward ? 0 : cells.length - 1];
break;
}
if (target) {
this.selectNodeContents(target);
} else if (table) {
table = getSelfOrAncestor(table, "table");
var parent = table.parentNode;
var elements = parent.childNodes;
var length = elements.length;
var offset;
for (offset = 0; offset < length; offset++) {
if (table === elements[offset]) {
if (forward) {
offset++;
}
this.selectRange(parent, offset, parent, offset);
}
}
}
};
Wysiwyg.prototype.formatCodeBlock = function () {
if (this.selectionContainsTagName("table") || this.selectionContainsTagName("pre")) {
return;
}
if (!this.getSelectionText()) {
var node = this.getFocusNode();
while (node.nodeType === 3) {
node = node.parentNode;
}
this.selectNode(node);
}
var fragment = this.getSelectionFragment();
var text = this.domToWikitext(fragment, this.options).replace(/\s+$/, "");
var d = this.contentDocument;
var anonymous = d.createElement("div");
var pre = d.createElement("pre");
pre.className = "wiki";
anonymous.appendChild(pre);
if (text) {
pre.appendChild(d.createTextNode(text));
}
this.insertHTML(anonymous.innerHTML);
this.selectionChanged();
};
Wysiwyg.prototype.insertHorizontalRule = function () {
if (this.selectionContainsTagName("table") || this.selectionContainsTagName("pre")) {
return;
}
if (!this.execCommand("inserthorizontalrule")) {
this.insertHTML("
");
}
this.selectionChanged();
};
Wysiwyg.prototype.insertCollapsibleSection = function (mode) {
var self = this;
var range = this.getSelectionRange();
var d = this.contentDocument;
function topNode(node) {
while (node.parentNode && node.parentNode !== self.frame) {
node = node.parentNode;
}
return node;
}
var nodes, node;
var start = topNode(range.startContainer);
if (range.startContainer === range.endContainer) {
nodes = range.startOffset === range.endOffset ? [] : [ topNode(range.startContainer) ];
} else {
var end = topNode(range.endContainer);
nodes = [];
for (node = start; node !== end; node = node.nextSibling) {
nodes.push(node);
}
nodes.push(end);
}
var classes = (mode) ? " " + mode : "";
var collapsible = d.createElement("div");
collapsible.setAttribute("class", "collapsible" + classes);
start.parentNode.insertBefore(collapsible, start);
var sectionName = d.createElement("p");
sectionName.appendChild(d.createTextNode("section title"));
collapsible.appendChild(sectionName);
for (node in nodes) {
//noinspection JSUnfilteredForInLoop
collapsible.appendChild(nodes[node]);
}
this.selectNode(sectionName);
};
Wysiwyg.prototype.deleteCollapsibleSection = function () {
var pos = this.getSelectionPosition();
var startCol = $(pos.start).parents("div.collapsible")[0];
var endCol = $(pos.end).parents("div.collapsible")[0];
if (startCol === endCol) {
$(startCol).before($(startCol).children());
$(startCol).remove();
}
};
Wysiwyg.prototype.createLink = function () {
if (this.selectionContainsTagName("pre")) {
return;
}
var focus = this.getFocusNode();
var anchor = Wysiwyg.getSelfOrAncestor(focus, "a");
var expand = anchor || Wysiwyg.getSelfOrAncestor(focus, "tt");
var currLink;
if (anchor) {
var autolink = anchor.getAttribute("data-wysiwyg-autolink");
if (autolink === "true") {
var pattern = this.wikiDetectLinkPattern;
pattern.lastIndex = 0;
var label = Wysiwyg.getTextContent(anchor);
var match = pattern.exec(label);
if (match && match.index === 0 && match[0].length === label.length) {
currLink = this.normalizeLink(label);
}
}
if (!currLink) {
currLink = anchor.getAttribute("data-wysiwyg-link") || anchor.href;
}
} else {
currLink = "";
}
if (expand) {
this.selectNodeContents(expand);
}
var text = this.getSelectionText() || "";
var newLink = (prompt(text ? "Enter link:" : "Insert link:", currLink) || "").replace(/^\s+|\s+$/g, "");
if (newLink && newLink !== currLink) {
text = text || newLink;
newLink = this.normalizeLink(newLink);
var id = this.generateDomId();
var d = this.contentDocument;
var anonymous = d.createElement("div");
anchor = this.createAnchor(newLink, text, { id: id });
anonymous.appendChild(anchor);
this.insertHTML(anonymous.innerHTML);
anchor = d.getElementById(id);
if (anchor) {
this.selectNodeContents(anchor);
}
}
this.selectionChanged();
};
Wysiwyg.prototype.createAnchor = function (link, label, attrs) {
var d = this.contentDocument;
var anchor = d.createElement("a");
var name;
for (name in attrs) {
if (attrs.hasOwnProperty(name)) {
var value = attrs[name];
anchor.setAttribute(name, value);
}
}
anchor.href = link;
anchor.title = link;
anchor.setAttribute("data-wysiwyg-link", link);
if (label) {
anchor.appendChild(d.createTextNode(label));
}
return anchor;
};
Wysiwyg.prototype.createCollapsibleSection = function () {
var collapsible = this.contentDocument.createElement("div");
$(collapsible).addClass("collapsible");
return collapsible;
};
Wysiwyg.prototype.collectChildNodes = function (dest, source) {
var childNodes = source.childNodes;
var i;
for (i = childNodes.length - 1; i >= 0; i--) {
dest.insertBefore(childNodes[i], dest.firstChild);
}
};
Wysiwyg.prototype.generateDomId = function () {
var d = this.contentDocument;
while (true) {
var id = "tmp-" + (new Date().valueOf().toString(36));
if (!d.getElementById(id)) {
return id;
}
}
};
Wysiwyg.prototype.selectionChanged = function () {
var status = {
strong: false,
em: false,
underline: false,
strike: false,
sub: false,
sup: false,
escape: false,
paragraph: false,
heading1: false,
heading2: false,
heading3: false,
heading4: false,
heading5: false,
heading6: false,
link: false,
ol: false,
ul: false,
outdent: false,
indent: false,
table: false,
code: false,
quote: false,
hr: false,
br: false
};
var tagNameToKey = {
b: "strong",
i: "em",
u: "underline",
del: "strike",
tt: "escape",
p: "paragraph",
h1: "heading1",
h2: "heading2",
h3: "heading3",
h4: "heading4",
h5: "heading5",
h6: "heading6",
a: "link",
pre: "code"
};
var position = this.getSelectionPosition();
var node, toolbarButtons, name;
var hashTable = false;
if (position.start) {
node = position.start === position.end ? position.start.firstChild : position.start.nextSibling;
node = node || position.start;
} else {
node = null;
}
while (node) {
if (node.nodeType === 1) {
name = node.tagName.toLowerCase();
if (tagNameToKey.hasOwnProperty(name)) {
name = tagNameToKey[name];
}
status[name] = true;
hashTable |= this.isHashTable(node);
}
node = node.parentNode;
}
toolbarButtons = this.toolbarButtons;
for (name in status) {
if (status.hasOwnProperty(name)) {
var button = toolbarButtons[name];
if (button) {
var parent = button.parentNode;
parent.className = (parent.className || "").replace(/ *\bselected\b|$/, status[name] ? " selected" : "");
}
}
}
if (hashTable) {
$(".wysiwyg-toolbar .non-table").hide();
$(".wysiwyg-toolbar .in-table").hide();
$(".wysiwyg-toolbar .in-hash-table").show();
} else if (status["table"]) {
$(".wysiwyg-toolbar .non-table").hide();
$(".wysiwyg-toolbar .in-table").show();
$(".wysiwyg-toolbar .in-hash-table").hide();
} else {
$(".wysiwyg-toolbar .non-table").show();
$(".wysiwyg-toolbar .in-table").hide();
$(".wysiwyg-toolbar .in-hash-table").hide();
}
$(window).resize();
var styles = [ "quote", "paragraph", "code", "heading1",
"heading2", "heading3", "heading4", "heading5", "heading6" ];
var styleButton = toolbarButtons.style;
var styleButtonClass = "wysiwyg-menu-style";
var i;
for (i = 0; i < styles.length; i++) {
name = styles[i];
if (status[name]) {
styleButtonClass = "wysiwyg-menu-" + name;
break;
}
}
styleButton.parentNode.className = styleButtonClass;
};
if (window.getSelection) {
Wysiwyg.prototype.insertParagraphOnEnter = function (event) {
var range = this.getSelectionRange();
var node = range.endContainer;
var header = null;
if (node && node.nodeType === 3 && range.endOffset === node.nodeValue.length) {
var nextSibling = node.nextSibling;
if (!nextSibling || nextSibling.tagName.toLowerCase() === "br") {
while (node) {
if (node.nodeType === 1 && /^h[1-6]$/i.exec(node.tagName)) {
header = node;
break;
}
node = node.parentNode;
}
if (header) {
var parent = header.parentNode;
var childNodes = parent.childNodes;
var length = childNodes.length;
var offset;
for (offset = 0; offset < length; offset++) {
if (childNodes[offset] === header) {
offset++;
break;
}
}
this.selectRange(parent, offset, parent, offset);
this.insertHTML('
');
Wysiwyg.stopEvent(event);
}
}
}
};
Wysiwyg.prototype.tableHTML = function (id, row, col, className) {
var html = this._tableHTML(row, col, className);
return html.replace(/<\/td>/g, '
').replace(//, ' ');
};
Wysiwyg.prototype.insertTableCell = function (row, index) {
var cell = row.insertCell(index);
this.appendBogusLineBreak(cell);
return cell;
};
Wysiwyg.prototype.getFocusNode = function () {
return this.contentWindow.getSelection().focusNode;
};
if (window.opera) {
Wysiwyg.prototype.insertLineBreak = function () {
this.execCommand("inserthtml", "
");
};
Wysiwyg.prototype.insertLineBreakOnShiftEnter = null;
} else if (window.getSelection().setBaseAndExtent) { // Safari 2+
Wysiwyg.prototype.insertLineBreak = function () {
this.execCommand("insertlinebreak");
};
Wysiwyg.prototype.insertLineBreakOnShiftEnter = function (event) {
this.insertLineBreak();
Wysiwyg.stopEvent(event);
};
} else { // Firefox 2+
Wysiwyg.prototype.insertLineBreak = function () {
var event = this.contentDocument.createEvent("KeyboardEvent");
event.initKeyEvent("keypress", true, true, null, false, false, true, false, 0x000d, 0);
this.frame.dispatchEvent(event);
};
Wysiwyg.prototype.insertLineBreakOnShiftEnter = null;
}
if (window.getSelection().removeAllRanges) {
Wysiwyg.prototype.selectNode = function (node) {
var selection = this.contentWindow.getSelection();
selection.removeAllRanges();
var range = this.contentDocument.createRange();
range.selectNode(node);
selection.addRange(range);
};
Wysiwyg.prototype.selectNodeContents = function (node) {
var selection = this.contentWindow.getSelection();
selection.removeAllRanges();
var range = this.contentDocument.createRange();
range.selectNodeContents(node);
selection.addRange(range);
};
Wysiwyg.prototype.selectRange = function (start, startOffset, end, endOffset) {
var selection = this.contentWindow.getSelection();
selection.removeAllRanges();
var range = this.contentDocument.createRange();
range.setStart(start, startOffset);
range.setEnd(end, endOffset);
selection.addRange(range);
};
Wysiwyg.prototype.getNativeSelectionRange = function () {
var selection = this.contentWindow.getSelection();
return selection.rangeCount > 0 ? selection.getRangeAt(0) : null;
};
Wysiwyg.prototype.expandSelectionToElement = function (arg) {
if (arg.start || arg.end) {
var selection = this.contentWindow.getSelection();
var range = this.getNativeSelectionRange() || this.contentDocument.createRange();
selection.removeAllRanges();
if (arg.start) {
range.setStartBefore(arg.start);
}
if (arg.end) {
range.setEndAfter(arg.end);
}
selection.addRange(range);
}
};
Wysiwyg.prototype.insertHTML = function (html) {
this.execCommand("inserthtml", html);
};
} else { // Safari 2
Wysiwyg.prototype.selectNode = function (node) {
var selection = this.contentWindow.getSelection();
var range = this.contentDocument.createRange();
range.selectNode(node);
selection.setBaseAndExtent(range.startContainer, range.startOffset, range.endContainer, range.endOffset);
range.detach();
};
Wysiwyg.prototype.selectNodeContents = function (node) {
this.selectRange(node, 0, node, node.childNodes.length);
};
Wysiwyg.prototype.selectRange = function (start, startOffset, end, endOffset) {
var selection = this.contentWindow.getSelection();
selection.setBaseAndExtent(start, startOffset, end, endOffset);
};
Wysiwyg.prototype.getNativeSelectionRange = function () {
var selection = this.contentWindow.getSelection();
if (selection.anchorNode) {
var range = this.contentDocument.createRange();
range.setStart(selection.baseNode, selection.baseOffset);
range.setEnd(selection.extentNode, selection.extentOffset);
if (range.collapsed && !selection.isCollapsed) {
range.setStart(selection.extentNode, selection.extentOffset);
range.setEnd(selection.baseNode, selection.baseOffset);
}
return range;
}
return null;
};
Wysiwyg.prototype.expandSelectionToElement = function (arg) {
if (arg.start || arg.end) {
var selection = this.contentWindow.getSelection();
var range = this.getNativeSelectionRange();
if (arg.start) {
range.setStartBefore(arg.start);
}
if (arg.end) {
range.setEndAfter(arg.end);
}
selection.setBaseAndExtent(range.startContainer, range.startOffset, range.endContainer, range.endOffset);
range.detach();
}
};
Wysiwyg.prototype.insertHTML = function (html) {
var range = this.getNativeSelectionRange();
if (range) {
var d = this.contentDocument;
var tmp = d.createRange();
tmp.setStart(this.frame, 0);
tmp.setEnd(this.frame, 0);
var fragment = tmp.createContextualFragment(html);
range.deleteContents();
range.insertNode(fragment);
range.detach();
tmp.detach();
}
};
}
Wysiwyg.prototype.getSelectionRange = Wysiwyg.prototype.getNativeSelectionRange;
Wysiwyg.prototype.getSelectionText = function () {
var range = this.getNativeSelectionRange();
return range ? range.toString() : null;
};
Wysiwyg.prototype.getSelectionHTML = function () {
var fragment = this.getSelectionFragment();
var anonymous = this.contentDocument.createElement("div");
anonymous.appendChild(fragment);
return anonymous.innerHTML;
};
Wysiwyg.prototype.getSelectionFragment = function () {
var range = this.getNativeSelectionRange();
return range ? range.cloneContents() : this.contentDocument.createDocumentFragment();
};
Wysiwyg.prototype.getSelectionPosition = function () {
var range = this.getNativeSelectionRange();
var position = { start: null, end: null };
if (range) {
position.start = range.startContainer;
position.end = range.endContainer;
}
return position;
};
Wysiwyg.prototype.selectionContainsTagName = function (name) {
var selection = this.contentWindow.getSelection();
var range = this.getNativeSelectionRange();
if (!range) {
return false;
}
var ancestor = range.commonAncestorContainer;
if (!ancestor) {
return false;
}
if (Wysiwyg.getSelfOrAncestor(ancestor, name)) {
return true;
}
if (ancestor.nodeType !== 1) {
return false;
}
var elements = ancestor.getElementsByTagName(name);
var length = elements.length;
var i;
for (i = 0; i < length; i++) {
if (selection.containsNode(elements[i], true)) {
return true;
}
}
return false;
};
} else if (document.selection) {
// For IE <= 8
Wysiwyg.prototype.insertParagraphOnEnter = null;
Wysiwyg.prototype.insertLineBreak = function () {
this.insertHTML("
");
};
Wysiwyg.prototype.insertLineBreakOnShiftEnter = null;
Wysiwyg.prototype.tableHTML = function (id, row, col, className) {
var html = this._tableHTML(row, col, className);
return html.replace(/ /, ' ');
};
Wysiwyg.prototype.insertTableCell = function (row, index) {
return row.insertCell(index);
};
Wysiwyg.prototype.getFocusNode = function () {
this.frame.focus();
var d = this.contentDocument;
var range = d.selection.createRange();
var node = range.item ? range.item(0) : range.parentElement();
return node.ownerDocument === d ? node : null;
};
Wysiwyg.prototype.selectNode = function (node) {
var d = this.contentDocument;
var body = this.frame;
var range;
d.selection.empty();
try {
range = body.createControlRange();
range.addElement(node);
} catch (e) {
range = body.createTextRange();
range.moveToElementText(node);
}
range.select();
};
Wysiwyg.prototype.selectNodeContents = function (node) {
var d = this.contentDocument;
d.selection.empty();
var range = this.frame.createTextRange();
range.moveToElementText(node);
range.select();
};
Wysiwyg.prototype.selectRange = function (start, startOffset, end, endOffset) {
var d = this.contentDocument;
var body = this.frame;
d.selection.empty();
var range = endPoint(start, startOffset);
if (start !== end || startOffset !== endOffset) {
range.setEndPoint("EndToEnd", endPoint(end, endOffset));
}
range.select();
function endPoint(node, offset) {
var range;
if (node.nodeType === 1) {
var childNodes = node.childNodes;
if (offset >= childNodes.length) {
range = body.createTextRange();
range.moveToElementText(node);
range.collapse(false);
return range;
}
node = childNodes[offset];
if (node.nodeType === 1) {
range = body.createTextRange();
range.moveToElementText(node);
range.collapse(true);
switch (node.tagName.toLowerCase()) {
case "table":
range.move("character", -1);
break;
}
return range;
}
return endPoint(node, 0);
}
if (node.nodeType !== 3) {
throw "selectRange: nodeType != @".replace(/@/, node.nodeType);
}
range = body.createTextRange();
var element = node.previousSibling;
while (element) {
var nodeType = element.nodeType;
if (nodeType === 1) {
range.moveToElementText(element);
range.collapse(false);
break;
}
if (nodeType === 3) {
offset += element.nodeValue.length;
}
element = element.previousSibling;
}
if (!element) {
range.moveToElementText(node.parentNode);
range.collapse(true);
}
if (offset !== 0) {
range.move("character", offset);
}
return range;
}
};
Wysiwyg.prototype.getSelectionRange = function () {
var body = this.frame;
var pseudo = {};
var start = this.getNativeSelectionRange();
if (start.item) {
var element = start.item(0);
var parent = element.parentNode;
var childNodes = parent.childNodes;
var length = childNodes.length;
var i;
for (i = 0; i < length; i++) {
if (childNodes[i] === element) {
pseudo.startOffset = i;
pseudo.endOffset = i + 1;
break;
}
}
pseudo.collapsed = false;
pseudo.startContainer = pseudo.endContainer = parent;
return pseudo;
}
var end = start.duplicate();
pseudo.collapsed = start.compareEndPoints("StartToEnd", end) === 0;
start.collapse(true);
end.collapse(false);
function nextElement(range) {
var parent = range.parentElement();
var childNodes = parent.childNodes;
var length = childNodes.length;
var i;
for (i = 0; i < length; i++) {
var node = childNodes[i];
if (node.nodeType === 1) {
var tmp = body.createTextRange();
tmp.moveToElementText(node);
if (range.compareEndPoints("EndToStart", tmp) <= 0) {
return node;
}
}
}
return null;
}
function nodeOffset(range, parent, element, index, length) {
var tmp = body.createTextRange();
var len;
tmp.moveToElementText(element || parent);
tmp.collapse(!!element);
tmp.move("character", -index);
if (!element) {
length++;
}
for (len = length; len >= 0; len--) {
if (tmp.compareEndPoints("EndToStart", range) === 0) {
return len;
}
tmp.move("character", -1);
}
return null;
}
function setContainerOffset(range, containerKey, offsetKey) {
var parent = range.parentElement();
var element = nextElement(range);
var index = 0;
var node = element ? element.previousSibling : parent.lastChild;
var offset, length;
while (node && node.nodeType === 3) {
length = node.nodeValue.length;
offset = nodeOffset(range, parent, element, index, length);
if (offset !== null) {
pseudo[containerKey] = node;
pseudo[offsetKey] = offset;
return;
}
index += length;
node = node.previousSibling;
}
var childNodes = parent.childNodes;
length = childNodes.length;
if (length > 0) {
pseudo[containerKey] = parent;
pseudo[offsetKey] = containerKey === "startContainer" ? 0 : length - 1;
return;
}
element = parent;
parent = element.parentNode;
childNodes = parent.childNodes;
length = childNodes.length;
for (offset = 0; offset < length; offset++) {
if (element === childNodes[offset]) {
pseudo[containerKey] = parent;
pseudo[offsetKey] = offset;
return;
}
}
}
setContainerOffset(start, "startContainer", "startOffset");
setContainerOffset(end, "endContainer", "endOffset");
return pseudo;
};
Wysiwyg.prototype.getNativeSelectionRange = function () {
this.contentWindow.focus();
return this.contentDocument.selection.createRange();
};
Wysiwyg.prototype.getSelectionText = function () {
var range = this.getNativeSelectionRange();
if (range) {
return range.item ? range.item(0).innerText : range.text;
}
return null;
};
Wysiwyg.prototype.getSelectionHTML = function () {
var range = this.getNativeSelectionRange();
if (range) {
return range.item ? range.item(0).innerHTML : range.htmlText;
}
return null;
};
Wysiwyg.prototype.getSelectionFragment = function () {
var d = this.contentDocument;
var fragment = d.createDocumentFragment();
var anonymous = d.createElement("div");
anonymous.innerHTML = this.getSelectionHTML();
this.collectChildNodes(fragment, anonymous);
return fragment;
};
Wysiwyg.prototype.getSelectionPosition = function () {
this.frame.focus();
var d = this.contentDocument;
var range = d.selection.createRange();
var startNode = null;
var endNode = null;
if (range.item) {
if (range.item(0).ownerDocument === d) {
startNode = range.item(0);
endNode = range.item(range.length - 1);
}
} else {
if (range.parentElement().ownerDocument === d) {
var startRange = range.duplicate();
startRange.collapse(true);
startNode = startRange.parentElement();
var endRange = range.duplicate();
endRange.collapse(false);
endNode = endRange.parentElement();
}
}
return { start: startNode, end: endNode };
};
Wysiwyg.prototype.expandSelectionToElement = function (arg) {
this.frame.focus();
var d = this.contentDocument;
var body = this.frame;
var range = d.selection.createRange();
var tmp;
if (arg.start) {
tmp = body.createTextRange();
tmp.moveToElementText(arg.start);
range.setEndPoint("StartToStart", tmp);
}
if (arg.end) {
tmp = body.createTextRange();
tmp.moveToElementText(arg.end);
range.setEndPoint("EndToEnd", tmp);
}
if (tmp) {
range.select();
}
};
Wysiwyg.prototype.selectionContainsTagName = function (name) {
this.frame.focus();
var d = this.contentDocument;
var selection = d.selection;
var range = selection.createRange();
var parent = range.item ? range.item(0) : range.parentElement();
if (!parent) {
return false;
}
if (Wysiwyg.getSelfOrAncestor(parent, name)) {
return true;
}
var elements = parent.getElementsByTagName(name);
var length = elements.length;
var i;
for (i = 0; i < length; i++) {
var testRange = selection.createRange();
testRange.moveToElementText(elements[i]);
if (range.compareEndPoints("StartToEnd", testRange) <= 0
&& range.compareEndPoints("EndToStart", testRange) >= 0) {
return true;
}
}
return false;
};
Wysiwyg.prototype.insertHTML = function (html) {
this.frame.focus();
var selection = this.contentDocument.selection;
var range = selection.createRange();
range.pasteHTML(html.replace(/\t/g, " "));
range.collapse(false);
range.select();
range = this.contentDocument.selection.createRange();
};
} else {
Wysiwyg.prototype.insertParagraphOnEnter = null;
Wysiwyg.prototype.insertLineBreak = function () { };
Wysiwyg.prototype.insertTableCell = function () { return null; };
Wysiwyg.prototype.getFocusNode = function () { return null; };
Wysiwyg.prototype.selectNode = function (node) { };
Wysiwyg.prototype.selectNodeContents = function () { return null; };
Wysiwyg.prototype.selectRange = function (start, startOffset, end, endOffset) { };
Wysiwyg.prototype.getSelectionRange = function () { return null; };
Wysiwyg.prototype.getNativeSelectionRange = function () { return null; };
Wysiwyg.prototype.getSelectionText = function () { return null; };
Wysiwyg.prototype.getSelectionHTML = function () { return null; };
Wysiwyg.prototype.getSelectionFragment = function () { return null; };
Wysiwyg.prototype.getSelectionPosition = function () { return null; };
Wysiwyg.prototype.expandSelectionToElement = function () { };
Wysiwyg.prototype.selectionContainsTagName = function () { return false; };
Wysiwyg.prototype.insertHTML = function (html) { };
}
Wysiwyg.prototype._treeWalkEmulation = function (root, iterator) {
if (!root.firstChild) {
iterator(null);
return;
}
var element = root;
while (element) {
if (element.firstChild) {
element = element.firstChild;
} else if (element.nextSibling) {
element = element.nextSibling;
} else {
while (true) {
element = element.parentNode;
if (element === root || !element) {
iterator(null);
return;
}
if (element.nextSibling) {
element = element.nextSibling;
break;
}
}
}
iterator(element);
}
};
if (document.createTreeWalker) {
Wysiwyg.prototype.treeWalk = function (root, iterator) {
var walker = root.ownerDocument.createTreeWalker(
root,
NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT,
null,
true
);
while (walker.nextNode()) {
iterator(walker.currentNode);
}
iterator(null);
};
} else {
Wysiwyg.prototype.treeWalk = Wysiwyg.prototype._treeWalkEmulation;
}
Wysiwyg.count = 0;
Wysiwyg.newInstance = function (textarea, options) {
return new Wysiwyg(textarea, options);
};
Wysiwyg.getOptions = function () {
var options = {};
//noinspection JSUnresolvedVariable
if (window._wysiwyg) {
options = window._wysiwyg;
}
return options;
};
Wysiwyg.getEditorMode = function () {
if (Wysiwyg.editorMode) {
return Wysiwyg.editorMode;
}
var mode = null;
var cookies = (document.cookie || "").split(";");
var length = cookies.length;
var i;
for (i = 0; i < length; i++) {
var match = /^\s*wysiwyg=(\S*)/.exec(cookies[i]);
if (match) {
switch (match[1]) {
case "wysiwyg":
mode = match[1];
break;
default: // "textarea"
mode = null;
break;
}
break;
}
}
Wysiwyg.editorMode = mode || "textarea";
return Wysiwyg.editorMode;
};
Wysiwyg.setCookie = function (key, val) {
var now = new Date();
var expires = new Date(now.getTime() + 365 * 86400 * 1000);
var pieces = [ key + "=" + val,
"expires=" + expires.toUTCString() ];
document.cookie = pieces.join(";");
};
Wysiwyg.removeEvent = function (element, type, func) {
jQuery(element).unbind(type, func);
};
Wysiwyg.stopEvent = function (event) {
if (event.preventDefault) {
event.preventDefault();
event.stopPropagation();
} else {
event.returnValue = false;
event.cancelBubble = true;
}
};
Wysiwyg.setStyle = function (element, object) {
var style = element.style;
var name;
for (name in object) {
if (object.hasOwnProperty(name)) {
style[name] = object[name];
}
}
};
if (document.defaultView) {
Wysiwyg.getStyle = function (element, name) {
var value = element.style[name];
if (!value) {
var style = element.ownerDocument.defaultView.getComputedStyle(element, null);
value = style ? style[name] : null;
}
return value;
};
} else {
Wysiwyg.getStyle = function (element, name) {
return element.style[name] || element.currentStyle[name];
};
}
// Find parent element of type 'name', stop if an element of type 'notName' is found.
Wysiwyg.getSelfOrAncestor = function (element, name, notName) {
var target = element;
var d = element.ownerDocument;
if (name instanceof RegExp) {
while (target && target !== d) {
switch (target.nodeType) {
case 1: // element
if (name.test(target.tagName.toLowerCase())) {
return target;
}
break;
case 11: // fragment
return null;
}
target = target.parentNode;
}
} else {
name = name.toLowerCase();
while (target && target !== d) {
switch (target.nodeType) {
case 1: // element
if (target.tagName.toLowerCase() === name) {
return target;
} else if (target.tagName.toLowerCase() === notName || target.tagName.toLowerCase() === "div") {
return null;
}
break;
case 11: // fragment
return null;
}
target = target.parentNode;
}
}
return null;
};
Wysiwyg.getTextContent = (function () {
var anonymous = document.createElement("div");
if (typeof anonymous.textContent !== undefined) {
return function (element) { return element.textContent; };
} else if (typeof anonymous.innerText !== undefined) {
return function (element) { return element.innerText; };
} else {
return function () { return null; };
}
})();
Wysiwyg.initialize = function (textArea) {
if ("replace".replace(/[a-e]/g, function () { return "*"; }) !== "r*pl***") {
return;
}
if (typeof document.designMode === undefined) {
return;
}
var options = Wysiwyg.getOptions();
return Wysiwyg.newInstance(textArea, options);
};
// vim:et:ai:ts=4
© 2015 - 2025 Weber Informatics LLC | Privacy Policy