Przeglądaj źródła

Merge branch 'master' into i/5189

Marek Lewandowski 6 lat temu
rodzic
commit
ad2b2e1369

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

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

+ 7 - 0
packages/ckeditor5-widget/CHANGELOG.md

@@ -1,6 +1,13 @@
 Changelog
 Changelog
 =========
 =========
 
 
+## [16.0.0](https://github.com/ckeditor/ckeditor5-widget/compare/v15.0.0...v16.0.0) (2019-12-04)
+
+### Other changes
+
+* Updated translations. ([b3bf5f0](https://github.com/ckeditor/ckeditor5-widget/commit/b3bf5f0)) 
+
+
 ## [15.0.0](https://github.com/ckeditor/ckeditor5-widget/compare/v11.1.0...v15.0.0) (2019-10-23)
 ## [15.0.0](https://github.com/ckeditor/ckeditor5-widget/compare/v11.1.0...v15.0.0) (2019-10-23)
 
 
 ### MAJOR BREAKING CHANGES
 ### MAJOR BREAKING CHANGES

+ 21 - 0
packages/ckeditor5-widget/lang/translations/he.po

@@ -0,0 +1,21 @@
+# 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 "The label used by assistive technologies describing a toolbar attached to a widget."
+msgid "Widget toolbar"
+msgstr "סרגל יישומון"

+ 21 - 0
packages/ckeditor5-widget/lang/translations/uk.po

@@ -0,0 +1,21 @@
+# 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: Ukrainian (https://www.transifex.com/ckeditor/teams/11143/uk/)\n"
+"Language: uk\n"
+"Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n % 10 == 1 && n % 100 != 11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || (n % 100 >=11 && n % 100 <=14 )) ? 2: 3);\n"
+
+msgctxt "The label used by assistive technologies describing a toolbar attached to a widget."
+msgid "Widget toolbar"
+msgstr "Панель інструментів віджетів"

+ 21 - 0
packages/ckeditor5-widget/lang/translations/vi.po

@@ -0,0 +1,21 @@
+# 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 "The label used by assistive technologies describing a toolbar attached to a widget."
+msgid "Widget toolbar"
+msgstr "Thanh công cụ tiện ích"

+ 25 - 19
packages/ckeditor5-widget/package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "@ckeditor/ckeditor5-widget",
   "name": "@ckeditor/ckeditor5-widget",
-  "version": "15.0.0",
+  "version": "16.0.0",
   "description": "Widget API for CKEditor 5.",
   "description": "Widget API for CKEditor 5.",
   "keywords": [
   "keywords": [
     "ckeditor",
     "ckeditor",
@@ -9,29 +9,31 @@
     "ckeditor5-lib"
     "ckeditor5-lib"
   ],
   ],
   "dependencies": {
   "dependencies": {
-    "@ckeditor/ckeditor5-core": "^15.0.0",
-    "@ckeditor/ckeditor5-engine": "^15.0.0",
-    "@ckeditor/ckeditor5-ui": "^15.0.0",
-    "@ckeditor/ckeditor5-utils": "^15.0.0",
+    "@ckeditor/ckeditor5-core": "^16.0.0",
+    "@ckeditor/ckeditor5-engine": "^16.0.0",
+    "@ckeditor/ckeditor5-ui": "^16.0.0",
+    "@ckeditor/ckeditor5-utils": "^16.0.0",
     "lodash-es": "^4.17.10"
     "lodash-es": "^4.17.10"
   },
   },
   "devDependencies": {
   "devDependencies": {
-    "@ckeditor/ckeditor5-basic-styles": "^15.0.0",
-    "@ckeditor/ckeditor5-block-quote": "^15.0.0",
-    "@ckeditor/ckeditor5-clipboard": "^15.0.0",
-    "@ckeditor/ckeditor5-editor-balloon": "^15.0.0",
-    "@ckeditor/ckeditor5-editor-classic": "^15.0.0",
-    "@ckeditor/ckeditor5-enter": "^15.0.0",
-    "@ckeditor/ckeditor5-essentials": "^15.0.0",
-    "@ckeditor/ckeditor5-heading": "^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-clipboard": "^16.0.0",
+    "@ckeditor/ckeditor5-editor-balloon": "^16.0.0",
+    "@ckeditor/ckeditor5-editor-classic": "^16.0.0",
+    "@ckeditor/ckeditor5-enter": "^16.0.0",
+    "@ckeditor/ckeditor5-essentials": "^16.0.0",
+    "@ckeditor/ckeditor5-heading": "^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",
@@ -51,11 +53,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": [

+ 100 - 4
packages/ckeditor5-widget/src/widgettoolbarrepository.js

@@ -70,6 +70,23 @@ export default class WidgetToolbarRepository extends Plugin {
 			}, { priority: 'high' } );
 			}, { priority: 'high' } );
 		}
 		}
 
 
+		/**
+		 * Flag indicating whether a plugin is enabled or disabled.
+		 * A disabled plugin won't show any toolbar.
+		 *
+		 * Plugin can be simply disabled like that:
+		 *
+		 *		// Disable the plugin so that no toolbars are visible.
+		 *		editor.plugins.get( 'WidgetToolbarRepository' ).isEnabled = false;
+		 *
+		 * You can also use {@link #forceDisabled} method.
+		 *
+		 * @observable
+		 * @readonly
+		 * @member {Boolean} #isEnabled
+		 */
+		this.set( 'isEnabled', true );
+
 		/**
 		/**
 		 * A map of toolbar definitions.
 		 * A map of toolbar definitions.
 		 *
 		 *
@@ -83,6 +100,18 @@ export default class WidgetToolbarRepository extends Plugin {
 		 */
 		 */
 		this._balloon = this.editor.plugins.get( 'ContextualBalloon' );
 		this._balloon = this.editor.plugins.get( 'ContextualBalloon' );
 
 
+		/**
+		 * Holds identifiers for {@link #forceDisabled} mechanism.
+		 *
+		 * @type {Set.<String>}
+		 * @private
+		 */
+		this._disableStack = new Set();
+
+		this.on( 'change:isEnabled', () => {
+			this._updateToolbarsVisibility();
+		} );
+
 		this.listenTo( editor.ui, 'update', () => {
 		this.listenTo( editor.ui, 'update', () => {
 			this._updateToolbarsVisibility();
 			this._updateToolbarsVisibility();
 		} );
 		} );
@@ -142,6 +171,67 @@ export default class WidgetToolbarRepository extends Plugin {
 		} );
 		} );
 	}
 	}
 
 
+	/**
+	 * Forces the plugin to be disabled.
+	 *
+	 * Plugin may be disabled by multiple features or algorithms (at once). When disabling a plugin, unique id should be passed
+	 * (e.g. feature name). The same identifier should be used when {@link #clearForceDisabled enabling back} the plugin.
+	 * The plugin becomes enabled only after all features {@link #clearForceDisabled enabled it back}.
+	 *
+	 * Disabling and enabling a plugin:
+	 *
+	 *		const plugin = editor.plugins.get( 'WidgetToolbarRepository' );
+	 *
+	 *		plugin.isEnabled; // -> true
+	 *		plugin.forceDisabled( 'MyFeature' );
+	 *		plugin.isEnabled; // -> false
+	 *		plugin.clearForceDisabled( 'MyFeature' );
+	 *		plugin.isEnabled; // -> true
+	 *
+	 * Plugin disabled by multiple features:
+	 *
+	 *		plugin.forceDisabled( 'MyFeature' );
+	 *		plugin.forceDisabled( 'OtherFeature' );
+	 *		plugin.clearForceDisabled( 'MyFeature' );
+	 *		plugin.isEnabled; // -> false
+	 *		plugin.clearForceDisabled( 'OtherFeature' );
+	 *		plugin.isEnabled; // -> true
+	 *
+	 * Multiple disabling with the same identifier is redundant:
+	 *
+	 *		plugin.forceDisabled( 'MyFeature' );
+	 *		plugin.forceDisabled( 'MyFeature' );
+	 *		plugin.clearForceDisabled( 'MyFeature' );
+	 *		plugin.isEnabled; // -> true
+	 *
+	 * **Note:** some plugins or algorithms may have more complex logic when it comes to enabling or disabling certain plugins,
+	 * so the plugin might be still disabled after {@link #clearForceDisabled} was used.
+	 *
+	 * @param {String} id Unique identifier for disabling. Use the same id when {@link #clearForceDisabled enabling back} the plugin.
+	 */
+	forceDisabled( id ) {
+		this._disableStack.add( id );
+
+		if ( this._disableStack.size == 1 ) {
+			this.on( 'set:isEnabled', forceDisable, { priority: 'highest' } );
+			this.isEnabled = false;
+		}
+	}
+
+	/**
+	 * Clears forced disable previously set through {@link #forceDisabled}. See {@link #forceDisabled}.
+	 *
+	 * @param {String} id Unique identifier, equal to the one passed in {@link #forceDisabled} call.
+	 */
+	clearForceDisabled( id ) {
+		this._disableStack.delete( id );
+
+		if ( this._disableStack.size == 0 ) {
+			this.off( 'set:isEnabled', forceDisable );
+			this.isEnabled = true;
+		}
+	}
+
 	/**
 	/**
 	 * Iterates over stored toolbars and makes them visible or hidden.
 	 * Iterates over stored toolbars and makes them visible or hidden.
 	 *
 	 *
@@ -155,12 +245,12 @@ export default class WidgetToolbarRepository extends Plugin {
 		for ( const definition of this._toolbarDefinitions.values() ) {
 		for ( const definition of this._toolbarDefinitions.values() ) {
 			const relatedElement = definition.getRelatedElement( this.editor.editing.view.document.selection );
 			const relatedElement = definition.getRelatedElement( this.editor.editing.view.document.selection );
 
 
-			if ( !this.editor.ui.focusTracker.isFocused ) {
-				if ( this._isToolbarVisible( definition ) ) {
+			if ( !this.isEnabled || !relatedElement ) {
+				if ( this._isToolbarInBalloon( definition ) ) {
 					this._hideToolbar( definition );
 					this._hideToolbar( definition );
 				}
 				}
-			} else if ( !relatedElement ) {
-				if ( this._isToolbarInBalloon( definition ) ) {
+			} else if ( !this.editor.ui.focusTracker.isFocused ) {
+				if ( this._isToolbarVisible( definition ) ) {
 					this._hideToolbar( definition );
 					this._hideToolbar( definition );
 				}
 				}
 			} else {
 			} else {
@@ -293,3 +383,9 @@ function isWidgetSelected( selection ) {
  * there is no such element). The function accepts an instance of {@link module:engine/view/selection~Selection}.
  * there is no such element). The function accepts an instance of {@link module:engine/view/selection~Selection}.
  * @property {String} balloonClassName CSS class for the widget balloon when a toolbar is displayed.
  * @property {String} balloonClassName CSS class for the widget balloon when a toolbar is displayed.
  */
  */
+
+// Helper function that forces command to be disabled.
+function forceDisable( evt ) {
+	evt.return = false;
+	evt.stop();
+}

+ 102 - 0
packages/ckeditor5-widget/tests/widgettoolbarrepository.js

@@ -141,6 +141,32 @@ describe( 'WidgetToolbarRepository', () => {
 			expect( balloon.visibleView ).to.equal( fakeWidgetToolbarView );
 			expect( balloon.visibleView ).to.equal( fakeWidgetToolbarView );
 		} );
 		} );
 
 
+		it( 'toolbar should be hidden when the plugin gets disabled', () => {
+			widgetToolbarRepository.register( 'fake', {
+				items: editor.config.get( 'fake.toolbar' ),
+				getRelatedElement: getSelectedFakeWidget
+			} );
+
+			setData( model, '<paragraph>foo</paragraph>[<fake-widget></fake-widget>]' );
+
+			widgetToolbarRepository.isEnabled = false;
+
+			expect( balloon.visibleView ).to.be.null;
+		} );
+
+		it( 'toolbar should be hidden when the plugin was disabled prior changing selection', () => {
+			widgetToolbarRepository.register( 'fake', {
+				items: editor.config.get( 'fake.toolbar' ),
+				getRelatedElement: getSelectedFakeWidget
+			} );
+
+			widgetToolbarRepository.isEnabled = false;
+
+			setData( model, '<paragraph>foo</paragraph>[<fake-widget></fake-widget>]' );
+
+			expect( balloon.visibleView ).to.be.null;
+		} );
+
 		it( 'toolbar should be hidden when the `getRelatedElement` callback returns null', () => {
 		it( 'toolbar should be hidden when the `getRelatedElement` callback returns null', () => {
 			widgetToolbarRepository.register( 'fake', {
 			widgetToolbarRepository.register( 'fake', {
 				items: editor.config.get( 'fake.toolbar' ),
 				items: editor.config.get( 'fake.toolbar' ),
@@ -510,6 +536,82 @@ describe( 'WidgetToolbarRepository - integration with the BalloonToolbar', () =>
 
 
 		expect( balloon.visibleView ).to.equal( balloonToolbar.toolbarView );
 		expect( balloon.visibleView ).to.equal( balloonToolbar.toolbarView );
 	} );
 	} );
+
+	describe( 'disableable', () => {
+		describe( 'isEnabled', () => {
+			it( 'is enabled by default', () => {
+				expect( widgetToolbarRepository.isEnabled ).to.be.true;
+			} );
+
+			it( 'fires change event', () => {
+				const spy = sinon.spy();
+
+				widgetToolbarRepository.on( 'change:isEnabled', spy );
+
+				widgetToolbarRepository.isEnabled = false;
+
+				expect( spy.calledOnce ).to.be.true;
+			} );
+		} );
+
+		describe( 'forceDisabled() / clearForceDisabled()', () => {
+			it( 'forceDisabled() should disable the plugin', () => {
+				widgetToolbarRepository.forceDisabled( 'foo' );
+				widgetToolbarRepository.isEnabled = true;
+
+				expect( widgetToolbarRepository.isEnabled ).to.be.false;
+			} );
+
+			it( 'clearForceDisabled() should enable the plugin', () => {
+				widgetToolbarRepository.forceDisabled( 'foo' );
+				widgetToolbarRepository.clearForceDisabled( 'foo' );
+
+				expect( widgetToolbarRepository.isEnabled ).to.be.true;
+			} );
+
+			it( 'clearForceDisabled() used with wrong identifier should not enable the plugin', () => {
+				widgetToolbarRepository.forceDisabled( 'foo' );
+				widgetToolbarRepository.clearForceDisabled( 'bar' );
+				widgetToolbarRepository.isEnabled = true;
+
+				expect( widgetToolbarRepository.isEnabled ).to.be.false;
+			} );
+
+			it( 'using forceDisabled() twice with the same identifier should not have any effect', () => {
+				widgetToolbarRepository.forceDisabled( 'foo' );
+				widgetToolbarRepository.forceDisabled( 'foo' );
+				widgetToolbarRepository.clearForceDisabled( 'foo' );
+
+				expect( widgetToolbarRepository.isEnabled ).to.be.true;
+			} );
+
+			it( 'plugin is enabled only after all disables were cleared', () => {
+				widgetToolbarRepository.forceDisabled( 'foo' );
+				widgetToolbarRepository.forceDisabled( 'bar' );
+				widgetToolbarRepository.clearForceDisabled( 'foo' );
+				widgetToolbarRepository.isEnabled = true;
+
+				expect( widgetToolbarRepository.isEnabled ).to.be.false;
+
+				widgetToolbarRepository.clearForceDisabled( 'bar' );
+
+				expect( widgetToolbarRepository.isEnabled ).to.be.true;
+			} );
+
+			it( 'plugin should remain disabled if isEnabled has a callback disabling it', () => {
+				widgetToolbarRepository.on( 'set:isEnabled', evt => {
+					evt.return = false;
+					evt.stop();
+				} );
+
+				widgetToolbarRepository.forceDisabled( 'foo' );
+				widgetToolbarRepository.clearForceDisabled( 'foo' );
+				widgetToolbarRepository.isEnabled = true;
+
+				expect( widgetToolbarRepository.isEnabled ).to.be.false;
+			} );
+		} );
+	} );
 } );
 } );
 
 
 function getSelectedFakeWidget( selection ) {
 function getSelectedFakeWidget( selection ) {

+ 7 - 7
packages/ckeditor5-widget/theme/widget.css

@@ -21,13 +21,6 @@
 	/* Make the widget wrapper a relative positioning container for the drag handle. */
 	/* Make the widget wrapper a relative positioning container for the drag handle. */
 	position: relative;
 	position: relative;
 
 
-	/* Show the selection handle on mouse hover over the widget. */
-	&:hover {
-		& .ck-widget__selection-handle {
-			visibility: visible;
-		}
-	}
-
 	& .ck-widget__selection-handle {
 	& .ck-widget__selection-handle {
 		position: absolute;
 		position: absolute;
 
 
@@ -38,6 +31,13 @@
 		}
 		}
 	}
 	}
 
 
+	/* Show the selection handle on mouse hover over the widget. */
+	&:hover {
+		& .ck-widget__selection-handle {
+			visibility: visible;
+		}
+	}
+
 	/* Show the selection handle when the widget is selected. */
 	/* Show the selection handle when the widget is selected. */
 	&.ck-widget_selected .ck-widget__selection-handle {
 	&.ck-widget_selected .ck-widget__selection-handle {
 		visibility: visible;
 		visibility: visible;