/** * @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 ui/toolbar/toolbarview */ /* globals console */ import View from '../view'; import FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker'; import FocusCycler from '../focuscycler'; import KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler'; import ToolbarSeparatorView from './toolbarseparatorview'; import preventDefault from '../bindings/preventdefault.js'; import '../../theme/components/toolbar/toolbar.css'; import { attachLinkToDocumentation } from '@ckeditor/ckeditor5-utils/src/ckeditorerror'; /** * The toolbar view class. * * @extends module:ui/view~View * @implements module:ui/dropdown/dropdownpanelfocusable~DropdownPanelFocusable */ export default class ToolbarView extends View { /** * @inheritDoc */ constructor( locale ) { super( locale ); const bind = this.bindTemplate; /** * Collection of the toolbar items (like buttons). * * @readonly * @member {module:ui/viewcollection~ViewCollection} */ this.items = this.createCollection(); /** * Tracks information about DOM focus in the list. * * @readonly * @member {module:utils/focustracker~FocusTracker} */ this.focusTracker = new FocusTracker(); /** * Instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}. * * @readonly * @member {module:utils/keystrokehandler~KeystrokeHandler} */ this.keystrokes = new KeystrokeHandler(); /** * Controls the orientation of toolbar items. * * @observable * @member {Boolean} #isVertical */ this.set( 'isVertical', false ); /** * An additional CSS class added to the {@link #element}. * * @observable * @member {String} #class */ this.set( 'class' ); /** * Helps cycling over focusable {@link #items} in the toolbar. * * @readonly * @protected * @member {module:ui/focuscycler~FocusCycler} */ this._focusCycler = new FocusCycler( { focusables: this.items, focusTracker: this.focusTracker, keystrokeHandler: this.keystrokes, actions: { // Navigate toolbar items backwards using the arrow[left,up] keys. focusPrevious: [ 'arrowleft', 'arrowup' ], // Navigate toolbar items forwards using the arrow[right,down] keys. focusNext: [ 'arrowright', 'arrowdown' ] } } ); this.setTemplate( { tag: 'div', attributes: { class: [ 'ck', 'ck-toolbar', bind.if( 'isVertical', 'ck-toolbar_vertical' ), bind.to( 'class' ) ] }, children: this.items, on: { // https://github.com/ckeditor/ckeditor5-ui/issues/206 mousedown: preventDefault( this ) } } ); } /** * @inheritDoc */ render() { super.render(); // Items added before rendering should be known to the #focusTracker. for ( const item of this.items ) { this.focusTracker.add( item.element ); } this.items.on( 'add', ( evt, item ) => { this.focusTracker.add( item.element ); } ); this.items.on( 'remove', ( evt, item ) => { this.focusTracker.remove( item.element ); } ); // Start listening for the keystrokes coming from #element. this.keystrokes.listenTo( this.element ); } /** * Focuses the first focusable in {@link #items}. */ focus() { this._focusCycler.focusFirst(); } /** * Focuses the last focusable in {@link #items}. */ focusLast() { this._focusCycler.focusLast(); } /** * A utility which expands a plain toolbar configuration into * {@link module:ui/toolbar/toolbarview~ToolbarView#items} using a given component factory. * * @param {Array.} config The toolbar items config. * @param {module:ui/componentfactory~ComponentFactory} factory A factory producing toolbar items. */ fillFromConfig( config, factory ) { config.map( name => { if ( name == '|' ) { this.items.add( new ToolbarSeparatorView() ); } else if ( factory.has( name ) ) { this.items.add( factory.create( name ) ); } else { /** * There was a problem processing the configuration of the toolbar. The item with the given * name does not exist so it was omitted when rendering the toolbar. * * This warning usually shows up when the {@link module:core/plugin~Plugin} which is supposed * to provide a toolbar item has not been loaded or there is a typo in the configuration. * * Make sure the plugin responsible for this toolbar item is loaded and the toolbar configuration * is correct, e.g. {@link module:basic-styles/bold~Bold} is loaded for the `'bold'` toolbar item. * * You can use the following snippet to retrieve all available toolbar items: * * Array.from( editor.ui.componentFactory.names() ); * * @error toolbarview-item-unavailable * @param {String} name The name of the component. */ console.warn( attachLinkToDocumentation( 'toolbarview-item-unavailable: The requested toolbar item is unavailable.', { name } ) ); } } ); } }