From 3befae3799548715a9e44fbd472b91b754834942 Mon Sep 17 00:00:00 2001 From: Zhu Liang Date: Sun, 14 Aug 2016 02:27:06 +0800 Subject: [PATCH 1/2] Added unwrapTags option to paste extension --- OPTIONS.md | 6 ++++++ README.md | 1 + spec/paste.spec.js | 19 ++++++++++++++++--- src/js/extensions/paste.js | 11 ++++++++++- src/js/util.js | 14 +++++++++----- 5 files changed, 42 insertions(+), 9 deletions(-) diff --git a/OPTIONS.md b/OPTIONS.md index be7074be9..31c9a89ca 100644 --- a/OPTIONS.md +++ b/OPTIONS.md @@ -521,6 +521,12 @@ List of element attributes to remove during paste when __cleanPastedHTML__ is `t List of element tag names to remove during paste when __cleanPastedHTML__ is `true` or when calling `cleanPaste(text)` or `pasteHTML(html,options)` helper methods. +*** +#### `unwrapTags` +**Default:** `[]` + +List of element tag names to unwrap (remove the element tag but retain its child elements) during paste when __cleanPastedHTML__ is `true` or when calling `cleanPaste(text)` or `pasteHTML(html,options)` helper methods. + ### Disabling Paste Handling To disable MediumEditor manipulating pasted content, set the both the `forcePlainText` and `cleanPastedHTML` options to `false`: diff --git a/README.md b/README.md index 2aa83c2c8..fcfacc670 100644 --- a/README.md +++ b/README.md @@ -348,6 +348,7 @@ var editor = new MediumEditor('.editable', { * __cleanReplacements__: custom pairs (2 element arrays) of RegExp and replacement text to use during paste when __forcePlainText__ or __cleanPastedHTML__ are `true` OR when calling `cleanPaste(text)` helper method. These replacements are executed _after_ builtin replacements. Default: `[]` * __cleanAttrs__: list of element attributes to remove during paste when __cleanPastedHTML__ is `true` or when calling `cleanPaste(text)` or `pasteHTML(html,options)` helper methods. Default: `['class', 'style', 'dir']` * __cleanTags__: list of element tag names to remove during paste when __cleanPastedHTML__ is `true` or when calling `cleanPaste(text)` or `pasteHTML(html,options)` helper methods. Default: `['meta']` +* __unwrapTags__: list of element tag names to unwrap (remove the element tag but retain its child elements) during paste when __cleanPastedHTML__ is `true` or when calling `cleanPaste(text)` or `pasteHTML(html,options)` helper methods. Default: `[]` ### KeyboardCommands Options diff --git a/spec/paste.spec.js b/spec/paste.spec.js index 012ae90e9..1ab7f4de9 100644 --- a/spec/paste.spec.js +++ b/spec/paste.spec.js @@ -716,21 +716,34 @@ describe('Pasting content', function () { expect(editor.elements[0].innerHTML).toBe('
test
'); }); + it('should accept a list of tags to unwrap', function () { + var editor = this.newMediumEditor('.editor'); + selectElementContents(this.el.firstChild); + editor.pasteHTML( + '
testtesttest
', + { unwrapTags: ['sub', 'sup'] } + ); + expect(editor.elements[0].innerHTML).toBe('
testtesttest
'); + }); + it('should respect custom clean up options passed during instantiation', function () { var editor = this.newMediumEditor('.editor', { paste: { cleanAttrs: ['style', 'dir'], - cleanTags: ['meta', 'b'] + cleanTags: ['meta', 'b'], + unwrapTags: ['sub', 'sup'] } }); selectElementContents(this.el.firstChild); editor.pasteHTML( '
test
' + - '
testtest
' + '
testtest
' + + '
testtesttest
' ); expect(editor.elements[0].innerHTML).toBe( '
test
' + - '
test
' + '
test
' + + '
testtest
' ); }); }); diff --git a/src/js/extensions/paste.js b/src/js/extensions/paste.js index 6993fb49f..ece31869d 100644 --- a/src/js/extensions/paste.js +++ b/src/js/extensions/paste.js @@ -139,6 +139,13 @@ */ cleanTags: ['meta'], + /* unwrapTags: [Array] + * list of element tag names to unwrap (remove the element tag but retain its child elements) + * during paste when __cleanPastedHTML__ is `true` or when + * calling `cleanPaste(text)` or `pasteHTML(html, options)` helper methods. + */ + unwrapTags: [], + init: function () { MediumEditor.Extension.prototype.init.apply(this, arguments); @@ -422,7 +429,8 @@ pasteHTML: function (html, options) { options = MediumEditor.util.defaults({}, options, { cleanAttrs: this.cleanAttrs, - cleanTags: this.cleanTags + cleanTags: this.cleanTags, + unwrapTags: this.unwrapTags }); var elList, workEl, i, fragmentBody, pasteBlock = this.document.createDocumentFragment(); @@ -444,6 +452,7 @@ MediumEditor.util.cleanupAttrs(workEl, options.cleanAttrs); MediumEditor.util.cleanupTags(workEl, options.cleanTags); + MediumEditor.util.unwrapTags(workEl, options.unwrapTags); } MediumEditor.util.insertHTMLCommand(this.document, fragmentBody.innerHTML.replace(/ /g, ' ')); diff --git a/src/js/util.js b/src/js/util.js index a05962f1a..cab64b769 100644 --- a/src/js/util.js +++ b/src/js/util.js @@ -1024,11 +1024,15 @@ }, cleanupTags: function (el, tags) { - tags.forEach(function (tag) { - if (el.nodeName.toLowerCase() === tag) { - el.parentNode.removeChild(el); - } - }); + if (tags.indexOf(el.nodeName.toLowerCase()) !== -1) { + el.parentNode.removeChild(el); + } + }, + + unwrapTags: function (el, tags) { + if (tags.indexOf(el.nodeName.toLowerCase()) !== -1) { + MediumEditor.util.unwrap(el, document); + } }, // get the closest parent From 5846a9756590eacb7e70354a11096640e354ae83 Mon Sep 17 00:00:00 2001 From: Zhu Liang Date: Sun, 14 Aug 2016 02:55:23 +0800 Subject: [PATCH 2/2] update OPTIONS.md using doctoc --- OPTIONS.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/OPTIONS.md b/OPTIONS.md index 31c9a89ca..4e7a83a8f 100644 --- a/OPTIONS.md +++ b/OPTIONS.md @@ -11,6 +11,7 @@ var editor = new MediumEditor('.editor', { + - [Core Options](#core-options) - [`activeButtonClass`](#activebuttonclass) - [`buttonLabels`](#buttonlabels) @@ -32,17 +33,20 @@ var editor = new MediumEditor('.editor', { - [`diffTop`](#difftop) - [`firstButtonClass`](#firstbuttonclass) - [`lastButtonClass`](#lastbuttonclass) + - [`relativeContainer`](#relativecontainer) - [`standardizeSelectionStart`](#standardizeselectionstart) - [`static`](#static) - ['static' Toolbar Options](#static-toolbar-options) - [`align`](#align) - [`sticky`](#sticky) + - [`stickyTopOffset`](#stickytopoffset) - [`updateOnEmptySelection`](#updateonemptyselection) - [Disabling Toolbar](#disabling-toolbar) - [Anchor Preview options](#anchor-preview-options) - [`hideDelay`](#hidedelay) - [`previewValueSelector`](#previewvalueselector) - [`showOnEmptyLinks`](#showonemptylinks) + - [`showWhenToolbarIsVisible`](#showwhentoolbarisvisible) - [Disabling Anchor Preview](#disabling-anchor-preview) - [Placeholder Options](#placeholder-options) - [`text`](#text) @@ -61,6 +65,7 @@ var editor = new MediumEditor('.editor', { - [`cleanReplacements`](#cleanreplacements) - [`cleanAttrs`](#cleanattrs) - [`cleanTags`](#cleantags) + - [`unwrapTags`](#unwraptags) - [Disabling Paste Handling](#disabling-paste-handling) - [KeyboardCommands Options](#keyboardcommands-options) - [`commands`](#commands)