|
|
@@ -1,196 +1,39 @@
|
|
|
/**
|
|
|
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
|
|
|
+ * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
|
|
|
* For licensing, see LICENSE.md.
|
|
|
*/
|
|
|
|
|
|
-/* globals console:false, document, window */
|
|
|
+/* globals document */
|
|
|
|
|
|
-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 ViewDocument from '/ckeditor5/engine/view/document.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' );
|
|
|
+import { setData } from '/ckeditor5/engine/dev-utils/view.js';
|
|
|
+
|
|
|
+const viewDocument = new ViewDocument();
|
|
|
+const domEditable = document.getElementById( 'editor' );
|
|
|
+const viewRoot = viewDocument.createRoot( domEditable );
|
|
|
+let viewStrong;
|
|
|
+
|
|
|
+document.getElementById( 'create-fake' ).addEventListener( 'click', () => {
|
|
|
+ const viewP = viewRoot.getChild( 0 );
|
|
|
+ viewStrong = viewP.getChild( 1 );
|
|
|
+ const range = ViewRange.createOn( viewStrong );
|
|
|
+ viewDocument.selection.setRanges( [ range ] );
|
|
|
+ viewDocument.selection.setFake( true, { label: 'fake selection over bar' } );
|
|
|
+ viewStrong.setStyle( 'background-color', 'yellow' );
|
|
|
+ viewDocument.focus();
|
|
|
+} );
|
|
|
+
|
|
|
+viewDocument.on( 'selectionChange', ( evt, data ) => {
|
|
|
+ viewDocument.selection.setTo( data.newSelection );
|
|
|
+ viewDocument.render();
|
|
|
+} );
|
|
|
+
|
|
|
+viewDocument.selection.on( 'change', () => {
|
|
|
+ if ( viewStrong && !viewDocument.selection.isFake ) {
|
|
|
+ viewStrong.removeStyle( 'background-color' );
|
|
|
}
|
|
|
-}
|
|
|
-
|
|
|
-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;
|
|
|
-}
|
|
|
+setData( viewDocument, '<container:p>{}foo<strong>bar</strong>baz</container:p>' );
|
|
|
+viewDocument.focus();
|