Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Paste from google docs support #2472

Closed
wants to merge 37 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
c7ee4a0
Refactored pastefromword into generic plugin.
jacekbogdanski Sep 26, 2018
dea4b61
Moved pastefromword tests into generic plugin tests.
jacekbogdanski Sep 26, 2018
f7a9fea
Refactored pastefromword to use generic paste plugin.
jacekbogdanski Sep 26, 2018
92bb1ef
Styling changes.
jacekbogdanski Sep 26, 2018
84578b5
Updated lang files.
jacekbogdanski Sep 26, 2018
2bb2c7c
Name refactoring.
jacekbogdanski Sep 26, 2018
9ad2d44
Fixed unit tests.
jacekbogdanski Sep 26, 2018
ef2b723
Restored pastefromword tests.
jacekbogdanski Oct 6, 2018
840f97c
Refactored pastefromword test to utilize uberpaste.
jacekbogdanski Oct 6, 2018
62866bc
Removed redundant uberpaste tests.
jacekbogdanski Oct 6, 2018
578526a
Splitted paste handling into strategy.
jacekbogdanski Oct 7, 2018
b0695f3
Refactored default filter.
jacekbogdanski Oct 7, 2018
9ee02b9
Refactored filter into template method.
jacekbogdanski Oct 8, 2018
b622f78
Namespaces refactoring.
jacekbogdanski Oct 8, 2018
a7ba6ce
Simplified parse function factory.
jacekbogdanski Oct 8, 2018
4f15949
Fixed issue with event singleton.
jacekbogdanski Oct 8, 2018
df7768c
Moved custom data type detection into main function.
jacekbogdanski Oct 8, 2018
795de24
Simple refactoring and updated version tags.
jacekbogdanski Oct 8, 2018
5af9807
Attribute cleaning.
jacekbogdanski Oct 9, 2018
3b16f68
Removed redundant list item paragraph.
jacekbogdanski Oct 9, 2018
f58451e
Moved pastefromword tests into uberpaste namespace.
jacekbogdanski Oct 10, 2018
9179a39
Added list specific filters.
jacekbogdanski Oct 10, 2018
7bd4291
Updated list filtering.
jacekbogdanski Oct 10, 2018
40d92b9
Removed redundant br class.
jacekbogdanski Oct 10, 2018
16b645d
Removed unused tests.
jacekbogdanski Oct 10, 2018
bc79fe4
Skipped invalid styles.
jacekbogdanski Oct 10, 2018
bbebdb6
Added style tests.
jacekbogdanski Oct 10, 2018
1c2efe7
Added list tests and updated wrapper test.
jacekbogdanski Oct 10, 2018
f053297
Added text alignment test.
jacekbogdanski Oct 10, 2018
3e7a1a3
Removed invalid comment.
jacekbogdanski Oct 11, 2018
b480a23
Small test update.
jacekbogdanski Oct 11, 2018
1eb4e6c
Refactoring.
jacekbogdanski Apr 15, 2019
ff37b2f
Updated uberpaste to the latest major.
jacekbogdanski Apr 15, 2019
6601d9f
Test renaming for rebase.
jacekbogdanski Apr 15, 2019
8c85cc9
Moved test namespace.
jacekbogdanski Apr 15, 2019
c76ef92
Updated lang files.
jacekbogdanski Apr 15, 2019
b9752a9
Refactoring.
jacekbogdanski Apr 15, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
181 changes: 4 additions & 177 deletions plugins/pastefromword/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,191 +4,18 @@
*/

( function() {
/* global confirm */

CKEDITOR.plugins.add( 'pastefromword', {
requires: 'clipboard',
// jscs:disable maximumLineLength
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%
// jscs:enable maximumLineLength
icons: 'pastefromword,pastefromword-rtl', // %REMOVE_LINE_CORE%
hidpi: true, // %REMOVE_LINE_CORE%
requires: 'uberpaste',
init: function( editor ) {
// Flag indicate this command is actually been asked instead of a generic pasting.
var forceFromWord = 0,
path = this.path,
configInlineImages = editor.config.pasteFromWord_inlineImages === undefined ? true : editor.config.pasteFromWord_inlineImages;

editor.addCommand( 'pastefromword', {
// Snapshots are done manually by editable.insertXXX methods.
canUndo: false,
async: true,

/**
* The Paste from Word command. It will determine its pasted content from Word automatically if possible.
*
* At the time of writing it was working correctly only in Internet Explorer browsers, due to their
* `paste` support in `document.execCommand`.
*
* @private
* @param {CKEDITOR.editor} editor An instance of the editor where the command is being executed.
* @param {Object} [data] The options object.
* @param {Boolean/String} [data.notification=true] Content for a notification shown after an unsuccessful
* paste attempt. If `false`, the notification will not be displayed. This parameter was added in 4.7.0.
* @member CKEDITOR.editor.commands.pastefromword
*/
exec: function( editor, data ) {
forceFromWord = 1;
editor.execCommand( 'paste', {
type: 'html',
notification: data && typeof data.notification !== 'undefined' ? data.notification : true
} );
}
} );

// Register the toolbar button.
CKEDITOR.plugins.clipboard.addPasteButton( editor, 'PasteFromWord', {
label: editor.lang.pastefromword.toolbar,
command: 'pastefromword',
toolbar: 'clipboard,50'
editor.once( 'pluginsLoaded', function() {
// Create an alias for `pastefromword` command.
editor.addCommand( 'pastefromword', editor.getCommand( 'uberpaste' ) );
} );

// Features brought by this command beside the normal process:
// 1. No more bothering of user about the clean-up.
// 2. Perform the clean-up even if content is not from Microsoft Word.
// (e.g. from a Microsoft Word similar application.)
// 3. Listen with high priority (3), so clean up is done before content
// type sniffing (priority = 6).
editor.on( 'paste', function( evt ) {
var data = evt.data,
dataTransferHtml = CKEDITOR.plugins.clipboard.isCustomDataTypesSupported ?
data.dataTransfer.getData( 'text/html', true ) : null,
// Required in Paste from Word Image plugin (#662).
dataTransferRtf = CKEDITOR.plugins.clipboard.isCustomDataTypesSupported ?
data.dataTransfer.getData( 'text/rtf' ) : null,
// Some commands fire paste event without setting dataTransfer property. In such case
// dataValue should be used.
mswordHtml = dataTransferHtml || data.dataValue,
pfwEvtData = { dataValue: mswordHtml, dataTransfer: { 'text/rtf': dataTransferRtf } },
officeMetaRegexp = /<meta\s*name=(?:\"|\')?generator(?:\"|\')?\s*content=(?:\"|\')?microsoft/gi,
wordRegexp = /(class=\"?Mso|style=(?:\"|\')[^\"]*?\bmso\-|w:WordDocument|<o:\w+>|<\/font>)/,
isOfficeContent = officeMetaRegexp.test( mswordHtml ) || wordRegexp.test( mswordHtml );

if ( !mswordHtml || !( forceFromWord || isOfficeContent ) ) {
return;
}

// PFW might still get prevented, if it's not forced.
if ( editor.fire( 'pasteFromWord', pfwEvtData ) === false && !forceFromWord ) {
return;
}

// Do not apply paste filter to data filtered by the Word filter (https://dev.ckeditor.com/ticket/13093).
data.dontFilter = true;

// If filter rules aren't loaded then cancel 'paste' event,
// load them and when they'll get loaded fire new paste event
// for which data will be filtered in second execution of
// this listener.
var isLazyLoad = loadFilterRules( editor, path, function() {
// Event continuation with the original data.
if ( isLazyLoad ) {
editor.fire( 'paste', data );
} else if ( !editor.config.pasteFromWordPromptCleanup || ( forceFromWord || confirm( editor.lang.pastefromword.confirmCleanup ) ) ) {

pfwEvtData.dataValue = CKEDITOR.cleanWord( pfwEvtData.dataValue, editor );

editor.fire( 'afterPasteFromWord', pfwEvtData );

data.dataValue = pfwEvtData.dataValue;

if ( editor.config.forcePasteAsPlainText === true ) {
// If `config.forcePasteAsPlainText` set to true, force plain text even on Word content (#1013).
data.type = 'text';
} else if ( !CKEDITOR.plugins.clipboard.isCustomCopyCutSupported && editor.config.forcePasteAsPlainText === 'allow-word' ) {
// In browsers using pastebin when pasting from Word, evt.data.type is 'auto' (not 'html') so it gets converted
// by 'pastetext' plugin to 'text'. We need to restore 'html' type (#1013) and (#1638).
data.type = 'html';
}
}

// Reset forceFromWord.
forceFromWord = 0;
} );

// The cleanup rules are to be loaded, we should just cancel
// this event.
isLazyLoad && evt.cancel();
}, null, null, 3 );

// Paste From Word Image:
// RTF clipboard is required for embedding images.
// If img tags are not allowed there is no point to process images.
if ( CKEDITOR.plugins.clipboard.isCustomDataTypesSupported && configInlineImages ) {
editor.on( 'afterPasteFromWord', imagePastingListener );
}

function imagePastingListener( evt ) {
var pfw = CKEDITOR.plugins.pastefromword && CKEDITOR.plugins.pastefromword.images,
imgTags,
hexImages,
newSrcValues = [],
i;

// If pfw images namespace is unavailable or img tags are not allowed we simply skip adding images.
if ( !pfw || !evt.editor.filter.check( 'img[src]' ) ) {
return;
}

function createSrcWithBase64( img ) {
return img.type ? 'data:' + img.type + ';base64,' + CKEDITOR.tools.convertBytesToBase64( CKEDITOR.tools.convertHexStringToBytes( img.hex ) ) : null;
}

imgTags = pfw.extractTagsFromHtml( evt.data.dataValue );
if ( imgTags.length === 0 ) {
return;
}

hexImages = pfw.extractFromRtf( evt.data.dataTransfer[ 'text/rtf' ] );
if ( hexImages.length === 0 ) {
return;
}

CKEDITOR.tools.array.forEach( hexImages, function( img ) {
newSrcValues.push( createSrcWithBase64( img ) );
}, this );

// Assuming there is equal amount of Images in RTF and HTML source, so we can match them accordingly to the existing order.
if ( imgTags.length === newSrcValues.length ) {
for ( i = 0; i < imgTags.length; i++ ) {
// Replace only `file` urls of images ( shapes get newSrcValue with null ).
if ( ( imgTags[ i ].indexOf( 'file://' ) === 0 ) && newSrcValues[ i ] ) {
evt.data.dataValue = evt.data.dataValue.replace( imgTags[ i ], newSrcValues[ i ] );
}
}
}
}
}

} );

function loadFilterRules( editor, path, callback ) {
var isLoaded = CKEDITOR.cleanWord;

if ( isLoaded )
callback();
else {
var filterFilePath = CKEDITOR.getUrl( editor.config.pasteFromWordCleanupFile || ( path + 'filter/default.js' ) );

// Load with busy indicator.
CKEDITOR.scriptLoader.load( filterFilePath, callback, null, true );
}

return !isLoaded;
}
} )();


/**
* Whether to prompt the user about the clean up of content being pasted from Microsoft Word.
*
Expand Down
Loading