All Downloads are FREE. Search and download functionalities are using the official Maven repository.

fitnesse.resources.wysiwyg.wysiwyg.js Maven / Gradle / Ivy

The newest version!
"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 = [ '

Normal

', '

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