Skip to content
This repository has been archived by the owner on Jun 26, 2020. It is now read-only.

Provide support for pasting lists from google docs #72

Merged
merged 35 commits into from
Aug 5, 2019
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
173e44d
Add support for pasting lists from google docs.
Jul 29, 2019
7c4f7dc
Add unit test for google docslist item filters.
Jul 29, 2019
1111bea
Add data for autoamtic tests for pasted lists from google docs.
Jul 30, 2019
11cbe07
Provide option to obtain model's data.
Jul 30, 2019
348f3b6
Fix typo in folder name.
Jul 30, 2019
419ff3d
Correct test files. Add entry point for tests, add test to dataset.
Jul 30, 2019
3eda19c
Add unit test for mixed lists.
Jul 30, 2019
4a566b2
Fix small typos.
Jul 30, 2019
5bf77e7
Introduce generic nromalizer, to patch content which is wrong but not…
Jul 30, 2019
f6ee361
Add support and provide normalization for repeatedly nested lists.
Jul 31, 2019
2fb7ddb
Ad unit test for fixed filter.
Jul 31, 2019
e8e12c9
Add new automatic test for repeatedly nested lists.
Jul 31, 2019
6c9f2e9
Merge branch 'master' into t/69
Aug 1, 2019
975992e
Support mort cases with unwrapping lists.
Aug 1, 2019
cfb2a35
Fix sibling lists.
Aug 1, 2019
95c024f
Add unit test for sibling list, add autoamtic test for partially sele…
Aug 1, 2019
3806a55
Move generic nromalizer as last one which will be always active.
Aug 1, 2019
16ca74f
Move google docs list filter to list.js file.
Aug 1, 2019
4aa476a
Remove getModelData from manual test.
Aug 1, 2019
70495e8
Remove unecessary if. There always should be at least one active norm…
Aug 1, 2019
68d155e
Rename unwrapParagraph and moveNestedLists... function.
Aug 1, 2019
b8eaff4
Move description to jsdoc.
Aug 1, 2019
861ba50
Utilize walker insted of recurence to fix lists indentation.
Aug 1, 2019
a6fa897
Replace recurrence in unwrapParagraph with treewalker.
Aug 1, 2019
40c88a2
Simplify comment.
Aug 1, 2019
c9b208f
Correct names of generic normalizer in unit tests.
Aug 1, 2019
85c8764
Apply suggestions from code review
msamsel Aug 2, 2019
4a1dd43
Utilize new API of upcast writer.
Aug 2, 2019
383b387
Add comment to code and improve docs description.
Aug 2, 2019
1a95ece
Correct variables names and docs entries.
Aug 2, 2019
676730c
Remove generic normalizer.
Aug 2, 2019
d2da715
Fix examples alignment in the docs of fixListIndentation() function.
jodator Aug 5, 2019
5513c92
Use isList() helper function in isNewListNeeded.
jodator Aug 5, 2019
3d467da
Move unwrapParagraphInListItem & fixListIndentation to the top of a f…
jodator Aug 5, 2019
0a56b5e
Remove comment.
jodator Aug 5, 2019
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
89 changes: 89 additions & 0 deletions src/filters/common.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/**
* @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/

/**
* @module paste-from-office/filters/common
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's keep them separated like removeBoldWrapper().

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those filters are for lists and only list so they should go to the lists.js IMO.

Now I'm worried that we're going to introduce some mess in the /filters namespace. So at the moment, I'd move those 2 methods to the lists.js (so do not create another 2 files) And we can iron out the layout of the filters later on when we gonna have more filters.

*/

/**
* Removes paragraph wrapping content inside list item.
*
* @param {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment} elementOrDocumentFragment
* @param {module:engine/view/upcastwriter~UpcastWriter} writer
*/
export function unwrapParagraph( elementOrDocumentFragment, writer ) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe unwrapParagraphInList()? I worry that the context is not clear enough.

const iterableNodes = elementOrDocumentFragment.is( 'element' ) ? elementOrDocumentFragment.getChildren() : elementOrDocumentFragment;

for ( const element of iterableNodes ) {
if ( element.is( 'element', 'p' ) && element.parent.is( 'element', 'li' ) ) {
unwrapSingleElement( element, writer );
}

if ( element.is( 'element' ) && element.childCount ) {
unwrapParagraph( element, writer );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly to the method below, I think that we can get rid of recursion here by inspectign children of the li rahter then parent of p.

}
}
}

/**
* Moves nested list inside previous sibling element, what is a proper HTML standard.
*
* @param {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment} elementOrDocumentFragment
* @param {module:engine/view/upcastwriter~UpcastWriter} writer
*/
export function moveNestedListToListItem( elementOrDocumentFragment, writer ) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixListIndentation() ? The name moveNestedListToListItem() is based on function execution rather then on what this filter fixes.

// There are 2 situations which are fixed in the for loop:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be moved to the method description.

//
// 1. Move list to previous list item:
// OL OL
// |-> LI |-> LI
// |-> OL |-> OL
// |-> LI |-> LI
//
// 2. Unwrap nested list to avoid situation that UL or OL is direct child of another UL or OL.
// OL OL
// |-> LI |-> LI
// |-> OL |-> OL
// |-> OL |-> LI
// | |-> OL |-> LI
// | |-> OL
// | |-> LI
// |-> LI
const iterableNodes = elementOrDocumentFragment.is( 'element' ) ? elementOrDocumentFragment.getChildren() : elementOrDocumentFragment;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find this method a bit complicated because of the recursion.

I did small tests and it seems that we can get rid of the recursion here by using tree walker (by creating a range inside document fragment).

I'd go with something like this:

for ( const value of writer.createRangeIn( elementOrDocumentFragment ) ) {
		const element = value.item;

		// 2.
		if ( element.is( 'li' ) ) {
			const next = element.nextSibling;

			if ( next && isList( next ) ) {
				writer.remove( next );
				writer.insertChild( element.childCount, next, element );
			}
		}

		// 1.
		if ( isList( element ) ) {
			let firstChild = element.getChild( 0 );

			while ( isList( firstChild ) ) {
				unwrapSingleElement( firstChild, writer );
				firstChild = element.getChild( 0 );
			}
		}
	}

I think that using tree walker here should be safe as long we mangle with a node after (not a node before) or it's children of current walker value.


for ( const element of iterableNodes ) {
if ( isList( element ) && isList( element.parent ) ) {
// 1.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some text would be nice - ie case 1: Move to the previous item

const previous = element.previousSibling;

writer.remove( element );
writer.insertChild( previous.childCount, element, previous );

// 2.
let firstChild = element.getChild( 0 );

while ( isList( firstChild ) ) {
unwrapSingleElement( firstChild, writer );
firstChild = element.getChild( 0 );
}
}

if ( element.is( 'element' ) && element.childCount ) {
moveNestedListToListItem( element, writer );
}
}
}

function isList( element ) {
return element.is( 'element', 'ol' ) || element.is( 'element', 'ul' );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't element.is( 'ol' ) enough?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ps.: this applies to other is() checks.

}

function unwrapSingleElement( element, writer ) {
const parent = element.parent;
const childIndex = parent.getChildIndex( element );

writer.remove( element );
writer.insertChild( childIndex, element.getChildren(), parent );
}
35 changes: 35 additions & 0 deletions src/normalizers/genericnormalizer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/

/**
* @module paste-from-office/normalizers/genericnormalizer
*/

import { unwrapParagraph, moveNestedListToListItem } from '../filters/common';
import UpcastWriter from '@ckeditor/ckeditor5-engine/src/view/upcastwriter';

/**
* Normalizer for the content pasted from different sources, where we can detect wrong syntax.
*
* @implements module:paste-from-office/normalizer~Normalizer
*/
export default class GenericNormalizer {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we need GenericNormalizer. It duplicates fixes for GD normalizer. It probably might also duplicate MSWord normalizer.

Right now I don't have a clear idea of how to deal with those fixes - they might be helpfull generally speaking one can copy such weird list indentation from various sources. But OTOH such argument is also valid for every other filter.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm thinking about removing this ATM but I'll give it another thought.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here are the details and comments about why it's important:
#72 (comment)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it happen only on Safari? If so I'd still ad some env checking to be sure that this normalizer doesn't fire up too often. @mlewand WDYT? OTOH this normalizer will always fix pasted lists (even from other sources) so it may be beneficial.

I see two routes:

  1. Make it run only for Safari and name it more specific, like: SafariListNormalizer
  2. Make it general list fixer - the I'd name it NestedListNormalizer and maybe add a check if pasted content has broken list (AFAICS ul></ul, /p></li and /li><ul could be checked - with ul|ol variants check) - but the check idea is something to give another though if it makes sense.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would not stick to "List" name here. As content is unrecognizable for any filter.
Google Docs for some specific contents (with tables) under Safari doesn't provide any string which could provide us info, that content came from Google Docs. It's just regular broken HTML.
So the same situation will repeat for heading filters or any other further filters. Where we still won't be knowing that content came from Google Docs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So in such cases better could be SafariNormalizer however this might be a little bit confusing, as there will be content from Safari that sometimes will activate SafariNormalizer and sometimes GoogleDocsNormalizer
We can prioritize it, but then it will be an exact copy of GoogleDocs normalizer and in such case, in my opinion, better will be making a change in isActive() method of google normalizer:

isActive( htmlString ) {
	return googleDocsMatch.test( htmlString ) || env.isSafari;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jodator @msamsel I took a peek at it and I see that:

  • Safari problem described in Provide support for pasting lists from google docs #72 (comment) happens when table is first, but does not happen if there's anything preceding it, which makes the bug that much less common (safari * edge case = very rare case).

    First of all it does look like upstream issue, I suspected Safari at first, but given that id appears if table is not the first item it sounds it's more of a Google Docs bug. Have we checked if this issue can be reported and tracked?

  • I don't feel good with exposing this filter as a generic feature if we don't have any need for it (no requests, no real use cases).

Since still pretty much all the cases will be handled on safari except this particular oddity, let's wait for some real life cases where it will be useful. Until then let's extract mentioned Safari problem as a separate issue and put it to backlog.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jodator I removed this normalizer.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I extracted this case to separate issue: #75

/**
* @inheritDoc
*/
isActive() {
return true;
}

/**
* @inheritDoc
*/
execute( data ) {
const writer = new UpcastWriter();

moveNestedListToListItem( data.content, writer );
unwrapParagraph( data.content, writer );
}
}
3 changes: 3 additions & 0 deletions src/normalizers/googledocsnormalizer.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/

import removeBoldWrapper from '../filters/removeboldwrapper';
import { unwrapParagraph, moveNestedListToListItem } from '../filters/common';
import UpcastWriter from '@ckeditor/ckeditor5-engine/src/view/upcastwriter';

const googleDocsMatch = /id=("|')docs-internal-guid-[-0-9a-f]+("|')/i;
Expand All @@ -32,5 +33,7 @@ export default class GoogleDocsNormalizer {
const writer = new UpcastWriter();

removeBoldWrapper( data.content, writer );
moveNestedListToListItem( data.content, writer );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this trick also closes the #19? Would be sweet if we could add this also to the MSWord normalizer :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If so I 'd try to refactor the MSWordNormalizer if doable in 2-3 hours. Pulling up the upcast writer up from inner methods like transformListItemLikeElementsIntoLists() to MSWordNormalzier() seems like pretty straightforward task and could be doable.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But only if this PR would also fix the MSWord lists.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, it requires some deeper analysis and most probably attaching somewhere inside word filter. :(

a simple adding new filter like this:

data.content = body;

fixListIndentation( data.content, new UpcastWriter() );

or at the beginning of transforming content doesn't work.

It looks like this uber-filter for MS Word makes all lists flat and it doesn't keep information about indentation.

unwrapParagraph( data.content, writer );
}
}
6 changes: 6 additions & 0 deletions src/pastefromoffice.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
import GoogleDocsNormalizer from './normalizers/googledocsnormalizer';
import MSWordNormalizer from './normalizers/mswordnormalizer';
import Clipboard from '@ckeditor/ckeditor5-clipboard/src/clipboard';
import GenericNormalizer from './normalizers/genericnormalizer';

/**
* The Paste from Office plugin.
Expand Down Expand Up @@ -49,6 +50,7 @@ export default class PasteFromOffice extends Plugin {
init() {
const editor = this.editor;
const normalizers = [];
const genericNormalizer = new GenericNormalizer();

normalizers.push( new MSWordNormalizer() );
normalizers.push( new GoogleDocsNormalizer() );
Expand All @@ -66,6 +68,10 @@ export default class PasteFromOffice extends Plugin {
if ( activeNormalizer ) {
activeNormalizer.execute( data );

data.isTransformedWithPasteFromOffice = true;
} else {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need that. If you'd add the GenericNormalizer to the normalizers array as the last element it will be always returned if no other normalizers before would return true.

Might be invalid if we don't want GenericNormalizer.

genericNormalizer.execute( data );

data.isTransformedWithPasteFromOffice = true;
}
},
Expand Down
22 changes: 22 additions & 0 deletions tests/_data/generic/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/

import listInTable from './list-in-table/input.html';
import listInTableNormalized from './list-in-table/normalized.html';
import listInTableModel from './list-in-table/model.html';

export const fixtures = {
input: {
listInTable
},
normalized: {
listInTable: listInTableNormalized
},
model: {
listInTable: listInTableModel
}
};

export const browserFixtures = {};
1 change: 1 addition & 0 deletions tests/_data/generic/list-in-table/input.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<div dir="ltr" style="font-family: -webkit-standard; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); margin-left: 0pt;"><table style="border: none; border-collapse: collapse; width: 468pt;"><tbody><tr style="height: 50pt;"><td style="border: 1pt solid rgb(0, 0, 0); vertical-align: top; padding: 5pt;"><ul style="margin-top: 0pt; margin-bottom: 0pt;"><li dir="ltr" style="list-style-type: disc; font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: 400; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-position: normal; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" style="line-height: 1.2; margin-top: 0pt; margin-bottom: 0pt;"><span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: 400; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-position: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">One</span></p></li><li dir="ltr" style="list-style-type: disc; font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: 400; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-position: normal; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" style="line-height: 1.2; margin-top: 0pt; margin-bottom: 0pt;"><span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: 400; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-position: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Two</span></p></li><li dir="ltr" style="list-style-type: disc; font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: 400; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-position: normal; text-decoration: none; vertical-align: baseline; white-space: pre;"><p dir="ltr" style="line-height: 1.2; margin-top: 0pt; margin-bottom: 0pt;"><span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: 400; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-variant-position: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Three</span></p></li></ul></td></tr></tbody></table></div>
1 change: 1 addition & 0 deletions tests/_data/generic/list-in-table/lists-in-table.html

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions tests/_data/generic/list-in-table/model.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<table><tableRow><tableCell><listItem listIndent="0" listType="bulleted">One</listItem><listItem listIndent="0" listType="bulleted">Two</listItem><listItem listIndent="0" listType="bulleted">Three</listItem></tableCell></tableRow></table>
1 change: 1 addition & 0 deletions tests/_data/generic/list-in-table/normalized.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<div dir="ltr" style="-webkit-text-size-adjust:auto;-webkit-text-stroke-width:0px;caret-color:rgb(0, 0, 0);color:rgb(0, 0, 0);font-family:-webkit-standard;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;margin-left:0pt;orphans:auto;text-align:start;text-decoration:none;text-indent:0px;text-transform:none;white-space:normal;widows:auto;word-spacing:0px"><table style="border:none;border-collapse:collapse;width:468pt"><tbody><tr style="height:50pt"><td style="border:1pt solid rgb(0, 0, 0);padding:5pt;vertical-align:top"><ul style="margin-bottom:0pt;margin-top:0pt"><li dir="ltr" style="background-color:transparent;color:rgb(0, 0, 0);font-family:Arial;font-size:11pt;font-style:normal;font-variant-caps:normal;font-variant-east-asian:normal;font-variant-ligatures:normal;font-variant-position:normal;font-weight:400;list-style-type:disc;text-decoration:none;vertical-align:baseline;white-space:pre"><span style="background-color:transparent;color:rgb(0, 0, 0);font-family:Arial;font-size:11pt;font-style:normal;font-variant-caps:normal;font-variant-east-asian:normal;font-variant-ligatures:normal;font-variant-position:normal;font-weight:400;text-decoration:none;vertical-align:baseline;white-space:pre-wrap">One</span></li><li dir="ltr" style="background-color:transparent;color:rgb(0, 0, 0);font-family:Arial;font-size:11pt;font-style:normal;font-variant-caps:normal;font-variant-east-asian:normal;font-variant-ligatures:normal;font-variant-position:normal;font-weight:400;list-style-type:disc;text-decoration:none;vertical-align:baseline;white-space:pre"><span style="background-color:transparent;color:rgb(0, 0, 0);font-family:Arial;font-size:11pt;font-style:normal;font-variant-caps:normal;font-variant-east-asian:normal;font-variant-ligatures:normal;font-variant-position:normal;font-weight:400;text-decoration:none;vertical-align:baseline;white-space:pre-wrap">Two</span></li><li dir="ltr" style="background-color:transparent;color:rgb(0, 0, 0);font-family:Arial;font-size:11pt;font-style:normal;font-variant-caps:normal;font-variant-east-asian:normal;font-variant-ligatures:normal;font-variant-position:normal;font-weight:400;list-style-type:disc;text-decoration:none;vertical-align:baseline;white-space:pre"><span style="background-color:transparent;color:rgb(0, 0, 0);font-family:Arial;font-size:11pt;font-style:normal;font-variant-caps:normal;font-variant-east-asian:normal;font-variant-ligatures:normal;font-variant-position:normal;font-weight:400;text-decoration:none;vertical-align:baseline;white-space:pre-wrap">Three</span></li></ul></td></tr></tbody></table></div>
36 changes: 36 additions & 0 deletions tests/_data/paste-from-google-docs/lists/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/

import nestedOrderedList from './nested-ordered-lists/input.html';
import nestedOrderedListNormalized from './nested-ordered-lists/normalized.html';
import nestedOrderedListModel from './nested-ordered-lists/model.html';

import mixedList from './mixed-list/input.html';
import mixedListNormalized from './mixed-list/normalized.html';
import mixedListModel from './mixed-list/model.html';

import repeatedlyNestedList from './repeatedly-nested-list/input.html';
import repeatedlyNestedListNormalized from './repeatedly-nested-list/normalized.html';
import repeatedlyNestedListModel from './repeatedly-nested-list/model.html';

export const fixtures = {
input: {
nestedOrderedList,
mixedList,
repeatedlyNestedList
},
normalized: {
nestedOrderedList: nestedOrderedListNormalized,
mixedList: mixedListNormalized,
repeatedlyNestedList: repeatedlyNestedListNormalized
},
model: {
nestedOrderedList: nestedOrderedListModel,
mixedList: mixedListModel,
repeatedlyNestedList: repeatedlyNestedListModel
}
};

export const browserFixtures = {};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<meta charset='utf-8'><meta charset="utf-8"><b style="font-weight:normal;" id="docs-internal-guid-6aba46e4-7fff-ffbf-43f7-6080e7ecadb8"><ol style="margin-top:0pt;margin-bottom:0pt;"><li dir="ltr" style="list-style-type:decimal;font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;"><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt;"><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">1</span></p></li><ul style="margin-top:0pt;margin-bottom:0pt;"><li dir="ltr" style="list-style-type:circle;font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;"><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt;"><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">A</span></p></li><ol style="margin-top:0pt;margin-bottom:0pt;"><li dir="ltr" style="list-style-type:lower-roman;font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;"><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt;"><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">1</span></p></li></ol></ul><li dir="ltr" style="list-style-type:decimal;font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;"><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt;"><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">2</span></p></li><li dir="ltr" style="list-style-type:decimal;font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;"><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt;"><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">3</span></p></li><ul style="margin-top:0pt;margin-bottom:0pt;"><li dir="ltr" style="list-style-type:circle;font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;"><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt;"><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">A</span></p></li><li dir="ltr" style="list-style-type:circle;font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;"><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt;"><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">B</span></p></li></ul></ol><ul style="margin-top:0pt;margin-bottom:0pt;"><li dir="ltr" style="list-style-type:disc;font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;"><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt;"><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">A</span></p></li><ol style="margin-top:0pt;margin-bottom:0pt;"><li dir="ltr" style="list-style-type:lower-alpha;font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;"><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt;"><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">1</span></p></li><li dir="ltr" style="list-style-type:lower-alpha;font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;"><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt;"><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">2</span></p></li></ol></ul></b>

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<listItem listIndent="0" listType="numbered">1</listItem><listItem listIndent="1" listType="bulleted">A</listItem><listItem listIndent="2" listType="numbered">1</listItem><listItem listIndent="0" listType="numbered">2</listItem><listItem listIndent="0" listType="numbered">3</listItem><listItem listIndent="1" listType="bulleted">A</listItem><listItem listIndent="1" listType="bulleted">B</listItem><listItem listIndent="0" listType="bulleted">A</listItem><listItem listIndent="1" listType="numbered">1</listItem><listItem listIndent="1" listType="numbered">2</listItem>
Loading