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

Introduce paste from libre office plugin #3624

Merged
merged 95 commits into from
Jan 20, 2020
Merged
Show file tree
Hide file tree
Changes from 91 commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
bc9347f
Simplify regexps. Implement detection of meta generator tag, which al…
Oct 16, 2019
3869651
Remove double spaces.
Oct 16, 2019
f0cc898
Add mockup for paste from libre office plugin.
Oct 16, 2019
0efa84d
Add rule to filter doctype element.
Oct 16, 2019
0a55169
Temporary add paste from libre office to main sample config.
Oct 16, 2019
9fff21a
Add first autogenerated unit test for paste from libre office.
Oct 16, 2019
7eb010f
Activate filter for safari. Add test with link. Implement new rules r…
Oct 17, 2019
bb19a78
Rename source file.
Oct 17, 2019
f94b0a1
Add support for strikthrough. Improve styles analysis for links.
Oct 17, 2019
fd8b113
Add fixtures for basic styles.
Oct 17, 2019
1da8e0d
Add missing clipboard data for IE11, remove datatransfer browser from…
Oct 17, 2019
358d82c
Remove extra color style inside links which are generated inside IE11.
Oct 17, 2019
cd081d1
Fix font sizes which was applied inside sub and sup elements
Oct 17, 2019
9c99fdd
Add font color fixtures.
Oct 17, 2019
7468c89
Add support for font colors.
Oct 17, 2019
68eea10
Add missing edge browser
Oct 17, 2019
ad41bde
Add font face and size test clipboards.
Oct 17, 2019
8f20a55
Add expected output of font tests and add it to the test suite.
Oct 17, 2019
684f18f
Add tests for lists.
Oct 18, 2019
21554d5
Add clipoard data and expected result for more compliacted lists (mix…
Oct 18, 2019
099ffea
Add support for line hight and correct tests. Provide libreoffice fil…
Oct 21, 2019
4655eb7
Add expected markup for safari where line-heught is provided in px no…
Oct 21, 2019
6c0d83f
Run libre office filter after paste from word filter to avoid situati…
Oct 21, 2019
bc5dd9e
Move style removing logic to common filter.
Oct 22, 2019
0defe49
Replace expected output after improved filtering in common filter.
Oct 22, 2019
f52cb99
Fix background-color style under IE11, which wasn't overwritten for t…
Oct 22, 2019
c096aae
Reduce unwanted safari styles.
Oct 22, 2019
96ff4e5
Correct typo.
Oct 22, 2019
7d74c35
Add white-space style to ignored during style stack creation.
Oct 22, 2019
9ce321b
Fix expected result for safari after general styles filtration.
Oct 22, 2019
b0843e1
Improve expected output after accepting more style types.
Oct 23, 2019
f66faa8
Fix filter to properly transfiorm apple spaces.
Oct 23, 2019
6b7db49
Fix basic style expected output for safari.
Oct 23, 2019
d555dbe
Fix font color expected output for safari.
Oct 23, 2019
99ca871
Fix font expected output for safari.
Oct 23, 2019
97c13cf
Fix lists expected output for safari.
Oct 23, 2019
b982737
Create config dedicated for PFLO, allow on passing white-space style,…
Oct 23, 2019
39fa7c9
Fix issue with apple spaces from safari.
Oct 23, 2019
5dea386
Fix not passing backgroudn color to table cells in IE8.
Oct 23, 2019
d4bf6f4
Fix filter which generates unecessary textnode direclty in document f…
Oct 23, 2019
e391d7b
Fix font issue integration between PFLO and PFW.
Oct 23, 2019
9cf74c9
Add support for nested lists of different types.
Oct 28, 2019
9bfddb0
Fix situation where test in PFW failed if paste form libre office was…
Oct 28, 2019
70adf37
Remove test with advanced lists.
Oct 28, 2019
9037894
Add test with mixed list.
Oct 28, 2019
b3e8b30
Add support for text alignment.
Oct 29, 2019
f68532d
Add unit generated test for text-align.
Oct 29, 2019
e167e1e
Remove images without src.
Oct 29, 2019
36e3b94
Add font-face fixer to common filter.
Oct 29, 2019
e50ba50
Update font-face style in expected markup after adding font-face fixe…
Oct 29, 2019
37ad349
Fix font-styles in libre office samples, after implementing common fo…
Oct 29, 2019
7a89cef
Add unit tests for common filter.
Oct 30, 2019
6744ecf
Add fix for preserving background colors of a table.
Oct 30, 2019
d380218
Add support for percentage values of width and heigh of a td.
Oct 31, 2019
c416d5b
Add unit test for table border.
Oct 31, 2019
d86426c
Unify removed attributes between pfw and pflo to not generate differe…
Oct 31, 2019
e1c2f50
Add tests for paragraph formats.
Oct 31, 2019
d8be64a
Add basic image filter for paste from libre office.
Nov 4, 2019
2431726
Fix failing tests for paragraph formats.
Nov 4, 2019
d6d25b4
Update regesp to match more images pasted from libre office.
Nov 4, 2019
c744ba4
Add unit test with simple image in libre office document.
Nov 4, 2019
b295be7
Add more complicated test with image for unit testing.
Nov 4, 2019
9f2b8b1
Add unit test for linked images and for transformed images
Nov 4, 2019
64a13d4
Provide different expected output for Edge. Libre office under window…
Nov 5, 2019
b843209
Add unit test dedicated directly for image filter.
Nov 5, 2019
7e8b918
Fix failing tests on firefox, becasue style stack is created in diffe…
Nov 5, 2019
0ddc7c7
Add tag to image test.
Nov 6, 2019
17b0067
Manual tests for paste from libre office.
Nov 6, 2019
bf9b02d
Apply suggestions from code review
msamsel Nov 18, 2019
7a3f63f
Fix function names.
Nov 19, 2019
a30a2ee
Add issue reference.
Nov 19, 2019
47f8a7a
Extract removing default link styles to separate function.
Nov 19, 2019
96520c3
Correct function name to use verb in it.
Nov 19, 2019
c7b23a2
Prevent of creatign new evaluator with each loop step, simplify if st…
Nov 19, 2019
0dc6b52
Extract common logic to a separate function.
Nov 19, 2019
3625b4b
Remove text-align:start style from superfluous style list.
Nov 20, 2019
38e770f
Fix spelling.
Nov 20, 2019
41d1ff0
Add issue reference.
Nov 20, 2019
6b14a13
Fix text after restoring text-align style.
Nov 21, 2019
a823f69
Add new helper to paste tools which detects generator type.
Nov 21, 2019
fbd3ac1
Little refactor of pastetools test, preparation for more tests.
Nov 21, 2019
8fa3758
Add unit test for getContentGeneratorName.
Nov 21, 2019
d9fad64
Correct document content to mention libre office not gdocs.
Nov 21, 2019
2f7ba06
Ignore image related tests on edge. Improve expected edge content, as…
Nov 21, 2019
9d1f569
Apply suggestions from code review
msamsel Jan 15, 2020
dacd719
Update plugins/pastetools/filter/image.js
msamsel Jan 15, 2020
e261134
Sort alphabetically plugin list in config.
Jan 15, 2020
9c701c3
Add page break support for PFLO.
Jan 15, 2020
1ee1130
Add page break unit tests.
Jan 15, 2020
9007d4f
Rename variable.
Jan 15, 2020
d5f0737
Move priority key to be more visible and provide description to it in…
Jan 15, 2020
7b7fb98
Add paste from libre office to dev/builder.
Jan 16, 2020
5d6f8fe
Add supported environment to paste from libre office plugin.
Jan 16, 2020
ad546d7
Replace 'trim' with 'replace' to fix error on IE8.
Jan 17, 2020
034aa54
Add changelog entry [ci skip].
Comandeer Jan 20, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ CKEDITOR.editorConfig = function( config ) {
'newpage,' +
'pagebreak,' +
'pastefromgdocs,' +
'pastefromlibreoffice,' +
'pastefromword,' +
'pastetext,' +
'preview,' +
Expand Down
334 changes: 334 additions & 0 deletions plugins/pastefromlibreoffice/filter/default.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,334 @@
/**
* @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/

/* globals CKEDITOR */

( function() {
'use strict';

var pastetools = CKEDITOR.plugins.pastetools,
commonFilter = pastetools.filters.common,
Style = commonFilter.styles;

/**
* Set of Paste from Libre Office plugin helpers.
*
* @since 4.14.0
* @private
* @member CKEDITOR.plugins.pastetools.filters
*/
CKEDITOR.plugins.pastetools.filters.libreoffice = {
/**
* Rules for the Paste from Libre Office filter.
*
* @since 4.14.0
* @private
* @member CKEDITOR.plugins.pastetools.filters.libreoffice
*/
rules: function( html, editor, filter ) {
return {
root: function( element ) {
element.filterChildren( filter );
},

comment: function() {
return false;
},

elementNames: [
[ /^head$/i, '' ],
[ /^meta$/i, '' ],
[ /^strike$/i, 's' ]
],

elements: {
// Required due to bug (#3664).
'!doctype': function( el ) {
el.replaceWithChildren();
Comandeer marked this conversation as resolved.
Show resolved Hide resolved
},

'span': function( element ) {
if ( element.attributes.style ) {
element.attributes.style = Style.normalizedStyles( element, editor );

Style.createStyleStack( element, filter, editor );
}

replaceEmptyElementWithChildren( element );
},

'p': function( element ) {
var styles = CKEDITOR.tools.parseCssText( element.attributes.style );

if ( editor.plugins.pagebreak &&
( styles[ 'page-break-before' ] === 'always' || styles[ 'break-before' ] === 'page' )
) {
insertPageBreakBefore( editor, element );
}

if ( element.attributes.align ) {
styles[ 'text-align' ] = element.attributes.align;
delete element.attributes.align;
}

element.attributes.style = CKEDITOR.tools.writeCssText( styles );

element.filterChildren( filter );
Style.createStyleStack( element, filter, editor );
},

'div': function( element ) {
Style.createStyleStack( element, filter, editor );
},

'a': function( el ) {
if ( el.attributes.style ) {
el.attributes.style = removeDefaultLinkStyles( el.attributes.style );
}
},

'h1': function( el ) {
Style.createStyleStack( el, filter, editor );
},

'h2': function( el ) {
Style.createStyleStack( el, filter, editor );
},

'h3': function( el ) {
Style.createStyleStack( el, filter, editor );
},

'h4': function( el ) {
Style.createStyleStack( el, filter, editor );
},

'h5': function( el ) {
Style.createStyleStack( el, filter, editor );
},

'h6': function( el ) {
Style.createStyleStack( el, filter, editor );
},

'pre': function( el ) {
Style.createStyleStack( el, filter, editor );
},

'font': function( el ) {
if ( shouldReplaceFontWithChildren( el ) ) {
el.replaceWithChildren();
}

// 1. Case there is no style stack
// 2. font-size is child of this node
// 3. font-size is parent of this node
var styles = CKEDITOR.tools.parseCssText( el.attributes.style );
var firstChild = el.getFirst();

if ( el.attributes.size &&
firstChild &&
firstChild.type === CKEDITOR.NODE_ELEMENT &&
/font-size/.test( firstChild.attributes.style )
) {
el.replaceWithChildren();
}

if ( styles[ 'font-size' ] ) {
// We need to remove 'size' and transform font to span with 'font-size'.
delete el.attributes.size;
el.name = 'span';

if ( firstChild && firstChild.type === CKEDITOR.NODE_ELEMENT && firstChild.attributes.size ) {
firstChild.replaceWithChildren();
}
}
},

'ul': function( el ) {
if ( listMerger( el, filter ) ) {
return false;
}
},

'ol': function( el ) {
if ( listMerger( el, filter ) ) {
return false;
}
},

'img': function( el ) {
var src = el.attributes.src;

if ( !src ) {
return false;
}
}
},

attributes: {
'style': function( styles, element ) {
// Returning false deletes the attribute.
return Style.normalizedStyles( element, editor ) || false;
},

'cellspacing': remove,

'cellpadding': remove,

'border': remove
}
};
}
};

function replaceEmptyElementWithChildren( element ) {
if ( !CKEDITOR.tools.object.entries( element.attributes ).length ) {
element.replaceWithChildren();
Comandeer marked this conversation as resolved.
Show resolved Hide resolved
}
}

function shouldReplaceFontWithChildren( element ) {
// Anchor is additionaly styled with font.
if ( element.parent.name === 'a' && element.attributes.color === '#000080' ) {
return true;
}

// Sub or sup is additionaly styled with font
if ( element.parent.children.length === 1 && ( element.parent.name === 'sup' || element.parent.name === 'sub' ) && element.attributes.size === '2' ) {
return true;
}

return false;
}

// Return true if sucesfuly merge list to previous item.
function listMerger( el, filter ) {
if ( !shouldMergeToPreviousList( el ) ) {
return false;
}

var previous = el.previous,
lastLi = getLastListItem( previous ),
liDepthValue = checkDepth( lastLi ),
innerList = unwrapList( el, liDepthValue );

if ( innerList ) {
lastLi.add( innerList );
innerList.filterChildren( filter );
return true;
}

return false;
}

function shouldMergeToPreviousList( element ) {
// There need to be previous list where element should be merged.
if ( !element.previous || !isList( element.previous ) ) {
return false;
}

// There might be cases in PFW where li element has no children (test Tickets/7131 word2013 chrome)
if ( !element.getFirst().children.length ) {
return false;
}

// Current list need to be nested list, what points that is sublist.
if ( element.children.length !== 1 || !isList( element.getFirst().getFirst() ) ) {
return false;
}

return true;
}

// Checks level of nested list for given element.
// It's exepected that argument is the `li` element.
function checkDepth( element ) {
var level = 0,
currentElement = element,
listEvaluator = getListEvaluator();

while ( ( currentElement = currentElement.getAscendant( listEvaluator ) ) ) {
level++;
}

return level;
}

function getLastListItem( el ) {
var lastChild = el.children[ el.children.length - 1 ];

if ( !isList( lastChild ) && lastChild.name !== 'li' ) {
return el;
}

return getLastListItem( lastChild );
}

function getListEvaluator() {
var isInBlock = false;

return function( element ) {
// There might be situation that list is somehow nested in other type of element, quotes, div, table, etc.
// When such situation happen we should not search for any above list.
if ( isInBlock ) {
return false;
}

if ( !isList( element ) && element.name !== 'li' ) {
isInBlock = true;
return false;
}

return isList( element );
};
}

// Get nested list by first items
function unwrapList( list, count ) {
if ( count ) {
return unwrapList( list.getFirst().getFirst(), --count );
}

return list;
}

function isList( element ) {
return element.name === 'ol' || element.name === 'ul';
}

function remove() {
return false;
}

function removeDefaultLinkStyles( styles ) {
var parsedStyles = CKEDITOR.tools.parseCssText( styles );

if ( parsedStyles.color === '#000080' ) {
delete parsedStyles.color;
}

if ( parsedStyles[ 'text-decoration' ] === 'underline' ) {
delete parsedStyles[ 'text-decoration' ];
}

return CKEDITOR.tools.writeCssText( parsedStyles );
}

function insertPageBreakBefore( editor, element ) {
var pagebreakEl = CKEDITOR.plugins.pagebreak.createElement( editor );

pagebreakEl = CKEDITOR.htmlParser.fragment.fromHtml( pagebreakEl.getOuterHtml() ).children[ 0 ];

pagebreakEl.insertBefore( element );
}

CKEDITOR.pasteFilters.libreoffice = pastetools.createFilter( {
rules: [
commonFilter.rules,
CKEDITOR.plugins.pastetools.filters.libreoffice.rules
]
} );
} )();
Loading