diff --git a/app/assets/javascripts/comfy/vendor/redactor.js b/app/assets/javascripts/comfy/vendor/redactor.js
index 89174d00..955dc1a5 100755
--- a/app/assets/javascripts/comfy/vendor/redactor.js
+++ b/app/assets/javascripts/comfy/vendor/redactor.js
@@ -13,9195 +13,9001 @@
fixes and tweaks annotated with "COMFY FIX"
*/
-import jQuery from "jquery";
-
-(function ($) {
- "use strict";
-
- if (!Function.prototype.bind) {
- Function.prototype.bind = function (scope) {
- var fn = this;
- return function () {
- return fn.apply(scope);
- };
- };
- }
-
- var uuid = 0;
-
- // Plugin
- $.fn.redactor = function (options) {
- var val = [];
- var args = Array.prototype.slice.call(arguments, 1);
-
- if (typeof options === "string") {
- this.each(function () {
- var instance = $.data(this, "redactor");
- var func;
-
- if (options.search(/\./) != "-1") {
- func = options.split(".");
- if (typeof instance[func[0]] != "undefined") {
- func = instance[func[0]][func[1]];
- }
- } else {
- func = instance[options];
- }
-
- if (typeof instance !== "undefined" && $.isFunction(func)) {
- var methodVal = func.apply(instance, args);
- if (methodVal !== undefined && methodVal !== instance) {
- val.push(methodVal);
- }
- } else {
- $.error('No such method "' + options + '" for Redactor');
- }
- });
- } else {
- this.each(function () {
- $.data(this, "redactor", {});
- $.data(this, "redactor", Redactor(this, options));
- });
- }
-
- if (val.length === 0) return this;
- else if (val.length === 1) return val[0];
- else return val;
- };
-
- // Initialization
- function Redactor(el, options) {
- return new Redactor.prototype.init(el, options);
- }
-
- // Functionality
- $.Redactor = Redactor;
- $.Redactor.VERSION = "10.2.5";
- $.Redactor.modules = [
- "alignment",
- "autosave",
- "block",
- "buffer",
- "build",
- "button",
- "caret",
- "clean",
- "code",
- "core",
- "dropdown",
- "file",
- "focus",
- "image",
- "indent",
- "inline",
- "insert",
- "keydown",
- "keyup",
- "lang",
- "line",
- "link",
- "linkify",
- "list",
- "modal",
- "observe",
- "paragraphize",
- "paste",
- "placeholder",
- "progress",
- "selection",
- "shortcuts",
- "tabifier",
- "tidy",
- "toolbar",
- "upload",
- "utils",
- ];
-
- $.Redactor.opts = {
- // settings
- lang: "en",
- direction: "ltr", // ltr or rtl
-
- plugins: false, // array
-
- focus: false,
- focusEnd: false,
-
- placeholder: false,
-
- visual: true,
- tabindex: false,
-
- minHeight: false,
- maxHeight: false,
-
- linebreaks: false,
- replaceDivs: true,
- paragraphize: true,
- cleanStyleOnEnter: false,
- enterKey: true,
-
- cleanOnPaste: true,
- cleanSpaces: true,
- pastePlainText: false,
-
- autosave: false, // false or url
- autosaveName: false,
- autosaveInterval: 60, // seconds
- autosaveOnChange: false,
- autosaveFields: false,
-
- linkTooltip: true,
- linkProtocol: "http",
- linkNofollow: false,
- linkSize: 50,
-
- imageEditable: true,
- imageLink: true,
- imagePosition: true,
- imageFloatMargin: "10px",
- imageResizable: true,
-
- imageUpload: null,
- imageUploadParam: "file",
-
- uploadImageField: false,
-
- dragImageUpload: true,
-
- fileUpload: null,
- fileUploadParam: "file",
-
- dragFileUpload: true,
-
- s3: false,
-
- convertLinks: true,
- convertUrlLinks: true,
- convertImageLinks: true,
- convertVideoLinks: true,
-
- preSpaces: 4, // or false
- tabAsSpaces: false, // true or number of spaces
- tabKey: true,
-
- scrollTarget: false,
-
- toolbar: true,
- toolbarFixed: true,
- toolbarFixedTarget: document,
- toolbarFixedTopOffset: 0, // pixels
- toolbarExternal: false, // ID selector
- toolbarOverflow: false,
-
- source: true,
- buttons: [
- "html",
- "formatting",
- "bold",
- "italic",
- "deleted",
- "unorderedlist",
- "orderedlist",
- "outdent",
- "indent",
- "image",
- "file",
- "link",
- "alignment",
- "horizontalrule",
- ], // + 'underline'
-
- buttonsHide: [],
- buttonsHideOnMobile: [],
-
- formatting: ["p", "blockquote", "pre", "h1", "h2", "h3", "h4", "h5", "h6"],
- formattingAdd: false,
-
- tabifier: true,
-
- deniedTags: ["script", "style"],
- allowedTags: false, // or array
-
- paragraphizeBlocks: [
- "table",
- "div",
- "pre",
- "form",
- "ul",
- "ol",
- "h1",
- "h2",
- "h3",
- "h4",
- "h5",
- "h6",
- "dl",
- "blockquote",
- "figcaption",
- "address",
- "section",
- "header",
- "footer",
- "aside",
- "article",
- "object",
- "style",
- "script",
- "iframe",
- "select",
- "input",
- "textarea",
- "button",
- "option",
- "map",
- "area",
- "math",
- "hr",
- "fieldset",
- "legend",
- "hgroup",
- "nav",
- "figure",
- "details",
- "menu",
- "summary",
- "p",
- ],
-
- removeComments: false,
- replaceTags: [
- ["strike", "del"],
- ["b", "strong"],
- ],
- replaceStyles: [
- ["font-weight:\\s?bold", "strong"],
- ["font-style:\\s?italic", "em"],
- ["text-decoration:\\s?underline", "u"],
- ["text-decoration:\\s?line-through", "del"],
- ],
- removeDataAttr: false,
-
- removeAttr: false, // or multi array
- allowedAttr: false, // or multi array
-
- removeWithoutAttr: ["span"], // or false
- removeEmpty: ["p"], // or false;
-
- activeButtons: [
- "deleted",
- "italic",
- "bold",
- "underline",
- "unorderedlist",
- "orderedlist",
- "alignleft",
- "aligncenter",
- "alignright",
- "justify",
- ],
- activeButtonsStates: {
- b: "bold",
- strong: "bold",
- i: "italic",
- em: "italic",
- del: "deleted",
- strike: "deleted",
- ul: "unorderedlist",
- ol: "orderedlist",
- u: "underline",
- },
-
- shortcuts: {
- "ctrl+shift+m, meta+shift+m": { func: "inline.removeFormat" },
- "ctrl+b, meta+b": { func: "inline.format", params: ["bold"] },
- "ctrl+i, meta+i": { func: "inline.format", params: ["italic"] },
- "ctrl+h, meta+h": { func: "inline.format", params: ["superscript"] },
- "ctrl+l, meta+l": { func: "inline.format", params: ["subscript"] },
- "ctrl+k, meta+k": { func: "link.show" },
- "ctrl+shift+7": { func: "list.toggle", params: ["orderedlist"] },
- "ctrl+shift+8": { func: "list.toggle", params: ["unorderedlist"] },
- },
- shortcutsAdd: false,
-
- // private
- buffer: [],
- rebuffer: [],
- emptyHtml: "
",
- invisibleSpace: "",
- imageTypes: ["image/png", "image/jpeg", "image/gif"],
- indentValue: 20,
- verifiedTags: [
- "a",
- "img",
- "b",
- "strong",
- "sub",
- "sup",
- "i",
- "em",
- "u",
- "small",
- "strike",
- "del",
- "cite",
- "ul",
- "ol",
- "li",
- ], // and for span tag special rule
- inlineTags: [
- "strong",
- "b",
- "u",
- "em",
- "i",
- "code",
- "del",
- "ins",
- "samp",
- "kbd",
- "sup",
- "sub",
- "mark",
- "var",
- "cite",
- "small",
- ],
- alignmentTags: [
- "P",
- "H1",
- "H2",
- "H3",
- "H4",
- "H5",
- "H6",
- "DL",
- "DT",
- "DD",
- "DIV",
- "TD",
- "BLOCKQUOTE",
- "OUTPUT",
- "FIGCAPTION",
- "ADDRESS",
- "SECTION",
- "HEADER",
- "FOOTER",
- "ASIDE",
- "ARTICLE",
- ],
- blockLevelElements: ["PRE", "UL", "OL", "LI"],
- highContrast: false,
- observe: {
- dropdowns: [],
- },
-
- // lang
- langs: {
- en: {
- html: "HTML",
- video: "Insert Video",
- image: "Insert Image",
- table: "Table",
- link: "Link",
- link_insert: "Insert link",
- link_edit: "Edit link",
- unlink: "Unlink",
- formatting: "Formatting",
- paragraph: "Normal text",
- quote: "Quote",
- code: "Code",
- header1: "Header 1",
- header2: "Header 2",
- header3: "Header 3",
- header4: "Header 4",
- header5: "Header 5",
- bold: "Bold",
- italic: "Italic",
- fontcolor: "Font Color",
- backcolor: "Back Color",
- unorderedlist: "Unordered List",
- orderedlist: "Ordered List",
- outdent: "Outdent",
- indent: "Indent",
- cancel: "Cancel",
- insert: "Insert",
- save: "Save",
- _delete: "Delete",
- insert_table: "Insert Table",
- insert_row_above: "Add Row Above",
- insert_row_below: "Add Row Below",
- insert_column_left: "Add Column Left",
- insert_column_right: "Add Column Right",
- delete_column: "Delete Column",
- delete_row: "Delete Row",
- delete_table: "Delete Table",
- rows: "Rows",
- columns: "Columns",
- add_head: "Add Head",
- delete_head: "Delete Head",
- title: "Title",
- image_position: "Position",
- none: "None",
- left: "Left",
- right: "Right",
- center: "Center",
- image_web_link: "Image Web Link",
- text: "Text",
- mailto: "Email",
- web: "URL",
- video_html_code: "Video Embed Code or Youtube/Vimeo Link",
- file: "Insert File",
- upload: "Upload",
- download: "Download",
- choose: "Choose",
- or_choose: "Or choose",
- drop_file_here: "Drop file here",
- align_left: "Align text to the left",
- align_center: "Center text",
- align_right: "Align text to the right",
- align_justify: "Justify text",
- horizontalrule: "Insert Horizontal Rule",
- deleted: "Deleted",
- anchor: "Anchor",
- link_new_tab: "Open link in new tab",
- underline: "Underline",
- alignment: "Alignment",
- filename: "Name (optional)",
- edit: "Edit",
- upload_label: "Drop file here or ",
- },
- },
-
- linkify: {
- regexps: {
- youtube:
- /https?:\/\/(?:[0-9A-Z-]+\.)?(?:youtu\.be\/|youtube\.com\S*[^\w\-\s])([\w\-]{11})(?=[^\w\-]|$)(?![?=&+%\w.\-]*(?:['"][^<>]*>|<\/a>))[?=&+%\w.-]*/gi,
- vimeo: /https?:\/\/(www\.)?vimeo.com\/(\d+)($|\/)/,
- image: /((https?|www)[^\s]+\.)(jpe?g|png|gif)(\?[^\s-]+)?/gi,
- url: /(https?:\/\/(?:www\.|(?!www))[^\s\.]+\.[^\s]{2,}|www\.[^\s]+\.[^\s]{2,})/gi,
- },
- },
-
- codemirror: false,
- };
-
- // Functionality
- Redactor.fn = $.Redactor.prototype = {
- keyCode: {
- BACKSPACE: 8,
- DELETE: 46,
- UP: 38,
- DOWN: 40,
- ENTER: 13,
- SPACE: 32,
- ESC: 27,
- TAB: 9,
- CTRL: 17,
- META: 91,
- SHIFT: 16,
- ALT: 18,
- RIGHT: 39,
- LEFT: 37,
- LEFT_WIN: 91,
- },
-
- // Initialization
- init: function (el, options) {
- this.$element = $(el);
- this.uuid = uuid++;
-
- // if paste event detected = true
- this.rtePaste = false;
- this.$pasteBox = false;
-
- this.loadOptions(options);
- this.loadModules();
-
- // formatting storage
- this.formatting = {};
-
- // block level tags
- $.merge(this.opts.blockLevelElements, this.opts.alignmentTags);
- this.reIsBlock = new RegExp(
- "^(" + this.opts.blockLevelElements.join("|") + ")$",
- "i"
- );
-
- // setup allowed and denied tags
- this.tidy.setupAllowed();
-
- // setup denied tags
- if (this.opts.deniedTags !== false) {
- var tags = ["html", "head", "link", "body", "meta", "applet"];
- for (var i = 0; i < tags.length; i++) {
- this.opts.deniedTags.push(tags[i]);
- }
- }
-
- // load lang
- this.lang.load();
-
- // extend shortcuts
- $.extend(this.opts.shortcuts, this.opts.shortcutsAdd);
-
- // start callback
- this.core.setCallback("start");
-
- // build
- this.start = true;
- this.build.run();
- },
-
- loadOptions: function (options) {
- this.opts = $.extend(
- {},
- $.extend(true, {}, $.Redactor.opts),
- this.$element.data(),
- options
- );
- },
- getModuleMethods: function (object) {
- return Object.getOwnPropertyNames(object).filter(function (property) {
- return typeof object[property] == "function";
- });
- },
- loadModules: function () {
- var len = $.Redactor.modules.length;
- for (var i = 0; i < len; i++) {
- this.bindModuleMethods($.Redactor.modules[i]);
- }
- },
- bindModuleMethods: function (module) {
- if (typeof this[module] == "undefined") return;
-
- // init module
- this[module] = this[module]();
-
- var methods = this.getModuleMethods(this[module]);
- var len = methods.length;
-
- // bind methods
- for (var z = 0; z < len; z++) {
- this[module][methods[z]] = this[module][methods[z]].bind(this);
- }
- },
- alignment: function () {
- return {
- left: function () {
- this.alignment.set("");
- },
- right: function () {
- this.alignment.set("right");
- },
- center: function () {
- this.alignment.set("center");
- },
- justify: function () {
- this.alignment.set("justify");
- },
- set: function (type) {
- // focus
- if (!this.utils.browser("msie") && !this.opts.linebreaks) {
- this.$editor.focus();
- }
-
- // get blocks
- this.alignment.blocks = this.selection.getBlocks();
- this.alignment.type = type;
-
- this.buffer.set();
- this.selection.save();
-
- // set alignment
- if (this.alignment.isLinebreaksOrNoBlocks()) {
- this.alignment.setText();
- } else {
- this.alignment.setBlocks();
- }
-
- // sync
- this.selection.restore();
- this.code.sync();
- },
- setText: function () {
- var wrapper = this.selection.wrap("div");
- $(wrapper)
- .attr("data-tagblock", "redactor")
- .css("text-align", this.alignment.type);
- },
- setBlocks: function () {
- $.each(
- this.alignment.blocks,
- $.proxy(function (i, el) {
- var $el = this.utils.getAlignmentElement(el);
- if (!$el) return;
-
- if (this.alignment.isNeedReplaceElement($el)) {
- this.alignment.replaceElement($el);
- } else {
- this.alignment.alignElement($el);
- }
- }, this)
- );
- },
- isLinebreaksOrNoBlocks: function () {
- return this.opts.linebreaks && this.alignment.blocks[0] === false;
- },
- isNeedReplaceElement: function ($el) {
- return (
- this.alignment.type === "" &&
- typeof $el.data("tagblock") !== "undefined"
- );
- },
- replaceElement: function ($el) {
- $el.replaceWith($el.html());
- },
- alignElement: function ($el) {
- $el.css("text-align", this.alignment.type);
- this.utils.removeEmptyAttr($el, "style");
- },
- };
- },
- autosave: function () {
- return {
- html: false,
- enable: function () {
- if (!this.opts.autosave) return;
-
- this.autosave.name = this.opts.autosaveName
- ? this.opts.autosaveName
- : this.$textarea.attr("name");
-
- if (this.opts.autosaveOnChange) return;
- this.autosaveInterval = setInterval(
- this.autosave.load,
- this.opts.autosaveInterval * 1000
- );
- },
- onChange: function () {
- if (!this.opts.autosaveOnChange) return;
- this.autosave.load();
- },
- load: function () {
- if (!this.opts.autosave) return;
-
- this.autosave.source = this.code.get();
-
- if (this.autosave.html === this.autosave.source) return;
-
- // data
- var data = {};
- data["name"] = this.autosave.name;
- data[this.autosave.name] = this.autosave.source;
- data = this.autosave.getHiddenFields(data);
-
- // ajax
- var jsxhr = $.ajax({
- url: this.opts.autosave,
- type: "post",
- data: data,
- });
-
- jsxhr.done(this.autosave.success);
- },
- getHiddenFields: function (data) {
- if (
- this.opts.autosaveFields === false ||
- typeof this.opts.autosaveFields !== "object"
- ) {
- return data;
- }
-
- $.each(
- this.opts.autosaveFields,
- $.proxy(function (k, v) {
- if (v !== null && v.toString().indexOf("#") === 0) v = $(v).val();
- data[k] = v;
- }, this)
- );
-
- return data;
- },
- success: function (data) {
- var json;
- try {
- json = $.parseJSON(data);
- } catch (e) {
- //data has already been parsed
- json = data;
- }
-
- var callbackName =
- typeof json.error == "undefined" ? "autosave" : "autosaveError";
-
- this.core.setCallback(callbackName, this.autosave.name, json);
- this.autosave.html = this.autosave.source;
- },
- disable: function () {
- clearInterval(this.autosaveInterval);
- },
- };
- },
- block: function () {
- return {
- formatting: function (name) {
- this.block.clearStyle = false;
- var type, value;
-
- if (typeof this.formatting[name].data != "undefined") type = "data";
- else if (typeof this.formatting[name].attr != "undefined")
- type = "attr";
- else if (typeof this.formatting[name]["class"] != "undefined")
- type = "class";
-
- if (typeof this.formatting[name].clear != "undefined") {
- this.block.clearStyle = true;
- }
-
- if (type) value = this.formatting[name][type];
-
- this.block.format(this.formatting[name].tag, type, value);
- },
- format: function (tag, type, value) {
- if (tag == "quote") tag = "blockquote";
-
- var formatTags = [
- "p",
- "pre",
- "blockquote",
- "h1",
- "h2",
- "h3",
- "h4",
- "h5",
- "h6",
- ];
- if ($.inArray(tag, formatTags) == -1) return;
-
- this.block.isRemoveInline =
- tag == "pre" || tag.search(/h[1-6]/i) != -1;
-
- // focus
- if (!this.utils.browser("msie")) this.$editor.focus();
-
- var html = $.trim(this.$editor.html());
- this.block.isEmpty = this.utils.isEmpty(html);
-
- // FF focus
- if (this.utils.browser("mozilla") && !this.focus.isFocused()) {
- if (this.block.isEmpty) {
- var $first;
- if (!this.opts.linebreaks) {
- $first = this.$editor.children().first();
- this.caret.setEnd($first);
- }
- }
- }
-
- this.block.blocks = this.selection.getBlocks();
-
- this.block.blocksSize = this.block.blocks.length;
- this.block.type = type;
- this.block.value = value;
-
- this.buffer.set();
- this.selection.save();
-
- this.block.set(tag);
-
- this.selection.restore();
- this.code.sync();
- this.observe.load();
- },
- set: function (tag) {
- this.selection.get();
- this.block.containerTag = this.range.commonAncestorContainer.tagName;
-
- if (this.range.collapsed) {
- this.block.setCollapsed(tag);
- } else {
- this.block.setMultiple(tag);
- }
- },
- setCollapsed: function (tag) {
- if (this.opts.linebreaks && this.block.isEmpty && tag != "p") {
- var node = document.createElement(tag);
- this.$editor.html(node);
- this.caret.setEnd(node);
-
- return;
- }
-
- var block = this.block.blocks[0];
- if (block === false) return;
-
- if (block.tagName == "LI") {
- if (tag != "blockquote") return;
-
- this.block.formatListToBlockquote();
- return;
- }
-
- var isContainerTable =
- this.block.containerTag == "TD" || this.block.containerTag == "TH";
- if (isContainerTable && !this.opts.linebreaks) {
- document.execCommand("formatblock", false, "<" + tag + ">");
-
- block = this.selection.getBlock();
- this.block.toggle($(block));
- } else if (block.tagName.toLowerCase() != tag) {
- if (this.opts.linebreaks && tag == "p") {
- $(block).append("
");
- this.utils.replaceWithContents(block);
- } else {
- var $formatted = this.utils.replaceToTag(block, tag);
-
- this.block.toggle($formatted);
-
- if (tag != "p" && tag != "blockquote")
- $formatted.find("img").remove();
- if (this.block.isRemoveInline)
- this.utils.removeInlineTags($formatted);
- if (tag == "p" || this.block.headTag)
- $formatted.find("p").contents().unwrap();
-
- this.block.formatTableWrapping($formatted);
- }
- } else if (
- tag == "blockquote" &&
- block.tagName.toLowerCase() == tag
- ) {
- // blockquote off
- if (this.opts.linebreaks) {
- $(block).append("
");
- this.utils.replaceWithContents(block);
- } else {
- var $el = this.utils.replaceToTag(block, "p");
- this.block.toggle($el);
- }
- } else if (block.tagName.toLowerCase() == tag) {
- this.block.toggle($(block));
- }
-
- if (
- typeof this.block.type == "undefined" &&
- typeof this.block.value == "undefined"
- ) {
- $(block).removeAttr("class").removeAttr("style");
- }
- },
- setMultiple: function (tag) {
- var block = this.block.blocks[0];
-
- var isContainerTable =
- this.block.containerTag == "TD" || this.block.containerTag == "TH";
-
- if (block !== false && this.block.blocksSize === 1) {
- if (block.tagName.toLowerCase() == tag && tag == "blockquote") {
- // blockquote off
- if (this.opts.linebreaks) {
- $(block).append("
");
- this.utils.replaceWithContents(block);
- } else {
- var $el = this.utils.replaceToTag(block, "p");
- this.block.toggle($el);
- }
- } else if (block.tagName == "LI") {
- if (tag != "blockquote") return;
-
- this.block.formatListToBlockquote();
- } else if (this.block.containerTag == "BLOCKQUOTE") {
- this.block.formatBlockquote(tag);
- } else if (
- this.opts.linebreaks &&
- (isContainerTable || this.range.commonAncestorContainer != block)
- ) {
- this.block.formatWrap(tag);
- } else {
- if (this.opts.linebreaks && tag == "p") {
- $(block).prepend("
").append("
");
- this.utils.replaceWithContents(block);
- } else if (block.tagName === "TD") {
- this.block.formatWrap(tag);
- } else {
- var $formatted = this.utils.replaceToTag(block, tag);
-
- this.block.toggle($formatted);
-
- if (this.block.isRemoveInline)
- this.utils.removeInlineTags($formatted);
- if (tag == "p" || this.block.headTag)
- $formatted.find("p").contents().unwrap();
- }
- }
- } else {
- if (this.opts.linebreaks || tag != "p") {
- if (tag == "blockquote") {
- var count = 0;
- for (var i = 0; i < this.block.blocksSize; i++) {
- if (this.block.blocks[i].tagName == "BLOCKQUOTE") count++;
- }
-
- // only blockquote selected
- if (count == this.block.blocksSize) {
- $.each(
- this.block.blocks,
- $.proxy(function (i, s) {
- var $formatted = false;
- if (this.opts.linebreaks) {
- $(s).prepend("
").append("
");
- $formatted = this.utils.replaceWithContents(s);
- } else {
- $formatted = this.utils.replaceToTag(s, "p");
- }
-
- if (
- $formatted &&
- typeof this.block.type == "undefined" &&
- typeof this.block.value == "undefined"
- ) {
- $formatted.removeAttr("class").removeAttr("style");
- }
- }, this)
- );
-
- return;
- }
- }
-
- this.block.formatWrap(tag);
- } else {
- var classSize = 0;
- var toggleType = false;
- if (this.block.type == "class") {
- toggleType = "toggle";
- classSize = $(this.block.blocks).filter(
- "." + this.block.value
- ).length;
-
- if (this.block.blocksSize == classSize) toggleType = "toggle";
- else if (this.block.blocksSize > classSize) toggleType = "set";
- else if (classSize === 0) toggleType = "set";
- }
-
- var exceptTags = ["ul", "ol", "li", "td", "th", "dl", "dt", "dd"];
- $.each(
- this.block.blocks,
- $.proxy(function (i, s) {
- if ($.inArray(s.tagName.toLowerCase(), exceptTags) != -1)
- return;
-
- var $formatted = this.utils.replaceToTag(s, tag);
-
- if (toggleType) {
- if (toggleType == "toggle") this.block.toggle($formatted);
- else if (toggleType == "remove")
- this.block.remove($formatted);
- else if (toggleType == "set")
- this.block.setForce($formatted);
- } else this.block.toggle($formatted);
-
- if (tag != "p" && tag != "blockquote")
- $formatted.find("img").remove();
- if (this.block.isRemoveInline)
- this.utils.removeInlineTags($formatted);
- if (tag == "p" || this.block.headTag)
- $formatted.find("p").contents().unwrap();
-
- if (
- typeof this.block.type == "undefined" &&
- typeof this.block.value == "undefined"
- ) {
- $formatted.removeAttr("class").removeAttr("style");
- }
- }, this)
- );
- }
- }
- },
- setForce: function ($el) {
- // remove style and class if the specified setting
- if (this.block.clearStyle) {
- $el.removeAttr("class").removeAttr("style");
- }
-
- if (this.block.type == "class") {
- $el.addClass(this.block.value);
- return;
- } else if (this.block.type == "attr" || this.block.type == "data") {
- $el.attr(this.block.value.name, this.block.value.value);
- return;
- }
- },
- toggle: function ($el) {
- // remove style and class if the specified setting
- if (this.block.clearStyle) {
- $el.removeAttr("class").removeAttr("style");
- }
-
- if (this.block.type == "class") {
- $el.toggleClass(this.block.value);
- return;
- } else if (this.block.type == "attr" || this.block.type == "data") {
- if ($el.attr(this.block.value.name) == this.block.value.value) {
- $el.removeAttr(this.block.value.name);
- } else {
- $el.attr(this.block.value.name, this.block.value.value);
- }
-
- return;
- } else {
- $el.removeAttr("style class");
- return;
- }
- },
- remove: function ($el) {
- $el.removeClass(this.block.value);
- },
- formatListToBlockquote: function () {
- var block = $(this.block.blocks[0]).closest(
- "ul, ol",
- this.$editor[0]
- );
-
- $(block).find("ul, ol").contents().unwrap();
- $(block).find("li").append($("
")).contents().unwrap();
-
- var $el = this.utils.replaceToTag(block, "blockquote");
- this.block.toggle($el);
- },
- formatBlockquote: function (tag) {
- document.execCommand("outdent");
- document.execCommand("formatblock", false, tag);
-
- this.clean.clearUnverified();
- this.$editor.find("p:empty").remove();
-
- var formatted = this.selection.getBlock();
-
- if (tag != "p") {
- $(formatted).find("img").remove();
- }
-
- if (!this.opts.linebreaks) {
- this.block.toggle($(formatted));
- }
-
- this.$editor
- .find("ul, ol, tr, blockquote, p")
- .each($.proxy(this.utils.removeEmpty, this));
-
- if (this.opts.linebreaks && tag == "p") {
- this.utils.replaceWithContents(formatted);
- }
- },
- formatWrap: function (tag) {
- if (
- this.block.containerTag == "UL" ||
- this.block.containerTag == "OL"
- ) {
- if (tag == "blockquote") {
- this.block.formatListToBlockquote();
- } else {
- return;
- }
- }
-
- var formatted = this.selection.wrap(tag);
- if (formatted === false) return;
-
- var $formatted = $(formatted);
-
- this.block.formatTableWrapping($formatted);
-
- var $elements = $formatted.find(
- this.opts.blockLevelElements.join(",") +
- ", td, table, thead, tbody, tfoot, th, tr"
- );
-
- $elements.contents().unwrap();
-
- if (tag != "p" && tag != "blockquote")
- $formatted.find("img").remove();
-
- $.each(this.block.blocks, $.proxy(this.utils.removeEmpty, this));
-
- $formatted.append(this.selection.getMarker(2));
-
- if (!this.opts.linebreaks) {
- this.block.toggle($formatted);
- }
-
- this.$editor
- .find("ul, ol, tr, blockquote, p")
- .each($.proxy(this.utils.removeEmpty, this));
- $formatted.find("blockquote:empty").remove();
-
- if (this.block.isRemoveInline) {
- this.utils.removeInlineTags($formatted);
- }
-
- if (this.opts.linebreaks && tag == "p") {
- this.utils.replaceWithContents($formatted);
- }
-
- if (this.opts.linebreaks) {
- var $next = $formatted.next().next();
- if ($next.size() != 0 && $next[0].tagName === "BR") {
- $next.remove();
- }
- }
- },
- formatTableWrapping: function ($formatted) {
- if ($formatted.closest("table", this.$editor[0]).length === 0) return;
-
- if ($formatted.closest("tr", this.$editor[0]).length === 0)
- $formatted.wrap("");
- if (
- $formatted.closest("td", this.$editor[0]).length === 0 &&
- $formatted.closest("th").length === 0
- ) {
- $formatted.wrap("");
- }
- },
- removeData: function (name, value) {
- var blocks = this.selection.getBlocks();
- $(blocks).removeAttr("data-" + name);
-
- this.code.sync();
- },
- setData: function (name, value) {
- var blocks = this.selection.getBlocks();
- $(blocks).attr("data-" + name, value);
-
- this.code.sync();
- },
- toggleData: function (name, value) {
- var blocks = this.selection.getBlocks();
- $.each(blocks, function () {
- if ($(this).attr("data-" + name)) {
- $(this).removeAttr("data-" + name);
- } else {
- $(this).attr("data-" + name, value);
- }
- });
- },
- removeAttr: function (attr, value) {
- var blocks = this.selection.getBlocks();
- $(blocks).removeAttr(attr);
-
- this.code.sync();
- },
- setAttr: function (attr, value) {
- var blocks = this.selection.getBlocks();
- $(blocks).attr(attr, value);
-
- this.code.sync();
- },
- toggleAttr: function (attr, value) {
- var blocks = this.selection.getBlocks();
- $.each(blocks, function () {
- if ($(this).attr(name)) {
- $(this).removeAttr(name);
- } else {
- $(this).attr(name, value);
- }
- });
- },
- removeClass: function (className) {
- var blocks = this.selection.getBlocks();
- $(blocks).removeClass(className);
-
- this.utils.removeEmptyAttr(blocks, "class");
-
- this.code.sync();
- },
- setClass: function (className) {
- var blocks = this.selection.getBlocks();
- $(blocks).addClass(className);
-
- this.code.sync();
- },
- toggleClass: function (className) {
- var blocks = this.selection.getBlocks();
- $(blocks).toggleClass(className);
-
- this.code.sync();
- },
- };
- },
- buffer: function () {
- return {
- set: function (type) {
- if (typeof type == "undefined" || type == "undo") {
- this.buffer.setUndo();
- } else {
- this.buffer.setRedo();
- }
- },
- setUndo: function () {
- this.selection.save();
- this.opts.buffer.push(this.$editor.html());
- this.selection.restore();
- },
- setRedo: function () {
- this.selection.save();
- this.opts.rebuffer.push(this.$editor.html());
- this.selection.restore();
- },
- getUndo: function () {
- this.$editor.html(this.opts.buffer.pop());
- },
- getRedo: function () {
- this.$editor.html(this.opts.rebuffer.pop());
- },
- add: function () {
- this.opts.buffer.push(this.$editor.html());
- },
- undo: function () {
- if (this.opts.buffer.length === 0) return;
-
- this.buffer.set("redo");
- this.buffer.getUndo();
-
- this.selection.restore();
-
- setTimeout($.proxy(this.observe.load, this), 50);
- },
- redo: function () {
- if (this.opts.rebuffer.length === 0) return;
-
- this.buffer.set("undo");
- this.buffer.getRedo();
-
- this.selection.restore();
-
- setTimeout($.proxy(this.observe.load, this), 50);
- },
- };
- },
- build: function () {
- return {
- focused: false,
- blured: true,
- run: function () {
- this.build.createContainerBox();
- this.build.loadContent();
- this.build.loadEditor();
- this.build.enableEditor();
- this.build.setCodeAndCall();
- },
- isTextarea: function () {
- return this.$element[0].tagName === "TEXTAREA";
- },
- createContainerBox: function () {
- this.$box = $('');
- },
- createTextarea: function () {
- this.$textarea = $("").attr(
- "name",
- this.build.getTextareaName()
- );
- },
- getTextareaName: function () {
- return typeof name == "undefined"
- ? "content-" + this.uuid
- : this.$element.attr("id");
- },
- loadContent: function () {
- var func = this.build.isTextarea() ? "val" : "html";
- this.content = $.trim(this.$element[func]());
- },
- enableEditor: function () {
- this.$editor.attr({
- contenteditable: true,
- dir: this.opts.direction,
- });
- },
- loadEditor: function () {
- var func = this.build.isTextarea() ? "fromTextarea" : "fromElement";
- this.build[func]();
- },
- fromTextarea: function () {
- this.$editor = $("");
- this.$textarea = this.$element;
- this.$box
- .insertAfter(this.$element)
- .append(this.$editor)
- .append(this.$element);
- this.$editor.addClass("redactor-editor");
-
- this.$element.hide();
- },
- fromElement: function () {
- this.$editor = this.$element;
- this.build.createTextarea();
- this.$box
- .insertAfter(this.$editor)
- .append(this.$editor)
- .append(this.$textarea);
- this.$editor.addClass("redactor-editor");
-
- this.$textarea.hide();
- },
- setCodeAndCall: function () {
- // set code
- this.code.set(this.content);
-
- this.build.setOptions();
- this.build.callEditor();
-
- // code mode
- if (this.opts.visual) return;
- setTimeout($.proxy(this.code.showCode, this), 200);
- },
- callEditor: function () {
- this.build.disableMozillaEditing();
- this.build.disableIeLinks();
- this.build.setEvents();
- this.build.setHelpers();
-
- // load toolbar
- if (this.opts.toolbar) {
- this.opts.toolbar = this.toolbar.init();
- this.toolbar.build();
- }
-
- // modal templates init
- this.modal.loadTemplates();
-
- // plugins
- this.build.plugins();
-
- // observers
- setTimeout($.proxy(this.observe.load, this), 4);
-
- // init callback
- this.core.setCallback("init");
- },
- setOptions: function () {
- // textarea direction
- $(this.$textarea).attr("dir", this.opts.direction);
-
- if (this.opts.linebreaks)
- this.$editor.addClass("redactor-linebreaks");
-
- if (this.opts.tabindex)
- this.$editor.attr("tabindex", this.opts.tabindex);
-
- if (this.opts.minHeight)
- this.$editor.css("minHeight", this.opts.minHeight);
- if (this.opts.maxHeight)
- this.$editor.css("maxHeight", this.opts.maxHeight);
- },
- setEventDropUpload: function (e) {
- e.preventDefault();
-
- if (!this.opts.dragImageUpload && !this.opts.dragFileUpload) return;
- if (this.opts.imageUpload === null && this.opts.fileUpload === null)
- return;
-
- var files = e.dataTransfer.files;
- this.upload.directUpload(files[0], e);
- },
- setEventDrop: function (e) {
- // COMFY FIX
- // Adding ability to drag-n-drop file links
- var text = e.dataTransfer.getData("text/plain");
- if (text) this.insert.html(text, false);
- // END COMFY FIX
-
- this.code.sync();
- setTimeout(this.clean.clearUnverified, 1);
- this.core.setCallback("drop", e);
- },
- setEvents: function () {
- // drop
- this.$editor.on("dragover.redactor dragenter.redactor", function (e) {
- e.preventDefault();
- e.stopPropagation();
- });
-
- this.$editor.on(
- "drop.redactor",
- $.proxy(function (e) {
- e = e.originalEvent || e;
-
- if (window.FormData === undefined || !e.dataTransfer) return true;
-
- if (e.dataTransfer.files.length === 0) {
- return this.build.setEventDrop(e);
- } else {
- this.build.setEventDropUpload(e);
- }
-
- setTimeout(this.clean.clearUnverified, 1);
- this.core.setCallback("drop", e);
- }, this)
- );
-
- // click
- this.$editor.on(
- "click.redactor",
- $.proxy(function (e) {
- var event = this.core.getEvent();
- var type = event == "click" || event == "arrow" ? false : "click";
-
- this.core.addEvent(type);
- this.utils.disableSelectAll();
- this.core.setCallback("click", e);
- }, this)
- );
-
- // paste
- this.$editor.on("paste.redactor", $.proxy(this.paste.init, this));
-
- // cut
- this.$editor.on("cut.redactor", $.proxy(this.code.sync, this));
-
- // keydown
- this.$editor.on("keydown.redactor", $.proxy(this.keydown.init, this));
-
- // keyup
- this.$editor.on("keyup.redactor", $.proxy(this.keyup.init, this));
-
- // textarea keydown
- if ($.isFunction(this.opts.codeKeydownCallback)) {
- this.$textarea.on(
- "keydown.redactor-textarea",
- $.proxy(this.opts.codeKeydownCallback, this)
- );
- }
-
- // textarea keyup
- if ($.isFunction(this.opts.codeKeyupCallback)) {
- this.$textarea.on(
- "keyup.redactor-textarea",
- $.proxy(this.opts.codeKeyupCallback, this)
- );
- }
-
- // focus
- this.$editor.on(
- "focus.redactor",
- $.proxy(function (e) {
- if ($.isFunction(this.opts.focusCallback)) {
- this.core.setCallback("focus", e);
- }
-
- this.build.focused = true;
- this.build.blured = false;
-
- if (this.selection.getCurrent() === false) {
- this.selection.get();
- this.range.setStart(this.$editor[0], 0);
- this.range.setEnd(this.$editor[0], 0);
- this.selection.addRange();
- }
- }, this)
- );
-
- // blur
- $(document).on(
- "mousedown.redactor-blur." + this.uuid,
- $.proxy(function (e) {
- if (this.start) return;
- if (this.rtePaste) return;
-
- if (
- $(e.target).closest(
- ".redactor-editor, .redactor-toolbar, .redactor-dropdown"
- ).length !== 0
- ) {
- return;
- }
-
- this.utils.disableSelectAll();
- if (!this.build.blured && $.isFunction(this.opts.blurCallback)) {
- this.core.setCallback("blur", e);
- }
-
- this.build.focused = false;
- this.build.blured = true;
- }, this)
- );
- },
- setHelpers: function () {
- // linkify
- if (this.linkify.isEnabled()) {
- this.linkify.format();
- }
-
- // placeholder
- this.placeholder.enable();
-
- // focus
- if (this.opts.focus) setTimeout(this.focus.setStart, 100);
- if (this.opts.focusEnd) setTimeout(this.focus.setEnd, 100);
- },
- plugins: function () {
- if (!this.opts.plugins) return;
-
- $.each(
- this.opts.plugins,
- $.proxy(function (i, s) {
- var func =
- typeof RedactorPlugins !== "undefined" &&
- typeof RedactorPlugins[s] !== "undefined"
- ? RedactorPlugins
- : Redactor.fn;
-
- if (!$.isFunction(func[s])) {
- return;
- }
-
- this[s] = func[s]();
-
- // get methods
- var methods = this.getModuleMethods(this[s]);
- var len = methods.length;
-
- // bind methods
- for (var z = 0; z < len; z++) {
- this[s][methods[z]] = this[s][methods[z]].bind(this);
- }
-
- if ($.isFunction(this[s].init)) {
- this[s].init();
- }
- }, this)
- );
- },
- disableMozillaEditing: function () {
- if (!this.utils.browser("mozilla")) return;
-
- // FF fix
- try {
- document.execCommand("enableObjectResizing", false, false);
- document.execCommand("enableInlineTableEditing", false, false);
- } catch (e) {}
- },
- disableIeLinks: function () {
- if (!this.utils.browser("msie")) return;
-
- // IE prevent converting links
- document.execCommand("AutoUrlDetect", false, false);
- },
- };
- },
- button: function () {
- return {
- build: function (btnName, btnObject) {
- var $button = $(
- ''
- ).attr({
- role: "button",
- "aria-label": btnObject.title,
- tabindex: "-1",
- });
-
- // click
- if (btnObject.func || btnObject.command || btnObject.dropdown) {
- this.button.setEvent($button, btnName, btnObject);
- }
-
- // dropdown
- if (btnObject.dropdown) {
- $button
- .addClass("redactor-toolbar-link-dropdown")
- .attr("aria-haspopup", true);
-
- var $dropdown = $(
- ''
- );
- $button.data("dropdown", $dropdown);
- this.dropdown.build(btnName, $dropdown, btnObject.dropdown);
- }
-
- // tooltip
- if (this.utils.isDesktop()) {
- this.button.createTooltip($button, btnName, btnObject.title);
- }
-
- return $button;
- },
- setEvent: function ($button, btnName, btnObject) {
- $button.on(
- "touchstart click",
- $.proxy(function (e) {
- if ($button.hasClass("redactor-button-disabled")) return false;
-
- var type = "func";
- var callback = btnObject.func;
-
- if (btnObject.command) {
- type = "command";
- callback = btnObject.command;
- } else if (btnObject.dropdown) {
- type = "dropdown";
- callback = false;
- }
-
- this.button.onClick(e, btnName, type, callback);
- }, this)
- );
- },
- createTooltip: function ($button, name, title) {
- var $tooltip = $(" ")
- .addClass(
- "redactor-toolbar-tooltip redactor-toolbar-tooltip-" +
- this.uuid +
- " redactor-toolbar-tooltip-" +
- name
- )
- .hide()
- .html(title);
- $tooltip.appendTo("body");
-
- $button.on("mouseover", function () {
- if ($(this).hasClass("redactor-button-disabled")) {
- return;
- }
-
- var pos = $button.offset();
-
- $tooltip.css({
- top: pos.top + $button.innerHeight() + "px",
- left:
- pos.left +
- $button.innerWidth() / 2 -
- $tooltip.innerWidth() / 2 +
- "px",
- });
- $tooltip.show();
- });
-
- $button.on("mouseout", function () {
- $tooltip.hide();
- });
- },
- onClick: function (e, btnName, type, callback) {
- this.button.caretOffset = this.caret.getOffset();
-
- e.preventDefault();
-
- $(document).find(".redactor-toolbar-tooltip").hide();
-
- if (this.utils.browser("msie")) e.returnValue = false;
-
- if (type == "command") this.inline.format(callback);
- else if (type == "dropdown") this.dropdown.show(e, btnName);
- else this.button.onClickCallback(e, callback, btnName);
- },
- onClickCallback: function (e, callback, btnName) {
- var func;
-
- if ($.isFunction(callback)) callback.call(this, btnName);
- else if (callback.search(/\./) != "-1") {
- func = callback.split(".");
- if (typeof this[func[0]] == "undefined") return;
-
- this[func[0]][func[1]](btnName);
- } else this[callback](btnName);
-
- this.observe.buttons(e, btnName);
- },
- get: function (key) {
- return this.$toolbar.find("a.re-" + key);
- },
- setActive: function (key) {
- this.button.get(key).addClass("redactor-act");
- },
- setInactive: function (key) {
- this.button.get(key).removeClass("redactor-act");
- },
- setInactiveAll: function (key) {
- if (typeof key === "undefined") {
- this.$toolbar.find("a.re-icon").removeClass("redactor-act");
- } else {
- this.$toolbar
- .find("a.re-icon")
- .not(".re-" + key)
- .removeClass("redactor-act");
- }
- },
- setActiveInVisual: function () {
- this.$toolbar
- .find("a.re-icon")
- .not("a.re-html, a.re-fullscreen")
- .removeClass("redactor-button-disabled");
- },
- setInactiveInCode: function () {
- this.$toolbar
- .find("a.re-icon")
- .not("a.re-html, a.re-fullscreen")
- .addClass("redactor-button-disabled");
- },
- changeIcon: function (key, classname) {
- this.button.get(key).addClass("re-" + classname);
- },
- removeIcon: function (key, classname) {
- this.button.get(key).removeClass("re-" + classname);
- },
- setAwesome: function (key, name) {
- var $button = this.button.get(key);
- $button.removeClass("redactor-btn-image").addClass("fa-redactor-btn");
- $button.html('');
- },
- addCallback: function ($btn, callback) {
- if ($btn == "buffer") return;
-
- var type = callback == "dropdown" ? "dropdown" : "func";
- var key = $btn.attr("rel");
- $btn.on(
- "touchstart click",
- $.proxy(function (e) {
- if ($btn.hasClass("redactor-button-disabled")) return false;
- this.button.onClick(e, key, type, callback);
- }, this)
- );
- },
- addDropdown: function ($btn, dropdown) {
- $btn
- .addClass("redactor-toolbar-link-dropdown")
- .attr("aria-haspopup", true);
-
- var key = $btn.attr("rel");
- this.button.addCallback($btn, "dropdown");
-
- var $dropdown = $(
- ''
- );
- $btn.data("dropdown", $dropdown);
-
- // build dropdown
- if (dropdown) this.dropdown.build(key, $dropdown, dropdown);
-
- return $dropdown;
- },
- add: function (key, title) {
- if (!this.opts.toolbar) return;
-
- if (this.button.isMobileUndoRedo(key)) return "buffer";
-
- var btn = this.button.build(key, { title: title });
- btn.addClass("redactor-btn-image");
-
- this.$toolbar.append($(" ").append(btn));
-
- return btn;
- },
- addFirst: function (key, title) {
- if (!this.opts.toolbar) return;
-
- if (this.button.isMobileUndoRedo(key)) return "buffer";
-
- var btn = this.button.build(key, { title: title });
- btn.addClass("redactor-btn-image");
- this.$toolbar.prepend($("").append(btn));
-
- return btn;
- },
- addAfter: function (afterkey, key, title) {
- if (!this.opts.toolbar) return;
-
- if (this.button.isMobileUndoRedo(key)) return "buffer";
-
- var btn = this.button.build(key, { title: title });
- btn.addClass("redactor-btn-image");
- var $btn = this.button.get(afterkey);
-
- if ($btn.length !== 0) $btn.parent().after($("").append(btn));
- else this.$toolbar.append($("").append(btn));
-
- return btn;
- },
- addBefore: function (beforekey, key, title) {
- if (!this.opts.toolbar) return;
-
- if (this.button.isMobileUndoRedo(key)) return "buffer";
-
- var btn = this.button.build(key, { title: title });
- btn.addClass("redactor-btn-image");
- var $btn = this.button.get(beforekey);
-
- if ($btn.length !== 0) $btn.parent().before($("").append(btn));
- else this.$toolbar.append($("").append(btn));
-
- return btn;
- },
- remove: function (key) {
- this.button.get(key).remove();
- },
- isMobileUndoRedo: function (key) {
- return (key == "undo" || key == "redo") && !this.utils.isDesktop();
- },
- };
- },
- caret: function () {
- return {
- setStart: function (node) {
- // inline tag
- if (!this.utils.isBlock(node)) {
- var space = this.utils.createSpaceElement();
-
- $(node).prepend(space);
- this.caret.setEnd(space);
- } else {
- this.caret.set(node, 0, node, 0);
- }
- },
- setEnd: function (node) {
- node = node[0] || node;
- if (node.lastChild.nodeType == 1) {
- return this.caret.setAfter(node.lastChild);
- }
-
- this.caret.set(node, 1, node, 1);
- },
- set: function (orgn, orgo, focn, foco) {
- // focus
- // disabled in 10.0.7
- // if (!this.utils.browser('msie')) this.$editor.focus();
-
- orgn = orgn[0] || orgn;
- focn = focn[0] || focn;
-
- if (this.utils.isBlockTag(orgn.tagName) && orgn.innerHTML === "") {
- orgn.innerHTML = this.opts.invisibleSpace;
- }
-
- if (orgn.tagName == "BR" && this.opts.linebreaks === false) {
- var parent = $(this.opts.emptyHtml)[0];
- $(orgn).replaceWith(parent);
- orgn = parent;
- focn = orgn;
- }
-
- this.selection.get();
-
- try {
- this.range.setStart(orgn, orgo);
- this.range.setEnd(focn, foco);
- } catch (e) {}
-
- this.selection.addRange();
- },
- setAfter: function (node) {
- try {
- var tag = $(node)[0].tagName;
-
- // inline tag
- if (tag != "BR" && !this.utils.isBlock(node)) {
- var space = this.utils.createSpaceElement();
-
- $(node).after(space);
- this.caret.setEnd(space);
- } else {
- if (tag != "BR" && this.utils.browser("msie")) {
- this.caret.setStart($(node).next());
- } else {
- this.caret.setAfterOrBefore(node, "after");
- }
- }
- } catch (e) {
- var space = this.utils.createSpaceElement();
- $(node).after(space);
- this.caret.setEnd(space);
- }
- },
- setBefore: function (node) {
- // block tag
- if (this.utils.isBlock(node)) {
- this.caret.setEnd($(node).prev());
- } else {
- this.caret.setAfterOrBefore(node, "before");
- }
- },
- setAfterOrBefore: function (node, type) {
- // focus
- if (!this.utils.browser("msie")) this.$editor.focus();
-
- node = node[0] || node;
-
- this.selection.get();
-
- if (type == "after") {
- try {
- this.range.setStartAfter(node);
- this.range.setEndAfter(node);
- } catch (e) {}
- } else {
- try {
- this.range.setStartBefore(node);
- this.range.setEndBefore(node);
- } catch (e) {}
- }
-
- this.range.collapse(false);
- this.selection.addRange();
- },
- getOffsetOfElement: function (node) {
- node = node[0] || node;
-
- this.selection.get();
-
- var cloned = this.range.cloneRange();
- cloned.selectNodeContents(node);
- cloned.setEnd(this.range.endContainer, this.range.endOffset);
-
- return $.trim(cloned.toString()).length;
- },
- getOffset: function () {
- var offset = 0;
- var sel = window.getSelection();
-
- if (sel.rangeCount > 0) {
- var range = window.getSelection().getRangeAt(0);
- var caretRange = range.cloneRange();
- caretRange.selectNodeContents(this.$editor[0]);
- caretRange.setEnd(range.endContainer, range.endOffset);
- offset = caretRange.toString().length;
- }
-
- return offset;
- },
- setOffset: function (start, end) {
- if (typeof end == "undefined") end = start;
- if (!this.focus.isFocused()) this.focus.setStart();
-
- var sel = this.selection.get();
- var node,
- offset = 0;
- var walker = document.createTreeWalker(
- this.$editor[0],
- NodeFilter.SHOW_TEXT,
- null,
- null
- );
-
- while ((node = walker.nextNode())) {
- offset += node.nodeValue.length;
- if (offset > start) {
- this.range.setStart(node, node.nodeValue.length + start - offset);
- start = Infinity;
- }
-
- if (offset >= end) {
- this.range.setEnd(node, node.nodeValue.length + end - offset);
- break;
- }
- }
-
- this.range.collapse(false);
- this.selection.addRange();
- },
- // deprecated
- setToPoint: function (start, end) {
- this.caret.setOffset(start, end);
- },
- getCoords: function () {
- return this.caret.getOffset();
- },
- };
- },
- clean: function () {
- return {
- onSet: function (html) {
- html = this.clean.savePreCode(html);
-
- // convert script tag
- html = html.replace(
- /"
- );
-
- // restore form tag
- html = this.clean.restoreFormTags(html);
-
- var chars = {
- "\u2122": "™",
- "\u00a9": "©",
- "\u2026": "…",
- "\u2014": "—",
- "\u2010": "‐",
- };
- // replace special characters
- $.each(chars, function (i, s) {
- html = html.replace(new RegExp(i, "g"), s);
- });
-
- // remove last br in FF
- if (this.utils.browser("mozilla")) {
- html = html.replace(/ $/gi, "");
- }
-
- // remove br in|of li tags
- html = html.replace(new RegExp("
", "gi"), "");
- html = html.replace(new RegExp(" ", "gi"), "");
-
- // remove empty attributes
- html = html.replace(/<(.*?)rel="\s*?"(.*?[^>]?)>/gi, '<$1$2">');
- html = html.replace(/<(.*?)style="\s*?"(.*?[^>]?)>/gi, '<$1$2">');
- html = html.replace(/="">/gi, ">");
- html = html.replace(/""">/gi, '">');
- html = html.replace(/"">/gi, '">');
-
- // remove verified
- html = html.replace(
- / ])>/gi,
- " "
- );
- html = html.replace(
- /<(.*?) data-verified="redactor"(.*?[^>])>/gi,
- "<$1$2>"
- );
-
- var $div = $(" ").html($.parseHTML(html, document, true));
- $div.find("span").removeAttr("rel");
-
- $div.find("pre .redactor-invisible-space").each(function () {
- $(this).contents().unwrap();
- });
-
- html = $div.html();
-
- // remove rel attribute from img
- html = html.replace(
- / ])rel="(.*?[^>])"(.*?[^>])>/gi,
- " "
- );
- html = html.replace(
- / (.*?)<\/span>/gi,
- "$1"
- );
-
- html = html.replace(/ data-save-url="(.*?[^>])"/gi, "");
-
- // remove image resize
- html = html.replace(
- /])>([\w\W]*?)<\/span>/gi,
- "$3"
- );
- html = html.replace(
- /])>(.*?)<\/span>/gi,
- ""
- );
- html = html.replace(
- /])>(.*?)<\/span>/gi,
- ""
- );
-
- // remove font tag
- html = html.replace(//gi, "");
- html = html.replace(/<\/font>/gi, "");
-
- // tidy html
- html = this.tidy.load(html);
-
- // link nofollow
- if (this.opts.linkNofollow) {
- html = html.replace(/])>/gi, "");
- html = html.replace(/])>/gi, '');
- }
-
- // reconvert inline
- html = html.replace(
- /\sdata-redactor-(tag|class|style)="(.*?[^>])"/gi,
- ""
- );
- html = html.replace(
- new RegExp('<(.*?) data-verified="redactor"(.*?[^>])>', "gi"),
- "<$1$2>"
- );
- html = html.replace(
- new RegExp('<(.*?) data-verified="redactor">', "gi"),
- "<$1>"
- );
-
- html = html.replace(/&/g, "&");
-
- return html;
- },
- onPaste: function (html, setMode) {
- html = $.trim(html);
- html = html.replace(/\$/g, "$");
-
- // convert dirty spaces
- html = html.replace(//gi, "");
- html = html.replace(
- / <\/span>/gi,
- " "
- );
- html = html.replace(
- /]*>\t<\/span>/gi,
- "\t"
- );
- html = html.replace(/]*>(\s| )<\/span>/gi, " ");
-
- if (this.opts.pastePlainText) {
- return this.clean.getPlainText(html);
- }
-
- if (!this.utils.isSelectAll() && typeof setMode == "undefined") {
- if (this.utils.isCurrentOrParent(["FIGCAPTION", "A"])) {
- return this.clean.getPlainText(html, false);
- }
-
- if (this.utils.isCurrentOrParent("PRE")) {
- html = html.replace(/”/g, '"');
- html = html.replace(/“/g, '"');
- html = html.replace(/‘/g, "'");
- html = html.replace(/’/g, "'");
-
- return this.clean.getPreCode(html);
- }
-
- if (
- this.utils.isCurrentOrParent([
- "BLOCKQUOTE",
- "H1",
- "H2",
- "H3",
- "H4",
- "H5",
- "H6",
- ])
- ) {
- html = this.clean.getOnlyImages(html);
-
- if (!this.utils.browser("msie")) {
- var block = this.selection.getBlock();
- if (block && block.tagName == "P") {
- html = html.replace(//gi, "");
- }
- }
-
- return html;
- }
-
- if (this.utils.isCurrentOrParent(["TD"])) {
- html = this.clean.onPasteTidy(html, "td");
-
- if (this.opts.linebreaks)
- html = this.clean.replaceParagraphsToBr(html);
-
- html = this.clean.replaceDivsToBr(html);
-
- return html;
- }
-
- if (this.utils.isCurrentOrParent(["LI"])) {
- return this.clean.onPasteTidy(html, "li");
- }
- }
-
- html = this.clean.isSingleLine(html, setMode);
-
- if (!this.clean.singleLine) {
- if (this.opts.linebreaks)
- html = this.clean.replaceParagraphsToBr(html);
- if (this.opts.replaceDivs) html = this.clean.replaceDivs(html);
-
- html = this.clean.saveFormTags(html);
- }
-
- html = this.clean.onPasteWord(html);
- html = this.clean.onPasteExtra(html);
-
- html = this.clean.onPasteTidy(html, "all");
-
- // paragraphize
- if (!this.clean.singleLine && this.opts.paragraphize) {
- html = this.paragraphize.load(html);
- }
-
- html = this.clean.removeDirtyStyles(html);
- html = this.clean.onPasteRemoveSpans(html);
- html = this.clean.onPasteRemoveEmpty(html);
-
- html = this.clean.convertInline(html);
-
- return html;
- },
- onPasteWord: function (html) {
- // comments
- html = html.replace(//gi, "");
-
- // style
- html = html.replace(/ |