X-Git-Url: https://scripts.mit.edu/gitweb/autoinstalls/wordpress.git/blobdiff_plain/9e77185fafaf4e60e2b73821e0e4b9b1a11fb85f..refs/tags/wordpress-4.3.1:/wp-includes/js/tinymce/plugins/paste/plugin.js?ds=sidebyside diff --git a/wp-includes/js/tinymce/plugins/paste/plugin.js b/wp-includes/js/tinymce/plugins/paste/plugin.js index 699096a3..9c504700 100644 --- a/wp-includes/js/tinymce/plugins/paste/plugin.js +++ b/wp-includes/js/tinymce/plugins/paste/plugin.js @@ -63,10 +63,12 @@ } function expose(ids) { - for (var i = 0; i < ids.length; i++) { - var target = exports; - var id = ids[i]; - var fragments = id.split(/[.\/]/); + var i, target, id, fragments, privateModules; + + for (i = 0; i < ids.length; i++) { + target = exports; + id = ids[i]; + fragments = id.split(/[.\/]/); for (var fi = 0; fi < fragments.length - 1; ++fi) { if (target[fragments[fi]] === undefined) { @@ -78,6 +80,21 @@ target[fragments[fragments.length - 1]] = modules[id]; } + + // Expose private modules for unit tests + if (exports.AMDLC_TESTS) { + privateModules = exports.privateModules || {}; + + for (id in modules) { + privateModules[id] = modules[id]; + } + + for (i = 0; i < ids.length; i++) { + delete privateModules[ids[i]]; + } + + exports.privateModules = privateModules; + } } // Included from: js/tinymce/plugins/paste/classes/Utils.js @@ -85,8 +102,8 @@ /** * Utils.js * - * Copyright, Moxiecode Systems AB * Released under LGPL License. + * Copyright (c) 1999-2015 Ephox Corp. All rights reserved * * License: http://www.tinymce.com/license * Contributing: http://www.tinymce.com/contributing @@ -95,8 +112,7 @@ /** * This class contails various utility functions for the paste plugin. * - * @class tinymce.pasteplugin.Clipboard - * @private + * @class tinymce.pasteplugin.Utils */ define("tinymce/pasteplugin/Utils", [ "tinymce/util/Tools", @@ -218,8 +234,8 @@ define("tinymce/pasteplugin/Utils", [ /** * Clipboard.js * - * Copyright, Moxiecode Systems AB * Released under LGPL License. + * Copyright (c) 1999-2015 Ephox Corp. All rights reserved * * License: http://www.tinymce.com/license * Contributing: http://www.tinymce.com/contributing @@ -246,12 +262,14 @@ define("tinymce/pasteplugin/Utils", [ */ define("tinymce/pasteplugin/Clipboard", [ "tinymce/Env", + "tinymce/dom/RangeUtils", "tinymce/util/VK", "tinymce/pasteplugin/Utils" -], function(Env, VK, Utils) { +], function(Env, RangeUtils, VK, Utils) { return function(editor) { var self = this, pasteBinElm, lastRng, keyboardPasteTimeStamp = 0, draggingInternally = false; var pasteBinDefaultContent = '%MCEPASTEBIN%', keyboardPastePlainTextState; + var mceInternalUrlPrefix = 'data:text/mce-internal,'; /** * Pastes the specified HTML. This means that the HTML is filtered and then @@ -280,7 +298,7 @@ define("tinymce/pasteplugin/Clipboard", [ } if (!args.isDefaultPrevented()) { - editor.insertContent(html, {merge: editor.settings.paste_merge_formats !== false}); + editor.insertContent(html, {merge: editor.settings.paste_merge_formats !== false, data: {paste: true}}); } } } @@ -345,15 +363,63 @@ define("tinymce/pasteplugin/Clipboard", [ } } + /** + * Returns the rect of the current caret if the caret is in an empty block before a + * BR we insert a temporary invisible character that we get the rect this way we always get a proper rect. + * + * TODO: This might be useful in core. + */ + function getCaretRect(rng) { + var rects, textNode, node, container = rng.startContainer; + + rects = rng.getClientRects(); + if (rects.length) { + return rects[0]; + } + + if (!rng.collapsed || container.nodeType != 1) { + return; + } + + node = container.childNodes[lastRng.startOffset]; + + // Skip empty whitespace nodes + while (node && node.nodeType == 3 && !node.data.length) { + node = node.nextSibling; + } + + if (!node) { + return; + } + + // Check if the location is |
+ // TODO: Might need to expand this to say | + if (node.tagName == 'BR') { + textNode = dom.doc.createTextNode('\uFEFF'); + node.parentNode.insertBefore(textNode, node); + + rng = dom.createRng(); + rng.setStartBefore(textNode); + rng.setEndAfter(textNode); + + rects = rng.getClientRects(); + dom.remove(textNode); + } + + if (rects.length) { + return rects[0]; + } + } + // Calculate top cordinate this is needed to avoid scrolling to top of document // We want the paste bin to be as close to the caret as possible to avoid scrolling if (lastRng.getClientRects) { - var rects = lastRng.getClientRects(); + var rect = getCaretRect(lastRng); - if (rects.length) { + if (rect) { // Client rects gets us closes to the actual // caret location in for example a wrapped paragraph block - top = scrollTop + (rects[0].top - dom.getPos(body).y); + top = scrollTop + (rect.top - dom.getPos(body).y); } else { top = scrollTop; @@ -460,7 +526,9 @@ define("tinymce/pasteplugin/Clipboard", [ if (dataTransfer.getData) { var legacyText = dataTransfer.getData('Text'); if (legacyText && legacyText.length > 0) { - data['text/plain'] = legacyText; + if (legacyText.indexOf(mceInternalUrlPrefix) == -1) { + data['text/plain'] = legacyText; + } } } @@ -498,9 +566,9 @@ define("tinymce/pasteplugin/Clipboard", [ var dataTransfer = e.clipboardData || e.dataTransfer; function processItems(items) { - var i, item, reader; + var i, item, reader, hadImage = false; - function pasteImage() { + function pasteImage(reader) { if (rng) { editor.selection.setRng(rng); rng = null; @@ -513,16 +581,18 @@ define("tinymce/pasteplugin/Clipboard", [ for (i = 0; i < items.length; i++) { item = items[i]; - if (/^image\/(jpeg|png|gif)$/.test(item.type)) { + if (/^image\/(jpeg|png|gif|bmp)$/.test(item.type)) { reader = new FileReader(); - reader.onload = pasteImage; + reader.onload = pasteImage.bind(null, reader); reader.readAsDataURL(item.getAsFile ? item.getAsFile() : item); e.preventDefault(); - return true; + hadImage = true; } } } + + return hadImage; } if (editor.settings.paste_data_images && dataTransfer) { @@ -531,40 +601,19 @@ define("tinymce/pasteplugin/Clipboard", [ } /** - * Chrome on Andoid doesn't support proper clipboard access so we have no choice but to allow the browser default behavior. + * Chrome on Android doesn't support proper clipboard access so we have no choice but to allow the browser default behavior. * * @param {Event} e Paste event object to check if it contains any data. * @return {Boolean} true/false if the clipboard is empty or not. */ - function isBrokenAndoidClipboardEvent(e) { + function isBrokenAndroidClipboardEvent(e) { var clipboardData = e.clipboardData; return navigator.userAgent.indexOf('Android') != -1 && clipboardData && clipboardData.items && clipboardData.items.length === 0; } function getCaretRangeFromEvent(e) { - var doc = editor.getDoc(), rng, point; - - if (doc.caretPositionFromPoint) { - point = doc.caretPositionFromPoint(e.clientX, e.clientY); - rng = doc.createRange(); - rng.setStart(point.offsetNode, point.offset); - rng.collapse(true); - } else if (doc.caretRangeFromPoint) { - rng = doc.caretRangeFromPoint(e.clientX, e.clientY); - } else if (doc.body.createTextRange) { - rng = doc.body.createTextRange(); - - try { - rng.moveToPoint(e.clientX, e.clientY); - rng.collapse(true); - } catch (ex) { - // Append to top or bottom depending on drop location - rng.collapse(e.clientY < doc.body.clientHeight); - } - } - - return rng; + return RangeUtils.getCaretRangeFromPoint(e.clientX, e.clientY, editor.getDoc()); } function hasContentType(clipboardContent, mimeType) { @@ -630,7 +679,7 @@ define("tinymce/pasteplugin/Clipboard", [ keyboardPastePlainTextState = false; - if (e.isDefaultPrevented() || isBrokenAndoidClipboardEvent(e)) { + if (e.isDefaultPrevented() || isBrokenAndroidClipboardEvent(e)) { removePasteBin(); return; } @@ -759,16 +808,8 @@ define("tinymce/pasteplugin/Clipboard", [ }); editor.on('dragover dragend', function(e) { - var i, dataTransfer = e.dataTransfer; - - if (editor.settings.paste_data_images && dataTransfer) { - for (i = 0; i < dataTransfer.types.length; i++) { - // Prevent default if we have files dragged into the editor since the pasteImageData handles that - if (dataTransfer.types[i] == "Files") { - e.preventDefault(); - return false; - } - } + if (editor.settings.paste_data_images) { + e.preventDefault(); } }); } @@ -781,19 +822,40 @@ define("tinymce/pasteplugin/Clipboard", [ // Remove all data images from paste for example from Gecko // except internal images like video elements - editor.parser.addNodeFilter('img', function(nodes) { - if (!editor.settings.paste_data_images) { + editor.parser.addNodeFilter('img', function(nodes, name, args) { + function isPasteInsert(args) { + return args.data && args.data.paste === true; + } + + function remove(node) { + if (!node.attr('data-mce-object') && src !== Env.transparentSrc) { + node.remove(); + } + } + + function isWebKitFakeUrl(src) { + return src.indexOf("webkit-fake-url") === 0; + } + + function isDataUri(src) { + return src.indexOf("data:") === 0; + } + + if (!editor.settings.paste_data_images && isPasteInsert(args)) { var i = nodes.length; while (i--) { var src = nodes[i].attributes.map.src; - // Some browsers automatically produce data uris on paste + if (!src) { + continue; + } + // Safari on Mac produces webkit-fake-url see: https://bugs.webkit.org/show_bug.cgi?id=49141 - if (src && /^(data:image|webkit\-fake\-url)/.test(src)) { - if (!nodes[i].attr('data-mce-object') && src !== Env.transparentSrc) { - nodes[i].remove(); - } + if (isWebKitFakeUrl(src)) { + remove(nodes[i]); + } else if (!editor.settings.allow_html_data_urls && isDataUri(src)) { + remove(nodes[i]); } } } @@ -807,8 +869,8 @@ define("tinymce/pasteplugin/Clipboard", [ /** * WordFilter.js * - * Copyright, Moxiecode Systems AB * Released under LGPL License. + * Copyright (c) 1999-2015 Ephox Corp. All rights reserved * * License: http://www.tinymce.com/license * Contributing: http://www.tinymce.com/contributing @@ -817,7 +879,7 @@ define("tinymce/pasteplugin/Clipboard", [ /** * This class parses word HTML into proper TinyMCE markup. * - * @class tinymce.pasteplugin.Quirks + * @class tinymce.pasteplugin.WordFilter * @private */ define("tinymce/pasteplugin/WordFilter", [ @@ -868,7 +930,7 @@ define("tinymce/pasteplugin/WordFilter", [ } function isBulletList(text) { - return /^[\s\u00a0]*[\u2022\u00b7\u00a7\u00d8\u25CF]\s*/.test(text); + return /^[\s\u00a0]*[\u2022\u00b7\u00a7\u25CF]\s*/.test(text); } function WordFilter(editor) { @@ -877,6 +939,10 @@ define("tinymce/pasteplugin/WordFilter", [ editor.on('BeforePastePreProcess', function(e) { var content = e.content, retainStyleProperties, validStyles; + // Remove google docs internal guid markers + content = content.replace(/]+id="?docs-internal-[^>]*>/gi, ''); + content = content.replace(/
/gi, ''); + retainStyleProperties = settings.paste_retain_style_properties; if (retainStyleProperties) { validStyles = Tools.makeMap(retainStyleProperties.split(/[, ]/)); @@ -980,14 +1046,26 @@ define("tinymce/pasteplugin/WordFilter", [ // Remove start of list item "1. " or "· " etc removeIgnoredNodes(paragraphNode); trimListStart(paragraphNode, /^\u00a0+/); - trimListStart(paragraphNode, /^\s*([\u2022\u00b7\u00a7\u00d8\u25CF]|\w+\.)/); + trimListStart(paragraphNode, /^\s*([\u2022\u00b7\u00a7\u25CF]|\w+\.)/); trimListStart(paragraphNode, /^\u00a0+/); } - var paragraphs = node.getAll('p'); + // Build a list of all root level elements before we start + // altering them in the loop below. + var elements = [], child = node.firstChild; + while (typeof child !== 'undefined' && child !== null) { + elements.push(child); - for (var i = 0; i < paragraphs.length; i++) { - node = paragraphs[i]; + child = child.walk(); + if (child !== null) { + while (typeof child !== 'undefined' && child.parent !== node) { + child = child.walk(); + } + } + } + + for (var i = 0; i < elements.length; i++) { + node = elements[i]; if (node.name == 'p' && node.firstChild) { // Find first text node in paragraph @@ -1002,7 +1080,7 @@ define("tinymce/pasteplugin/WordFilter", [ // Detect ordered lists 1., a. or ixv. if (isNumericList(nodeText)) { // Parse OL start number - var matches = /([0-9])\./.exec(nodeText); + var matches = /([0-9]+)\./.exec(nodeText); var start = 1; if (matches) { start = parseInt(matches[1], 10); @@ -1018,6 +1096,13 @@ define("tinymce/pasteplugin/WordFilter", [ continue; } + currentListNode = null; + } else { + // If the root level element isn't a p tag which can be + // processed by convertParagraphToLi, it interrupts the + // lists, causing a new list to start instead of having + // elements from the next list inserted above this tag. + prevListNode = currentListNode; currentListNode = null; } } @@ -1152,8 +1237,11 @@ define("tinymce/pasteplugin/WordFilter", [ var validElements = settings.paste_word_valid_elements; if (!validElements) { - validElements = '-strong/b,-em/i,-span,-p,-ol,-ul,-li,-h1,-h2,-h3,-h4,-h5,-h6,-p/div,' + - '-table[width],-tr,-td[colspan|rowspan|width],-th,-thead,-tfoot,-tbody,-a[href|name],sub,sup,strike,br,del'; + validElements = ( + '-strong/b,-em/i,-u,-span,-p,-ol,-ul,-li,-h1,-h2,-h3,-h4,-h5,-h6,' + + '-p/div,-a[href|name],sub,sup,strike,br,del,table[width],tr,' + + 'td[colspan|rowspan|width],th[colspan|rowspan|width],thead,tfoot,tbody' + ); } // Setup strict schema @@ -1165,6 +1253,7 @@ define("tinymce/pasteplugin/WordFilter", [ // Add style/class attribute to all element rules since the user might have removed them from // paste_word_valid_elements config option and we need to check them for properties Tools.each(schema.elements, function(rule) { + /*eslint dot-notation:0*/ if (!rule.attributes["class"]) { rule.attributes["class"] = {}; rule.attributesOrder.push("class"); @@ -1202,7 +1291,7 @@ define("tinymce/pasteplugin/WordFilter", [ node = nodes[i]; className = node.attr('class'); - if (/^(MsoCommentReference|MsoCommentText|msoDel|MsoCaption)$/i.test(className)) { + if (/^(MsoCommentReference|MsoCommentText|msoDel)$/i.test(className)) { node.remove(); } @@ -1261,7 +1350,9 @@ define("tinymce/pasteplugin/WordFilter", [ var rootNode = domParser.parse(content); // Process DOM - convertFakeListsToProperLists(rootNode); + if (settings.paste_convert_word_fake_lists !== false) { + convertFakeListsToProperLists(rootNode); + } // Serialize DOM back to HTML e.content = new Serializer({}, schema).serialize(rootNode); @@ -1279,8 +1370,8 @@ define("tinymce/pasteplugin/WordFilter", [ /** * Quirks.js * - * Copyright, Moxiecode Systems AB * Released under LGPL License. + * Copyright (c) 1999-2015 Ephox Corp. All rights reserved * * License: http://www.tinymce.com/license * Contributing: http://www.tinymce.com/contributing @@ -1441,8 +1532,8 @@ define("tinymce/pasteplugin/Quirks", [ /** * Plugin.js * - * Copyright, Moxiecode Systems AB * Released under LGPL License. + * Copyright (c) 1999-2015 Ephox Corp. All rights reserved * * License: http://www.tinymce.com/license * Contributing: http://www.tinymce.com/contributing @@ -1549,5 +1640,5 @@ define("tinymce/pasteplugin/Plugin", [ }); }); -expose(["tinymce/pasteplugin/Utils","tinymce/pasteplugin/WordFilter"]); +expose(["tinymce/pasteplugin/Utils"]); })(this); \ No newline at end of file