浏览代码

Merge branch 'master' into i/5189

Marek Lewandowski 6 年之前
父节点
当前提交
14421c0886

+ 3 - 0
packages/ckeditor5-image/.stylelintrc

@@ -0,0 +1,3 @@
+{
+	"extends": "stylelint-config-ckeditor5"
+}

+ 11 - 0
packages/ckeditor5-image/CHANGELOG.md

@@ -1,6 +1,17 @@
 Changelog
 Changelog
 =========
 =========
 
 
+## [16.0.0](https://github.com/ckeditor/ckeditor5-image/compare/v15.0.0...v16.0.0) (2019-12-04)
+
+### Bug fixes
+
+* Improved markup operation performance of the editor with the image plugin enabled. See [ckeditor/ckeditor5#4504](https://github.com/ckeditor/ckeditor5/issues/4504). ([6c7fc94](https://github.com/ckeditor/ckeditor5-image/commit/6c7fc94))
+
+### Other changes
+
+* Updated translations. ([01cdb59](https://github.com/ckeditor/ckeditor5-image/commit/01cdb59))
+
+
 ## [15.0.0](https://github.com/ckeditor/ckeditor5-image/compare/v14.0.0...v15.0.0) (2019-10-23)
 ## [15.0.0](https://github.com/ckeditor/ckeditor5-image/compare/v14.0.0...v15.0.0) (2019-10-23)
 
 
 ### MAJOR BREAKING CHANGES
 ### MAJOR BREAKING CHANGES

+ 65 - 0
packages/ckeditor5-image/lang/translations/he.po

@@ -0,0 +1,65 @@
+# Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
+#
+#                                     !!! IMPORTANT !!!
+#
+#         Before you edit this file, please keep in mind that contributing to the project
+#                translations is possible ONLY via the Transifex online service.
+#
+#         To submit your translations, visit https://www.transifex.com/ckeditor/ckeditor5.
+#
+#                   To learn more, check out the official contributor's guide:
+#     https://ckeditor.com/docs/ckeditor5/latest/framework/guides/contributing/contributing.html
+#
+msgid ""
+msgstr ""
+"Language-Team: Hebrew (https://www.transifex.com/ckeditor/teams/11143/he/)\n"
+"Language: he\n"
+"Plural-Forms: nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n == 2 && n % 1 == 0) ? 1: (n % 10 == 0 && n % 1 == 0 && n > 10) ? 2 : 3;\n"
+
+msgctxt "Label for the image widget."
+msgid "image widget"
+msgstr "תמונה"
+
+msgctxt "Label for the Side image option."
+msgid "Side image"
+msgstr "תמונת צד"
+
+msgctxt "Label for the Full size image option."
+msgid "Full size image"
+msgstr "תמונה בפריסה מלאה"
+
+msgctxt "Label for the Left aligned image option"
+msgid "Left aligned image"
+msgstr "תמונה מיושרת לשמאל"
+
+msgctxt "Label for the Centered image option"
+msgid "Centered image"
+msgstr "תמונה ממרוכזת"
+
+msgctxt "Label for the Right aligned image option"
+msgid "Right aligned image"
+msgstr "תמונה מיושרת לימין"
+
+msgctxt "Label for the Change image text alternative button."
+msgid "Change image text alternative"
+msgstr "שינוי טקסט אלטרנטיבי לתמונה"
+
+msgctxt "Label for the image text alternative input."
+msgid "Text alternative"
+msgstr "טקסט אלטרנטיבי"
+
+msgctxt "Placeholder text for image caption displayed when caption is empty."
+msgid "Enter image caption"
+msgstr "הזן כותרת תמונה"
+
+msgctxt "Label for the insert image toolbar button."
+msgid "Insert image"
+msgstr "הוספת תמונה"
+
+msgctxt "Title of the notification displayed when upload fails."
+msgid "Upload failed"
+msgstr "העלאה נכשלה"
+
+msgctxt "The label used by assistive technologies describing an image toolbar attached to an image widget."
+msgid "Image toolbar"
+msgstr "סרגל תמונה"

+ 1 - 1
packages/ckeditor5-image/lang/translations/uk.po

@@ -62,4 +62,4 @@ msgstr "Завантаження не вдалось"
 
 
 msgctxt "The label used by assistive technologies describing an image toolbar attached to an image widget."
 msgctxt "The label used by assistive technologies describing an image toolbar attached to an image widget."
 msgid "Image toolbar"
 msgid "Image toolbar"
-msgstr ""
+msgstr "Панелі інструментів зображення"

+ 65 - 0
packages/ckeditor5-image/lang/translations/vi.po

@@ -0,0 +1,65 @@
+# Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
+#
+#                                     !!! IMPORTANT !!!
+#
+#         Before you edit this file, please keep in mind that contributing to the project
+#                translations is possible ONLY via the Transifex online service.
+#
+#         To submit your translations, visit https://www.transifex.com/ckeditor/ckeditor5.
+#
+#                   To learn more, check out the official contributor's guide:
+#     https://ckeditor.com/docs/ckeditor5/latest/framework/guides/contributing/contributing.html
+#
+msgid ""
+msgstr ""
+"Language-Team: Vietnamese (https://www.transifex.com/ckeditor/teams/11143/vi/)\n"
+"Language: vi\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+
+msgctxt "Label for the image widget."
+msgid "image widget"
+msgstr "tiện ích ảnh"
+
+msgctxt "Label for the Side image option."
+msgid "Side image"
+msgstr "Ảnh một bên"
+
+msgctxt "Label for the Full size image option."
+msgid "Full size image"
+msgstr "Ảnh đầy đủ"
+
+msgctxt "Label for the Left aligned image option"
+msgid "Left aligned image"
+msgstr "Ảnh canh trái"
+
+msgctxt "Label for the Centered image option"
+msgid "Centered image"
+msgstr "Ảnh canh giữa"
+
+msgctxt "Label for the Right aligned image option"
+msgid "Right aligned image"
+msgstr "Ảnh canh phải"
+
+msgctxt "Label for the Change image text alternative button."
+msgid "Change image text alternative"
+msgstr "Đổi chữ alt của ảnh"
+
+msgctxt "Label for the image text alternative input."
+msgid "Text alternative"
+msgstr "Chữ alt"
+
+msgctxt "Placeholder text for image caption displayed when caption is empty."
+msgid "Enter image caption"
+msgstr "Nhập mô tả ảnh"
+
+msgctxt "Label for the insert image toolbar button."
+msgid "Insert image"
+msgstr "Chèn ảnh"
+
+msgctxt "Title of the notification displayed when upload fails."
+msgid "Upload failed"
+msgstr "Tải thất bại"
+
+msgctxt "The label used by assistive technologies describing an image toolbar attached to an image widget."
+msgid "Image toolbar"
+msgstr "Thanh công cụ hình ảnh"

+ 30 - 24
packages/ckeditor5-image/package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "@ckeditor/ckeditor5-image",
   "name": "@ckeditor/ckeditor5-image",
-  "version": "15.0.0",
+  "version": "16.0.0",
   "description": "Image feature for CKEditor 5.",
   "description": "Image feature for CKEditor 5.",
   "keywords": [
   "keywords": [
     "ckeditor",
     "ckeditor",
@@ -10,33 +10,35 @@
     "ckeditor5-plugin"
     "ckeditor5-plugin"
   ],
   ],
   "dependencies": {
   "dependencies": {
-    "@ckeditor/ckeditor5-core": "^15.0.0",
-    "@ckeditor/ckeditor5-engine": "^15.0.0",
-    "@ckeditor/ckeditor5-ui": "^15.0.0",
-    "@ckeditor/ckeditor5-upload": "^15.0.0",
-    "@ckeditor/ckeditor5-utils": "^15.0.0",
-    "@ckeditor/ckeditor5-widget": "^15.0.0"
+    "@ckeditor/ckeditor5-clipboard": "^16.0.0",
+    "@ckeditor/ckeditor5-core": "^16.0.0",
+    "@ckeditor/ckeditor5-engine": "^16.0.0",
+    "@ckeditor/ckeditor5-ui": "^16.0.0",
+    "@ckeditor/ckeditor5-upload": "^16.0.0",
+    "@ckeditor/ckeditor5-utils": "^16.0.0",
+    "@ckeditor/ckeditor5-widget": "^16.0.0"
   },
   },
   "devDependencies": {
   "devDependencies": {
-    "@ckeditor/ckeditor5-basic-styles": "^15.0.0",
-    "@ckeditor/ckeditor5-block-quote": "^15.0.0",
-    "@ckeditor/ckeditor5-cloud-services": "^15.0.0",
-    "@ckeditor/ckeditor5-clipboard": "^15.0.0",
-    "@ckeditor/ckeditor5-editor-classic": "^15.0.0",
-    "@ckeditor/ckeditor5-enter": "^15.0.0",
-    "@ckeditor/ckeditor5-easy-image": "^15.0.0",
-    "@ckeditor/ckeditor5-heading": "^15.0.0",
-    "@ckeditor/ckeditor5-indent": "^15.0.0",
-    "@ckeditor/ckeditor5-link": "^15.0.0",
-    "@ckeditor/ckeditor5-list": "^15.0.0",
-    "@ckeditor/ckeditor5-paragraph": "^15.0.0",
-    "@ckeditor/ckeditor5-table": "^15.0.0",
-    "@ckeditor/ckeditor5-typing": "^15.0.0",
-    "@ckeditor/ckeditor5-undo": "^15.0.0",
+    "@ckeditor/ckeditor5-basic-styles": "^16.0.0",
+    "@ckeditor/ckeditor5-block-quote": "^16.0.0",
+    "@ckeditor/ckeditor5-cloud-services": "^16.0.0",
+    "@ckeditor/ckeditor5-editor-classic": "^16.0.0",
+    "@ckeditor/ckeditor5-enter": "^16.0.0",
+    "@ckeditor/ckeditor5-easy-image": "^16.0.0",
+    "@ckeditor/ckeditor5-heading": "^16.0.0",
+    "@ckeditor/ckeditor5-indent": "^16.0.0",
+    "@ckeditor/ckeditor5-link": "^16.0.0",
+    "@ckeditor/ckeditor5-list": "^16.0.0",
+    "@ckeditor/ckeditor5-paragraph": "^16.0.0",
+    "@ckeditor/ckeditor5-table": "^16.0.0",
+    "@ckeditor/ckeditor5-typing": "^16.0.0",
+    "@ckeditor/ckeditor5-undo": "^16.0.0",
     "eslint": "^5.5.0",
     "eslint": "^5.5.0",
     "eslint-config-ckeditor5": "^2.0.0",
     "eslint-config-ckeditor5": "^2.0.0",
     "husky": "^1.3.1",
     "husky": "^1.3.1",
-    "lint-staged": "^7.0.0"
+    "lint-staged": "^7.0.0",
+    "stylelint": "^11.1.1",
+    "stylelint-config-ckeditor5": "^1.0.0"
   },
   },
   "engines": {
   "engines": {
     "node": ">=8.0.0",
     "node": ">=8.0.0",
@@ -56,11 +58,15 @@
     "theme"
     "theme"
   ],
   ],
   "scripts": {
   "scripts": {
-    "lint": "eslint --quiet '**/*.js'"
+    "lint": "eslint --quiet '**/*.js'",
+    "stylelint": "stylelint --quiet --allow-empty-input 'theme/**/*.css' 'docs/**/*.css'"
   },
   },
   "lint-staged": {
   "lint-staged": {
     "**/*.js": [
     "**/*.js": [
       "eslint --quiet"
       "eslint --quiet"
+    ],
+    "**/*.css": [
+      "stylelint --quiet --allow-empty-input"
     ]
     ]
   },
   },
   "eslintIgnore": [
   "eslintIgnore": [

+ 7 - 62
packages/ckeditor5-image/src/image/imageloadobserver.js

@@ -20,65 +20,18 @@ import Observer from '@ckeditor/ckeditor5-engine/src/view/observer/observer';
  * @extends module:engine/view/observer/observer~Observer
  * @extends module:engine/view/observer/observer~Observer
  */
  */
 export default class ImageLoadObserver extends Observer {
 export default class ImageLoadObserver extends Observer {
-	constructor( view ) {
-		super( view );
-
-		/**
-		 * List of img DOM elements that are observed by this observer.
-		 *
-		 * @private
-		 * @type {Set.<HTMLElement>}
-		 */
-		this._observedElements = new Set();
-	}
-
 	/**
 	/**
 	 * @inheritDoc
 	 * @inheritDoc
 	 */
 	 */
-	observe( domRoot, name ) {
-		const viewRoot = this.document.getRoot( name );
-
-		// When there is a change in one of the view element
-		// we need to check if there are any new `<img/>` elements to observe.
-		viewRoot.on( 'change:children', ( evt, node ) => {
-			// Wait for the render to be sure that `<img/>` elements are rendered in the DOM root.
-			this.view.once( 'render', () => this._updateObservedElements( domRoot, node ) );
-		} );
-	}
-
-	/**
-	 * Updates the list of observed `<img/>` elements.
-	 *
-	 * @private
-	 * @param {HTMLElement} domRoot DOM root element.
-	 * @param {module:engine/view/element~Element} viewNode View element where children have changed.
-	 */
-	_updateObservedElements( domRoot, viewNode ) {
-		if ( !viewNode.is( 'element' ) || viewNode.is( 'attributeElement' ) ) {
-			return;
-		}
-
-		const domNode = this.view.domConverter.mapViewToDom( viewNode );
+	observe( domRoot ) {
+		this.listenTo( domRoot, 'load', ( event, domEvent ) => {
+			const domElement = domEvent.target;
 
 
-		// If there is no `domNode` it means that it was removed from the DOM in the meanwhile.
-		if ( !domNode ) {
-			return;
-		}
-
-		for ( const domElement of domNode.querySelectorAll( 'img' ) ) {
-			if ( !this._observedElements.has( domElement ) ) {
-				this.listenTo( domElement, 'load', ( evt, domEvt ) => this._fireEvents( domEvt ) );
-				this._observedElements.add( domElement );
-			}
-		}
-
-		// Clean up the list of observed elements from elements that has been removed from the root.
-		for ( const domElement of this._observedElements ) {
-			if ( !domRoot.contains( domElement ) ) {
-				this.stopListening( domElement );
-				this._observedElements.delete( domElement );
+			if ( domElement.tagName == 'IMG' ) {
+				this._fireEvents( domEvent );
 			}
 			}
-		}
+			// Use capture phase for better performance (#4504).
+		}, { useCapture: true } );
 	}
 	}
 
 
 	/**
 	/**
@@ -95,14 +48,6 @@ export default class ImageLoadObserver extends Observer {
 			this.document.fire( 'imageLoaded', domEvent );
 			this.document.fire( 'imageLoaded', domEvent );
 		}
 		}
 	}
 	}
-
-	/**
-	 * @inheritDoc
-	 */
-	destroy() {
-		this._observedElements.clear();
-		super.destroy();
-	}
 }
 }
 
 
 /**
 /**

+ 7 - 2
packages/ckeditor5-image/tests/imagecaption.js

@@ -10,10 +10,10 @@ import ImageCaption from '../src/imagecaption';
 import ImageCaptionEditing from '../src/imagecaption/imagecaptionediting';
 import ImageCaptionEditing from '../src/imagecaption/imagecaptionediting';
 
 
 describe( 'ImageCaption', () => {
 describe( 'ImageCaption', () => {
-	let editor;
+	let editor, editorElement;
 
 
 	beforeEach( () => {
 	beforeEach( () => {
-		const editorElement = window.document.createElement( 'div' );
+		editorElement = window.document.createElement( 'div' );
 		window.document.body.appendChild( editorElement );
 		window.document.body.appendChild( editorElement );
 
 
 		return ClassicTestEditor
 		return ClassicTestEditor
@@ -25,6 +25,11 @@ describe( 'ImageCaption', () => {
 			} );
 			} );
 	} );
 	} );
 
 
+	afterEach( () => {
+		editorElement.remove();
+		return editor.destroy();
+	} );
+
 	it( 'should be loaded', () => {
 	it( 'should be loaded', () => {
 		expect( editor.plugins.get( ImageCaption ) ).to.instanceOf( ImageCaption );
 		expect( editor.plugins.get( ImageCaption ) ).to.instanceOf( ImageCaption );
 	} );
 	} );

+ 3 - 2
packages/ckeditor5-image/tests/imagestyle.js

@@ -11,10 +11,10 @@ import ImageStyleUI from '../src/imagestyle/imagestyleui';
 import global from '@ckeditor/ckeditor5-utils/src/dom/global';
 import global from '@ckeditor/ckeditor5-utils/src/dom/global';
 
 
 describe( 'ImageStyle', () => {
 describe( 'ImageStyle', () => {
-	let editor;
+	let editor, editorElement;
 
 
 	beforeEach( () => {
 	beforeEach( () => {
-		const editorElement = global.document.createElement( 'div' );
+		editorElement = global.document.createElement( 'div' );
 		global.document.body.appendChild( editorElement );
 		global.document.body.appendChild( editorElement );
 
 
 		return ClassicTestEditor
 		return ClassicTestEditor
@@ -27,6 +27,7 @@ describe( 'ImageStyle', () => {
 	} );
 	} );
 
 
 	afterEach( () => {
 	afterEach( () => {
+		editorElement.remove();
 		return editor.destroy();
 		return editor.destroy();
 	} );
 	} );
 
 

+ 13 - 9
packages/ckeditor5-image/tests/imagestyle/imagestyleui.js

@@ -13,7 +13,7 @@ import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
 import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor';
 import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor';
 
 
 describe( 'ImageStyleUI', () => {
 describe( 'ImageStyleUI', () => {
-	let editor;
+	let editor, editorElement;
 
 
 	const styles = [
 	const styles = [
 		{ name: 'style 1', title: 'Style 1 title', icon: 'style1-icon', isDefault: true },
 		{ name: 'style 1', title: 'Style 1 title', icon: 'style1-icon', isDefault: true },
@@ -22,7 +22,7 @@ describe( 'ImageStyleUI', () => {
 	];
 	];
 
 
 	beforeEach( () => {
 	beforeEach( () => {
-		const editorElement = global.document.createElement( 'div' );
+		editorElement = global.document.createElement( 'div' );
 		global.document.body.appendChild( editorElement );
 		global.document.body.appendChild( editorElement );
 
 
 		return ClassicTestEditor
 		return ClassicTestEditor
@@ -38,6 +38,7 @@ describe( 'ImageStyleUI', () => {
 	} );
 	} );
 
 
 	afterEach( () => {
 	afterEach( () => {
+		editorElement.remove();
 		return editor.destroy();
 		return editor.destroy();
 	} );
 	} );
 
 
@@ -91,11 +92,12 @@ describe( 'ImageStyleUI', () => {
 				}
 				}
 			} )
 			} )
 			.then( newEditor => {
 			.then( newEditor => {
-				editor = newEditor;
-
-				const buttonView = editor.ui.componentFactory.create( 'imageStyle:style 1' );
+				const buttonView = newEditor.ui.componentFactory.create( 'imageStyle:style 1' );
 
 
 				expect( buttonView.label ).to.equal( 'Default title' );
 				expect( buttonView.label ).to.equal( 'Default title' );
+
+				editorElement.remove();
+				return newEditor.destroy();
 			} );
 			} );
 	} );
 	} );
 
 
@@ -113,7 +115,9 @@ describe( 'ImageStyleUI', () => {
 			} )
 			} )
 			.then( newEditor => {
 			.then( newEditor => {
 				expect( newEditor.config.get( 'image.toolbar' ) ).to.deep.equal( [ 'foo', 'bar' ] );
 				expect( newEditor.config.get( 'image.toolbar' ) ).to.deep.equal( [ 'foo', 'bar' ] );
-				newEditor.destroy();
+
+				editorElement.remove();
+				return newEditor.destroy();
 			} );
 			} );
 	} );
 	} );
 
 
@@ -124,9 +128,7 @@ describe( 'ImageStyleUI', () => {
 					plugins: [ ImageStyleUI ]
 					plugins: [ ImageStyleUI ]
 				} )
 				} )
 				.then( newEditor => {
 				.then( newEditor => {
-					editor = newEditor;
-
-					const plugin = editor.plugins.get( ImageStyleUI );
+					const plugin = newEditor.plugins.get( ImageStyleUI );
 
 
 					expect( plugin.localizedDefaultStylesTitles ).to.deep.equal( {
 					expect( plugin.localizedDefaultStylesTitles ).to.deep.equal( {
 						'Full size image': 'Full size image',
 						'Full size image': 'Full size image',
@@ -135,6 +137,8 @@ describe( 'ImageStyleUI', () => {
 						'Centered image': 'Centered image',
 						'Centered image': 'Centered image',
 						'Right aligned image': 'Right aligned image'
 						'Right aligned image': 'Right aligned image'
 					} );
 					} );
+
+					return newEditor.destroy();
 				} );
 				} );
 		} );
 		} );
 	} );
 	} );

+ 2 - 9
packages/ckeditor5-image/tests/imageupload/imageuploadediting.js

@@ -25,7 +25,6 @@ import { getData as getViewData, stringify as stringifyView } from '@ckeditor/ck
 
 
 import env from '@ckeditor/ckeditor5-utils/src/env';
 import env from '@ckeditor/ckeditor5-utils/src/env';
 import Notification from '@ckeditor/ckeditor5-ui/src/notification/notification';
 import Notification from '@ckeditor/ckeditor5-ui/src/notification/notification';
-import { assertCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 
 describe( 'ImageUploadEditing', () => {
 describe( 'ImageUploadEditing', () => {
 	// eslint-disable-next-line max-len
 	// eslint-disable-next-line max-len
@@ -451,7 +450,6 @@ describe( 'ImageUploadEditing', () => {
 	it( 'should throw when other error happens during upload', done => {
 	it( 'should throw when other error happens during upload', done => {
 		const file = createNativeFileMock();
 		const file = createNativeFileMock();
 		const error = new Error( 'Foo bar baz' );
 		const error = new Error( 'Foo bar baz' );
-		error.stack = 'biz';
 		const uploadEditing = editor.plugins.get( ImageUploadEditing );
 		const uploadEditing = editor.plugins.get( ImageUploadEditing );
 		const loadSpy = sinon.spy( uploadEditing, '_readAndUpload' );
 		const loadSpy = sinon.spy( uploadEditing, '_readAndUpload' );
 		const catchSpy = sinon.spy();
 		const catchSpy = sinon.spy();
@@ -480,13 +478,8 @@ describe( 'ImageUploadEditing', () => {
 				sinon.assert.calledOnce( catchSpy );
 				sinon.assert.calledOnce( catchSpy );
 				const error = catchSpy.getCall( 0 ).args[ 0 ];
 				const error = catchSpy.getCall( 0 ).args[ 0 ];
 
 
-				assertCKEditorError( error, /unexpected-error/, editor, {
-					originalError: {
-						name: 'Error',
-						message: 'Foo bar baz',
-						stack: 'biz'
-					}
-				} );
+				expect( error ).to.be.instanceOf( Error );
+				expect( error ).to.haveOwnProperty( 'message', 'Foo bar baz' );
 
 
 				done();
 				done();
 			}, 0 );
 			}, 0 );