]> scripts.mit.edu Git - autoinstalls/wordpress.git/blobdiff - wp-includes/js/tinymce/plugins/paste/plugin.js
WordPress 4.7.2-scripts
[autoinstalls/wordpress.git] / wp-includes / js / tinymce / plugins / paste / plugin.js
index 9c504700d95ae8cd5cdb6ccd711902f9649647d6..7d2a71e5998bbbff64106b675b595a01b933dfb6 100644 (file)
@@ -216,16 +216,120 @@ define("tinymce/pasteplugin/Utils", [
                        /^[\s\S]*<body[^>]*>\s*|\s*<\/body[^>]*>[\s\S]*$/g, // Remove anything but the contents within the BODY element
                        /<!--StartFragment-->|<!--EndFragment-->/g, // Inner fragments (tables from excel on mac)
                        [/( ?)<span class="Apple-converted-space">\u00a0<\/span>( ?)/g, trimSpaces],
+                       /<br class="Apple-interchange-newline">/g,
                        /<br>$/i // Trailing BR elements
                ]);
 
                return html;
        }
 
+       // TODO: Should be in some global class
+       function createIdGenerator(prefix) {
+               var count = 0;
+
+               return function() {
+                       return prefix + (count++);
+               };
+       }
+
        return {
                filter: filter,
                innerText: innerText,
-               trimHtml: trimHtml
+               trimHtml: trimHtml,
+               createIdGenerator: createIdGenerator
+       };
+});
+
+// Included from: js/tinymce/plugins/paste/classes/SmartPaste.js
+
+/**
+ * SmartPaste.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * Tries to be smart depending on what the user pastes if it looks like an url
+ * it will make a link out of the current selection. If it's an image url that looks
+ * like an image it will check if it's an image and insert it as an image.
+ *
+ * @class tinymce.pasteplugin.SmartPaste
+ * @private
+ */
+define("tinymce/pasteplugin/SmartPaste", [
+       "tinymce/util/Tools"
+], function (Tools) {
+       var isAbsoluteUrl = function (url) {
+               return /^https?:\/\/[\w\?\-\/+=.&%@~#]+$/i.test(url);
+       };
+
+       var isImageUrl = function (url) {
+               return isAbsoluteUrl(url) && /.(gif|jpe?g|png)$/.test(url);
+       };
+
+       var createImage = function (editor, url, pasteHtml) {
+               editor.undoManager.extra(function () {
+                       pasteHtml(editor, url);
+               }, function () {
+                       editor.insertContent('<img src="' + url + '">');
+               });
+
+               return true;
+       };
+
+       var createLink = function (editor, url, pasteHtml) {
+               editor.undoManager.extra(function () {
+                       pasteHtml(editor, url);
+               }, function () {
+                       editor.execCommand('mceInsertLink', false, url);
+               });
+
+               return true;
+       };
+
+       var linkSelection = function (editor, html, pasteHtml) {
+               return editor.selection.isCollapsed() === false && isAbsoluteUrl(html) ? createLink(editor, html, pasteHtml) : false;
+       };
+
+       var insertImage = function (editor, html, pasteHtml) {
+               return isImageUrl(html) ? createImage(editor, html, pasteHtml) : false;
+       };
+
+       var pasteHtml = function (editor, html) {
+               editor.insertContent(html, {
+                       merge: editor.settings.paste_merge_formats !== false,
+                       paste: true
+               });
+
+               return true;
+       };
+
+       var smartInsertContent = function (editor, html) {
+               Tools.each([
+                       linkSelection,
+                       insertImage,
+                       pasteHtml
+               ], function (action) {
+                       return action(editor, html, pasteHtml) !== true;
+               });
+       };
+
+       var insertContent = function (editor, html) {
+               if (editor.settings.smart_paste === false) {
+                       pasteHtml(editor, html);
+               } else {
+                       smartInsertContent(editor, html);
+               }
+       };
+
+       return {
+               isImageUrl: isImageUrl,
+               isAbsoluteUrl: isAbsoluteUrl,
+               insertContent: insertContent
        };
 });
 
@@ -264,12 +368,15 @@ define("tinymce/pasteplugin/Clipboard", [
        "tinymce/Env",
        "tinymce/dom/RangeUtils",
        "tinymce/util/VK",
-       "tinymce/pasteplugin/Utils"
-], function(Env, RangeUtils, VK, Utils) {
+       "tinymce/pasteplugin/Utils",
+       "tinymce/pasteplugin/SmartPaste",
+       "tinymce/util/Delay"
+], function(Env, RangeUtils, VK, Utils, SmartPaste, Delay) {
        return function(editor) {
                var self = this, pasteBinElm, lastRng, keyboardPasteTimeStamp = 0, draggingInternally = false;
                var pasteBinDefaultContent = '%MCEPASTEBIN%', keyboardPastePlainTextState;
                var mceInternalUrlPrefix = 'data:text/mce-internal,';
+               var uniqueId = Utils.createIdGenerator("mceclip");
 
                /**
                 * Pastes the specified HTML. This means that the HTML is filtered and then
@@ -298,7 +405,7 @@ define("tinymce/pasteplugin/Clipboard", [
                                }
 
                                if (!args.isDefaultPrevented()) {
-                                       editor.insertContent(html, {merge: editor.settings.paste_merge_formats !== false, data: {paste: true}});
+                                       SmartPaste.insertContent(editor, html);
                                }
                        }
                }
@@ -519,7 +626,7 @@ define("tinymce/pasteplugin/Clipboard", [
                 * @return {Object} Object with mime types and data for those mime types.
                 */
                function getDataTransferItems(dataTransfer) {
-                       var data = {};
+                       var items = {};
 
                        if (dataTransfer) {
                                // Use old WebKit/IE API
@@ -527,7 +634,7 @@ define("tinymce/pasteplugin/Clipboard", [
                                        var legacyText = dataTransfer.getData('Text');
                                        if (legacyText && legacyText.length > 0) {
                                                if (legacyText.indexOf(mceInternalUrlPrefix) == -1) {
-                                                       data['text/plain'] = legacyText;
+                                                       items['text/plain'] = legacyText;
                                                }
                                        }
                                }
@@ -535,12 +642,12 @@ define("tinymce/pasteplugin/Clipboard", [
                                if (dataTransfer.types) {
                                        for (var i = 0; i < dataTransfer.types.length; i++) {
                                                var contentType = dataTransfer.types[i];
-                                               data[contentType] = dataTransfer.getData(contentType);
+                                               items[contentType] = dataTransfer.getData(contentType);
                                        }
                                }
                        }
 
-                       return data;
+                       return items;
                }
 
                /**
@@ -554,12 +661,65 @@ define("tinymce/pasteplugin/Clipboard", [
                        return getDataTransferItems(clipboardEvent.clipboardData || editor.getDoc().dataTransfer);
                }
 
+               function hasHtmlOrText(content) {
+                       return hasContentType(content, 'text/html') || hasContentType(content, 'text/plain');
+               }
+
+               function getBase64FromUri(uri) {
+                       var idx;
+
+                       idx = uri.indexOf(',');
+                       if (idx !== -1) {
+                               return uri.substr(idx + 1);
+                       }
+
+                       return null;
+               }
+
+               function isValidDataUriImage(settings, imgElm) {
+                       return settings.images_dataimg_filter ? settings.images_dataimg_filter(imgElm) : true;
+               }
+
+               function pasteImage(rng, reader, blob) {
+                       if (rng) {
+                               editor.selection.setRng(rng);
+                               rng = null;
+                       }
+
+                       var dataUri = reader.result;
+                       var base64 = getBase64FromUri(dataUri);
+
+                       var img = new Image();
+                       img.src = dataUri;
+
+                       // TODO: Move the bulk of the cache logic to EditorUpload
+                       if (isValidDataUriImage(editor.settings, img)) {
+                               var blobCache = editor.editorUpload.blobCache;
+                               var blobInfo, existingBlobInfo;
+
+                               existingBlobInfo = blobCache.findFirst(function(cachedBlobInfo) {
+                                       return cachedBlobInfo.base64() === base64;
+                               });
+
+                               if (!existingBlobInfo) {
+                                       blobInfo = blobCache.create(uniqueId(), blob, base64);
+                                       blobCache.add(blobInfo);
+                               } else {
+                                       blobInfo = existingBlobInfo;
+                               }
+
+                               pasteHtml('<img src="' + blobInfo.blobUri() + '">');
+                       } else {
+                               pasteHtml('<img src="' + dataUri + '">');
+                       }
+               }
+
                /**
                 * Checks if the clipboard contains image data if it does it will take that data
                 * and convert it into a data url image and paste that image at the caret location.
                 *
                 * @param  {ClipboardEvent} e Paste/drop event object.
-                * @param  {DOMRange} rng Optional rng object to move selection to.
+                * @param  {DOMRange} rng Rng object to move selection to.
                 * @return {Boolean} true/false if the image data was found or not.
                 */
                function pasteImageData(e, rng) {
@@ -568,23 +728,16 @@ define("tinymce/pasteplugin/Clipboard", [
                        function processItems(items) {
                                var i, item, reader, hadImage = false;
 
-                               function pasteImage(reader) {
-                                       if (rng) {
-                                               editor.selection.setRng(rng);
-                                               rng = null;
-                                       }
-
-                                       pasteHtml('<img src="' + reader.result + '">');
-                               }
-
                                if (items) {
                                        for (i = 0; i < items.length; i++) {
                                                item = items[i];
 
                                                if (/^image\/(jpeg|png|gif|bmp)$/.test(item.type)) {
+                                                       var blob = item.getAsFile ? item.getAsFile() : item;
+
                                                        reader = new FileReader();
-                                                       reader.onload = pasteImage.bind(null, reader);
-                                                       reader.readAsDataURL(item.getAsFile ? item.getAsFile() : item);
+                                                       reader.onload = pasteImage.bind(null, rng, reader, blob);
+                                                       reader.readAsDataURL(blob);
 
                                                        e.preventDefault();
                                                        hadImage = true;
@@ -668,6 +821,69 @@ define("tinymce/pasteplugin/Clipboard", [
                                }
                        });
 
+                       function insertClipboardContent(clipboardContent, isKeyBoardPaste, plainTextMode) {
+                               var content;
+
+                               // Grab HTML from Clipboard API or paste bin as a fallback
+                               if (hasContentType(clipboardContent, 'text/html')) {
+                                       content = clipboardContent['text/html'];
+                               } else {
+                                       content = getPasteBinHtml();
+
+                                       // If paste bin is empty try using plain text mode
+                                       // since that is better than nothing right
+                                       if (content == pasteBinDefaultContent) {
+                                               plainTextMode = true;
+                                       }
+                               }
+
+                               content = Utils.trimHtml(content);
+
+                               // WebKit has a nice bug where it clones the paste bin if you paste from for example notepad
+                               // so we need to force plain text mode in this case
+                               if (pasteBinElm && pasteBinElm.firstChild && pasteBinElm.firstChild.id === 'mcepastebin') {
+                                       plainTextMode = true;
+                               }
+
+                               removePasteBin();
+
+                               // If we got nothing from clipboard API and pastebin then we could try the last resort: plain/text
+                               if (!content.length) {
+                                       plainTextMode = true;
+                               }
+
+                               // Grab plain text from Clipboard API or convert existing HTML to plain text
+                               if (plainTextMode) {
+                                       // Use plain text contents from Clipboard API unless the HTML contains paragraphs then
+                                       // we should convert the HTML to plain text since works better when pasting HTML/Word contents as plain text
+                                       if (hasContentType(clipboardContent, 'text/plain') && content.indexOf('</p>') == -1) {
+                                               content = clipboardContent['text/plain'];
+                                       } else {
+                                               content = Utils.innerText(content);
+                                       }
+                               }
+
+                               // If the content is the paste bin default HTML then it was
+                               // impossible to get the cliboard data out.
+                               if (content == pasteBinDefaultContent) {
+                                       if (!isKeyBoardPaste) {
+                                               editor.windowManager.alert('Please use Ctrl+V/Cmd+V keyboard shortcuts to paste contents.');
+                                       }
+
+                                       return;
+                               }
+
+                               if (plainTextMode) {
+                                       pasteText(content);
+                               } else {
+                                       pasteHtml(content);
+                               }
+                       }
+
+                       var getLastRng = function() {
+                               return lastRng || editor.selection.getRng();
+                       };
+
                        editor.on('paste', function(e) {
                                // Getting content from the Clipboard can take some time
                                var clipboardTimer = new Date().getTime();
@@ -684,7 +900,7 @@ define("tinymce/pasteplugin/Clipboard", [
                                        return;
                                }
 
-                               if (pasteImageData(e)) {
+                               if (!hasHtmlOrText(clipboardContent) && pasteImageData(e, getLastRng())) {
                                        removePasteBin();
                                        return;
                                }
@@ -706,102 +922,63 @@ define("tinymce/pasteplugin/Clipboard", [
                                        clipboardContent["text/html"] = getPasteBinHtml();
                                }
 
-                               setTimeout(function() {
-                                       var content;
-
-                                       // Grab HTML from Clipboard API or paste bin as a fallback
-                                       if (hasContentType(clipboardContent, 'text/html')) {
-                                               content = clipboardContent['text/html'];
-                                       } else {
-                                               content = getPasteBinHtml();
-
-                                               // If paste bin is empty try using plain text mode
-                                               // since that is better than nothing right
-                                               if (content == pasteBinDefaultContent) {
-                                                       plainTextMode = true;
-                                               }
-                                       }
-
-                                       content = Utils.trimHtml(content);
-
-                                       // WebKit has a nice bug where it clones the paste bin if you paste from for example notepad
-                                       // so we need to force plain text mode in this case
-                                       if (pasteBinElm && pasteBinElm.firstChild && pasteBinElm.firstChild.id === 'mcepastebin') {
-                                               plainTextMode = true;
-                                       }
-
-                                       removePasteBin();
-
-                                       // If we got nothing from clipboard API and pastebin then we could try the last resort: plain/text
-                                       if (!content.length) {
-                                               plainTextMode = true;
-                                       }
-
-                                       // Grab plain text from Clipboard API or convert existing HTML to plain text
-                                       if (plainTextMode) {
-                                               // Use plain text contents from Clipboard API unless the HTML contains paragraphs then
-                                               // we should convert the HTML to plain text since works better when pasting HTML/Word contents as plain text
-                                               if (hasContentType(clipboardContent, 'text/plain') && content.indexOf('</p>') == -1) {
-                                                       content = clipboardContent['text/plain'];
-                                               } else {
-                                                       content = Utils.innerText(content);
-                                               }
-                                       }
-
-                                       // If the content is the paste bin default HTML then it was
-                                       // impossible to get the cliboard data out.
-                                       if (content == pasteBinDefaultContent) {
-                                               if (!isKeyBoardPaste) {
-                                                       editor.windowManager.alert('Please use Ctrl+V/Cmd+V keyboard shortcuts to paste contents.');
-                                               }
-
-                                               return;
-                                       }
-
-                                       if (plainTextMode) {
-                                               pasteText(content);
-                                       } else {
-                                               pasteHtml(content);
-                                       }
-                               }, 0);
+                               // If clipboard API has HTML then use that directly
+                               if (hasContentType(clipboardContent, 'text/html')) {
+                                       e.preventDefault();
+                                       insertClipboardContent(clipboardContent, isKeyBoardPaste, plainTextMode);
+                               } else {
+                                       Delay.setEditorTimeout(editor, function() {
+                                               insertClipboardContent(clipboardContent, isKeyBoardPaste, plainTextMode);
+                                       }, 0);
+                               }
                        });
 
                        editor.on('dragstart dragend', function(e) {
                                draggingInternally = e.type == 'dragstart';
                        });
 
+                       function isPlainTextFileUrl(content) {
+                               return content['text/plain'].indexOf('file://') === 0;
+                       }
+
                        editor.on('drop', function(e) {
-                               var rng = getCaretRangeFromEvent(e);
+                               var dropContent, rng;
+
+                               rng = getCaretRangeFromEvent(e);
 
                                if (e.isDefaultPrevented() || draggingInternally) {
                                        return;
                                }
 
-                               if (pasteImageData(e, rng)) {
+                               dropContent = getDataTransferItems(e.dataTransfer);
+
+                               if ((!hasHtmlOrText(dropContent) || isPlainTextFileUrl(dropContent)) && pasteImageData(e, rng)) {
                                        return;
                                }
 
                                if (rng && editor.settings.paste_filter_drop !== false) {
-                                       var dropContent = getDataTransferItems(e.dataTransfer);
                                        var content = dropContent['mce-internal'] || dropContent['text/html'] || dropContent['text/plain'];
 
                                        if (content) {
                                                e.preventDefault();
 
-                                               editor.undoManager.transact(function() {
-                                                       if (dropContent['mce-internal']) {
-                                                               editor.execCommand('Delete');
-                                                       }
+                                               // FF 45 doesn't paint a caret when dragging in text in due to focus call by execCommand
+                                               Delay.setEditorTimeout(editor, function() {
+                                                       editor.undoManager.transact(function() {
+                                                               if (dropContent['mce-internal']) {
+                                                                       editor.execCommand('Delete');
+                                                               }
 
-                                                       editor.selection.setRng(rng);
+                                                               editor.selection.setRng(rng);
 
-                                                       content = Utils.trimHtml(content);
+                                                               content = Utils.trimHtml(content);
 
-                                                       if (!dropContent['text/html']) {
-                                                               pasteText(content);
-                                                       } else {
-                                                               pasteHtml(content);
-                                                       }
+                                                               if (!dropContent['text/html']) {
+                                                                       pasteText(content);
+                                                               } else {
+                                                                       pasteHtml(content);
+                                                               }
+                                                       });
                                                });
                                        }
                                }
@@ -816,6 +993,7 @@ define("tinymce/pasteplugin/Clipboard", [
 
                self.pasteHtml = pasteHtml;
                self.pasteText = pasteText;
+               self.pasteImageData = pasteImageData;
 
                editor.on('preInit', function() {
                        registerEventHandlers();
@@ -1355,7 +1533,9 @@ define("tinymce/pasteplugin/WordFilter", [
                                }
 
                                // Serialize DOM back to HTML
-                               e.content = new Serializer({}, schema).serialize(rootNode);
+                               e.content = new Serializer({
+                                       validate: settings.validate
+                               }, schema).serialize(rootNode);
                        }
                });
        }
@@ -1556,23 +1736,43 @@ define("tinymce/pasteplugin/Plugin", [
        PluginManager.add('paste', function(editor) {
                var self = this, clipboard, settings = editor.settings;
 
+               function isUserInformedAboutPlainText() {
+                       return userIsInformed || editor.settings.paste_plaintext_inform === false;
+               }
+
                function togglePlainTextPaste() {
                        if (clipboard.pasteFormat == "text") {
                                this.active(false);
                                clipboard.pasteFormat = "html";
+                               editor.fire('PastePlainTextToggle', {state: false});
                        } else {
                                clipboard.pasteFormat = "text";
                                this.active(true);
 
-                               if (!userIsInformed) {
-                                       editor.windowManager.alert(
-                                               'Paste is now in plain text mode. Contents will now ' +
-                                               'be pasted as plain text until you toggle this option off.'
-                                       );
+                               if (!isUserInformedAboutPlainText()) {
+                                       var message = editor.translate('Paste is now in plain text mode. Contents will now ' +
+                                               'be pasted as plain text until you toggle this option off.');
+
+                                       editor.notificationManager.open({
+                                               text: message,
+                                               type: 'info'
+                                       });
 
                                        userIsInformed = true;
+                                       editor.fire('PastePlainTextToggle', {state: true});
                                }
                        }
+
+                       editor.focus();
+               }
+
+               // draw back if power version is requested and registered
+               if (/(^|[ ,])powerpaste([, ]|$)/.test(settings.plugins) && PluginManager.get('powerpaste')) {
+                       /*eslint no-console:0 */
+                       if (typeof console !== "undefined" && console.log) {
+                               console.log("PowerPaste is incompatible with Paste plugin! Remove 'paste' from the 'plugins' option.");
+                       }
+                       return;
                }
 
                self.clipboard = clipboard = new Clipboard(editor);
@@ -1606,7 +1806,7 @@ define("tinymce/pasteplugin/Plugin", [
                });
 
                // Block all drag/drop events
-               if (editor.paste_block_drop) {
+               if (editor.settings.paste_block_drop) {
                        editor.on('dragend dragover draggesture dragdrop drop drag', function(e) {
                                e.preventDefault();
                                e.stopPropagation();