| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
- /* globals $, window, console:false */
- // Basic classes to create an editor.
- import StandardEditor from '@ckeditor/ckeditor5-core/src/editor/standardeditor';
- import InlineEditableUIView from '@ckeditor/ckeditor5-ui/src/editableui/inline/inlineeditableuiview';
- import HtmlDataProcessor from '@ckeditor/ckeditor5-engine/src/dataprocessor/htmldataprocessor';
- import ElementReplacer from '@ckeditor/ckeditor5-utils/src/elementreplacer';
- // Basic features that every editor should enable.
- import Clipboard from '@ckeditor/ckeditor5-clipboard/src/clipboard';
- import Enter from '@ckeditor/ckeditor5-enter/src/enter';
- import Typing from '@ckeditor/ckeditor5-typing/src/typing';
- import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
- import UndoEngine from '@ckeditor/ckeditor5-undo/src/undoengine';
- // Basic features to associated with the edited content.
- import BoldEngine from '@ckeditor/ckeditor5-basic-styles/src/boldengine';
- import ItalicEngine from '@ckeditor/ckeditor5-basic-styles/src/italicengine';
- import UnderlineEngine from '@ckeditor/ckeditor5-basic-styles/src/underlineengine';
- import HeadingEngine from '@ckeditor/ckeditor5-heading/src/headingengine';
- // Extending the StandardEditor, which brings lots of essential API.
- export default class BootstrapEditor extends StandardEditor {
- constructor( element, config ) {
- super( element, config );
- // Create the ("main") root element of the model tree.
- this.document.createRoot();
- // Use the HTML data processor in this editor.
- this.data.processor = new HtmlDataProcessor();
- // This editor uses a single editable view in DOM.
- this.editable = new InlineEditableUIView( this.locale );
- // A helper to easily replace the editor#element with editor.editable#element.
- this._elementReplacer = new ElementReplacer();
- }
- destroy() {
- // When destroyed, editor sets the output of editor#getData() into editor#element...
- this.updateEditorElement();
- // ...and restores editor#element.
- this._elementReplacer.restore();
- return super.destroy();
- }
- static create( element, config ) {
- return new Promise( resolve => {
- const editor = new this( element, config );
- const editable = editor.editable;
- resolve(
- editor.initPlugins()
- // Initialize the editable view in DOM first.
- .then( () => editable.init() )
- // Replace the editor#element with editor.editable#element.
- .then( () => editor._elementReplacer.replace( element, editable.element ) )
- // Handle the UI of the editor.
- .then( () => {
- // Create an editing root in the editing layer. It will correspond with the
- // document root created in the constructor().
- const editingRoot = editor.editing.createRoot( 'div' );
- // Bind the basic attributes of the editable in DOM with the editing layer.
- editable.bind( 'isReadOnly' ).to( editingRoot );
- editable.bind( 'isFocused' ).to( editor.editing.view );
- editable.name = editingRoot.rootName;
- // Setup the external Bootstrap UI so it works with the editor.
- setupButtons( editor );
- setupHeadingDropdown( editor );
- // Tell the world that the UI of the editor is ready to use.
- editor.fire( 'uiReady' );
- } )
- // Bind the editor editing layer to the editable in DOM.
- .then( () => editor.editing.view.attachDomRoot( editable.element ) )
- .then( () => editor.loadDataFromEditorElement() )
- // Fire the events that announce that the editor is complete and ready to use.
- .then( () => {
- editor.fire( 'dataReady' );
- editor.fire( 'ready' );
- } )
- .then( () => editor )
- );
- } );
- }
- }
- // This function activates Bold, Italic, Underline, Undo and Redo buttons in the toolbar.
- function setupButtons( editor ) {
- [ 'bold', 'italic', 'underline', 'undo', 'redo' ].forEach( commandName => {
- // Retrieve the editor command corresponding with the id of the button in DOM.
- const command = editor.commands.get( commandName );
- // Retrieve the jQuery object corresponding with the button in DOM.
- const button = $( `#${ commandName }` );
- // Clicking on the buttons should execute the editor command...
- button.click( () => editor.execute( commandName ) );
- // ...but it should not steal the focus so the editing is uninterrupted.
- button.mousedown( evt => evt.preventDefault() );
- // Commands can become disabled, e.g. when the editor is read-only.
- // Make sure the buttons reflect this state change.
- command.on( 'change:isEnabled', onIsEnabledChange );
- onIsEnabledChange();
- // Bold, Italic and Underline commands have a value that changes
- // when the selection starts in an element the command creates.
- // The button should indicate that e.g. editing text which is already bold.
- if ( !new Set( [ 'undo', 'redo' ] ).has( commandName ) ) {
- command.on( 'change:value', onValueChange );
- onValueChange();
- }
- function onValueChange() {
- button.toggleClass( 'active', command.value );
- }
- function onIsEnabledChange() {
- button.attr( 'disabled', () => !command.isEnabled );
- }
- } );
- }
- // This function activates the headings dropdown in the toolbar.
- function setupHeadingDropdown( editor ) {
- const menu = $( '.ck-editor .dropdown-menu' );
- const button = $( '.ck-editor .dropdown-toggle' );
- // Create a dropdown menu entry for each heading configuration option.
- editor.config.get( 'heading.options' ).map( option => {
- // Retrieve the editor command corresponding with the configuration option.
- const command = editor.commands.get( option.modelElement );
- // Create the menu item DOM element.
- const menuItem = $(
- `<a href="#" class="dropdown-item heading-item_${ option.modelElement }">` +
- `${ option.title }` +
- '</a>' );
- // Upon click, the dropdown menua item should execute the command and focus
- // the editing view to keep the editing process uninterrupted.
- menuItem.click( () => {
- editor.execute( option.modelElement );
- editor.editing.view.focus();
- } );
- menu.append( menuItem );
- // Make sure the dropdown and its items reflect the state of the
- // currently active command.
- command.on( 'change:value', onValueChange );
- onValueChange();
- // Heading commands can become disabled, e.g. when the editor is read-only.
- // Make sure the UI reflects this state change.
- command.on( 'change:isEnabled', onIsEnabledChange );
- onIsEnabledChange();
- function onValueChange() {
- if ( command.value ) {
- button.children( ':first' ).text( option.title );
- }
- menuItem.toggleClass( 'active', command.value );
- }
- function onIsEnabledChange() {
- button.attr( 'disabled', () => !command.isEnabled );
- }
- } );
- }
- // Finally, create the BootstrapEditor instance with a selected set of features.
- BootstrapEditor
- .create( $( '#editor' ).get( 0 ), {
- plugins: [
- Clipboard, Enter, Typing, Paragraph,
- BoldEngine, ItalicEngine, UnderlineEngine, HeadingEngine, UndoEngine
- ]
- } )
- .then( editor => {
- window.editor = editor;
- $( '#toggle-readonly' ).on( 'click', () => {
- editor.isReadOnly = !editor.isReadOnly;
- } );
- } )
- .catch( err => {
- console.error( err.stack );
- } );
|