summaryrefslogtreecommitdiff
path: root/addons/web_editor/static/src/js/wysiwyg/plugin/text.js
diff options
context:
space:
mode:
authorGorash <chm@odoo.com>2019-08-20 06:23:06 +0000
committerDavid Monjoie <dmo@odoo.com>2019-08-21 18:52:36 +0000
commit35b61822a8b12ebbdb455495479df6f2e13db03e (patch)
tree999c382ea06b53b8da8d7db2d82e671d831dd856 /addons/web_editor/static/src/js/wysiwyg/plugin/text.js
parentf14cecfc0a7f401533213aaa968ee233e19d1325 (diff)
[REV] wev_editor, website: revert saas-12.2 editor
This commit reverts the saas-12.2 editor by putting back the editor of Odoo 12. The saas-12.2 editor was an intermediate work between the previous editor of Odoo 12 and the new one slated for Odoo 13. It was unstable but it was supposed to be replaced by the new editor of version 13. However, since the new editor has been postponed to Odoo 14, the saas-12.2 one would have been staying in Odoo 13, which would have been a nightmare to maintain. To avoid this outcome, we chose to put back the 12.0 editor in its place. This has the particular advantage that Odoo 13 will share the same bugfixes as Odoo 12 and 11 as they all run under the same core editor, while the saas-12.2 one would have been an entirely different beast to maintain. This is a partial revert of f2969923. Part of PR 35677. Co-authored-by: Nicolas Bayet <nby@odoo.com> Co-authored-by: Antoine Guenet <age@odoo.com> Co-authored-by: Christophe Matthieu <chm@odoo.com> Co-authored-by: David Monjoie <dmo@odoo.com>
Diffstat (limited to 'addons/web_editor/static/src/js/wysiwyg/plugin/text.js')
-rw-r--r--addons/web_editor/static/src/js/wysiwyg/plugin/text.js811
1 files changed, 0 insertions, 811 deletions
diff --git a/addons/web_editor/static/src/js/wysiwyg/plugin/text.js b/addons/web_editor/static/src/js/wysiwyg/plugin/text.js
deleted file mode 100644
index 2b7d10d02fd..00000000000
--- a/addons/web_editor/static/src/js/wysiwyg/plugin/text.js
+++ /dev/null
@@ -1,811 +0,0 @@
-odoo.define('web_editor.wysiwyg.plugin.text', function (require) {
-'use strict';
-
-var AbstractPlugin = require('web_editor.wysiwyg.plugin.abstract');
-var registry = require('web_editor.wysiwyg.plugin.registry');
-
-var dom = $.summernote.dom;
-dom.isAnchor = function (node) {
- return (node.tagName === 'A' || node.tagName === 'BUTTON' || $(node).hasClass('btn')) &&
- !$(node).hasClass('fa') && !$(node).hasClass('o_image');
-};
-
-
-var TextPlugin = AbstractPlugin.extend({
- events: {
- 'summernote.paste': '_onPaste',
- },
-
- // See: https://dvcs.w3.org/hg/editing/raw-file/tip/editing.html#removeformat-candidate
- formatTags: [
- 'abbr',
- 'acronym',
- 'b',
- 'bdi',
- 'bdo',
- 'big',
- 'blink',
- 'cite',
- 'code',
- 'dfn',
- 'em',
- 'font',
- 'i',
- 'ins',
- 'kbd',
- 'mark',
- 'nobr',
- 'q',
- 's',
- 'samp',
- 'small',
- 'span',
- 'strike',
- 'strong',
- 'sub',
- 'sup',
- 'tt',
- 'u',
- 'var',
- ],
- tab: '\u00A0\u00A0\u00A0\u00A0',
-
- //--------------------------------------------------------------------------
- // Public
- //--------------------------------------------------------------------------
-
- /**
- * Insert a Horizontal Rule element (hr).
- */
- insertHR: function () {
- var self = this;
- var hr = this.document.createElement('hr');
- this.context.invoke('HelperPlugin.insertBlockNode', hr);
- var point = this.context.invoke('HelperPlugin.makePoint', hr, 0);
- point = dom.nextPointUntil(point, function (pt) {
- return pt.node !== hr && !self.options.isUnbreakableNode(pt.node);
- }) || point;
- var range = $.summernote.range.create(point.node, point.offset);
- range.select();
- },
- /**
- * Insert a TAB (4 non-breakable spaces).
- */
- insertTab: function () {
- this.context.invoke('HelperPlugin.insertTextInline', this.tab);
- },
- /**
- * Paste nodes or their text content into the editor.
- *
- * @param {Node[]} nodes
- * @param {Boolean} textOnly true to allow only dropping plain text
- */
- pasteNodes: function (nodes, textOnly) {
- if (!nodes.length) {
- return;
- }
- nodes = textOnly ? this.document.createTextNode($(nodes).text()) : nodes;
- nodes = textOnly ? nodes : this._mergeAdjacentULs(nodes);
-
- var point = this._getPastePoint();
- // Prevent pasting HTML within a link:
- point = textOnly ? point : dom.nextPointUntil(point, this._isPointInAnchor.bind(this));
-
- this._insertNodesAt(nodes, point);
-
- var start = nodes[nodes.length - 1];
- this.context.invoke('editor.setRange', start, dom.nodeLength(start)).normalize().select();
- },
- /**
- * Prepare clipboard data for safe pasting into the editor.
- *
- * @see clipboardWhitelist
- * @see clipboardBlacklist
- *
- * @param {DOMString} clipboardData
- * @returns {Node[]}
- */
- prepareClipboardData: function (clipboardData) {
- var $html = $('<wrapper>' + clipboardData + '</wrapper>').contents();
- var $clipboardData = this._removeIllegalClipboardElements($html);
-
- var $all = $clipboardData.find('*').addBack();
- $all.filter('table').addClass('table table-bordered');
- this._wrapTDContents($all.filter('td'));
- this._fillEmptyBlocks($all);
- this._removeIllegalClipboardAttributes($all);
- $all.filter('a').removeClass();
- $all.filter('img').css('max-width', '100%');
-
- return $clipboardData.toArray();
- },
- /**
- * Format a 'format' block: change its tagName (eg: p -> h1).
- *
- * @param {string} tagName
- * P, H1, H2, H3, H4, H5, H6, BLOCKQUOTE, PRE
- */
- formatBlock: function (tagName) {
- var self = this;
- var r = this.context.invoke('editor.createRange');
- if (
- !r ||
- !this.$editable.has(r.sc).length ||
- !this.$editable.has(r.ec).length ||
- this.options.isUnbreakableNode(r.sc)
- ) {
- return;
- }
- var nodes = this.context.invoke('HelperPlugin.getSelectedNodes');
- nodes = this.context.invoke('HelperPlugin.filterFormatAncestors', nodes);
- if (!nodes.length) {
- var node = this.context.invoke('editor.createRange').sc;
- if (node.tagName === 'BR' || dom.isText(node)) {
- node = node.parentNode;
- }
- nodes = [node];
- }
- var changedNodes = [];
- _.each(nodes, function (node) {
- var newNode = self.document.createElement(tagName);
- $(newNode).append($(node).contents());
- var attributes = $(node).prop("attributes");
- _.each(attributes, function (attr) {
- $(newNode).attr(attr.name, attr.value);
- });
- $(node).replaceWith(newNode);
- changedNodes.push(newNode);
- });
-
- // Select all formatted nodes
- if (changedNodes.length) {
- var lastNode = changedNodes[changedNodes.length - 1];
- var startNode = changedNodes[0].firstChild || changedNodes[0];
- var endNode = lastNode.lastChild || lastNode;
- var range = this.context.invoke('editor.setRange', startNode, 0, endNode, dom.nodeLength(endNode));
- range.select();
- }
- },
- /**
- * Change the paragraph alignment of a 'format' block.
- *
- * @param {string} style
- * justifyLeft, justifyCenter, justifyRight, justifyFull
- */
- formatBlockStyle: function (style) {
- var self = this;
- var nodes = this.context.invoke('HelperPlugin.getSelectedNodes');
- nodes = this.context.invoke('HelperPlugin.filterFormatAncestors', nodes);
- var align = style === 'justifyLeft' ? 'left' :
- style === 'justifyCenter' ? 'center' :
- style === 'justifyRight' ? 'right' : 'justify';
- _.each(nodes, function (node) {
- if (dom.isText(node)) {
- return;
- }
- var textAlign = self.window.getComputedStyle(node).textAlign;
- if (align !== textAlign) {
- if (align !== self.window.getComputedStyle(node.parentNode).textAlign) {
- $(node).css('text-align', align);
- } else {
- $(node).css('text-align', '');
- }
- }
- });
- this.editable.normalize();
- },
- /**
- * (Un-)format text: make it bold, italic, ...
- *
- * @param {string} tagName
- * bold, italic, underline, strikethrough, superscript, subscript
- */
- formatText: function (tagName) {
- var self = this;
- var tag = {
- bold: 'B',
- italic: 'I',
- underline: 'U',
- strikethrough: 'S',
- superscript: 'SUP',
- subscript: 'SUB',
- } [tagName];
- if (!tag) {
- throw new Error(tagName);
- }
-
- var range = this.context.invoke('editor.createRange');
- if (!range || !this.$editable.has(range.sc).length || !this.$editable.has(range.ec).length) {
- return;
- }
- if (range.isCollapsed()) {
- var br;
- if (range.sc.tagName === 'BR') {
- br = range.sc;
- } else if (range.sc.firstChild && range.sc.firstChild.tagName === 'BR') {
- br = range.sc.firstChild;
- }
- if (br) {
- var emptyText = this.document.createTextNode('\u200B');
- $(br).before(emptyText).remove();
- range = this.context.invoke('editor.setRange', emptyText, 0, emptyText, 1);
- } else {
- var offset = range.so;
- this.context.invoke('HelperPlugin.insertTextInline', '\u200B');
- range = this.context.invoke('editor.createRange');
- range.so = offset;
- range.eo = offset + 1;
- }
- range.select();
- }
-
- var nodes = this.context.invoke('HelperPlugin.getSelectedNodes');
- var texts = this.context.invoke('HelperPlugin.filterLeafChildren', nodes);
- var formatted = this.context.invoke('HelperPlugin.filterFormatAncestors', nodes);
-
- var start = this.context.invoke('HelperPlugin.firstLeaf', nodes[0]);
- var end = this.context.invoke('HelperPlugin.lastLeaf', nodes[nodes.length - 1]);
-
- function containsOnlySelectedText(node) {
- return _.all(node.childNodes, function (n) {
- return _.any(texts, function (t) {
- return n === t && !(dom.isText(n) && n.textContent === '');
- }) && containsOnlySelectedText(n);
- });
- }
-
- function containsAllSelectedText(node) {
- return _.all(texts, function (t) {
- return _.any(node.childNodes, function (n) {
- return n === t && !(dom.isText(n) && n.textContent === '') || containsAllSelectedText(n);
- });
- });
- }
-
- var nodeAlreadyStyled = [];
- var toStyled = [];
- var notStyled = _.filter(texts, function (text, index) {
- if (toStyled.indexOf(text) !== -1 || nodeAlreadyStyled.indexOf(text) !== -1) {
- return;
- }
- nodeAlreadyStyled.push(text);
-
- end = text;
-
- var styled = dom.ancestor(text, function (node) {
- return node.tagName === tag;
- });
- if (styled) {
- if (
- !/^\u200B$/.test(text.textContent) &&
- containsAllSelectedText(styled) &&
- containsOnlySelectedText(styled)
- ) {
- // Unwrap all contents
- nodes = $(styled).contents();
- $(styled).before(nodes).remove();
- nodeAlreadyStyled.push.apply(nodeAlreadyStyled, nodes);
- end = _.last(nodeAlreadyStyled);
- } else {
- var options = {
- isSkipPaddingBlankHTML: true,
- isNotSplitEdgePoint: true,
- };
-
- if (
- nodeAlreadyStyled.indexOf(text.nextSibling) === -1 &&
- !dom.isRightEdgeOf(text, styled)
- ) {
- options.nextText = false;
- var point = self.context.invoke('HelperPlugin.makePoint', text, dom.nodeLength(text));
- if (dom.isMedia(text)) {
- point = dom.nextPoint(point);
- }
- var next = self.context.invoke('HelperPlugin.splitTree', styled, point, options);
- nodeAlreadyStyled.push(next);
- }
- if (
- nodeAlreadyStyled.indexOf(text.previousSibling) === -1 &&
- !dom.isLeftEdgeOf(text, styled)
- ) {
- options.nextText = true;
- var textPoint = self.context.invoke('HelperPlugin.makePoint', text, 0);
- text = self.context.invoke('HelperPlugin.splitTree', styled, textPoint, options);
- nodeAlreadyStyled.push(text);
- if (index === 0) {
- start = text;
- }
- end = text;
- }
-
- var toRemove = dom.ancestor(text, function (n) {
- return n.tagName === tag;
- });
- if (toRemove) {
- // Remove generated empty elements
- if (
- toRemove.nextSibling &&
- self.context.invoke('HelperPlugin.isBlankNode', toRemove.nextSibling)
- ) {
- $(toRemove.nextSibling).remove();
- }
- if (
- toRemove.previousSibling &&
- self.context.invoke('HelperPlugin.isBlankNode', toRemove.previousSibling)
- ) {
- $(toRemove.previousSibling).remove();
- }
-
- // Unwrap the element
- nodes = $(toRemove).contents();
- $(toRemove).before(nodes).remove();
- nodeAlreadyStyled.push.apply(nodeAlreadyStyled, nodes);
- end = _.last(nodeAlreadyStyled);
- }
- }
- }
-
- if (dom.ancestor(text, function (node) {
- return toStyled.indexOf(node) !== -1;
- })) {
- return;
- }
-
- var node = text;
- while (
- node && node.parentNode &&
- formatted.indexOf(node) === -1 &&
- formatted.indexOf(node.parentNode) === -1
- ) {
- node = node.parentNode;
- }
- if (node !== text) {
- if (containsAllSelectedText(node)) {
- toStyled.push.apply(toStyled, texts);
- node = text;
- } else if (!containsOnlySelectedText(node)) {
-
- node = text;
- }
- }
-
- if (toStyled.indexOf(node) === -1) {
- toStyled.push(node);
- }
- return !styled;
- });
-
- toStyled = _.uniq(toStyled);
-
- if (notStyled.length) {
- nodes = [];
- var toMerge = [];
- _.each(toStyled, function (node) {
- var next = true;
- if (node.nextSibling && node.nextSibling.tagName === tag) {
- $(node.nextSibling).prepend(node);
- next = false;
- }
- if (node.previousSibling && node.previousSibling.tagName === tag) {
- $(node.previousSibling).append(node);
- }
- if (node.parentNode && node.parentNode.tagName !== tag) {
- var styled = self.document.createElement(tag);
- if (node.tagName) {
- $(styled).append(node.childNodes);
- $(node).append(styled);
- } else {
- $(node).before(styled);
- styled.appendChild(node);
- }
- }
- // Add adjacent nodes with same tagName to list of nodes to merge
- if (
- node.parentNode && node.parentNode[next ? 'nextSibling' : 'previousSibling'] &&
- node.parentNode.tagName === node.parentNode[next ? 'nextSibling' : 'previousSibling'].tagName
- ) {
- toMerge.push(next ? node.parentNode : node.parentNode.previousSibling);
- }
- });
- // Merge what needs merging
- while (toMerge.length) {
- this.context.invoke('HelperPlugin.deleteEdge', toMerge.pop(), 'next');
- }
- }
-
- range = this.context.invoke('editor.setRange', start, 0, end, dom.nodeLength(end));
-
- if (range.sc === range.ec && range.sc.textContent === '\u200B') {
- range.so = range.eo = 1;
- }
-
- range.select();
- this.editable.normalize();
- },
- /**
- * Remove format on the current range.
- *
- * @see _isParentRemoveFormatCandidate
- */
- removeFormat: function () {
- this._selectCurrentIfCollapsed();
- var selectedText = this.context.invoke('HelperPlugin.getSelectedText');
- var selectedIcons = this.context.invoke('HelperPlugin.getSelectedNodes');
- selectedIcons = _.filter(selectedIcons, dom.isIcon);
- if (!selectedText.length && !selectedIcons.length) {
- return;
- }
- _.each(selectedIcons, this._removeIconFormat.bind(this));
- _.each(selectedText, this._removeTextFormat.bind(this));
- var startNode = selectedText[0];
- var endNode = selectedText[selectedText.length - 1];
- this.context.invoke('editor.setRange', startNode, 0, endNode, dom.nodeLength(endNode)).select();
- this.editable.normalize();
- this.context.invoke('editor.saveRange');
- },
-
- //--------------------------------------------------------------------------
- // Private
- //--------------------------------------------------------------------------
-
- /**
- * Remove the non-whitelisted or blacklisted
- * top level elements from clipboard data.
- *
- * @see clipboardWhitelist
- * @see clipboardBlacklist
- *
- * @private
- * @param {JQuery} $clipboardData
- * @returns {Object} {$clipboardData: JQuery, didRemoveNodes: Boolean}
- */
- _cleanClipboardRoot: function ($clipboardData) {
- var didRemoveNodes = false;
- var whiteList = this._clipboardWhitelist();
- var blackList = this._clipboardBlacklist();
- var $fakeParent = $(this.document.createElement('div'));
- _.each($clipboardData, function (node) {
- var isWhitelisted = dom.isText(node) || $(node).filter(whiteList.join(',')).length;
- var isBlacklisted = $(node).filter(blackList.join(',')).length;
- if (!isWhitelisted || isBlacklisted) {
- $fakeParent.append(node.childNodes);
- didRemoveNodes = true;
- } else {
- $fakeParent.append(node);
- }
- });
- return {
- $clipboardData: $fakeParent.contents(),
- didRemoveNodes: didRemoveNodes,
- };
- },
- /**
- * Return a list of jQuery selectors for prohibited nodes on paste.
- *
- * @private
- * @returns {String[]}
- */
- _clipboardBlacklist: function () {
- return ['.Apple-interchange-newline'];
- },
- /**
- * Return a list of jQuery selectors for exclusively authorized nodes on paste.
- *
- * @private
- * @returns {String[]}
- */
- _clipboardWhitelist: function () {
- var listSels = ['ul', 'ol', 'li'];
- var styleSels = ['i', 'b', 'u', 'em', 'strong'];
- var tableSels = ['table', 'th', 'tbody', 'tr', 'td'];
- var miscSels = ['img', 'br', 'a', '.fa'];
- return this.options.styleTags.concat(listSels, styleSels, tableSels, miscSels);
- },
- /**
- * Return a list of attribute names that are exclusively authorized on paste.
- *
- * @private
- * @returns {String[]}
- */
- _clipboardWhitelistAttr: function () {
- return ['class', 'href', 'src'];
- },
- /**
- * Fill up empty block elements with BR elements so the carret can enter them.
- *
- * @private
- * @param {JQuery} $els
- */
- _fillEmptyBlocks: function ($els) {
- var self = this;
-
- $els.filter(function (i, n) {
- return self.context.invoke('HelperPlugin.isNodeBlockType', n) && !n.childNodes;
- }).append(this.document.createElement('br'));
- },
- /**
- * Get all non-whitelisted or blacklisted elements from clipboard data.
- *
- * @private
- * @param {JQuery} $clipboardData
- * @returns {JQuery}
- */
- _filterIllegalClipboardElements: function ($clipboardData) {
- return $clipboardData.find('*').addBack()
- .not(this._clipboardWhitelist().join(','))
- .addBack(this._clipboardBlacklist().join(','))
- .filter(function () {
- return !dom.isText(this);
- });
- },
- /**
- * Get a legal point to paste at, from the current range's start point.
- *
- * @private
- * @returns {Object} {node: Node, offset: Number}
- */
- _getPastePoint: function () {
- var point = this.context.invoke('editor.createRange').getStartPoint();
- var offsetChild = point.node.childNodes[point.offset];
- point = offsetChild ? this.context.invoke('HelperPlugin.makePoint', offsetChild, 0) : point;
- return dom.nextPointUntil(point, this._isPastePointLegal.bind(this));
- },
- /**
- * Insert nodes at a point. Insert them inline if the first node is inline
- * and pasting inline is legal at that point.
- *
- * @private
- * @param {Node[]} nodes
- * @param {Object} point {node: Node, offset: Number}
- */
- _insertNodesAt: function (nodes, point) {
- var canInsertInline = dom.isText(point.node) || point.node.tagName === 'BR' || dom.isMedia(point.node);
- var $fakeParent = $(this.document.createElement('div'));
- $fakeParent.append(nodes);
- if (dom.isInline(nodes[0]) && canInsertInline) {
- point.node = point.node.tagName ? point.node : point.node.splitText(point.offset);
- $(point.node).before($fakeParent.contents());
- } else {
- this.context.invoke('HelperPlugin.insertBlockNode', $fakeParent[0]);
- }
- $fakeParent.contents().unwrap();
- },
- /**
- * Return true if the parent of the given node is a removeFormat candidate:
- * - It is a removeFormat candidate as defined by W3C
- * - It is contained within the editable area
- * - It is not unbreakable
- *
- * @see formatTags the list of removeFormat candidates as defined by W3C
- *
- * @private
- * @param {Node} node
- */
- _isParentRemoveFormatCandidate: function (node) {
- var parent = node.parentNode;
- if (!parent) {
- return false;
- }
- var isEditableOrAbove = parent && (parent === this.editable || $.contains(parent, this.editable));
- var isUnbreakable = parent && this.options.isUnbreakableNode(parent);
- var isRemoveFormatCandidate = parent && parent.tagName && this.formatTags.indexOf(parent.tagName.toLowerCase()) !== -1;
- return parent && !isEditableOrAbove && !isUnbreakable && isRemoveFormatCandidate;
- },
- /**
- * Return true if it's legal to paste nodes at the given point:
- * if the point is not within a void node and the point is not unbreakable.
- *
- * @private
- * @param {Object} point {node: Node, offset: Number}
- * @returns {Boolean}
- */
- _isPastePointLegal: function (point) {
- var node = point.node;
- var isWithinVoid = false;
- if (node.parentNode) {
- isWithinVoid = dom.isVoid(node.parentNode) || $(node.parentNode).filter('.fa').length;
- }
- return !isWithinVoid && !this.options.isUnbreakableNode(point.node);
- },
- /**
- * @private
- * @param {Object} point {node: Node, offset: Number}
- * @returns {Boolean}
- */
- _isPointInAnchor: function (point) {
- var ancestor = dom.ancestor(point.node, dom.isAnchor);
- return !ancestor || ancestor === this.editable;
- },
- /**
- * Check a list of nodes and merges all adjacent ULs together:
- * [ul, ul, p, ul, ul] will return [ul, p, ul], with the li's of
- * nodes[1] and nodes[4] appended to nodes[0] and nodes[3].
- *
- * @private
- * @param {Node[]} nodes
- * @return {Node[]} the remaining, merged nodes
- */
- _mergeAdjacentULs: function (nodes) {
- var res = [];
- var prevNode;
- _.each(nodes, function (node) {
- prevNode = res[res.length - 1];
- if (prevNode && node.tagName === 'UL' && prevNode.tagName === 'UL') {
- $(prevNode).append(node.childNodes);
- } else {
- res.push(node);
- }
- });
- return res;
- },
- /**
- * Remove an icon's format (colors, font size).
- *
- * @private
- * @param {Node} icon
- */
- _removeIconFormat: function (icon) {
- $(icon).css({
- color: '',
- backgroundColor: '',
- fontSize: '',
- });
- var reColorClasses = /(^|\s+)(bg|text)-\S*|/g;
- icon.className = icon.className.replace(reColorClasses, '').trim();
- },
- /**
- * Remove non-whitelisted attributes from clipboard.
- *
- * @private
- * @param {JQuery} $els
- */
- _removeIllegalClipboardAttributes: function ($els) {
- var self = this;
- $els.each(function () {
- var $node = $(this);
- _.each(_.pluck(this.attributes, 'name'), function (attribute) {
- if (self._clipboardWhitelistAttr().indexOf(attribute) === -1) {
- $node.removeAttr(attribute);
- }
- });
- }).removeClass('o_editable o_not_editable');
- },
- /**
- * Remove non-whitelisted and blacklisted elements from clipboard data.
- *
- * @private
- * @param {JQuery} $clipboardData
- * @returns {JQuery}
- */
- _removeIllegalClipboardElements: function ($clipboardData) {
- var root = true;
- $clipboardData = $clipboardData.not('meta').not('style').not('script');
- var $badNodes = this._filterIllegalClipboardElements($clipboardData);
-
- do {
- if (root) {
- root = false;
- var cleanData = this._cleanClipboardRoot($clipboardData);
- $clipboardData = cleanData.$clipboardData;
- root = cleanData.didRemoveNodes;
- } else {
- this._removeNodesPreserveContents($badNodes);
- }
-
- $badNodes = this._filterIllegalClipboardElements($clipboardData);
- } while ($badNodes.length);
- return $clipboardData;
- },
- /**
- * Remove nodes from the DOM while preserving their contents if any.
- *
- * @private
- * @param {JQuery} $nodes
- */
- _removeNodesPreserveContents: function ($nodes) {
- var $contents = $nodes.contents();
- if ($contents.length) {
- $contents.unwrap();
- } else {
- $nodes.remove();
- }
- },
- /**
- * Remove a text node's format: remove its style parents (b, i, u, ...).
- *
- * @private
- * @param {Node} textNode
- */
- _removeTextFormat: function (textNode) {
- var node = textNode;
- while (this._isParentRemoveFormatCandidate(node)) {
- this.context.invoke('HelperPlugin.splitAtNodeEnds', node);
- $(node.parentNode).before(node).remove();
- }
- },
- /**
- * Select the whole current node if the range is collapsed
- *
- * @private
- */
- _selectCurrentIfCollapsed: function () {
- var range = this.context.invoke('editor.createRange');
- if (!range.isCollapsed()) {
- return;
- }
- this.context.invoke('editor.setRange', range.sc, 0, range.sc, dom.nodeLength(range.sc)).select();
- this.context.invoke('editor.saveRange');
- },
- /**
- * Prevent inline nodes directly in TDs by wrapping them in P elements.
- *
- * @private
- * @param {JQuery} $tds
- */
- _wrapTDContents: function ($tds) {
- var self = this;
- var $inlinesInTD = $tds.contents().filter(function () {
- return !self.context.invoke('HelperPlugin.isNodeBlockType', this);
- });
- var parentsOfInlinesInTD = [];
- _.each($inlinesInTD, function (n) {
- parentsOfInlinesInTD.push(self.context.invoke('HelperPlugin.firstBlockAncestor', n));
- });
- $($.unique(parentsOfInlinesInTD)).wrapInner(this.document.createElement('p'));
- },
-
- //--------------------------------------------------------------------------
- // Handlers
- //--------------------------------------------------------------------------
-
- /**
- * Handle paste events to permit cleaning/sorting of the data before pasting.
- *
- * @private
- * @param {SummernoteEvent} se
- * @param {jQueryEvent} e
- */
- _onPaste: function (se, e) {
- var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
- var iPhone = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
- if (isSafari && !iPhone) {
- return;
- }
- se.preventDefault();
- se.stopImmediatePropagation();
- e.preventDefault();
- e.stopImmediatePropagation();
-
- this.context.invoke('editor.beforeCommand');
-
- // Clean up
- var clipboardData = e.originalEvent.clipboardData.getData('text/html');
- if (clipboardData) {
- clipboardData = this.prepareClipboardData(clipboardData);
- } else {
- clipboardData = e.originalEvent.clipboardData.getData('text/plain');
- // get that text as an array of text nodes separated by <br> where needed
- var allNewlines = /\n/g;
- clipboardData = _.str.trim(clipboardData)
- .replace(/</g, '&lt;').replace(/>/g, '&gt;')
- .replace(allNewlines, '<br>');
- clipboardData = $('<p>' + clipboardData + '</p>').contents().toArray();
- }
-
- // Delete selection
- this.context.invoke('HelperPlugin.deleteSelection');
-
- // Insert the nodes
- this.pasteNodes(clipboardData);
- this.context.invoke('HelperPlugin.normalize');
- this.context.invoke('editor.saveRange');
-
- this.context.invoke('editor.afterCommand');
- },
-});
-
-registry.add('TextPlugin', TextPlugin);
-
-return TextPlugin;
-
-});