]> scripts.mit.edu Git - autoinstalls/wordpress.git/blobdiff - wp-includes/js/tinymce/plugins/paste/plugin.js
WordPress 4.3.1
[autoinstalls/wordpress.git] / wp-includes / js / tinymce / plugins / paste / plugin.js
index 699096a39fa86845b5529aae6f7f4644502ab699..9c504700d95ae8cd5cdb6ccd711902f9649647d6 100644 (file)
        }
 
        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) {
 
                        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
 /**
  * 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
 /**
  * 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 |<br>
+                               // TODO: Might need to expand this to say |<table>
+                               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(/<b[^>]+id="?docs-internal-[^>]*>/gi, '');
+                       content = content.replace(/<br class="?Apple-interchange-newline"?>/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 "&middot; " 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