2015-06-18 03:54:37 -05:00
|
|
|
/*jshint strict:false, undef:false, unused:false */
|
|
|
|
|
2016-03-10 23:22:49 -05:00
|
|
|
var onCut = function ( event ) {
|
|
|
|
var clipboardData = event.clipboardData;
|
2015-06-18 03:54:37 -05:00
|
|
|
var range = this.getSelection();
|
2016-03-10 23:22:49 -05:00
|
|
|
var node = this.createElement( 'div' );
|
|
|
|
var body = this._body;
|
2015-06-18 03:54:37 -05:00
|
|
|
var self = this;
|
2016-03-10 23:22:49 -05:00
|
|
|
|
|
|
|
// Save undo checkpoint
|
2016-03-10 23:56:34 -05:00
|
|
|
this.saveUndoState( range );
|
2016-03-10 23:22:49 -05:00
|
|
|
|
|
|
|
// Edge only seems to support setting plain text as of 2016-03-11.
|
|
|
|
if ( !isEdge && clipboardData ) {
|
|
|
|
moveRangeBoundariesUpTree( range, body );
|
|
|
|
node.appendChild( deleteContentsOfRange( range, body ) );
|
|
|
|
clipboardData.setData( 'text/html', node.innerHTML );
|
2016-03-12 01:18:21 -05:00
|
|
|
clipboard.setData( 'text/plain', node.innerText || node.textContent );
|
2016-03-10 23:22:49 -05:00
|
|
|
event.preventDefault();
|
|
|
|
} else {
|
|
|
|
setTimeout( function () {
|
|
|
|
try {
|
|
|
|
// If all content removed, ensure div at start of body.
|
|
|
|
self._ensureBottomLine();
|
|
|
|
} catch ( error ) {
|
|
|
|
self.didError( error );
|
|
|
|
}
|
|
|
|
}, 0 );
|
|
|
|
}
|
|
|
|
|
2015-06-18 03:54:37 -05:00
|
|
|
this.setSelection( range );
|
2016-03-10 23:22:49 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
var onCopy = function ( event ) {
|
|
|
|
var clipboardData = event.clipboardData;
|
|
|
|
var range = this.getSelection();
|
|
|
|
var node = this.createElement( 'div' );
|
|
|
|
|
|
|
|
// Edge only seems to support setting plain text as of 2016-03-11.
|
|
|
|
if ( !isEdge && clipboardData ) {
|
|
|
|
node.appendChild( range.cloneContents() );
|
|
|
|
clipboardData.setData( 'text/html', node.innerHTML );
|
2016-03-12 01:18:21 -05:00
|
|
|
clipboard.setData( 'text/plain', node.innerText || node.textContent );
|
2016-03-10 23:22:49 -05:00
|
|
|
event.preventDefault();
|
|
|
|
}
|
2015-06-18 03:54:37 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
var onPaste = function ( event ) {
|
|
|
|
var clipboardData = event.clipboardData,
|
|
|
|
items = clipboardData && clipboardData.items,
|
|
|
|
fireDrop = false,
|
|
|
|
hasImage = false,
|
2015-06-18 21:57:32 -05:00
|
|
|
plainItem = null,
|
|
|
|
self = this,
|
2016-03-07 02:38:07 -05:00
|
|
|
l, item, type, types, data;
|
2015-06-18 21:57:32 -05:00
|
|
|
|
|
|
|
// Current HTML5 Clipboard interface
|
2015-06-19 00:35:18 -05:00
|
|
|
// ---------------------------------
|
2015-06-18 21:57:32 -05:00
|
|
|
// https://html.spec.whatwg.org/multipage/interaction.html
|
2015-06-19 00:35:18 -05:00
|
|
|
|
2016-03-10 23:22:49 -05:00
|
|
|
// Edge only provides access to plain text as of 2016-03-11.
|
|
|
|
if ( !isEdge && items ) {
|
2015-06-18 21:57:32 -05:00
|
|
|
event.preventDefault();
|
2015-06-18 03:54:37 -05:00
|
|
|
l = items.length;
|
|
|
|
while ( l-- ) {
|
2015-06-18 21:57:32 -05:00
|
|
|
item = items[l];
|
|
|
|
type = item.type;
|
2015-06-18 03:54:37 -05:00
|
|
|
if ( type === 'text/html' ) {
|
2015-06-18 21:57:32 -05:00
|
|
|
/*jshint loopfunc: true */
|
|
|
|
item.getAsString( function ( html ) {
|
|
|
|
self.insertHTML( html, true );
|
|
|
|
});
|
|
|
|
/*jshint loopfunc: false */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if ( type === 'text/plain' ) {
|
|
|
|
plainItem = item;
|
2015-06-18 03:54:37 -05:00
|
|
|
}
|
|
|
|
if ( /^image\/.*/.test( type ) ) {
|
|
|
|
hasImage = true;
|
|
|
|
}
|
|
|
|
}
|
2015-06-18 21:57:32 -05:00
|
|
|
// Treat image paste as a drop of an image file.
|
2015-06-18 03:54:37 -05:00
|
|
|
if ( hasImage ) {
|
2015-06-18 21:57:32 -05:00
|
|
|
this.fireEvent( 'dragover', {
|
2015-06-18 03:54:37 -05:00
|
|
|
dataTransfer: clipboardData,
|
|
|
|
/*jshint loopfunc: true */
|
|
|
|
preventDefault: function () {
|
|
|
|
fireDrop = true;
|
|
|
|
}
|
|
|
|
/*jshint loopfunc: false */
|
|
|
|
});
|
|
|
|
if ( fireDrop ) {
|
|
|
|
this.fireEvent( 'drop', {
|
|
|
|
dataTransfer: clipboardData
|
|
|
|
});
|
|
|
|
}
|
2015-06-18 21:57:32 -05:00
|
|
|
} else if ( plainItem ) {
|
|
|
|
item.getAsString( function ( text ) {
|
|
|
|
self.insertPlainText( text, true );
|
|
|
|
});
|
2015-06-18 03:54:37 -05:00
|
|
|
}
|
2015-06-18 21:57:32 -05:00
|
|
|
return;
|
2015-06-18 03:54:37 -05:00
|
|
|
}
|
|
|
|
|
2015-06-18 21:57:32 -05:00
|
|
|
// Old interface
|
2015-06-19 00:35:18 -05:00
|
|
|
// -------------
|
|
|
|
|
2015-07-14 14:59:27 -05:00
|
|
|
// Safari (and indeed many other OS X apps) copies stuff as text/rtf
|
|
|
|
// rather than text/html; even from a webpage in Safari. The only way
|
|
|
|
// to get an HTML version is to fallback to letting the browser insert
|
2015-07-16 12:46:29 -05:00
|
|
|
// the content. Same for getting image data. *Sigh*.
|
2016-03-07 02:38:07 -05:00
|
|
|
//
|
|
|
|
// Firefox is even worse: it doesn't even let you know that there might be
|
|
|
|
// an RTF version on the clipboard, but it will also convert to HTML if you
|
|
|
|
// let the browser insert the content. I've filed
|
|
|
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=1254028
|
|
|
|
types = clipboardData && clipboardData.types;
|
2016-03-10 23:22:49 -05:00
|
|
|
if ( !isEdge && types && (
|
2016-03-07 02:38:07 -05:00
|
|
|
indexOf.call( types, 'text/html' ) > -1 || (
|
|
|
|
!isGecko &&
|
|
|
|
indexOf.call( types, 'text/plain' ) > -1 &&
|
|
|
|
indexOf.call( types, 'text/rtf' ) < 0 )
|
|
|
|
)) {
|
2015-07-14 14:59:27 -05:00
|
|
|
event.preventDefault();
|
|
|
|
// Abiword on Linux copies a plain text and html version, but the HTML
|
|
|
|
// version is the empty string! So always try to get HTML, but if none,
|
|
|
|
// insert plain text instead.
|
2015-07-16 12:46:29 -05:00
|
|
|
if (( data = clipboardData.getData( 'text/html' ) )) {
|
2015-07-14 14:59:27 -05:00
|
|
|
this.insertHTML( data, true );
|
2015-07-16 12:46:29 -05:00
|
|
|
} else if (( data = clipboardData.getData( 'text/plain' ) )) {
|
|
|
|
this.insertPlainText( data, true );
|
2015-07-11 07:22:46 -05:00
|
|
|
}
|
2015-07-14 14:59:27 -05:00
|
|
|
return;
|
2015-07-11 07:22:46 -05:00
|
|
|
}
|
2015-06-18 21:57:32 -05:00
|
|
|
|
2016-03-10 23:22:49 -05:00
|
|
|
// No interface. Includes all versions of IE :(
|
|
|
|
// --------------------------------------------
|
2015-06-19 00:35:18 -05:00
|
|
|
|
2015-06-18 03:54:37 -05:00
|
|
|
this._awaitingPaste = true;
|
|
|
|
|
2015-06-18 21:57:32 -05:00
|
|
|
var body = this._body,
|
2015-06-18 03:54:37 -05:00
|
|
|
range = this.getSelection(),
|
2015-06-18 21:57:32 -05:00
|
|
|
startContainer = range.startContainer,
|
|
|
|
startOffset = range.startOffset,
|
|
|
|
endContainer = range.endContainer,
|
|
|
|
endOffset = range.endOffset,
|
|
|
|
startBlock = getStartBlockOfRange( range );
|
2015-06-18 03:54:37 -05:00
|
|
|
|
|
|
|
// We need to position the pasteArea in the visible portion of the screen
|
|
|
|
// to stop the browser auto-scrolling.
|
|
|
|
var pasteArea = this.createElement( 'DIV', {
|
|
|
|
style: 'position: absolute; overflow: hidden; top:' +
|
|
|
|
( body.scrollTop +
|
|
|
|
( startBlock ? startBlock.getBoundingClientRect().top : 0 ) ) +
|
|
|
|
'px; right: 150%; width: 1px; height: 1px;'
|
|
|
|
});
|
|
|
|
body.appendChild( pasteArea );
|
|
|
|
range.selectNodeContents( pasteArea );
|
|
|
|
this.setSelection( range );
|
|
|
|
|
|
|
|
// A setTimeout of 0 means this is added to the back of the
|
|
|
|
// single javascript thread, so it will be executed after the
|
|
|
|
// paste event.
|
|
|
|
setTimeout( function () {
|
|
|
|
try {
|
2015-06-21 21:32:47 -05:00
|
|
|
// IE sometimes fires the beforepaste event twice; make sure it is
|
|
|
|
// not run again before our after paste function is called.
|
2015-06-18 21:57:32 -05:00
|
|
|
self._awaitingPaste = false;
|
|
|
|
|
2015-06-18 03:54:37 -05:00
|
|
|
// Get the pasted content and clean
|
2015-06-18 21:57:32 -05:00
|
|
|
var html = '',
|
2015-06-18 03:54:37 -05:00
|
|
|
next = pasteArea,
|
|
|
|
first, range;
|
|
|
|
|
|
|
|
// #88: Chrome can apparently split the paste area if certain
|
|
|
|
// content is inserted; gather them all up.
|
|
|
|
while ( pasteArea = next ) {
|
|
|
|
next = pasteArea.nextSibling;
|
2015-06-21 21:32:47 -05:00
|
|
|
detach( pasteArea );
|
2015-06-18 03:54:37 -05:00
|
|
|
// Safari and IE like putting extra divs around things.
|
2015-06-18 21:57:32 -05:00
|
|
|
first = pasteArea.firstChild;
|
|
|
|
if ( first && first === pasteArea.lastChild &&
|
2015-06-18 03:54:37 -05:00
|
|
|
first.nodeName === 'DIV' ) {
|
2015-06-18 21:57:32 -05:00
|
|
|
pasteArea = first;
|
2015-06-18 03:54:37 -05:00
|
|
|
}
|
2015-06-18 21:57:32 -05:00
|
|
|
html += pasteArea.innerHTML;
|
2015-06-18 03:54:37 -05:00
|
|
|
}
|
|
|
|
|
2015-06-18 21:57:32 -05:00
|
|
|
range = self._createRange(
|
|
|
|
startContainer, startOffset, endContainer, endOffset );
|
2015-06-18 03:54:37 -05:00
|
|
|
self.setSelection( range );
|
|
|
|
|
2015-06-18 21:57:32 -05:00
|
|
|
if ( html ) {
|
|
|
|
self.insertHTML( html, true );
|
|
|
|
}
|
2015-06-18 03:54:37 -05:00
|
|
|
} catch ( error ) {
|
|
|
|
self.didError( error );
|
|
|
|
}
|
|
|
|
}, 0 );
|
|
|
|
};
|