Browse Source

Implemented the ListStylesUI plugin.

Aleksander Nowodzinski 5 years ago
parent
commit
c0d4212f4f
1 changed files with 190 additions and 1 deletions
  1. 190 1
      packages/ckeditor5-list/src/liststylesui.js

+ 190 - 1
packages/ckeditor5-list/src/liststylesui.js

@@ -8,8 +8,32 @@
  */
 
 import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
+import SplitButtonView from '@ckeditor/ckeditor5-ui/src/dropdown/button/splitbuttonview';
+import { createDropdown, addToolbarToDropdown } from '@ckeditor/ckeditor5-ui/src/dropdown/utils';
+import ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';
+
+import bulletedListIcon from '../theme/icons/bulletedlist.svg';
+import numberedListIcon from '../theme/icons/numberedlist.svg';
+
+import listStyleDiscIcon from '../theme/icons/liststyledisc.svg';
+import listStyleCircleIcon from '../theme/icons/liststylecircle.svg';
+import listStyleSquareIcon from '../theme/icons/liststylesquare.svg';
+import listStyleDecimalIcon from '../theme/icons/liststyledecimal.svg';
+import listStyleDecimalWithLeadingZeroIcon from '../theme/icons/liststyledecimalleadingzero.svg';
+import listStyleLowerRomanIcon from '../theme/icons/liststylelowerroman.svg';
+import listStyleUpperRomanIcon from '../theme/icons/liststyleupperroman.svg';
+import listStyleLowerLatinIcon from '../theme/icons/liststylelowerlatin.svg';
+import listStyleUpperLatinIcon from '../theme/icons/liststyleupperlatin.svg';
+
+import '../theme/liststyles.css';
 
 /**
+ * The list styles UI plugin. It introduces the extended `'bulletedList'` and `'numberedList'` toolbar
+ * buttons that allow users change styles of individual lists in the content.
+ *
+ * **Note**: Buttons introduces by this plugin override implementations from the {@link module:list/listui~ListUI}
+ * (because they share the same names).
+ *
  * @extends module:core/plugin~Plugin
  */
 export default class ListStylesUI extends Plugin {
@@ -21,6 +45,171 @@ export default class ListStylesUI extends Plugin {
 	}
 
 	init() {
-		return null;
+		const editor = this.editor;
+		const t = editor.locale.t;
+
+		editor.ui.componentFactory.add( 'bulletedList', getSplitButtonCreator( {
+			editor,
+			parentCommandName: 'bulletedList',
+			buttonLabel: t( 'Bulleted List' ),
+			buttonIcon: bulletedListIcon,
+			toolbarAriaLabel: t( 'Bulleted List styles toolbar' ),
+			styleDefinitions: [
+				{
+					label: t( 'Toggle the "disc" list style' ),
+					type: 'disc',
+					icon: listStyleDiscIcon
+				},
+				{
+					label: t( 'Toggle the "circle" list style' ),
+					type: 'circle',
+					icon: listStyleCircleIcon
+				},
+				{
+					label: t( 'Toggle the "square" list style' ),
+					type: 'square',
+					icon: listStyleSquareIcon
+				}
+			]
+		} ) );
+
+		editor.ui.componentFactory.add( 'numberedList', getSplitButtonCreator( {
+			editor,
+			parentCommandName: 'numberedList',
+			buttonLabel: t( 'Numbered List' ),
+			buttonIcon: numberedListIcon,
+			toolbarAriaLabel: t( 'Numbered List styles toolbar' ),
+			styleDefinitions: [
+				{
+					label: t( 'Toggle the decimal list style' ),
+					type: 'decimal',
+					icon: listStyleDecimalIcon
+				},
+				{
+					label: t( 'Toggle the decimal with leading zero list style' ),
+					type: 'decimal-leading-zero',
+					icon: listStyleDecimalWithLeadingZeroIcon
+				},
+				{
+					label: t( 'Toggle the lower roman list style' ),
+					type: 'lower-roman',
+					icon: listStyleLowerRomanIcon
+				},
+				{
+					label: t( 'Toggle the upper roman list style' ),
+					type: 'upper-roman',
+					icon: listStyleUpperRomanIcon
+				},
+				{
+					label: t( 'Toggle the upper latin list style' ),
+					type: 'upper-latin',
+					icon: listStyleUpperLatinIcon
+				},
+				{
+					label: t( 'Toggle the lower latin list style' ),
+					type: 'lower-latin',
+					icon: listStyleLowerLatinIcon
+				}
+			]
+		} ) );
 	}
 }
+
+// A helper that returns a function that creates a split button with a toolbar in the dropdown,
+// which in turn contains buttons allowing users to change list styles in the context of the current selection.
+//
+// @param {Object} options
+// @param {module:core/editor/editor~Editor} options.editor
+// @param {'bulletedList'|'numberedList'} options.parentCommandName The name of the higher-order editor command associated with
+// the set of particular list styles (e.g. "bulletedList" for "disc", "circle", and "square" styles).
+// @param {String} options.buttonLabel Label of the main part of the split button.
+// @param {String} options.buttonIcon The SVG string of an icon for the main part of the split button.
+// @param {String} options.toolbarAriaLabel The ARIA label for the toolbar in the split button dropdown.
+// @param {Object} options.styleDefinitions Definitions of the style buttons.
+// @returns {Function} A function that can be passed straight into {@link module:ui/componentfactory~ComponentFactory#add}.
+function getSplitButtonCreator( { editor, parentCommandName, buttonLabel, buttonIcon, toolbarAriaLabel, styleDefinitions } ) {
+	const parentCommand = editor.commands.get( parentCommandName );
+	const listStylesCommand = editor.commands.get( 'listStyles' );
+
+	// @param {module:utils/locale~Locale} locale
+	// @returns {module:ui/dropdown/dropdownview~DropdownView}
+	return locale => {
+		const dropdownView = createDropdown( locale, SplitButtonView );
+		const splitButtonView = dropdownView.buttonView;
+		const styleButtonCreator = getStyleButtonCreator( { editor, parentCommandName, listStylesCommand } );
+
+		addToolbarToDropdown( dropdownView, styleDefinitions.map( styleButtonCreator ) );
+
+		dropdownView.bind( 'isEnabled' ).to( parentCommand );
+		dropdownView.toolbarView.ariaLabel = toolbarAriaLabel;
+		dropdownView.class = 'ck-list-styles-dropdown';
+
+		splitButtonView.on( 'execute', () => {
+			editor.execute( parentCommandName );
+			editor.editing.view.focus();
+		} );
+
+		splitButtonView.set( {
+			label: buttonLabel,
+			icon: buttonIcon,
+			tooltip: true,
+			isToggleable: true
+		} );
+
+		splitButtonView.bind( 'isOn' ).to( parentCommand, 'value', value => !!value );
+
+		return dropdownView;
+	};
+}
+
+// A helper that returns a function (factory) that creates individual buttons used by users to change styles
+// of lists.
+//
+// @param {Object} options
+// @param {module:core/editor/editor~Editor} options.editor
+// @param {module:list/liststylescommand~ListStylesCommand} options.listStylesCommand The instance of the `ListStylesCommand` class.
+// @param {'bulletedList'|'numberedList'} options.parentCommandName The name of the higher-order command associated with a
+// particular list style (e.g. "bulletedList" is associated with "square" and "numberedList" is associated with "roman").
+// @returns {Function} A function that can be passed straight into {@link module:ui/componentfactory~ComponentFactory#add}.
+function getStyleButtonCreator( { editor, listStylesCommand, parentCommandName } ) {
+	const locale = editor.locale;
+	const parentCommand = editor.commands.get( parentCommandName );
+
+	// @param {String} label The label of the style button.
+	// @param {String} type The type of the style button (e.g. "roman" or "circle").
+	// @param {String} icon The SVG string of an icon of the style button.
+	// @returns {module:ui/button/buttonview~ButtonView}
+	return ( { label, type, icon } ) => {
+		const button = new ButtonView( locale );
+
+		button.set( { label, icon } );
+
+		listStylesCommand.on( 'change:value', () => {
+			button.isOn = listStylesCommand.value === type;
+		} );
+
+		button.on( 'execute', () => {
+			// If the content the selection is anchored to is a list, let's change its style.
+			if ( parentCommand.value ) {
+				// If the current list style is not set in the model or the style is different than the
+				// one to be applied, simply apply the new style.
+				if ( listStylesCommand.value !== type ) {
+					editor.execute( 'listStyles', { type } );
+				}
+				// If the style was the same, remove it (the button works as an off toggle).
+				else {
+					editor.execute( 'listStyles', { type: 'default' } );
+				}
+			}
+			// If the content the selection is anchored to is not a list, let's create a list of a desired style.
+			else {
+				editor.execute( parentCommandName );
+				editor.execute( 'listStyles', { type } );
+			}
+
+			editor.editing.view.focus();
+		} );
+
+		return button;
+	};
+}