| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- /**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
- /* globals console:false, document, window */
- import ClassicEditor from '/ckeditor5/editor-classic/classic.js';
- import testUtils from '/tests/utils/_utils/utils.js';
- import Feature from '/ckeditor5/core/feature.js';
- import buildModelConverter from '/ckeditor5/engine/conversion/buildmodelconverter.js';
- import buildViewConverter from '/ckeditor5/engine/conversion/buildviewconverter.js';
- import ViewContainerElement from '/ckeditor5/engine/view/containerelement.js';
- import ViewRange from '/ckeditor5/engine/view/range.js';
- import ModelElement from '/ckeditor5/engine/model/element.js';
- import ModelRange from '/ckeditor5/engine/model/range.js';
- import ModelLiveRange from '/ckeditor5/engine/model/liverange.js';
- import ClickObserver from '/ckeditor5/engine/view/observer/clickobserver.js';
- let editor, editable, observer;
- class Test extends Feature {
- /**
- * @inheritDoc
- */
- init() {
- const editor = this.editor;
- const data = editor.data;
- const editing = editor.editing;
- const view = editing.view;
- const document = editor.document;
- const selected = new Set();
- // Handle clicks on view elements.
- view.addObserver( ClickObserver );
- editor.editing.view.on( 'click', ( eventInfo, domEventData ) => {
- const target = domEventData.target;
- if ( target.name == 'span' ) {
- const viewRange = ViewRange.createOn( target );
- const modelRange = ModelLiveRange.createFromRange( editing.mapper.toModelRange( viewRange ) );
- // Put selection around span element.
- // TODO: Do we need this inside enq changes? Batch needed?
- document.enqueueChanges( ( ) => {
- document.selection.setRanges( [ modelRange ] );
- } );
- }
- } );
- // Handle selection conversion.
- editing.modelToView.on( 'selection', ( evt, data, consumable, conversionApi ) => {
- const viewSelection = conversionApi.viewSelection;
- const range = data.selection.getFirstRange();
- const nodeAfterStart = range.start.nodeAfter;
- // remove selection from all selected widgets
- for ( let viewElement of selected ) {
- viewElement.setStyle( 'border', '2px solid yellow' );
- }
- // This could be just one element instead of set.
- selected.clear();
- if ( !data.selection.isCollapsed && nodeAfterStart && nodeAfterStart.name == 'span' && ModelRange.createOn( nodeAfterStart ).isEqual( range ) ) {
- viewSelection.setFake( true, { label: 'span fake selection' } );
- const viewElement = conversionApi.mapper.toViewElement( nodeAfterStart );
- viewElement.setStyle( 'border', '2px solid red' );
- selected.add( viewElement );
- }
- }, { priority: 'low' } );
- // Allow bold attribute on all inline nodes.
- // document.schema.allow( { name: '$inline', attributes: [ 'span' ] } );
- document.schema.registerItem( 'span', '$inline' );
- document.schema.allow( { name: 'span', inside: '$block' } );
- // Build converter from model to view for data and editing pipelines.
- buildModelConverter().for( data.modelToView, editing.modelToView )
- .fromElement( 'span' )
- // .toElement( new ViewContainerElement( 'span' ) );
- .toElement( () => {
- const element = new ViewContainerElement( 'span', {
- contenteditable: 'false',
- style: 'background-color: yellow; color: black; border: 2px solid yellow;'
- } );
- return widgetize( element );
- } );
- // Build converter from view to model for data pipeline.
- buildViewConverter().for( data.viewToModel )
- .fromElement( 'span' )
- .toElement( 'span' );
- }
- }
- class BasicImage extends Feature {
- /**
- * @inheritDoc
- */
- init() {
- const editor = this.editor;
- const data = editor.data;
- const editing = editor.editing;
- const view = editing.view;
- const document = editor.document;
- const selected = new Set();
- // Handle clicks on view elements.
- view.addObserver( ClickObserver );
- editor.editing.view.on( 'click', ( eventInfo, domEventData ) => {
- const target = domEventData.target;
- if ( target.name == 'img' ) {
- const viewRange = ViewRange.createOn( target );
- const modelRange = ModelLiveRange.createFromRange( editing.mapper.toModelRange( viewRange ) );
- document.enqueueChanges( ( ) => {
- document.selection.setRanges( [ modelRange ] );
- } );
- }
- } );
- // Handle selection conversion.
- editing.modelToView.on( 'selection', ( evt, data, consumable, conversionApi ) => {
- const viewSelection = conversionApi.viewSelection;
- const range = data.selection.getFirstRange();
- const nodeAfterStart = range.start.nodeAfter;
- // remove selection from all selected widgets
- for ( let viewElement of selected ) {
- viewElement.setStyle( 'border', '2px solid yellow' );
- }
- // This could be just one element instead of set.
- selected.clear();
- if ( !data.selection.isCollapsed && nodeAfterStart && nodeAfterStart.name == 'image' && ModelRange.createOn( nodeAfterStart ).isEqual( range ) ) {
- viewSelection.setFake( true, { label: 'image fake selection' } );
- const viewElement = conversionApi.mapper.toViewElement( nodeAfterStart );
- viewElement.setStyle( 'border', '2px solid red' );
- selected.add( viewElement );
- }
- }, { priority: 'low' } );
- // Allow bold attribute on all inline nodes.
- // document.schema.allow( { name: '$inline', attributes: [ 'span' ] } );
- document.schema.registerItem( 'image', '$block' );
- document.schema.allow( { name: 'image', attributes: [ 'src', 'alt' ] } );
- // Build converter from model to view for data and editing pipelines.
- buildModelConverter().for( data.modelToView, editing.modelToView )
- .fromElement( 'image' )
- .toElement( ( data ) => {
- return widgetize( new ViewContainerElement( 'img', {
- src: data.item.getAttribute( 'src' ),
- alt: data.item.getAttribute( 'alt' ),
- style: 'border: 2px solid yellow'
- } ) );
- } );
- // Build converter from view to model for data pipeline.
- buildViewConverter().for( data.viewToModel )
- .fromElement( 'img' ).consuming( { name: true, attributes: [ 'src', 'alt' ] } )
- .toElement( ( viewElement ) => new ModelElement( 'image', {
- src: viewElement.getAttribute( 'src' ),
- alt: viewElement.getAttribute( 'alt' )
- } ) );
- }
- }
- function initEditor() {
- ClassicEditor.create( document.querySelector( '#editor' ), {
- features: [ 'enter', 'typing', 'paragraph', 'undo', 'heading', Test, BasicImage ],
- toolbar: [ 'headings' ]
- } )
- .then( newEditor => {
- window.editor = editor = newEditor;
- window.editable = editable = editor.editing.view.getRoot();
- observer = testUtils.createObserver();
- observer.observe( 'Editable', editable, [ 'isFocused' ] );
- } )
- .catch( err => {
- console.error( err.stack );
- } );
- }
- initEditor();
- function widgetize( element ) {
- element.isWidget = true;
- return element;
- }
|