| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- /**
- * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
- */
- /* globals console, window, document */
- import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';
- import Essentials from '@ckeditor/ckeditor5-essentials/src/essentials';
- import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
- import Heading from '@ckeditor/ckeditor5-heading/src/heading';
- import List from '@ckeditor/ckeditor5-list/src/list';
- import Bold from '@ckeditor/ckeditor5-basic-styles/src/bold';
- import Italic from '@ckeditor/ckeditor5-basic-styles/src/italic';
- import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
- import { toWidget, viewToModelPositionOutsideModelElement } from '@ckeditor/ckeditor5-widget/src/utils';
- import Widget from '@ckeditor/ckeditor5-widget/src/widget';
- import Command from '@ckeditor/ckeditor5-core/src/command';
- import { addListToDropdown, createDropdown } from '@ckeditor/ckeditor5-ui/src/dropdown/utils';
- import Collection from '@ckeditor/ckeditor5-utils/src/collection';
- import Model from '@ckeditor/ckeditor5-ui/src/model';
- class PlaceholderCommand extends Command {
- execute( { value } ) {
- const editor = this.editor;
- editor.model.change( writer => {
- // Create a <placeholder> elment with the "name" attribute...
- const placeholder = writer.createElement( 'placeholder', { name: value } );
- // ... and insert it into the document.
- editor.model.insertContent( placeholder );
- // Put the selection on the inserted element.
- writer.setSelection( placeholder, 'on' );
- } );
- }
- refresh() {
- const model = this.editor.model;
- const selection = model.document.selection;
- const isAllowed = model.schema.checkChild( selection.focus.parent, 'placeholder' );
- this.isEnabled = isAllowed;
- }
- }
- class Placeholder extends Plugin {
- static get requires() {
- return [ PlaceholderEditing, PlaceholderUI ];
- }
- }
- class PlaceholderUI extends Plugin {
- init() {
- const editor = this.editor;
- const t = editor.t;
- const placeholderNames = editor.config.get( 'placeholderConfig.types' );
- // The "placeholder" dropdown must be registered among the UI components of the editor
- // to be displayed in the toolbar.
- editor.ui.componentFactory.add( 'placeholder', locale => {
- const dropdownView = createDropdown( locale );
- // Populate the list in the dropdown with items.
- addListToDropdown( dropdownView, getDropdownItemsDefinitions( placeholderNames ) );
- dropdownView.buttonView.set( {
- // The t() function helps localize the editor. All strings enclosed in t() can be
- // translated and change when the language of the editor changes.
- label: t( 'Placeholder' ),
- tooltip: true,
- withText: true
- } );
- // Disable the placeholder button when the command is disabled.
- const command = editor.commands.get( 'placeholder' );
- dropdownView.bind( 'isEnabled' ).to( command );
- // Execute the command when the dropdown item is clicked (executed).
- this.listenTo( dropdownView, 'execute', evt => {
- editor.execute( 'placeholder', { value: evt.source.commandParam } );
- editor.editing.view.focus();
- } );
- return dropdownView;
- } );
- }
- }
- function getDropdownItemsDefinitions( placeholderNames ) {
- const itemDefinitions = new Collection();
- for ( const name of placeholderNames ) {
- const definition = {
- type: 'button',
- model: new Model( {
- commandParam: name,
- label: name,
- withText: true
- } )
- };
- // Add the item definition to the collection.
- itemDefinitions.add( definition );
- }
- return itemDefinitions;
- }
- class PlaceholderEditing extends Plugin {
- static get requires() {
- return [ Widget ];
- }
- init() {
- console.log( 'PlaceholderEditing#init() got called' );
- this._defineSchema();
- this._defineConverters();
- this.editor.commands.add( 'placeholder', new PlaceholderCommand( this.editor ) );
- this.editor.editing.mapper.on(
- 'viewToModelPosition',
- viewToModelPositionOutsideModelElement( this.editor.model, viewElement => viewElement.hasClass( 'placeholder' ) )
- );
- this.editor.config.define( 'placeholderConfig', {
- types: [ 'date', 'first name', 'surname' ]
- } );
- }
- _defineSchema() {
- const schema = this.editor.model.schema;
- schema.register( 'placeholder', {
- // Allow wherever text is allowed:
- allowWhere: '$text',
- // The placeholder will act as an inline node:
- isInline: true,
- // The inline widget is self-contained so it cannot be split by the caret and it can be selected:
- isObject: true,
- // The placeholder can have many types, like date, name, surname, etc:
- allowAttributes: [ 'name' ]
- } );
- }
- _defineConverters() {
- const conversion = this.editor.conversion;
- conversion.for( 'upcast' ).elementToElement( {
- view: {
- name: 'span',
- classes: [ 'placeholder' ]
- },
- model: ( viewElement, modelWriter ) => {
- // Extract the "name" from "{name}".
- const name = viewElement.getChild( 0 ).data.slice( 1, -1 );
- return modelWriter.createElement( 'placeholder', { name } );
- }
- } );
- conversion.for( 'editingDowncast' ).elementToElement( {
- model: 'placeholder',
- view: ( modelItem, viewWriter ) => {
- const widgetElement = createPlaceholderView( modelItem, viewWriter );
- // Enable widget handling on a placeholder element inside the editing view.
- return toWidget( widgetElement, viewWriter );
- }
- } );
- conversion.for( 'dataDowncast' ).elementToElement( {
- model: 'placeholder',
- view: createPlaceholderView
- } );
- // Helper method for both downcast converters.
- function createPlaceholderView( modelItem, viewWriter ) {
- const name = modelItem.getAttribute( 'name' );
- const placeholderView = viewWriter.createContainerElement( 'span', {
- class: 'placeholder'
- } );
- // Insert the placeholder name (as a text).
- const innerText = viewWriter.createText( '{' + name + '}' );
- viewWriter.insert( viewWriter.createPositionAt( placeholderView, 0 ), innerText );
- return placeholderView;
- }
- }
- }
- ClassicEditor
- .create( document.querySelector( '#snippet-inline-widget' ), {
- plugins: [ Essentials, Paragraph, Heading, List, Bold, Italic, Placeholder ],
- toolbar: [ 'heading', '|', 'bold', 'italic', 'numberedList', 'bulletedList', '|', 'placeholder' ],
- placeholderConfig: {
- types: [ 'date', 'color', 'first name', 'surname' ]
- }
- } )
- .then( editor => {
- console.log( 'Editor was initialized', editor );
- // Expose for playing in the console.
- window.editor = editor;
- } )
- .catch( error => {
- console.error( error.stack );
- } );
|