8
0
Просмотр исходного кода

Merge branch 'master' into t/ckeditor5/2009

# Conflicts:
#	src/todolistediting.js
#	tests/manual/todo-list.js
#	tests/todolistediting.js
Maciej Gołaszewski 6 лет назад
Родитель
Сommit
018bf4af18

+ 1 - 0
packages/ckeditor5-list/package.json

@@ -22,6 +22,7 @@
     "@ckeditor/ckeditor5-clipboard": "^12.0.2",
     "@ckeditor/ckeditor5-editor-classic": "^12.1.4",
     "@ckeditor/ckeditor5-enter": "^11.1.0",
+    "@ckeditor/ckeditor5-font": "^11.2.2",
     "@ckeditor/ckeditor5-heading": "^11.0.5",
     "@ckeditor/ckeditor5-highlight": "^11.0.5",
     "@ckeditor/ckeditor5-indent": "^10.1.0",

+ 9 - 4
packages/ckeditor5-list/src/todolistediting.js

@@ -95,7 +95,11 @@ export default class TodoListEditing extends Plugin {
 		//
 		// <blockquote><p>Foo{}</p></blockquote>
 		// <ul><li><checkbox/>Bar</li></ul>
-		editor.keystrokes.set( 'arrowleft', ( evt, stop ) => jumpOverCheckmarkOnLeftArrowKeyPress( stop, model ) );
+		//
+		// Note: When content language direction is RTL, the behaviour is mirrored.
+		const localizedJumpOverCheckmarkKey = editor.locale.contentLanguageDirection === 'ltr' ? 'arrowleft' : 'arrowright';
+
+		editor.keystrokes.set( localizedJumpOverCheckmarkKey, ( evt, stop ) => jumpOverCheckmarkOnSideArrowKeyPress( stop, model ) );
 
 		// Toggle check state of selected to-do list items on keystroke.
 		editor.keystrokes.set( 'Ctrl+space', () => editor.execute( 'todoListCheck' ) );
@@ -159,13 +163,14 @@ export default class TodoListEditing extends Plugin {
 	}
 }
 
-// Handles the left arrow key and moves the selection at the end of the previous block element if the selection is just after
-// the checkbox element. In other words, it jumps over the checkbox element when moving the selection to the left.
+// Handles the left/right (LTR/RTL content) arrow key and moves the selection at the end of the previous block element
+// if the selection is just after the checkbox element. In other words, it jumps over the checkbox element when
+// moving the selection to the left/right (LTR/RTL).
 //
 // @private
 // @param {Function} stopKeyEvent
 // @param {module:engine/model/model~Model} model
-function jumpOverCheckmarkOnLeftArrowKeyPress( stopKeyEvent, model ) {
+function jumpOverCheckmarkOnSideArrowKeyPress( stopKeyEvent, model ) {
 	const schema = model.schema;
 	const selection = model.document.selection;
 

+ 24 - 0
packages/ckeditor5-list/tests/manual/todo-list-rtl.html

@@ -0,0 +1,24 @@
+<div id="editor">
+	<p>مرحبا</p>
+	<ul>
+		<li><input type="checkbox">مرحبا</li>
+		<li><input type="checkbox" checked="checked">مرحبا</li>
+		<li><input type="checkbox">مرحبا</li>
+		<li><input type="checkbox" checked="checked">مرحبا</li>
+		<li><input type="checkbox">مرحبا</li>
+		<li><input type="checkbox">مرحبا</li>
+		<li><input type="checkbox" checked="checked">مرحبا</li>
+		<li><input type="checkbox">مرحبا</li>
+	</ul>
+	<p>مرحبا.</p>
+	<p>مرحبا</p>
+	<ol>
+		<li>مرحبا</li>
+	</ol>
+	<ul>
+		<li><input type="checkbox">مرحبا</li>
+	</ul>
+	<ul>
+		<li>مرحبا</li>
+	</ul>
+</div>

+ 41 - 0
packages/ckeditor5-list/tests/manual/todo-list-rtl.js

@@ -0,0 +1,41 @@
+/**
+ * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+
+/* globals console, window, document */
+
+import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';
+import Enter from '@ckeditor/ckeditor5-enter/src/enter';
+import Typing from '@ckeditor/ckeditor5-typing/src/typing';
+import Heading from '@ckeditor/ckeditor5-heading/src/heading';
+import Bold from '@ckeditor/ckeditor5-basic-styles/src/bold';
+import Highlight from '@ckeditor/ckeditor5-highlight/src/highlight';
+import Table from '@ckeditor/ckeditor5-table/src/table';
+import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
+import Undo from '@ckeditor/ckeditor5-undo/src/undo';
+import Clipboard from '@ckeditor/ckeditor5-clipboard/src/clipboard';
+import List from '../../src/list';
+import TodoList from '../../src/todolist';
+
+ClassicEditor
+	.create( document.querySelector( '#editor' ), {
+		plugins: [ Enter, Typing, Heading, Highlight, Table, Bold, Paragraph, Undo, List, TodoList, Clipboard ],
+		language: 'ar',
+		toolbar: [
+			'heading', '|', 'bulletedList', 'numberedList', 'todoList', '|', 'bold', 'highlight', 'insertTable', '|', 'undo', 'redo'
+		],
+		table: {
+			contentToolbar: [
+				'tableColumn',
+				'tableRow',
+				'mergeTableCells'
+			]
+		}
+	} )
+	.then( editor => {
+		window.editor = editor;
+	} )
+	.catch( err => {
+		console.error( err.stack );
+	} );

+ 19 - 0
packages/ckeditor5-list/tests/manual/todo-list-rtl.md

@@ -0,0 +1,19 @@
+## To–do list and RTL (right–to–left content)
+
+### UI
+
+1. Make sure the list is displayed correctly.
+	1. Check boxes should be on the left side of the text.
+	2. There should be some space between the text and the check mark.
+	3. List should be indented from the right side.
+
+### Keyboard navigation
+
+1. Put a selection at the beginning of the document.
+2. Use the **right arrow** key to navigate forwards.
+3. Go through the to–do list.
+4. The navigation should
+	* be uninterrupted,
+	* go always forward.
+5. Reach the end of the document.
+6. Go backwards using the **left arrow** key and repeat the entire scenario.

+ 9 - 2
packages/ckeditor5-list/tests/manual/todo-list.js

@@ -17,13 +17,20 @@ import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
 import Undo from '@ckeditor/ckeditor5-undo/src/undo';
 import Clipboard from '@ckeditor/ckeditor5-clipboard/src/clipboard';
 import List from '../../src/list';
+import FontSize from '@ckeditor/ckeditor5-font/src/fontsize';
 import TodoList from '../../src/todolist';
 
 ClassicEditor
 	.create( document.querySelector( '#editor' ), {
-		plugins: [ Enter, Typing, Heading, Highlight, Table, Bold, Paragraph, Undo, List, TodoList, Clipboard, Link ],
+		plugins: [ Enter, Typing, Heading, Highlight, Table, Bold, Paragraph, Undo, List, TodoList, Clipboard, Link, FontSize ],
 		toolbar: [
-			'heading', '|', 'bulletedList', 'numberedList', 'todoList', '|', 'bold', 'link', 'highlight', 'insertTable', '|', 'undo', 'redo'
+			'heading',
+			'|',
+			'bulletedList', 'numberedList', 'todoList',
+			'|',
+			'bold', 'link', 'highlight', 'insertTable', 'fontSize',
+			'|',
+			'undo', 'redo'
 		],
 		table: {
 			contentToolbar: [

+ 120 - 47
packages/ckeditor5-list/tests/todolistediting.js

@@ -863,69 +863,142 @@ describe( 'TodoListEditing', () => {
 		} );
 	} );
 
-	describe( 'leftArrow key handling', () => {
-		let domEvtDataStub;
+	describe( 'arrow key handling', () => {
+		let editor, model, view, viewDoc, domEvtDataStub;
+
+		describe( 'left arrow in a LTR (left–to–right) content', () => {
+			beforeEach( () => {
+				return VirtualTestEditor
+					.create( {
+						language: 'en',
+						plugins: [ TodoListEditing, Typing, BoldEditing, BlockQuoteEditing ]
+					} )
+					.then( newEditor => {
+						editor = newEditor;
+
+						model = editor.model;
+						view = editor.editing.view;
+						viewDoc = view.document;
+
+						model.schema.register( 'foo', {
+							allowWhere: '$block',
+							allowAttributes: [ 'listIndent', 'listType' ],
+							isBlock: true,
+							isObject: true
+						} );
+
+						domEvtDataStub = {
+							keyCode: getCode( 'arrowLeft' ),
+							preventDefault: sinon.spy(),
+							stopPropagation: sinon.spy(),
+							domTarget: {
+								ownerDocument: {
+									defaultView: {
+										getSelection: () => ( { rangeCount: 0 } )
+									}
+								}
+							}
+						};
+					} );
+			} );
 
-		beforeEach( () => {
-			domEvtDataStub = {
-				keyCode: getCode( 'arrowLeft' ),
-				preventDefault: sinon.spy(),
-				stopPropagation: sinon.spy(),
-				domTarget: {
-					ownerDocument: {
-						defaultView: {
-							getSelection: () => ( { rangeCount: 0 } )
-						}
-					}
-				}
-			};
-		} );
+			afterEach( () => {
+				editor.destroy();
+			} );
 
-		it( 'should jump at the end of the previous node when selection is after checkmark element', () => {
-			setModelData( model,
-				'<blockQuote><paragraph>foo</paragraph></blockQuote>' +
-				'<listItem listIndent="0" listType="todo">[]bar</listItem>'
-			);
+			testArrowKey();
+		} );
 
-			viewDoc.fire( 'keydown', domEvtDataStub );
+		describe( 'right arrow in a RTL (left–to–right) content', () => {
+			beforeEach( () => {
+				return VirtualTestEditor
+					.create( {
+						language: 'ar',
+						plugins: [ TodoListEditing, Typing, BoldEditing, BlockQuoteEditing ]
+					} )
+					.then( newEditor => {
+						editor = newEditor;
+
+						model = editor.model;
+						view = editor.editing.view;
+						viewDoc = view.document;
+
+						model.schema.register( 'foo', {
+							allowWhere: '$block',
+							allowAttributes: [ 'listIndent', 'listType' ],
+							isBlock: true,
+							isObject: true
+						} );
+
+						domEvtDataStub = {
+							keyCode: getCode( 'arrowRight' ),
+							preventDefault: sinon.spy(),
+							stopPropagation: sinon.spy(),
+							domTarget: {
+								ownerDocument: {
+									defaultView: {
+										getSelection: () => ( { rangeCount: 0 } )
+									}
+								}
+							}
+						};
+					} );
+			} );
 
-			assertEqualMarkup( getModelData( model ),
-				'<blockQuote><paragraph>foo[]</paragraph></blockQuote>' +
-				'<listItem listIndent="0" listType="todo">bar</listItem>'
-			);
+			afterEach( () => {
+				editor.destroy();
+			} );
 
-			sinon.assert.calledOnce( domEvtDataStub.preventDefault );
-			sinon.assert.calledOnce( domEvtDataStub.stopPropagation );
+			testArrowKey();
 		} );
 
-		it( 'should do nothing when list item is a first block element in the root', () => {
-			setModelData( model, '<listItem listIndent="0" listType="todo">[]bar</listItem>' );
+		function testArrowKey() {
+			it( 'should jump at the end of the previous node when selection is after checkmark element', () => {
+				setModelData( model,
+					'<blockQuote><paragraph>foo</paragraph></blockQuote>' +
+					'<listItem listIndent="0" listType="todo">[]bar</listItem>'
+				);
 
-			viewDoc.fire( 'keydown', domEvtDataStub );
+				viewDoc.fire( 'keydown', domEvtDataStub );
 
-			sinon.assert.notCalled( domEvtDataStub.preventDefault );
-			sinon.assert.notCalled( domEvtDataStub.stopPropagation );
+				assertEqualMarkup( getModelData( model ),
+					'<blockQuote><paragraph>foo[]</paragraph></blockQuote>' +
+					'<listItem listIndent="0" listType="todo">bar</listItem>'
+				);
 
-			assertEqualMarkup( getModelData( model ), '<listItem listIndent="0" listType="todo">[]bar</listItem>' );
-		} );
+				sinon.assert.calledOnce( domEvtDataStub.preventDefault );
+				sinon.assert.calledOnce( domEvtDataStub.stopPropagation );
+			} );
 
-		it( 'should do nothing when selection is not collapsed', () => {
-			setModelData( model, '<listItem listIndent="0" listType="todo">[bar]</listItem>' );
+			it( 'should do nothing when list item is a first block element in the root', () => {
+				setModelData( model, '<listItem listIndent="0" listType="todo">[]bar</listItem>' );
 
-			viewDoc.fire( 'keydown', domEvtDataStub );
+				viewDoc.fire( 'keydown', domEvtDataStub );
 
-			sinon.assert.notCalled( domEvtDataStub.preventDefault );
-			sinon.assert.notCalled( domEvtDataStub.stopPropagation );
-		} );
+				sinon.assert.notCalled( domEvtDataStub.preventDefault );
+				sinon.assert.notCalled( domEvtDataStub.stopPropagation );
 
-		it( 'should do nothing when selection is not at the beginning list item', () => {
-			setModelData( model, '<listItem listIndent="0" listType="todo">b[]ar</listItem>' );
+				assertEqualMarkup( getModelData( model ), '<listItem listIndent="0" listType="todo">[]bar</listItem>' );
+			} );
 
-			viewDoc.fire( 'keydown', domEvtDataStub );
+			it( 'should do nothing when selection is not collapsed', () => {
+				setModelData( model, '<listItem listIndent="0" listType="todo">[bar]</listItem>' );
 
-			sinon.assert.notCalled( domEvtDataStub.preventDefault );
-			sinon.assert.notCalled( domEvtDataStub.stopPropagation );
-		} );
+				viewDoc.fire( 'keydown', domEvtDataStub );
+
+				sinon.assert.notCalled( domEvtDataStub.preventDefault );
+				sinon.assert.notCalled( domEvtDataStub.stopPropagation );
+			} );
+
+			it( 'should do nothing when selection is not at the beginning list item', () => {
+				setModelData( model, '<listItem listIndent="0" listType="todo">b[]ar</listItem>' );
+
+				viewDoc.fire( 'keydown', domEvtDataStub );
+
+				sinon.assert.notCalled( domEvtDataStub.preventDefault );
+				sinon.assert.notCalled( domEvtDataStub.stopPropagation );
+			} );
+		}
 	} );
 
 	describe( 'Ctrl+space keystroke handling', () => {

+ 20 - 72
packages/ckeditor5-list/theme/list.css

@@ -1,78 +1,26 @@
-:root {
-	--ck-todo-list-checkmark-size: 16px;
-	--ck-color-todo-list-checkmark-background: hsl(120, 100%, 42%);
-	--ck-color-todo-list-checkmark-border: hsl( 120, 100%, 27%);
-}
-
-.ck .todo-list {
-	list-style: none;
-}
-
-.ck .todo-list > li {
-	margin-bottom: 5px;
-}
-
-.ck .todo-list > li > .todo-list {
-	margin-top: 5px;
-}
-
 /*
- * Let's hide native checkbox and make a fancy one.
- *
- * Note: Checkbox element cannot be hidden using `display: block` or `visibility: hidden`.
- * It has to be clickable to not steal the focus after clicking on it.
+ * Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
  */
-.ck .todo-list__checkmark input[type='checkbox'] {
-	display: block;
-	width: 100%;
-	height: 100%;
-	opacity: 0;
-	margin: 0;
-}
 
-.ck .todo-list__checkmark {
-	cursor: pointer;
-	width: var(--ck-todo-list-checkmark-size);
-	height: var(--ck-todo-list-checkmark-size);
-	position: relative;
+.ck-editor__editable .todo-list__checkmark {
 	display: inline-block;
-	left: -23px;
-	margin-right: -16px;
-	top: 2px;
-}
-
-.ck .todo-list__checkmark::before {
-	content: '';
-	position: absolute;
-	display: block;
-	width: 100%;
-	height: 100%;
-	border: 1px solid var(--ck-color-base-text);
-	border-radius: var(--ck-border-radius);
-	transition: 250ms ease-in-out box-shadow, 250ms ease-in-out background, 250ms ease-in-out border;
-	box-sizing: border-box;
-}
-
-.ck .todo-list__checkmark::after {
-	box-sizing: content-box;
-	pointer-events: none;
-	content: '';
-	position: absolute;
-	left: 5px;
-	top: 3px;
-	display: block;
-	width: 3px;
-	height: 6px;
-	border: solid #fff;
-	border-width: 0 2px 2px 0;
-	transform: rotate(45deg);
-}
-
-.ck .todo-list__checkmark:hover::before {
-	box-shadow: 0 0 0 5px hsla(0, 0%, 0%, 0.1)
-}
+	position: relative;
 
-.ck .todo-list__checkmark_checked::before {
-	background: var(--ck-color-todo-list-checkmark-background);
-	border-color: var(--ck-color-todo-list-checkmark-border);
+	&::before {
+		display: block;
+		position: absolute;
+		box-sizing: border-box;
+	}
+
+	&::after {
+		display: block;
+		position: absolute;
+		box-sizing: content-box;
+		pointer-events: none;
+	}
+
+	& input[type='checkbox'] {
+		display: block;
+	}
 }