// -- Paste command\r
// * fire 'paste' on editable ('beforepaste' for IE)\r
// * !canceled && execCommand 'paste'\r
-// * !success && fire 'pasteDialog' on editor\r
// -- Paste from native context menu & menubar\r
// (Fx & Webkits are handled in 'paste' default listener.\r
// Opera cannot be handled at all because it doesn't fire any events\r
( function() {\r
// Register the plugin.\r
CKEDITOR.plugins.add( 'clipboard', {\r
- requires: 'dialog',\r
+ requires: 'notification,toolbar',\r
// jscs:disable maximumLineLength\r
- lang: 'af,ar,az,bg,bn,bs,ca,cs,cy,da,de,de-ch,el,en,en-au,en-ca,en-gb,eo,es,et,eu,fa,fi,fo,fr,fr-ca,gl,gu,he,hi,hr,hu,id,is,it,ja,ka,km,ko,ku,lt,lv,mk,mn,ms,nb,nl,no,oc,pl,pt,pt-br,ro,ru,si,sk,sl,sq,sr,sr-latn,sv,th,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%\r
+ lang: 'af,ar,az,bg,bn,bs,ca,cs,cy,da,de,de-ch,el,en,en-au,en-ca,en-gb,eo,es,es-mx,et,eu,fa,fi,fo,fr,fr-ca,gl,gu,he,hi,hr,hu,id,is,it,ja,ka,km,ko,ku,lt,lv,mk,mn,ms,nb,nl,no,oc,pl,pt,pt-br,ro,ru,si,sk,sl,sq,sr,sr-latn,sv,th,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%\r
// jscs:enable maximumLineLength\r
icons: 'copy,copy-rtl,cut,cut-rtl,paste,paste-rtl', // %REMOVE_LINE_CORE%\r
hidpi: true, // %REMOVE_LINE_CORE%\r
initPasteClipboard( editor );\r
initDragDrop( editor );\r
\r
- CKEDITOR.dialog.add( 'paste', CKEDITOR.getUrl( this.path + 'dialogs/paste.js' ) );\r
-\r
// Convert image file (if present) to base64 string for Firefox. Do it as the first\r
// step as the conversion is asynchronous and should hold all further paste processing.\r
if ( CKEDITOR.env.gecko ) {\r
data = dataObj.dataValue,\r
dataTransfer = dataObj.dataTransfer;\r
\r
- // If data empty check for image content inside data transfer. #16705\r
+ // If data empty check for image content inside data transfer. http://dev.ckeditor.com/ticket/16705\r
if ( !data && dataObj.method == 'paste' && dataTransfer && dataTransfer.getFilesCount() == 1 && latestId != dataTransfer.id ) {\r
var file = dataTransfer.getFile( 0 );\r
\r
data = data.replace( /(<[^>]+) class="Apple-[^"]*"/gi, '$1' );\r
}\r
\r
- // Strip editable that was copied from inside. (#9534)\r
+ // Strip editable that was copied from inside. (http://dev.ckeditor.com/ticket/9534)\r
if ( data.match( /^<[^<]+cke_(editable|contents)/i ) ) {\r
var tmp,\r
editable_wrapper,\r
wrapper = new CKEDITOR.dom.element( 'div' );\r
\r
wrapper.setHtml( data );\r
- // Verify for sure and check for nested editor UI parts. (#9675)\r
+ // Verify for sure and check for nested editor UI parts. (http://dev.ckeditor.com/ticket/9675)\r
while ( wrapper.getChildCount() == 1 &&\r
( tmp = wrapper.getFirst() ) &&\r
tmp.type == CKEDITOR.NODE_ELEMENT && // Make sure first-child is element.\r
\r
editor.on( 'paste', function( evt ) {\r
var dataObj = evt.data,\r
- type = dataObj.type,\r
+ type = editor._.nextPasteType || dataObj.type,\r
data = dataObj.dataValue,\r
trueType,\r
// Default is 'html'.\r
trueType = recogniseContentType( data );\r
}\r
\r
+ delete editor._.nextPasteType;\r
+\r
// Unify text markup.\r
if ( trueType == 'htmlifiedtext' ) {\r
data = htmlifiedTextHtmlification( editor.config, data );\r
}\r
\r
// Strip presentational markup & unify text markup.\r
- // Forced plain text (dialog or forcePAPT).\r
+ // Forced plain text.\r
// Note: we do not check dontFilter option in this case, because forcePAPT was implemented\r
// before pasteFilter and pasteFilter is automatically used on Webkit&Blink since 4.5, so\r
// forcePAPT should have priority as it had before 4.5.\r
}, 0 );\r
}\r
}, null, null, 1000 );\r
-\r
- editor.on( 'pasteDialog', function( evt ) {\r
- // TODO it's possible that this setTimeout is not needed any more,\r
- // because of changes introduced in the same commit as this comment.\r
- // Editor.getClipboardData adds listener to the dialog's events which are\r
- // fired after a while (not like 'showDialog').\r
- setTimeout( function() {\r
- // Open default paste dialog.\r
- editor.openDialog( 'paste', evt.data );\r
- }, 0 );\r
- } );\r
}\r
} );\r
\r
}\r
\r
// Because of FF bug we need to use this hack, otherwise cursor is hidden\r
- // or it is not possible to move it (#12420).\r
- // Also, check that editor.toolbox exists, because the toolbar plugin might not be loaded (#13305).\r
+ // or it is not possible to move it (http://dev.ckeditor.com/ticket/12420).\r
+ // Also, check that editor.toolbox exists, because the toolbar plugin might not be loaded (http://dev.ckeditor.com/ticket/13305).\r
if ( CKEDITOR.env.gecko && data.method == 'drop' && editor.toolbox ) {\r
editor.once( 'afterPaste', function() {\r
editor.toolbox.focus();\r
addButtonsCommands();\r
\r
/**\r
- * Gets clipboard data by directly accessing the clipboard (IE only) or opening the paste dialog window.\r
+ * Gets clipboard data by directly accessing the clipboard (IE only).\r
*\r
- * editor.getClipboardData( { title: 'Get my data' }, function( data ) {\r
+ * editor.getClipboardData( function( data ) {\r
* if ( data )\r
* alert( data.type + ' ' + data.dataValue );\r
* } );\r
*\r
* @member CKEDITOR.editor\r
- * @param {Object} options\r
- * @param {String} [options.title] The title of the paste dialog window.\r
- * @param {Function} callback A function that will be executed with `data.type` and `data.dataValue`\r
- * or `null` if none of the capturing methods succeeded.\r
+ * @param {Function/Object} callbackOrOptions For function, see the `callback` parameter documentation. The object was used before 4.7.0 with the `title` property, to set the paste dialog's title.\r
+ * @param {Function} callback A function that will be executed with the `data` property of the\r
+ * {@link CKEDITOR.editor#event-paste paste event} or `null` if none of the capturing methods succeeded.\r
+ * Since 4.7.0 the `callback` should be provided as a first argument, just like in the example above. This parameter will be removed in\r
+ * an upcoming major release.\r
*/\r
- editor.getClipboardData = function( options, callback ) {\r
- var beforePasteNotCanceled = false,\r
- dataType = 'auto',\r
- dialogCommited = false;\r
-\r
+ editor.getClipboardData = function( callbackOrOptions, callback ) {\r
// Options are optional - args shift.\r
if ( !callback ) {\r
- callback = options;\r
- options = null;\r
+ callback = callbackOrOptions;\r
+ callbackOrOptions = null;\r
}\r
\r
// Listen with maximum priority to handle content before everyone else.\r
// access to the clipboard succeed in IE.\r
editor.on( 'paste', onPaste, null, null, 0 );\r
\r
- // Listen at the end of listeners chain to see if event wasn't canceled\r
- // and to retrieve modified data.type.\r
- editor.on( 'beforePaste', onBeforePaste, null, null, 1000 );\r
-\r
- // getClipboardDataDirectly() will fire 'beforePaste' synchronously, so we can\r
- // check if it was canceled and if any listener modified data.type.\r
-\r
// If command didn't succeed (only IE allows to access clipboard and only if\r
- // user agrees) open and handle paste dialog.\r
+ // user agrees) invoke callback with null, meaning that paste is not blocked.\r
if ( getClipboardDataDirectly() === false ) {\r
// Direct access to the clipboard wasn't successful so remove listener.\r
editor.removeListener( 'paste', onPaste );\r
\r
- // If beforePaste was canceled do not open dialog.\r
- // Add listeners only if dialog really opened. 'pasteDialog' can be canceled.\r
- if ( beforePasteNotCanceled && editor.fire( 'pasteDialog', onDialogOpen ) ) {\r
- editor.on( 'pasteDialogCommit', onDialogCommit );\r
-\r
- // 'dialogHide' will be fired after 'pasteDialogCommit'.\r
- editor.on( 'dialogHide', function( evt ) {\r
- evt.removeListener();\r
- evt.data.removeListener( 'pasteDialogCommit', onDialogCommit );\r
-\r
- // Because Opera has to wait a while in pasteDialog we have to wait here.\r
- setTimeout( function() {\r
- // Notify even if user canceled dialog (clicked 'cancel', ESC, etc).\r
- if ( !dialogCommited )\r
- callback( null );\r
- }, 10 );\r
- } );\r
- } else {\r
- callback( null );\r
- }\r
+ callback( null );\r
}\r
\r
function onPaste( evt ) {\r
evt.cancel();\r
callback( evt.data );\r
}\r
-\r
- function onBeforePaste( evt ) {\r
- evt.removeListener();\r
- beforePasteNotCanceled = true;\r
- dataType = evt.data.type;\r
- }\r
-\r
- function onDialogCommit( evt ) {\r
- evt.removeListener();\r
- // Cancel pasteDialogCommit so paste dialog won't automatically fire\r
- // 'paste' evt by itself.\r
- evt.cancel();\r
- dialogCommited = true;\r
- callback( {\r
- type: dataType,\r
- dataValue: evt.data.dataValue,\r
- dataTransfer: evt.data.dataTransfer,\r
- method: 'paste'\r
- } );\r
- }\r
-\r
- function onDialogOpen() {\r
- this.customTitle = ( options && options.title );\r
- }\r
};\r
\r
function addButtonsCommands() {\r
\r
if ( CKEDITOR.plugins.clipboard.isCustomCopyCutSupported ) {\r
var initOnCopyCut = function( evt ) {\r
- // If user tries to cut in read-only editor, we must prevent default action. (#13872)\r
+ // If user tries to cut in read-only editor, we must prevent default action. (http://dev.ckeditor.com/ticket/13872)\r
if ( !editor.readOnly || evt.name != 'cut' ) {\r
clipboard.initPasteDataTransfer( evt, editor );\r
}\r
\r
// Delete content with the low priority so one can overwrite cut data.\r
editable.on( 'cut', function() {\r
- // If user tries to cut in read-only editor, we must prevent default action. (#13872)\r
+ // If user tries to cut in read-only editor, we must prevent default action. (http://dev.ckeditor.com/ticket/13872)\r
if ( !editor.readOnly ) {\r
editor.extractSelectedHtml();\r
}\r
pasteDataFromClipboard( evt );\r
\r
// Force IE to paste content into pastebin so pasteDataFromClipboard will work.\r
- if ( !execIECommand( 'paste' ) ) {\r
- editor.openDialog( 'paste' );\r
- }\r
+ execIECommand( 'paste' );\r
} );\r
\r
// If mainPasteEvent is 'beforePaste' (IE before Edge),\r
- // dismiss the (wrong) 'beforepaste' event fired on context/toolbar menu open. (#7953)\r
+ // dismiss the (wrong) 'beforepaste' event fired on context/toolbar menu open. (http://dev.ckeditor.com/ticket/7953)\r
editable.on( 'contextmenu', preventBeforePasteEventNow, null, null, 0 );\r
\r
editable.on( 'beforepaste', function( evt ) {\r
- // Do not prevent event on CTRL+V and SHIFT+INS because it blocks paste (#11970).\r
+ // Do not prevent event on CTRL+V and SHIFT+INS because it blocks paste (http://dev.ckeditor.com/ticket/11970).\r
if ( evt.data && !evt.data.$.ctrlKey && !evt.data.$.shiftKey )\r
preventBeforePasteEventNow();\r
}, null, null, 0 );\r
\r
// Use editor.document instead of editable in non-IEs for observing mouseup\r
// since editable won't fire the event if selection process started within\r
- // iframe and ended out of the editor (#9851).\r
+ // iframe and ended out of the editor (http://dev.ckeditor.com/ticket/9851).\r
editable.attachListener( CKEDITOR.env.ie ? editable : editor.document.getDocumentElement(), 'mouseup', function() {\r
mouseupTimeout = setTimeout( function() {\r
setToolbarStates();\r
\r
// Make sure that deferred mouseup callback isn't executed after editor instance\r
// had been destroyed. This may happen when editor.destroy() is called in parallel\r
- // with mouseup event (i.e. a button with onclick callback) (#10219).\r
+ // with mouseup event (i.e. a button with onclick callback) (http://dev.ckeditor.com/ticket/10219).\r
editor.on( 'destroy', function() {\r
clearTimeout( mouseupTimeout );\r
} );\r
canUndo: false,\r
async: true,\r
fakeKeystroke: CKEDITOR.CTRL + 86 /*V*/,\r
+\r
+ /**\r
+ * The default implementation of the paste command.\r
+ *\r
+ * @private\r
+ * @param {CKEDITOR.editor} editor An instance of the editor where the command is being executed.\r
+ * @param {Object/String} data If `data` is a string, then it is considered content that is being pasted.\r
+ * Otherwise it is treated as an object with options.\r
+ * @param {Boolean/String} [data.notification=true] Content for a notification shown after an unsuccessful\r
+ * paste attempt. If `false`, the notification will not be displayed. This parameter was added in 4.7.0.\r
+ * @param {String} [data.type='html'] The type of pasted content. There are two allowed values:\r
+ * * 'html'\r
+ * * 'text'\r
+ * @param {String/Object} data.dataValue Content being pasted. If this parameter is an object, it\r
+ * is supposed to be a `data` property of the {@link CKEDITOR.editor#paste} event.\r
+ * @param {CKEDITOR.plugins.clipboard.dataTransfer} data.dataTransfer Data transfer instance connected\r
+ * with the current paste action.\r
+ * @member CKEDITOR.editor.commands.paste\r
+ */\r
exec: function( editor, data ) {\r
+ data = typeof data !== 'undefined' && data !== null ? data : {};\r
+\r
var cmd = this,\r
- fire = function( data, withBeforePaste ) {\r
- data && firePasteEvents( editor, data, !!withBeforePaste );\r
-\r
- editor.fire( 'afterCommandExec', {\r
- name: 'paste',\r
- command: cmd,\r
- returnValue: !!data\r
- } );\r
- };\r
-\r
- // Check data precisely - don't open dialog on empty string.\r
- if ( typeof data == 'string' )\r
- fire( {\r
- dataValue: data,\r
- method: 'paste',\r
- dataTransfer: clipboard.initPasteDataTransfer()\r
- }, 1 );\r
- else\r
- editor.getClipboardData( fire );\r
+ notification = typeof data.notification !== 'undefined' ? data.notification : true,\r
+ forcedType = data.type,\r
+ keystroke = CKEDITOR.tools.keystrokeToString( editor.lang.common.keyboard,\r
+ editor.getCommandKeystroke( this ) ),\r
+ msg = typeof notification === 'string' ? notification : editor.lang.clipboard.pasteNotification\r
+ .replace( /%1/, '<kbd aria-label="' + keystroke.aria + '">' + keystroke.display + '</kbd>' ),\r
+ pastedContent = typeof data === 'string' ? data : data.dataValue;\r
+\r
+ function callback( data, withBeforePaste ) {\r
+ withBeforePaste = typeof withBeforePaste !== 'undefined' ? withBeforePaste : true;\r
+\r
+ if ( data ) {\r
+ data.method = 'paste';\r
+\r
+ if ( !data.dataTransfer ) {\r
+ data.dataTransfer = clipboard.initPasteDataTransfer();\r
+ }\r
+\r
+ firePasteEvents( editor, data, withBeforePaste );\r
+ } else if ( notification ) {\r
+ editor.showNotification( msg, 'info', editor.config.clipboard_notificationDuration );\r
+ }\r
+\r
+ editor.fire( 'afterCommandExec', {\r
+ name: 'paste',\r
+ command: cmd,\r
+ returnValue: !!data\r
+ } );\r
+ }\r
+\r
+ // Force type for the next paste.\r
+ if ( forcedType ) {\r
+ editor._.nextPasteType = forcedType;\r
+ } else {\r
+ delete editor._.nextPasteType;\r
+ }\r
+\r
+ if ( typeof pastedContent === 'string' ) {\r
+ callback( {\r
+ dataValue: pastedContent\r
+ } );\r
+ } else {\r
+ editor.getClipboardData( callback );\r
+ }\r
}\r
};\r
}\r
return enabled;\r
}\r
\r
- // Cutting off control type element in IE standards breaks the selection entirely. (#4881)\r
+ // Cutting off control type element in IE standards breaks the selection entirely. (http://dev.ckeditor.com/ticket/4881)\r
function fixCut() {\r
if ( !CKEDITOR.env.ie || CKEDITOR.env.quirks )\r
return;\r
},\r
blurListener;\r
\r
- // Avoid recursions on 'paste' event or consequent paste too fast. (#5730)\r
+ // Avoid recursions on 'paste' event or consequent paste too fast. (http://dev.ckeditor.com/ticket/5730)\r
if ( doc.getById( 'cke_pastebin' ) )\r
return;\r
\r
var sel = editor.getSelection();\r
var bms = sel.createBookmarks();\r
\r
- // #11384. On IE9+ we use native selectionchange (i.e. editor#selectionCheck) to cache the most\r
+ // http://dev.ckeditor.com/ticket/11384. On IE9+ we use native selectionchange (i.e. editor#selectionCheck) to cache the most\r
// recent selection which we then lock on editable blur. See selection.js for more info.\r
// selectionchange fired before getClipboardDataByPastebin() cached selection\r
// before creating bookmark (cached selection will be invalid, because bookmarks modified the DOM),\r
// It's better to paste close to the real paste destination, so inherited styles\r
// (which Webkits will try to compensate by styling span) differs less from the destination's one.\r
editable.append( pastebin );\r
- // Style pastebin like .cke_editable, to minimize differences between origin and destination. (#9754)\r
+ // Style pastebin like .cke_editable, to minimize differences between origin and destination. (http://dev.ckeditor.com/ticket/9754)\r
pastebin.addClass( 'cke_editable' );\r
\r
// Compensate position of offsetParent.\r
padding: 0\r
} );\r
\r
- // Paste fails in Safari when the body tag has 'user-select: none'. (#12506)\r
+ // Paste fails in Safari when the body tag has 'user-select: none'. (http://dev.ckeditor.com/ticket/12506)\r
if ( CKEDITOR.env.safari )\r
pastebin.setStyles( CKEDITOR.tools.cssVendorPrefix( 'user-select', 'text' ) );\r
\r
\r
// Webkit fill fire blur on editable when moving selection to\r
// pastebin (if body is used). Cancel it because it causes incorrect\r
- // selection lock in case of inline editor (#10644).\r
- // The same seems to apply to Firefox (#10787).\r
+ // selection lock in case of inline editor (http://dev.ckeditor.com/ticket/10644).\r
+ // The same seems to apply to Firefox (http://dev.ckeditor.com/ticket/10787).\r
if ( CKEDITOR.env.webkit || CKEDITOR.env.gecko )\r
blurListener = editable.once( 'blur', cancel, null, null, -100 );\r
\r
// If non-native paste is executed, IE will open security alert and blur editable.\r
// Editable will then lock selection inside itself and after accepting security alert\r
// this selection will be restored. We overwrite stored selection, so it's restored\r
- // in pastebin. (#9552)\r
+ // in pastebin. (http://dev.ckeditor.com/ticket/9552)\r
if ( CKEDITOR.env.ie ) {\r
blurListener = editable.once( 'blur', function() {\r
editor.lockSelection( selPastebin );\r
// Wait a while and grab the pasted contents.\r
setTimeout( function() {\r
// Restore main window's scroll position which could have been changed\r
- // by browser in cases described in #9771.\r
+ // by browser in cases described in http://dev.ckeditor.com/ticket/9771.\r
if ( CKEDITOR.env.webkit )\r
CKEDITOR.document.getBody().$.scrollTop = scrollTop;\r
\r
// Blur will be fired only on non-native paste. In other case manually remove listener.\r
blurListener && blurListener.removeListener();\r
\r
- // Restore properly the document focus. (#8849)\r
+ // Restore properly the document focus. (http://dev.ckeditor.com/ticket/8849)\r
if ( CKEDITOR.env.ie )\r
editable.focus();\r
\r
- // IE7: selection must go before removing pastebin. (#8691)\r
+ // IE7: selection must go before removing pastebin. (http://dev.ckeditor.com/ticket/8691)\r
sel.selectBookmarks( bms );\r
pastebin.remove();\r
\r
// On other browsers we should fire beforePaste event and return false.\r
function getClipboardDataDirectly() {\r
if ( clipboard.mainPasteEvent == 'paste' ) {\r
- // beforePaste should be fired when dialog open so it can be canceled.\r
editor.fire( 'beforePaste', { type: 'auto', method: 'paste' } );\r
return false;\r
}\r
// we're canceling it.\r
preventPasteEventNow();\r
\r
- // #9247: Lock focus to prevent IE from hiding toolbar for inline editor.\r
+ // http://dev.ckeditor.com/ticket/9247: Lock focus to prevent IE from hiding toolbar for inline editor.\r
var focusManager = editor.focusManager;\r
focusManager.lock();\r
\r
editor.fire( 'saveSnapshot' ); // Save before cut\r
setTimeout( function() {\r
editor.fire( 'saveSnapshot' ); // Save after cut\r
- }, 50 ); // OSX is slow (#11416).\r
+ }, 50 ); // OSX is slow (http://dev.ckeditor.com/ticket/11416).\r
}\r
}\r
\r
\r
// -------------- DRAGOVER TOP & BOTTOM --------------\r
\r
- // Not allowing dragging on toolbar and bottom (#12613).\r
+ // Not allowing dragging on toolbar and bottom (http://dev.ckeditor.com/ticket/12613).\r
clipboard.preventDefaultDropOnElement( top );\r
clipboard.preventDefaultDropOnElement( bottom );\r
\r
// Save drag range globally for cross editor D&D.\r
var dragRange = clipboard.dragRange = editor.getSelection().getRanges()[ 0 ];\r
\r
- // Store number of children, so we can later tell if any text node was split on drop. (#13011, #13447)\r
+ // Store number of children, so we can later tell if any text node was split on drop. (http://dev.ckeditor.com/ticket/13011, http://dev.ckeditor.com/ticket/13447)\r
if ( CKEDITOR.env.ie && CKEDITOR.env.version < 10 ) {\r
clipboard.dragStartContainerChildCount = dragRange ? getContainerChildCount( dragRange.startContainer ) : null;\r
clipboard.dragEndContainerChildCount = dragRange ? getContainerChildCount( dragRange.endContainer ) : null;\r
// we drop image it will overwrite document.\r
\r
editable.attachListener( dropTarget, 'dragover', function( evt ) {\r
+ // Edge requires this handler to have `preventDefault()` regardless of the situation.\r
+ if ( CKEDITOR.env.edge ) {\r
+ evt.data.preventDefault();\r
+ return;\r
+ }\r
+\r
var target = evt.data.getTarget();\r
\r
- // Prevent reloading page when dragging image on empty document (#12619).\r
+ // Prevent reloading page when dragging image on empty document (http://dev.ckeditor.com/ticket/12619).\r
if ( target && target.is && target.is( 'html' ) ) {\r
evt.data.preventDefault();\r
return;\r
// -------------- DROP --------------\r
\r
editable.attachListener( dropTarget, 'drop', function( evt ) {\r
- // Do nothing if event was already prevented. (#13879)\r
+ // Do nothing if event was already prevented. (http://dev.ckeditor.com/ticket/13879)\r
if ( evt.data.$.defaultPrevented ) {\r
return;\r
}\r
var target = evt.data.getTarget(),\r
readOnly = target.isReadOnly();\r
\r
- // Do nothing if drop on non editable element (#13015).\r
+ // Do nothing if drop on non editable element (http://dev.ckeditor.com/ticket/13015).\r
// The <html> tag isn't editable (body is), but we want to allow drop on it\r
// (so it is possible to drop below editor contents).\r
if ( readOnly && !( target.type == CKEDITOR.NODE_ELEMENT && target.is( 'html' ) ) ) {\r
}\r
\r
// In Chrome we can trust Clipboard API, with the exception of Chrome on Android (in both - mobile and desktop modes), where\r
- // clipboard API is not available so we need to check it (#13187).\r
+ // clipboard API is not available so we need to check it (http://dev.ckeditor.com/ticket/13187).\r
if ( CKEDITOR.env.chrome && !dataTransfer.isEmpty() ) {\r
return true;\r
}\r
\r
// Because of a Firefox bug HTML data are not available in some cases (e.g. paste from Word), in such cases we\r
- // need to use the pastebin (#13528, https://bugzilla.mozilla.org/show_bug.cgi?id=1183686).\r
+ // need to use the pastebin (http://dev.ckeditor.com/ticket/13528, https://bugzilla.mozilla.org/show_bug.cgi?id=1183686).\r
if ( CKEDITOR.env.gecko && ( dataTransfer.getData( 'text/html' ) || dataTransfer.getFilesCount() ) ) {\r
return true;\r
}\r
\r
- // In Safari and IE HTML data is not available though the Clipboard API.\r
+ // Safari fixed clipboard in 10.1 (https://bugs.webkit.org/show_bug.cgi?id=19893) (http://dev.ckeditor.com/ticket/16982).\r
+ // However iOS version still doesn't work well enough (https://bugs.webkit.org/show_bug.cgi?id=19893#c34).\r
+ if ( CKEDITOR.env.safari && CKEDITOR.env.version >= 603 && !CKEDITOR.env.iOS ) {\r
+ return true;\r
+ }\r
+\r
+ // In older Safari and IE HTML data is not available though the Clipboard API.\r
// In Edge things are a bit messy at the moment -\r
// https://connect.microsoft.com/IE/feedback/details/1572456/edge-clipboard-api-text-html-content-messed-up-in-event-clipboarddata\r
// It is safer to use the paste bin in unknown cases.\r
getDropTarget: function( editor ) {\r
var editable = editor.editable();\r
\r
- // #11123 Firefox needs to listen on document, because otherwise event won't be fired.\r
- // #11086 IE8 cannot listen on document.\r
+ // http://dev.ckeditor.com/ticket/11123 Firefox needs to listen on document, because otherwise event won't be fired.\r
+ // http://dev.ckeditor.com/ticket/11086 IE8 cannot listen on document.\r
if ( ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 ) || editable.isInline() ) {\r
return editable;\r
} else {\r
// Check if drop range is inside range.\r
// This is an edge case when we drop something on editable's margin/padding.\r
// That space is not treated as a part of the range we drag, so it is possible to drop there.\r
- // When we drop, browser tries to find closest drop position and it finds it inside drag range. (#13453)\r
+ // When we drop, browser tries to find closest drop position and it finds it inside drag range. (http://dev.ckeditor.com/ticket/13453)\r
var startNode = dragBookmark.startNode,\r
endNode = dragBookmark.endNode,\r
dropNode = dropBookmark.startNode,\r
return dropEvt.data.testRange;\r
\r
// Webkits.\r
- if ( document.caretRangeFromPoint ) {\r
+ if ( document.caretRangeFromPoint && editor.document.$.caretRangeFromPoint( x, y ) ) {\r
$range = editor.document.$.caretRangeFromPoint( x, y );\r
range.setStart( CKEDITOR.dom.node( $range.startContainer ), $range.startOffset );\r
range.collapse( true );\r
*/\r
initPasteDataTransfer: function( evt, sourceEditor ) {\r
if ( !this.isCustomCopyCutSupported ) {\r
- // Edge does not support custom copy/cut, but it have some useful data in the clipboardData (#13755).\r
+ // Edge does not support custom copy/cut, but it have some useful data in the clipboardData (http://dev.ckeditor.com/ticket/13755).\r
return new this.dataTransfer( ( CKEDITOR.env.edge && evt && evt.data.$ && evt.data.$.clipboardData ) || null, sourceEditor );\r
} else if ( evt && evt.data && evt.data.$ ) {\r
var dataTransfer = new this.dataTransfer( evt.data.$.clipboardData, sourceEditor );\r
* Facade for the native `getData` method.\r
*\r
* @param {String} type The type of data to retrieve.\r
+ * @param {Boolean} [getNative=false] Indicates if the whole, original content of the dataTransfer should be returned.\r
+ * Introduced in CKEditor 4.7.0.\r
* @returns {String} type Stored data for the given type or an empty string if the data for that type does not exist.\r
*/\r
- getData: function( type ) {\r
+ getData: function( type, getNative ) {\r
function isEmpty( data ) {\r
return data === undefined || data === null || data === '';\r
}\r
\r
+ function filterUnwantedCharacters( data ) {\r
+ if ( typeof data !== 'string' ) {\r
+ return data;\r
+ }\r
+\r
+ var htmlEnd = data.indexOf( '</html>' );\r
+\r
+ if ( htmlEnd !== -1 ) {\r
+ // Just cut everything after `</html>`, so everything after htmlEnd index + length of `</html>`.\r
+ // Required to workaround bug: https://bugs.chromium.org/p/chromium/issues/detail?id=696978\r
+ return data.substring( 0, htmlEnd + 7 );\r
+ }\r
+\r
+ return data;\r
+ }\r
+\r
type = this._.normalizeType( type );\r
\r
var data = this._.data[ type ],\r
// This code removes meta tags and returns only the contents of the <body> element if found. Note that\r
// some significant content may be placed outside Start/EndFragment comments so it's kept.\r
//\r
- // See #13583 for more details.\r
- if ( type == 'text/html' ) {\r
+ // See http://dev.ckeditor.com/ticket/13583 for more details.\r
+ // Additionally http://dev.ckeditor.com/ticket/16847 adds a flag allowing to get the whole, original content.\r
+ if ( type == 'text/html' && !getNative ) {\r
data = data.replace( this._.metaRegExp, '' );\r
\r
// Keep only contents of the <body> element\r
data = '';\r
}\r
\r
- return data;\r
+ return filterUnwantedCharacters( data );\r
},\r
\r
/**\r
}\r
\r
// If we use the text type to bind the ID, then if someone tries to set the text, we must also\r
- // update ID accordingly. #13468.\r
+ // update ID accordingly. http://dev.ckeditor.com/ticket/13468.\r
if ( clipboardIdDataType == 'Text' && type == 'Text' ) {\r
this.id = value;\r
}\r
function getAndSetData( type ) {\r
type = that._.normalizeType( type );\r
\r
- var data = that.getData( type );\r
+ var data = that.getData( type, true );\r
if ( data ) {\r
that._.data[ type ] = data;\r
}\r
if ( ( this.$ && this.$.files ) || file ) {\r
this._.files = [];\r
\r
- // Edge have empty files property with no length (#13755).\r
+ // Edge have empty files property with no length (http://dev.ckeditor.com/ticket/13755).\r
if ( this.$.files && this.$.files.length ) {\r
for ( i = 0; i < this.$.files.length; i++ ) {\r
this._.files.push( this.$.files[ i ] );\r
\r
/**\r
* When the content of the clipboard is pasted in Chrome, the clipboard data object has an empty `files` property,\r
- * but it is possible to get the file as `items[0].getAsFile();` (#12961).\r
+ * but it is possible to get the file as `items[0].getAsFile();` (http://dev.ckeditor.com/ticket/12961).\r
*\r
* @private\r
* @returns {File} File instance or `null` if not found.\r
* @member CKEDITOR.editor\r
*/\r
\r
- /**\r
+/**\r
* Fired after the {@link #paste} event if content was modified. Note that if the paste\r
* event does not insert any data, the `afterPaste` event will not be fired.\r
*\r
* @member CKEDITOR.editor\r
*/\r
\r
-/**\r
- * Internal event to open the Paste dialog window.\r
- *\r
- * @private\r
- * @event pasteDialog\r
- * @member CKEDITOR.editor\r
- * @param {CKEDITOR.editor} editor This editor instance.\r
- * @param {Function} [data] Callback that will be passed to {@link CKEDITOR.editor#openDialog}.\r
- */\r
-\r
/**\r
* Facade for the native `drop` event. Fired when the native `drop` event occurs.\r
*\r
* @property {CKEDITOR.filter} [pasteFilter]\r
* @member CKEDITOR.editor\r
*/\r
+\r
+/**\r
+ * Duration of the notification displayed after pasting was blocked by the browser.\r
+ *\r
+ * @since 4.7.0\r
+ * @cfg {Number} [clipboard_notificationDuration=10000]\r
+ * @member CKEDITOR.config\r
+ */\r
+CKEDITOR.config.clipboard_notificationDuration = 10000;\r