/** * rmFormat plugin * * Depends on jWYSIWYG */ (function ($) { if (undefined === $.wysiwyg) { throw "wysiwyg.rmFormat.js depends on $.wysiwyg"; } /* * Wysiwyg namespace: public properties and methods */ var rmFormat = { name: "rmFormat", version: "", defaults: { rules: { heading: false, table: false, /* * rmAttr - { "all" | object with names } remove all * attributes or attributes with following names * * rmWhenEmpty - if element contains no text or { \s, \n,
,
} * then it will be removed * * rmWhenNoAttr - if element contains no attributes (i.e. Some Text) * then it will be removed */ msWordMarkup: { enabled: false, tags: { "a": { rmWhenEmpty: true }, "b": { rmWhenEmpty: true }, "div": { rmWhenEmpty: true, rmWhenNoAttr: true }, "em": { rmWhenEmpty: true }, "font": { rmAttr: { "face": "", "size": "" }, rmWhenEmpty: true, rmWhenNoAttr: true }, "h1": { rmAttr: "all", rmWhenEmpty: true }, "h2": { rmAttr: "all", rmWhenEmpty: true }, "h3": { rmAttr: "all", rmWhenEmpty: true }, "h4": { rmAttr: "all", rmWhenEmpty: true }, "h5": { rmAttr: "all", rmWhenEmpty: true }, "h6": { rmAttr: "all", rmWhenEmpty: true }, "i": { rmWhenEmpty: true }, "p": { rmAttr: "all", rmWhenEmpty: true }, "span": { rmAttr: { lang: "" }, rmWhenEmpty: true, rmWhenNoAttr: true }, "strong": { rmWhenEmpty: true }, "u": { rmWhenEmpty: true } } } } }, options: {}, enabled: false, debug: false, domRemove: function (node) { // replace h1-h6 with p if (this.options.rules.heading) { if (node.nodeName.toLowerCase().match(/^h[1-6]$/)) { // in chromium change this to // $(node).replaceWith($('

').html(node.innerHTML)); // to except DOM error: also try in other browsers $(node).replaceWith($('

').html($(node).contents())); return true; } } // remove tables not smart enough ) if (this.options.rules.table) { if (node.nodeName.toLowerCase().match(/^(table|t[dhr]|t(body|foot|head))$/)) { $(node).replaceWith($(node).contents()); return true; } } return false; }, domTraversing: function (el, start, end, canRemove, cnt) { if (null === canRemove) { canRemove = false; } var isDomRemoved, p; while (el) { if (this.debug) { console.log(cnt, "canRemove=", canRemove); } if (el.firstElementChild) { if (this.debug) { console.log(cnt, "domTraversing", el.firstElementChild); } return this.domTraversing(el.firstElementChild, start, end, canRemove, cnt + 1); } else { if (this.debug) { console.log(cnt, "routine", el); } isDomRemoved = false; if (start === el) { canRemove = true; } if (canRemove) { if (el.previousElementSibling) { p = el.previousElementSibling; } else { p = el.parentNode; } if (this.debug) { console.log(cnt, el.nodeName, el.previousElementSibling, el.parentNode, p); } isDomRemoved = this.domRemove(el); if (this.domRemove(el)) { if (this.debug) { console.log("p", p); } // step back to parent or previousElement to traverse again then element is removed el = p; } if (start !== end && end === el) { return true; } } if (false === isDomRemoved) { el = el.nextElementSibling; } } } return false; }, msWordMarkup: function (text) { var tagName, attrName, rules, reg, regAttr, found, attrs; // @link https://github.com/akzhan/jwysiwyg/issues/165 text = text.replace(/</g, "<").replace(/>/g, ">"); text = text.replace(/]+>/g, ""); text = text.replace(/]+>/g, ""); text = text.replace(/[\s\S]*?<\/title>/g, ""); text = text.replace(/<style(?:\s[^>]*)?>[\s\S]*?<\/style>/gm, ""); text = text.replace(/<w:([^\s>]+)(?:\s[^\/]+)?\/>/g, ""); text = text.replace(/<w:([^\s>]+)(?:\s[^>]+)?>[\s\S]*?<\/w:\1>/gm, ""); text = text.replace(/<m:([^\s>]+)(?:\s[^\/]+)?\/>/g, ""); text = text.replace(/<m:([^\s>]+)(?:\s[^>]+)?>[\s\S]*?<\/m:\1>/gm, ""); // after running the above.. it still needed these text = text.replace(/<xml>[\s\S]*?<\/xml>/g, ""); text = text.replace(/<object(?:\s[^>]*)?>[\s\S]*?<\/object>/g, ""); text = text.replace(/<o:([^\s>]+)(?:\s[^\/]+)?\/>/g, ""); text = text.replace(/<o:([^\s>]+)(?:\s[^>]+)?>[\s\S]*?<\/o:\1>/gm, ""); text = text.replace(/<st1:([^\s>]+)(?:\s[^\/]+)?\/>/g, ""); text = text.replace(/<st1:([^\s>]+)(?:\s[^>]+)?>[\s\S]*?<\/st1:\1>/gm, ""); // ---- text = text.replace(/<!--[^>]+>\s*<[^>]+>/gm, ""); // firefox needed this 1 text = text.replace(/^[\s\n]+/gm, ""); if (this.options.rules.msWordMarkup.tags) { for (tagName in this.options.rules.msWordMarkup.tags) { rules = this.options.rules.msWordMarkup.tags[tagName]; if ("string" === typeof (rules)) { if ("" === rules) { reg = new RegExp("<" + tagName + "(?:\\s[^>]+)?/?>", "gmi"); text = text.replace(reg, "<" + tagName + ">"); } } else if ("object" === typeof (rules)) { reg = new RegExp("<" + tagName + "(\\s[^>]+)?/?>", "gmi"); found = reg.exec(text); attrs = ""; if (found && found[1]) { attrs = found[1]; } if (rules.rmAttr) { if ("all" === rules.rmAttr) { attrs = ""; } else if ("object" === typeof (rules.rmAttr) && attrs) { for (attrName in rules.rmAttr) { regAttr = new RegExp(attrName + '="[^"]*"', "mi"); attrs = attrs.replace(regAttr, ""); } } } if (attrs) { attrs = attrs.replace(/[\s\n]+/gm, " "); if (" " === attrs) { attrs = ""; } } text = text.replace(reg, "<" + tagName + attrs + ">"); } } for (tagName in this.options.rules.msWordMarkup.tags) { rules = this.options.rules.msWordMarkup.tags[tagName]; if ("string" === typeof (rules)) { // } else if ("object" === typeof (rules)) { if (rules.rmWhenEmpty) { reg = new RegExp("<" + tagName + "(\\s[^>]+)?>(?:[\\s\\n]|<br/?>)*?</" + tagName + ">", "gmi"); text = text.replace(reg, ""); } if (rules.rmWhenNoAttr) { reg = new RegExp("<" + tagName + ">(?!<" + tagName + ">)([\\s\\S]*?)</" + tagName + ">", "mi"); found = reg.exec(text); while (found) { text = text.replace(reg, found[1]); found = reg.exec(text); } } } } } return text; }, run: function (Wysiwyg, options) { options = options || {}; this.options = $.extend(true, this.defaults, options); if (this.options.rules.heading || this.options.rules.table) { var r = Wysiwyg.getInternalRange(), start, end, node, traversing; start = r.startContainer; if (start.nodeType === 3) { start = start.parentNode; } end = r.endContainer; if (end.nodeType === 3) { end = end.parentNode; } if (this.debug) { console.log("start", start, start.nodeType, start.nodeName, start.parentNode); console.log("end", end, end.nodeType, end.nodeName, end.parentNode); } node = r.commonAncestorContainer; if (node.nodeType === 3) { node = node.parentNode; } if (this.debug) { console.log("node", node, node.nodeType, node.nodeName.toLowerCase(), node.parentNode, node.firstElementChild); console.log(start === end); } traversing = null; if (start === end) { traversing = this.domTraversing(node, start, end, true, 1); } else { traversing = this.domTraversing(node.firstElementChild, start, end, null, 1); } if (this.debug) { console.log("DomTraversing=", traversing); } } if (this.options.rules.msWordMarkup.enabled) { Wysiwyg.setContent(this.msWordMarkup(Wysiwyg.getContent())); } } }; $.wysiwyg.plugin.register(rmFormat); })(jQuery);