@ckeditor/ckeditor5-engine
Advanced tools
Comparing version 13.2.1 to 14.0.0
{ | ||
"name": "@ckeditor/ckeditor5-engine", | ||
"version": "13.2.1", | ||
"version": "14.0.0", | ||
"description": "The editing engine of CKEditor 5 – the best browser-based rich text editor.", | ||
@@ -24,20 +24,20 @@ "keywords": [ | ||
"dependencies": { | ||
"@ckeditor/ckeditor5-utils": "^13.0.1", | ||
"@ckeditor/ckeditor5-utils": "^14.0.0", | ||
"lodash-es": "^4.17.10" | ||
}, | ||
"devDependencies": { | ||
"@ckeditor/ckeditor5-basic-styles": "^11.1.3", | ||
"@ckeditor/ckeditor5-block-quote": "^11.1.2", | ||
"@ckeditor/ckeditor5-core": "^12.2.1", | ||
"@ckeditor/ckeditor5-editor-classic": "^12.1.3", | ||
"@ckeditor/ckeditor5-enter": "^11.0.4", | ||
"@ckeditor/ckeditor5-essentials": "^11.0.4", | ||
"@ckeditor/ckeditor5-heading": "^11.0.4", | ||
"@ckeditor/ckeditor5-link": "^11.1.1", | ||
"@ckeditor/ckeditor5-list": "^12.0.4", | ||
"@ckeditor/ckeditor5-paragraph": "^11.0.4", | ||
"@ckeditor/ckeditor5-theme-lark": "^14.1.1", | ||
"@ckeditor/ckeditor5-typing": "^12.1.1", | ||
"@ckeditor/ckeditor5-undo": "^11.0.4", | ||
"@ckeditor/ckeditor5-widget": "^11.0.4", | ||
"@ckeditor/ckeditor5-basic-styles": "^11.1.4", | ||
"@ckeditor/ckeditor5-block-quote": "^11.1.3", | ||
"@ckeditor/ckeditor5-core": "^12.3.0", | ||
"@ckeditor/ckeditor5-editor-classic": "^12.1.4", | ||
"@ckeditor/ckeditor5-enter": "^11.1.0", | ||
"@ckeditor/ckeditor5-essentials": "^11.0.5", | ||
"@ckeditor/ckeditor5-heading": "^11.0.5", | ||
"@ckeditor/ckeditor5-link": "^11.1.2", | ||
"@ckeditor/ckeditor5-list": "^12.1.0", | ||
"@ckeditor/ckeditor5-paragraph": "^11.0.5", | ||
"@ckeditor/ckeditor5-theme-lark": "^14.2.0", | ||
"@ckeditor/ckeditor5-typing": "^12.2.0", | ||
"@ckeditor/ckeditor5-undo": "^11.0.5", | ||
"@ckeditor/ckeditor5-widget": "^11.1.0", | ||
"eslint": "^5.5.0", | ||
@@ -55,3 +55,3 @@ "eslint-config-ckeditor5": "^2.0.0", | ||
"homepage": "https://ckeditor.com/ckeditor-5", | ||
"bugs": "https://github.com/ckeditor/ckeditor5-engine/issues", | ||
"bugs": "https://github.com/ckeditor/ckeditor5/issues", | ||
"repository": { | ||
@@ -58,0 +58,0 @@ "type": "git", |
@@ -90,3 +90,3 @@ /** | ||
this.view.change( writer => { | ||
this.downcastDispatcher.convertChanges( doc.differ, writer ); | ||
this.downcastDispatcher.convertChanges( doc.differ, markers, writer ); | ||
this.downcastDispatcher.convertSelection( selection, markers, writer ); | ||
@@ -93,0 +93,0 @@ } ); |
@@ -109,6 +109,6 @@ /** | ||
* @see module:engine/conversion/downcastdispatcher~DowncastConversionApi | ||
* @param {Object} [conversionApi] Additional properties for interface that will be passed to events fired | ||
* @param {Object} conversionApi Additional properties for interface that will be passed to events fired | ||
* by `DowncastDispatcher`. | ||
*/ | ||
constructor( conversionApi = {} ) { | ||
constructor( conversionApi ) { | ||
/** | ||
@@ -126,5 +126,6 @@ * Interface passed by dispatcher to the events callbacks. | ||
* @param {module:engine/model/differ~Differ} differ Differ object with buffered changes. | ||
* @param {module:engine/model/markercollection~MarkerCollection} markers Markers connected with converted model. | ||
* @param {module:engine/view/downcastwriter~DowncastWriter} writer View writer that should be used to modify view document. | ||
*/ | ||
convertChanges( differ, writer ) { | ||
convertChanges( differ, markers, writer ) { | ||
// Before the view is updated, remove markers which have changed. | ||
@@ -147,2 +148,9 @@ for ( const change of differ.getMarkersToRemove() ) { | ||
for ( const markerName of this.conversionApi.mapper.flushUnboundMarkerNames() ) { | ||
const markerRange = markers.get( markerName ).getRange(); | ||
this.convertMarkerRemove( markerName, markerRange, writer ); | ||
this.convertMarkerAdd( markerName, markerRange, writer ); | ||
} | ||
// After the view is updated, convert markers which have changed. | ||
@@ -258,3 +266,3 @@ for ( const change of differ.getMarkersToAdd() ) { | ||
* @param {module:engine/model/selection~Selection} selection Selection to convert. | ||
* @param {Array.<module:engine/model/markercollection~Marker>} markers Array of markers containing model markers. | ||
* @param {module:engine/model/markercollection~MarkerCollection} markers Markers connected with converted model. | ||
* @param {module:engine/view/downcastwriter~DowncastWriter} writer View writer that should be used to modify view document. | ||
@@ -539,3 +547,2 @@ */ | ||
* @param {*} data.attributeNewValue New attribute value. | ||
* @param {module:engine/conversion/modelconsumable~ModelConsumable} consumable Values to consume. | ||
* @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface | ||
@@ -550,3 +557,2 @@ * to be used by callback, passed in `DowncastDispatcher` constructor. | ||
* @param {module:engine/model/selection~Selection} selection Selection that is converted. | ||
* @param {module:engine/conversion/modelconsumable~ModelConsumable} consumable Values to consume. | ||
* @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface | ||
@@ -567,3 +573,3 @@ * to be used by callback, passed in `DowncastDispatcher` constructor. | ||
* * the event is fired for each item in the marker range one by one, | ||
* * consumables object includes each item of the marker range and the consumable value is same as event name. | ||
* * `conversionApi.consumable` includes each item of the marker range and the consumable value is same as event name. | ||
* | ||
@@ -573,3 +579,3 @@ * If the marker range is collapsed: | ||
* * there is only one event, | ||
* * consumables object includes marker range with event name. | ||
* * `conversionApi.consumable` includes marker range with event name. | ||
* | ||
@@ -579,3 +585,3 @@ * If selection inside a marker is converted: | ||
* * there is only one event, | ||
* * consumables object includes selection instance with event name. | ||
* * `conversionApi.consumable` includes selection instance with event name. | ||
* | ||
@@ -590,3 +596,2 @@ * @event addMarker | ||
* @param {String} data.markerName Marker name. | ||
* @param {module:engine/conversion/modelconsumable~ModelConsumable} consumable Values to consume. | ||
* @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface | ||
@@ -593,0 +598,0 @@ * to be used by callback, passed in `DowncastDispatcher` constructor. |
@@ -6,2 +6,8 @@ /** | ||
/** | ||
* Contains downcast (model-to-view) converters for {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher}. | ||
* | ||
* @module engine/conversion/downcasthelpers | ||
*/ | ||
import ModelRange from '../model/range'; | ||
@@ -15,12 +21,6 @@ import ModelSelection from '../model/selection'; | ||
import log from '@ckeditor/ckeditor5-utils/src/log'; | ||
import { cloneDeep } from 'lodash-es'; | ||
import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror'; | ||
/** | ||
* Contains downcast (model-to-view) converters for {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher}. | ||
* | ||
* @module engine/conversion/downcasthelpers | ||
*/ | ||
/** | ||
* Downcast conversion helper functions. | ||
@@ -735,5 +735,4 @@ * | ||
conversionApi.mapper.unbindElementsFromMarkerName( data.markerName ); | ||
for ( const element of elements ) { | ||
conversionApi.mapper.unbindElementFromMarkerName( element, data.markerName ); | ||
conversionApi.writer.clear( conversionApi.writer.createRangeOn( element ), element ); | ||
@@ -830,6 +829,7 @@ } | ||
*/ | ||
log.warn( 'conversion-attribute-to-attribute-on-text: ' + | ||
'Trying to convert text node\'s attribute with attribute-to-attribute converter.' ); | ||
return; | ||
throw new CKEditorError( | ||
'conversion-attribute-to-attribute-on-text: ' + | ||
'Trying to convert text node\'s attribute with attribute-to-attribute converter.', | ||
[ data, conversionApi ] | ||
); | ||
} | ||
@@ -1037,5 +1037,5 @@ | ||
conversionApi.mapper.unbindElementsFromMarkerName( data.markerName ); | ||
for ( const element of elements ) { | ||
conversionApi.mapper.unbindElementFromMarkerName( element, data.markerName ); | ||
for ( const element of elements ) { | ||
if ( element.is( 'attributeElement' ) ) { | ||
@@ -1042,0 +1042,0 @@ conversionApi.writer.unwrap( conversionApi.writer.createRangeOn( element ), viewHighlightElement ); |
@@ -80,2 +80,21 @@ /** | ||
/** | ||
* View element to model marker names mapping. | ||
* | ||
* This is reverse to {@link ~Mapper#_markerNameToElements} map. | ||
* | ||
* @private | ||
* @member {Map} | ||
*/ | ||
this._elementToMarkerNames = new Map(); | ||
/** | ||
* Stores marker names of markers which has changed due to unbinding a view element (so it is assumed that the view element | ||
* has been removed, moved or renamed). | ||
* | ||
* @private | ||
* @member {Set.<module:engine/model/markercollection~Marker>} | ||
*/ | ||
this._unboundMarkerNames = new Set(); | ||
// Default mapper algorithm for mapping model position to view position. | ||
@@ -136,2 +155,8 @@ this.on( 'modelToViewPosition', ( evt, data ) => { | ||
if ( this._elementToMarkerNames.has( viewElement ) ) { | ||
for ( const markerName of this._elementToMarkerNames.get( viewElement ) ) { | ||
this._unboundMarkerNames.add( markerName ); | ||
} | ||
} | ||
if ( this._modelToViewMapping.get( modelElement ) == viewElement ) { | ||
@@ -172,18 +197,54 @@ this._modelToViewMapping.delete( modelElement ); | ||
const elements = this._markerNameToElements.get( name ) || new Set(); | ||
elements.add( element ); | ||
const names = this._elementToMarkerNames.get( element ) || new Set(); | ||
names.add( name ); | ||
this._markerNameToElements.set( name, elements ); | ||
this._elementToMarkerNames.set( element, names ); | ||
} | ||
/** | ||
* Unbinds all elements from given marker name. | ||
* Unbinds an element from given marker name. | ||
* | ||
* @param {module:engine/view/element~Element} element Element to unbind. | ||
* @param {String} name Marker name. | ||
*/ | ||
unbindElementsFromMarkerName( name ) { | ||
this._markerNameToElements.delete( name ); | ||
unbindElementFromMarkerName( element, name ) { | ||
const nameToElements = this._markerNameToElements.get( name ); | ||
if ( nameToElements ) { | ||
nameToElements.delete( element ); | ||
if ( nameToElements.size == 0 ) { | ||
this._markerNameToElements.delete( name ); | ||
} | ||
} | ||
const elementToNames = this._elementToMarkerNames.get( element ); | ||
if ( elementToNames ) { | ||
elementToNames.delete( name ); | ||
if ( elementToNames.size == 0 ) { | ||
this._elementToMarkerNames.delete( element ); | ||
} | ||
} | ||
} | ||
/** | ||
* Returns all marker names of markers which has changed due to unbinding a view element (so it is assumed that the view element | ||
* has been removed, moved or renamed) since the last flush. After returning, the marker names list is cleared. | ||
* | ||
* @returns {Array.<String>} | ||
*/ | ||
flushUnboundMarkerNames() { | ||
const markerNames = Array.from( this._unboundMarkerNames ); | ||
this._unboundMarkerNames.clear(); | ||
return markerNames; | ||
} | ||
/** | ||
* Removes all model to view and view to model bindings. | ||
@@ -195,2 +256,4 @@ */ | ||
this._markerNameToElements = new Map(); | ||
this._elementToMarkerNames = new Map(); | ||
this._unboundMarkerNames = new Set(); | ||
} | ||
@@ -197,0 +260,0 @@ |
@@ -58,2 +58,23 @@ /** | ||
* | ||
* // Convert <p>'s font-size style. | ||
* // Note: You should use a low-priority observer in order to ensure that | ||
* // it's executed after the element-to-element converter. | ||
* editor.data.upcastDispatcher.on( 'element:p', ( evt, data, conversionApi ) => { | ||
* const { consumable, schema, writer } = conversionApi; | ||
* | ||
* if ( !consumable.consume( data.viewItem, { style: 'font-size' } ) ) { | ||
* return; | ||
* } | ||
* | ||
* const fontSize = data.viewItem.getStyle( 'font-size' ); | ||
* | ||
* // Don't go for the model element after data.modelCursor because it might happen | ||
* // that a single view element was converted to multiple model elements. Get all of them. | ||
* for ( const item of data.modelRange.getItems( { shallow: true } ) ) { | ||
* if ( schema.checkAttribute( item, 'fontSize' ) ) { | ||
* writer.setAttribute( 'fontSize', fontSize, item ); | ||
* } | ||
* } | ||
* }, { priority: 'low' } ); | ||
* | ||
* // Convert all elements which have no custom converter into paragraph (autoparagraphing). | ||
@@ -60,0 +81,0 @@ * editor.data.upcastDispatcher.on( 'element', ( evt, data, conversionApi ) => { |
@@ -159,3 +159,3 @@ /** | ||
* If `String` is given, the model attribute value will be set to `true`. | ||
* @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority. | ||
* @param {module:utils/priorities~PriorityString} [config.converterPriority='low'] Converter priority. | ||
* @returns {module:engine/conversion/upcasthelpers~UpcastHelpers} | ||
@@ -426,3 +426,3 @@ */ | ||
// If `String` is given, the model attribute value will be set to `true`. | ||
// @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority. | ||
// @param {module:utils/priorities~PriorityString} [config.converterPriority='low'] Converter priority. | ||
// @returns {Function} Conversion helper. | ||
@@ -429,0 +429,0 @@ function upcastElementToAttribute( config ) { |
@@ -114,2 +114,28 @@ /** | ||
/** | ||
* Marks given `item` in differ to be "refreshed". It means that the item will be marked as removed and inserted in the differ changes | ||
* set, so it will be effectively re-converted when differ changes will be handled by a dispatcher. | ||
* | ||
* @param {module:engine/model/item~Item} item Item to refresh. | ||
*/ | ||
refreshItem( item ) { | ||
if ( this._isInInsertedElement( item.parent ) ) { | ||
return; | ||
} | ||
this._markRemove( item.parent, item.startOffset, item.offsetSize ); | ||
this._markInsert( item.parent, item.startOffset, item.offsetSize ); | ||
const range = Range._createOn( item ); | ||
for ( const marker of this._markerCollection.getMarkersIntersectingRange( range ) ) { | ||
const markerRange = marker.getRange(); | ||
this.bufferMarkerChange( marker.name, markerRange, markerRange, marker.affectsData ); | ||
} | ||
// Clear cache after each buffered operation as it is no longer valid. | ||
this._cachedChanges = null; | ||
} | ||
/** | ||
* Buffers the given operation. An operation has to be buffered before it is executed. | ||
@@ -140,3 +166,3 @@ * | ||
case 'changeAttribute': { | ||
for ( const item of operation.range.getItems() ) { | ||
for ( const item of operation.range.getItems( { shallow: true } ) ) { | ||
if ( this._isInInsertedElement( item.parent ) ) { | ||
@@ -1091,3 +1117,5 @@ continue; | ||
if ( change.offset > offset ) { | ||
actions.push( ...'e'.repeat( change.offset - offset ).split( '' ) ); | ||
for ( let i = 0; i < change.offset - offset; i++ ) { | ||
actions.push( 'e' ); | ||
} | ||
@@ -1099,3 +1127,5 @@ oldChildrenHandled += change.offset - offset; | ||
if ( change.type == 'insert' ) { | ||
actions.push( ...'i'.repeat( change.howMany ).split( '' ) ); | ||
for ( let i = 0; i < change.howMany; i++ ) { | ||
actions.push( 'i' ); | ||
} | ||
@@ -1105,3 +1135,5 @@ // The last handled offset is after inserted range. | ||
} else if ( change.type == 'remove' ) { | ||
actions.push( ...'r'.repeat( change.howMany ).split( '' ) ); | ||
for ( let i = 0; i < change.howMany; i++ ) { | ||
actions.push( 'r' ); | ||
} | ||
@@ -1125,3 +1157,5 @@ // The last handled offset is at the position where the nodes were removed. | ||
if ( oldChildrenHandled < oldChildrenLength ) { | ||
actions.push( ...'e'.repeat( oldChildrenLength - oldChildrenHandled ).split( '' ) ); | ||
for ( let i = 0; i < oldChildrenLength - oldChildrenHandled - offset; i++ ) { | ||
actions.push( 'e' ); | ||
} | ||
} | ||
@@ -1128,0 +1162,0 @@ |
@@ -119,6 +119,13 @@ /** | ||
/** | ||
* Checks whether given model tree object is of given type. | ||
* Checks whether this object is of the given type. | ||
* | ||
* Read more in {@link module:engine/model/node~Node#is}. | ||
* docFrag.is( 'documentFragment' ); // -> true | ||
* docFrag.is( 'model:documentFragment' ); // -> true | ||
* | ||
* docFrag.is( 'view:documentFragment' ); // -> false | ||
* docFrag.is( 'element' ); // -> false | ||
* docFrag.is( 'node' ); // -> false | ||
* | ||
* {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method. | ||
* | ||
* @param {String} type | ||
@@ -128,3 +135,3 @@ * @returns {Boolean} | ||
is( type ) { | ||
return type == 'documentFragment'; | ||
return type == 'documentFragment' || type == 'model:documentFragment'; | ||
} | ||
@@ -131,0 +138,0 @@ |
@@ -20,3 +20,2 @@ /** | ||
import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror'; | ||
import log from '@ckeditor/ckeditor5-utils/src/log'; | ||
import uid from '@ckeditor/ckeditor5-utils/src/uid'; | ||
@@ -372,12 +371,15 @@ | ||
/** | ||
* Checks whether object is of given type following the convention set by | ||
* {@link module:engine/model/node~Node#is `Node#is()`}. | ||
* Checks whether this object is of the given type. | ||
* | ||
* const selection = new DocumentSelection( ... ); | ||
* selection.is( 'selection' ); // -> true | ||
* selection.is( 'documentSelection' ); // -> true | ||
* selection.is( 'model:selection' ); // -> true | ||
* selection.is( 'model:documentSelection' ); // -> true | ||
* | ||
* selection.is( 'selection' ); // true | ||
* selection.is( 'documentSelection' ); // true | ||
* selection.is( 'node' ); // false | ||
* selection.is( 'element' ); // false | ||
* selection.is( 'view:selection' ); // -> false | ||
* selection.is( 'element' ); // -> false | ||
* selection.is( 'node' ); // -> false | ||
* | ||
* {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method. | ||
* | ||
* @param {String} type | ||
@@ -387,3 +389,6 @@ * @returns {Boolean} | ||
is( type ) { | ||
return type == 'selection' || type == 'documentSelection'; | ||
return type == 'selection' || | ||
type == 'model:selection' || | ||
type == 'documentSelection' || | ||
type == 'model:documentSelection'; | ||
} | ||
@@ -810,8 +815,3 @@ | ||
if ( range.root == this._document.graveyard ) { | ||
/** | ||
* Trying to add a Range that is in the graveyard root. Range rejected. | ||
* | ||
* @warning model-selection-range-in-graveyard | ||
*/ | ||
log.warn( 'model-selection-range-in-graveyard: Trying to add a Range that is in the graveyard root. Range rejected.' ); | ||
// @if CK_DEBUG // console.warn( 'Trying to add a Range that is in the graveyard root. Range rejected.' ); | ||
@@ -818,0 +818,0 @@ return; |
@@ -22,3 +22,3 @@ /** | ||
* | ||
* @extends {module:engine/model/node~Node} | ||
* @extends module:engine/model/node~Node | ||
*/ | ||
@@ -93,15 +93,21 @@ export default class Element extends Node { | ||
/** | ||
* Checks whether this model object is of the given type. | ||
* Checks whether this object is of the given. | ||
* | ||
* obj.name; // 'listItem' | ||
* obj instanceof Element; // true | ||
* element.is( 'element' ); // -> true | ||
* element.is( 'node' ); // -> true | ||
* element.is( 'model:element' ); // -> true | ||
* element.is( 'model:node' ); // -> true | ||
* | ||
* obj.is( 'element' ); // true | ||
* obj.is( 'listItem' ); // true | ||
* obj.is( 'element', 'listItem' ); // true | ||
* obj.is( 'text' ); // false | ||
* obj.is( 'element', 'image' ); // false | ||
* element.is( 'view:element' ); // -> false | ||
* element.is( 'documentSelection' ); // -> false | ||
* | ||
* Read more in {@link module:engine/model/node~Node#is `Node#is()`}. | ||
* Assuming that the object being checked is an element, you can also check its | ||
* {@link module:engine/model/element~Element#name name}: | ||
* | ||
* element.is( 'image' ); // -> true if this is an <image> element | ||
* element.is( 'element', 'image' ); // -> same as above | ||
* text.is( 'image' ); -> false | ||
* | ||
* {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method. | ||
* | ||
* @param {String} type Type to check when `name` parameter is present. | ||
@@ -113,6 +119,8 @@ * Otherwise, it acts like the `name` parameter. | ||
is( type, name = null ) { | ||
const cutType = type.replace( /^model:/, '' ); | ||
if ( !name ) { | ||
return type == 'element' || type == this.name || super.is( type ); | ||
return cutType == 'element' || cutType == this.name || super.is( type ); | ||
} else { | ||
return type == 'element' && name == this.name; | ||
return cutType == 'element' && name == this.name; | ||
} | ||
@@ -119,0 +127,0 @@ } |
@@ -67,2 +67,22 @@ /** | ||
/** | ||
* Checks whether this object is of the given. | ||
* | ||
* livePosition.is( 'position' ); // -> true | ||
* livePosition.is( 'model:position' ); // -> true | ||
* livePosition.is( 'liveposition' ); // -> true | ||
* livePosition.is( 'model:livePosition' ); // -> true | ||
* | ||
* livePosition.is( 'view:position' ); // -> false | ||
* livePosition.is( 'documentSelection' ); // -> false | ||
* | ||
* {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method. | ||
* | ||
* @param {String} type | ||
* @returns {Boolean} | ||
*/ | ||
is( type ) { | ||
return type == 'livePosition' || type == 'model:livePosition' || super.is( type ); | ||
} | ||
/** | ||
* Creates a {@link module:engine/model/position~Position position instance}, which is equal to this live position. | ||
@@ -69,0 +89,0 @@ * |
@@ -44,2 +44,22 @@ /** | ||
/** | ||
* Checks whether this object is of the given. | ||
* | ||
* liveRange.is( 'range' ); // -> true | ||
* liveRange.is( 'model:range' ); // -> true | ||
* liveRange.is( 'liveRange' ); // -> true | ||
* liveRange.is( 'model:liveRange' ); // -> true | ||
* | ||
* liveRange.is( 'view:range' ); // -> false | ||
* liveRange.is( 'documentSelection' ); // -> false | ||
* | ||
* {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method. | ||
* | ||
* @param {String} type | ||
* @returns {Boolean} | ||
*/ | ||
is( type ) { | ||
return type == 'liveRange' || type == 'model:liveRange' || super.is( type ); | ||
} | ||
/** | ||
* Creates a {@link module:engine/model/range~Range range instance} that is equal to this live range. | ||
@@ -46,0 +66,0 @@ * |
@@ -452,2 +452,20 @@ /** | ||
/** | ||
* Checks whether this object is of the given. | ||
* | ||
* marker.is( 'marker' ); // -> true | ||
* marker.is( 'model:marker' ); // -> true | ||
* | ||
* marker.is( 'view:element' ); // -> false | ||
* marker.is( 'documentSelection' ); // -> false | ||
* | ||
* {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method. | ||
* | ||
* @param {String} type | ||
* @returns {Boolean} | ||
*/ | ||
is( type ) { | ||
return type == 'marker' || type == 'model:marker'; | ||
} | ||
/** | ||
* Binds new live range to the marker and detach the old one if is attached. | ||
@@ -454,0 +472,0 @@ * |
@@ -400,2 +400,49 @@ /** | ||
/** | ||
* Checks whether this object is of the given type. | ||
* | ||
* This method is useful when processing model objects that are of unknown type. For example, a function | ||
* may return a {@link module:engine/model/documentfragment~DocumentFragment} or a {@link module:engine/model/node~Node} | ||
* that can be either a text node or an element. This method can be used to check what kind of object is returned. | ||
* | ||
* someObject.is( 'element' ); // -> true if this is an element | ||
* someObject.is( 'node' ); // -> true if this is a node (a text node or an element) | ||
* someObject.is( 'documentFragment' ); // -> true if this is a document fragment | ||
* | ||
* Since this method is also available on a range of view objects, you can prefix the type of the object with | ||
* `model:` or `view:` to check, for example, if this is the model's or view's element: | ||
* | ||
* modelElement.is( 'model:element' ); // -> true | ||
* modelElement.is( 'view:element' ); // -> false | ||
* | ||
* By using this method it is also possible to check a name of an element: | ||
* | ||
* imageElement.is( 'image' ); // -> true | ||
* imageElement.is( 'element', 'image' ); // -> same as above | ||
* imageElement.is( 'model:element', 'image' ); // -> same as above, but more precise | ||
* | ||
* The list of model objects which implement the `is()` method: | ||
* | ||
* * {@link module:engine/model/node~Node#is `Node#is()`} | ||
* * {@link module:engine/model/text~Text#is `Text#is()`} | ||
* * {@link module:engine/model/element~Element#is `Element#is()`} | ||
* * {@link module:engine/model/rootelement~RootElement#is `RootElement#is()`} | ||
* * {@link module:engine/model/position~Position#is `Position#is()`} | ||
* * {@link module:engine/model/liveposition~LivePosition#is `LivePosition#is()`} | ||
* * {@link module:engine/model/range~Range#is `Range#is()`} | ||
* * {@link module:engine/model/liverange~LiveRange#is `LiveRange#is()`} | ||
* * {@link module:engine/model/documentfragment~DocumentFragment#is `DocumentFragment#is()`} | ||
* * {@link module:engine/model/selection~Selection#is `Selection#is()`} | ||
* * {@link module:engine/model/documentselection~DocumentSelection#is `DocumentSelection#is()`} | ||
* * {@link module:engine/model/markercollection~Marker#is `Marker#is()`} | ||
* * {@link module:engine/model/textproxy~TextProxy#is `TextProxy#is()`} | ||
* | ||
* @method #is | ||
* @param {String} type | ||
* @returns {Boolean} | ||
*/ | ||
is( type ) { | ||
return type == 'node' || type == 'model:node'; | ||
} | ||
/** | ||
* Creates a copy of this node, that is a node with exactly same attributes, and returns it. | ||
@@ -464,25 +511,2 @@ * | ||
} | ||
/** | ||
* Checks whether given model tree object is of given type. | ||
* | ||
* This method is useful when processing model tree objects that are of unknown type. For example, a function | ||
* may return {@link module:engine/model/documentfragment~DocumentFragment} or {@link module:engine/model/node~Node} | ||
* that can be either text node or element. This method can be used to check what kind of object is returned. | ||
* | ||
* obj.is( 'node' ); // true for any node, false for document fragment and text fragment | ||
* obj.is( 'documentFragment' ); // true for document fragment, false for any node | ||
* obj.is( 'element' ); // true for any element, false for text node or document fragment | ||
* obj.is( 'element', 'paragraph' ); // true only for element which name is 'paragraph' | ||
* obj.is( 'paragraph' ); // shortcut for obj.is( 'element', 'paragraph' ) | ||
* obj.is( 'text' ); // true for text node, false for element and document fragment | ||
* obj.is( 'textProxy' ); // true for text proxy object | ||
* | ||
* @method #is | ||
* @param {'element'|'rootElement'|'text'|'textProxy'|'documentFragment'} type | ||
* @returns {Boolean} | ||
*/ | ||
is( type ) { | ||
return type == 'node'; | ||
} | ||
} | ||
@@ -489,0 +513,0 @@ |
@@ -144,5 +144,5 @@ /** | ||
// Validate whether merge operation has correct parameters. | ||
if ( !sourceElement || !sourceElement.is( 'element' ) || !sourceElement.parent ) { | ||
if ( !sourceElement.parent ) { | ||
/** | ||
* Merge source position is invalid. | ||
* Merge source position is invalid. The element to be merged must have a parent node. | ||
* | ||
@@ -152,5 +152,5 @@ * @error merge-operation-source-position-invalid | ||
throw new CKEditorError( 'merge-operation-source-position-invalid: Merge source position is invalid.', this ); | ||
} else if ( !targetElement || !targetElement.is( 'element' ) || !targetElement.parent ) { | ||
} else if ( !targetElement.parent ) { | ||
/** | ||
* Merge target position is invalid. | ||
* Merge target position is invalid. The element to be merged must have a parent node. | ||
* | ||
@@ -157,0 +157,0 @@ * @error merge-operation-target-position-invalid |
@@ -126,13 +126,4 @@ /** | ||
// We expect that many errors might be connected with one of scenarios described below. | ||
if ( !sourceElement || !targetElement ) { | ||
if ( sourceOffset + this.howMany > sourceElement.maxOffset ) { | ||
/** | ||
* Source position or target position is invalid. | ||
* | ||
* @error move-operation-position-invalid | ||
*/ | ||
throw new CKEditorError( | ||
'move-operation-position-invalid: Source position or target position is invalid.', this | ||
); | ||
} else if ( sourceOffset + this.howMany > sourceElement.maxOffset ) { | ||
/** | ||
* The nodes which should be moved do not exist. | ||
@@ -139,0 +130,0 @@ * |
@@ -74,7 +74,7 @@ /** | ||
* | ||
* @error model-position-path-incorrect | ||
* @error model-position-path-incorrect-format | ||
* @param path | ||
*/ | ||
throw new CKEditorError( | ||
'model-position-path-incorrect: Position path must be an array with at least one item.', | ||
'model-position-path-incorrect-format: Position path must be an array with at least one item.', | ||
root, | ||
@@ -165,3 +165,3 @@ { path } | ||
* @readonly | ||
* @type {module:engine/model/element~Element} | ||
* @type {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment} | ||
*/ | ||
@@ -173,4 +173,27 @@ get parent() { | ||
parent = parent.getChild( parent.offsetToIndex( this.path[ i ] ) ); | ||
if ( !parent ) { | ||
throw new CKEditorError( 'model-position-path-incorrect: The position\'s path is incorrect.', this, { position: this } ); | ||
} | ||
} | ||
if ( parent.is( 'text' ) ) { | ||
/** | ||
* The position's path is incorrect. This means that a position does not point to | ||
* a correct place in the tree and hence, some of its methods and getters cannot work correctly. | ||
* | ||
* **Note**: Unlike DOM and view positions, in the model, the | ||
* {@link module:engine/model/position~Position#parent position's parent} is always an element or a document fragment. | ||
* The last offset in the {@link module:engine/model/position~Position#path position's path} is the point in this element where | ||
* this position points. | ||
* | ||
* Read more about model positions and offsets in | ||
* the {@glink framework/guides/architecture/editing-engine#indexes-and-offsets Editing engine architecture guide}. | ||
* | ||
* @error position-incorrect-path | ||
* @param {module:engine/model/position~Position} position The incorrect position. | ||
*/ | ||
throw new CKEditorError( 'model-position-path-incorrect: The position\'s path is incorrect.', this, { position: this } ); | ||
} | ||
return parent; | ||
@@ -509,2 +532,20 @@ } | ||
/** | ||
* Checks whether this object is of the given. | ||
* | ||
* position.is( 'position' ); // -> true | ||
* position.is( 'model:position' ); // -> true | ||
* | ||
* position.is( 'view:position' ); // -> false | ||
* position.is( 'documentSelection' ); // -> false | ||
* | ||
* {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method. | ||
* | ||
* @param {String} type | ||
* @returns {Boolean} | ||
*/ | ||
is( type ) { | ||
return type == 'position' || type == 'model:position'; | ||
} | ||
/** | ||
* Checks if two positions are in the same parent. | ||
@@ -511,0 +552,0 @@ * |
@@ -147,2 +147,20 @@ /** | ||
/** | ||
* Checks whether this object is of the given. | ||
* | ||
* range.is( 'range' ); // -> true | ||
* range.is( 'model:range' ); // -> true | ||
* | ||
* range.is( 'view:range' ); // -> false | ||
* range.is( 'documentSelection' ); // -> false | ||
* | ||
* {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method. | ||
* | ||
* @param {String} type | ||
* @returns {Boolean} | ||
*/ | ||
is( type ) { | ||
return type == 'range' || type == 'model:range'; | ||
} | ||
/** | ||
* Two ranges are equal if their {@link #start} and {@link #end} positions are equal. | ||
@@ -149,0 +167,0 @@ * |
@@ -58,9 +58,34 @@ /** | ||
/** | ||
* @inheritDoc | ||
* Checks whether this object is of the given. | ||
* | ||
* rootElement.is( 'rootElement' ); // -> true | ||
* rootElement.is( 'element' ); // -> true | ||
* rootElement.is( 'node' ); // -> true | ||
* rootElement.is( 'model:rootElement' ); // -> true | ||
* rootElement.is( 'model:element' ); // -> true | ||
* rootElement.is( 'model:node' ); // -> true | ||
* | ||
* rootElement.is( 'view:element' ); // -> false | ||
* rootElement.is( 'documentFragment' ); // -> false | ||
* | ||
* Assuming that the object being checked is an element, you can also check its | ||
* {@link module:engine/model/element~Element#name name}: | ||
* | ||
* rootElement.is( '$root' ); // -> true if this is a $root element | ||
* rootElement.is( 'rootElement', '$root' ); // -> same as above | ||
* text.is( '$root' ); -> false | ||
* | ||
* {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method. | ||
* | ||
* @param {String} type Type to check when `name` parameter is present. | ||
* Otherwise, it acts like the `name` parameter. | ||
* @param {String} [name] Element name. | ||
* @returns {Boolean} | ||
*/ | ||
is( type, name ) { | ||
const cutType = type.replace( 'model:', '' ); | ||
if ( !name ) { | ||
return type == 'rootElement' || super.is( type ); | ||
return cutType == 'rootElement' || super.is( type ); | ||
} else { | ||
return ( type == 'rootElement' && name == this.name ) || super.is( type, name ); | ||
return ( cutType == 'rootElement' && name == this.name ) || super.is( type, name ); | ||
} | ||
@@ -67,0 +92,0 @@ } |
@@ -1366,2 +1366,3 @@ /** | ||
* `fontSize` rather than semantic attribute (such as `src`, `listType`, etc.). For example, it is used by the "Remove format" feature. | ||
* @property {Boolean} [copyOnEnter] Indicates that given text attribute should be copied to the next block when enter is pressed. | ||
*/ | ||
@@ -1368,0 +1369,0 @@ |
@@ -626,11 +626,12 @@ /** | ||
/** | ||
* Checks whether object is of given type following the convention set by | ||
* {@link module:engine/model/node~Node#is `Node#is()`}. | ||
* Checks whether this object is of the given. | ||
* | ||
* const selection = new Selection( ... ); | ||
* selection.is( 'selection' ); // -> true | ||
* selection.is( 'model:selection' ); // -> true | ||
* | ||
* selection.is( 'selection' ); // true | ||
* selection.is( 'node' ); // false | ||
* selection.is( 'element' ); // false | ||
* selection.is( 'view:selection' ); // -> false | ||
* selection.is( 'range' ); // -> false | ||
* | ||
* {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method. | ||
* | ||
* @param {String} type | ||
@@ -640,3 +641,3 @@ * @returns {Boolean} | ||
is( type ) { | ||
return type == 'selection'; | ||
return type == 'selection' || type == 'model:selection'; | ||
} | ||
@@ -643,0 +644,0 @@ |
@@ -23,3 +23,3 @@ /** | ||
* | ||
* @extends {module:engine/model/node~Node} | ||
* @extends module:engine/model/node~Node | ||
*/ | ||
@@ -67,6 +67,20 @@ export default class Text extends Node { | ||
/** | ||
* @inheritDoc | ||
* Checks whether this object is of the given. | ||
* | ||
* text.is( 'text' ); // -> true | ||
* text.is( 'node' ); // -> true | ||
* text.is( 'model:text' ); // -> true | ||
* text.is( 'model:node' ); // -> true | ||
* | ||
* text.is( 'view:text' ); // -> false | ||
* text.is( 'documentSelection' ); // -> false | ||
* | ||
* {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method. | ||
* | ||
* @param {String} type Type to check when `name` parameter is present. | ||
* Otherwise, it acts like the `name` parameter. | ||
* @returns {Boolean} | ||
*/ | ||
is( type ) { | ||
return type == 'text' || super.is( type ); | ||
return type == 'text' || type == 'model:text' || super.is( type ); | ||
} | ||
@@ -73,0 +87,0 @@ |
@@ -176,6 +176,12 @@ /** | ||
/** | ||
* Checks whether given model tree object is of given type. | ||
* Checks whether this object is of the given. | ||
* | ||
* Read more in {@link module:engine/model/node~Node#is}. | ||
* textProxy.is( 'textProxy' ); // -> true | ||
* textProxy.is( 'model:textProxy' ); // -> true | ||
* | ||
* textProxy.is( 'view:textProxy' ); // -> false | ||
* textProxy.is( 'range' ); // -> false | ||
* | ||
* {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method. | ||
* | ||
* @param {String} type | ||
@@ -185,3 +191,3 @@ * @returns {Boolean} | ||
is( type ) { | ||
return type == 'textProxy'; | ||
return type == 'textProxy' || type == 'model:textProxy'; | ||
} | ||
@@ -188,0 +194,0 @@ |
@@ -14,5 +14,5 @@ /** | ||
import Range from '../range'; | ||
import log from '@ckeditor/ckeditor5-utils/src/log'; | ||
import DocumentSelection from '../documentselection'; | ||
import Selection from '../selection'; | ||
import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror'; | ||
@@ -89,9 +89,4 @@ /** | ||
// an insertion without proper range to select. | ||
/** | ||
* Cannot determine a proper selection range after insertion. | ||
* | ||
* @warning insertcontent-no-range | ||
*/ | ||
log.warn( 'insertcontent-no-range: Cannot determine a proper selection range after insertion.' ); | ||
// | ||
// @if CK_DEBUG // console.warn( 'Cannot determine a proper selection range after insertion.' ); | ||
} | ||
@@ -327,8 +322,15 @@ | ||
// Note that it would often be a silent issue if we insert node in a place where it's not allowed. | ||
log.error( | ||
'insertcontent-wrong-position: The node cannot be inserted on the given position.', | ||
/** | ||
* Given node cannot be inserted on the given position. | ||
* | ||
* @error insertcontent-wrong-position | ||
* @param {module:engine/model/node~Node} node Node to insert. | ||
* @param {module:engine/model/position~Position} position Position to insert the node at. | ||
*/ | ||
throw new CKEditorError( | ||
'insertcontent-wrong-position: Given node cannot be inserted on the given position.', | ||
this, | ||
{ node, position: this.position } | ||
); | ||
return; | ||
} | ||
@@ -448,3 +450,9 @@ | ||
// it should need to be secured as in the left merge case. | ||
log.error( 'insertcontent-wrong-position-on-merge: The insertion position should equal the merge position' ); | ||
/** | ||
* An internal error occured during merging insertion content with siblings. | ||
* The insertion position should equal to the merge position. | ||
* | ||
* @error insertcontent-invalid-insertion-position | ||
*/ | ||
throw new CKEditorError( 'insertcontent-invalid-insertion-position', this ); | ||
} | ||
@@ -451,0 +459,0 @@ |
@@ -1013,3 +1013,3 @@ /** | ||
* @see module:engine/model/markercollection~Marker | ||
* @param {String} markerOrName Name of a marker to update, or a marker instance. | ||
* @param {String|module:engine/model/markercollection~Marker} markerOrName Name of a marker to update, or a marker instance. | ||
* @param {Object} [options] If options object is not defined then marker will be refreshed by triggering | ||
@@ -1016,0 +1016,0 @@ * downcast conversion for this marker with the same data. |
@@ -14,3 +14,3 @@ /** | ||
/** | ||
* This helper enabled the two-step caret (phantom) movement behavior for the given {@link module:engine/model/model~Model} | ||
* This helper enables the two-step caret (phantom) movement behavior for the given {@link module:engine/model/model~Model} | ||
* attribute on arrow right (<kbd>→</kbd>) and left (<kbd>←</kbd>) key press. | ||
@@ -21,2 +21,5 @@ * | ||
* | ||
* **Note:** This helper support right–to–left (Arabic, Hebrew, etc.) content by mirroring its behavior | ||
* but for the sake of simplicity examples showcase only left–to–right use–cases. | ||
* | ||
* # Forward movement | ||
@@ -83,9 +86,11 @@ * | ||
* | ||
* @param {module:engine/view/view~View} view View controller instance. | ||
* @param {module:engine/model/model~Model} model Data model instance. | ||
* @param {module:utils/dom/emittermixin~Emitter} emitter The emitter to which this behavior should be added | ||
* @param {Object} options Helper options. | ||
* @param {module:engine/view/view~View} options.view View controller instance. | ||
* @param {module:engine/model/model~Model} options.model Data model instance. | ||
* @param {module:utils/dom/emittermixin~Emitter} options.emitter The emitter to which this behavior should be added | ||
* (e.g. a plugin instance). | ||
* @param {String} attribute Attribute for which this behavior will be added. | ||
* @param {String} options.attribute Attribute for which this behavior will be added. | ||
* @param {module:utils/locale~Locale} options.locale The {@link module:core/editor/editor~Editor#locale} instance. | ||
*/ | ||
export default function bindTwoStepCaretToAttribute( view, model, emitter, attribute ) { | ||
export default function bindTwoStepCaretToAttribute( { view, model, emitter, attribute, locale } ) { | ||
const twoStepCaretHandler = new TwoStepCaretHandler( model, emitter, attribute ); | ||
@@ -126,5 +131,6 @@ const modelSelection = model.document.selection; | ||
const position = modelSelection.getFirstPosition(); | ||
const contentDirection = locale.contentLanguageDirection; | ||
let isMovementHandled; | ||
if ( arrowRightPressed ) { | ||
if ( ( contentDirection === 'ltr' && arrowRightPressed ) || ( contentDirection === 'rtl' && arrowLeftPressed ) ) { | ||
isMovementHandled = twoStepCaretHandler.handleForwardMovement( position, data ); | ||
@@ -135,3 +141,3 @@ } else { | ||
// Stop the keydown event if the two-step arent movement handled it. Avoid collisions | ||
// Stop the keydown event if the two-step caret movement handled it. Avoid collisions | ||
// with other features which may also take over the caret movement (e.g. Widget). | ||
@@ -145,9 +151,9 @@ if ( isMovementHandled ) { | ||
/** | ||
* This is a private helper–class for {@link module:engine/utils/bindtwostepcarettoattribute}. | ||
* This is a protected helper–class for {@link module:engine/utils/bindtwostepcarettoattribute}. | ||
* It handles the state of the 2-step caret movement for a single {@link module:engine/model/model~Model} | ||
* attribute upon the `keypress` in the {@link module:engine/view/view~View}. | ||
* | ||
* @private | ||
* @protected | ||
*/ | ||
class TwoStepCaretHandler { | ||
export class TwoStepCaretHandler { | ||
/* | ||
@@ -154,0 +160,0 @@ * Creates two step handler instance. |
@@ -128,9 +128,35 @@ /** | ||
/** | ||
* @inheritDoc | ||
* Checks whether this object is of the given. | ||
* | ||
* attributeElement.is( 'attributeElement' ); // -> true | ||
* attributeElement.is( 'element' ); // -> true | ||
* attributeElement.is( 'node' ); // -> true | ||
* attributeElement.is( 'view:attributeElement' ); // -> true | ||
* attributeElement.is( 'view:element' ); // -> true | ||
* attributeElement.is( 'view:node' ); // -> true | ||
* | ||
* attributeElement.is( 'model:element' ); // -> false | ||
* attributeElement.is( 'documentFragment' ); // -> false | ||
* | ||
* Assuming that the object being checked is an attribute element, you can also check its | ||
* {@link module:engine/view/attributeelement~AttributeElement#name name}: | ||
* | ||
* attributeElement.is( 'b' ); // -> true if this is a bold element | ||
* attributeElement.is( 'attributeElement', 'b' ); // -> same as above | ||
* text.is( 'b' ); -> false | ||
* | ||
* {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method. | ||
* | ||
* @param {String} type Type to check when `name` parameter is present. | ||
* Otherwise, it acts like the `name` parameter. | ||
* @param {String} [name] Element name. | ||
* @returns {Boolean} | ||
*/ | ||
is( type, name = null ) { | ||
const cutType = type && type.replace( /^view:/, '' ); | ||
if ( !name ) { | ||
return type == 'attributeElement' || super.is( type ); | ||
return cutType == 'attributeElement' || super.is( type ); | ||
} else { | ||
return ( type == 'attributeElement' && name == this.name ) || super.is( type, name ); | ||
return ( cutType == 'attributeElement' && name == this.name ) || super.is( type, name ); | ||
} | ||
@@ -137,0 +163,0 @@ } |
@@ -54,9 +54,34 @@ /** | ||
/** | ||
* @inheritDoc | ||
* Checks whether this object is of the given. | ||
* | ||
* containerElement.is( 'containerElement' ); // -> true | ||
* containerElement.is( 'element' ); // -> true | ||
* containerElement.is( 'node' ); // -> true | ||
* containerElement.is( 'view:containerElement' ); // -> true | ||
* containerElement.is( 'view:element' ); // -> true | ||
* containerElement.is( 'view:node' ); // -> true | ||
* | ||
* containerElement.is( 'model:element' ); // -> false | ||
* containerElement.is( 'documentFragment' ); // -> false | ||
* | ||
* Assuming that the object being checked is a container element, you can also check its | ||
* {@link module:engine/view/containerelement~ContainerElement#name name}: | ||
* | ||
* containerElement.is( 'div' ); // -> true if this is a div container element | ||
* containerElement.is( 'contaienrElement', 'div' ); // -> same as above | ||
* text.is( 'div' ); -> false | ||
* | ||
* {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method. | ||
* | ||
* @param {String} type Type to check when `name` parameter is present. | ||
* Otherwise, it acts like the `name` parameter. | ||
* @param {String} [name] Element name. | ||
* @returns {Boolean} | ||
*/ | ||
is( type, name = null ) { | ||
const cutType = type && type.replace( /^view:/, '' ); | ||
if ( !name ) { | ||
return type == 'containerElement' || super.is( type ); | ||
return cutType == 'containerElement' || super.is( type ); | ||
} else { | ||
return ( type == 'containerElement' && name == this.name ) || super.is( type, name ); | ||
return ( cutType == 'containerElement' && name == this.name ) || super.is( type, name ); | ||
} | ||
@@ -63,0 +88,0 @@ } |
@@ -103,6 +103,6 @@ /** | ||
/** | ||
* Used to register a post-fixer callback. A post-fixers mechanism allows to update view tree just before rendering | ||
* Allows registering post-fixer callbacks. A post-fixers mechanism allows to update the view tree just before it is rendered | ||
* to the DOM. | ||
* | ||
* Post-fixers are fired just after all changes from the outermost change block were applied but | ||
* Post-fixers are executed right after all changes from the outermost change block were applied but | ||
* before the {@link module:engine/view/view~View#event:render render event} is fired. If a post-fixer callback made | ||
@@ -112,12 +112,38 @@ * a change, it should return `true`. When this happens, all post-fixers are fired again to check if something else should | ||
* | ||
* View post-fixers are useful when you wants to update view structure whenever it changes, for instance add some classes | ||
* to elements based on the view structure or selection. However, is you need DOM elements to be already updated, use | ||
* {@link module:engine/view/view~View#event:render render event}. | ||
* View post-fixers are useful when you want to apply some fixes whenever the view structure changes. Keep in mind that | ||
* changes executed in a view post-fixer should not break model-view mapping. | ||
* | ||
* As a parameter, a post-fixer callback receives a {@link module:engine/view/downcastwriter~DowncastWriter downcast writer} | ||
* instance connected with the executed changes block. | ||
* The types of changes which should be safe: | ||
* | ||
* Note that registering a post-fixer won't re-render the editor's view. If the view should change after registering the post-fixer then | ||
* it should be done manually calling `view.forceRender();`. | ||
* * adding or removing attribute from elements, | ||
* * changes inside of {@link module:engine/view/uielement~UIElement UI elements}, | ||
* * {@link module:engine/model/differ~Differ#refreshItem marking some of the model elements to be re-converted}. | ||
* | ||
* Try to avoid changes which touch view structure: | ||
* | ||
* * you should not add or remove nor wrap or unwrap any view elements, | ||
* * you should not change the editor data model in a view post-fixer. | ||
* | ||
* As a parameter, a post-fixer callback receives a {@link module:engine/view/downcastwriter~DowncastWriter downcast writer}. | ||
* | ||
* Typically, a post-fixer will look like this: | ||
* | ||
* editor.editing.view.document.registerPostFixer( writer => { | ||
* if ( checkSomeCondition() ) { | ||
* writer.doSomething(); | ||
* | ||
* // Let other post-fixers know that something changed. | ||
* return true; | ||
* } | ||
* } ); | ||
* | ||
* Note that nothing happens right after you register a post-fixer (e.g. execute such a code in the console). | ||
* That is because adding a post-fixer does not execute it. | ||
* The post-fixer will be executed as soon as any change in the document needs to cause its rendering. | ||
* If you want to re-render the editor's view after registering the post-fixer then you should do it manually by calling | ||
* {@link module:engine/view/view~View#forceRender `view.forceRender()`}. | ||
* | ||
* If you need to register a callback which is executed when DOM elements are already updated, | ||
* use {@link module:engine/view/view~View#event:render render event}. | ||
* | ||
* @param {Function} postFixer | ||
@@ -124,0 +150,0 @@ */ |
@@ -97,6 +97,13 @@ /** | ||
/** | ||
* Checks whether given view tree object is of given type. | ||
* Checks whether this object is of the given type. | ||
* | ||
* Read more in {@link module:engine/view/node~Node#is}. | ||
* docFrag.is( 'documentFragment' ); // -> true | ||
* docFrag.is( 'view:documentFragment' ); // -> true | ||
* | ||
* docFrag.is( 'model:documentFragment' ); // -> false | ||
* docFrag.is( 'element' ); // -> false | ||
* docFrag.is( 'node' ); // -> false | ||
* | ||
* {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method. | ||
* | ||
* @param {String} type | ||
@@ -106,3 +113,3 @@ * @returns {Boolean} | ||
is( type ) { | ||
return type == 'documentFragment'; | ||
return type == 'documentFragment' || type == 'view:documentFragment'; | ||
} | ||
@@ -109,0 +116,0 @@ |
@@ -278,12 +278,15 @@ /** | ||
/** | ||
* Checks whether object is of given type following the convention set by | ||
* {@link module:engine/view/node~Node#is `Node#is()`}. | ||
* Checks whether this object is of the given type. | ||
* | ||
* const selection = new DocumentSelection( ... ); | ||
* docSelection.is( 'selection' ); // -> true | ||
* docSelection.is( 'documentSelection' ); // -> true | ||
* docSelection.is( 'view:selection' ); // -> true | ||
* docSelection.is( 'view:documentSelection' ); // -> true | ||
* | ||
* selection.is( 'selection' ); // true | ||
* selection.is( 'documentSelection' ); // true | ||
* selection.is( 'node' ); // false | ||
* selection.is( 'element' ); // false | ||
* docSelection.is( 'model:documentSelection' ); // -> false | ||
* docSelection.is( 'element' ); // -> false | ||
* docSelection.is( 'node' ); // -> false | ||
* | ||
* {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method. | ||
* | ||
* @param {String} type | ||
@@ -293,3 +296,6 @@ * @returns {Boolean} | ||
is( type ) { | ||
return type == 'selection' || type == 'documentSelection'; | ||
return type == 'selection' || | ||
type == 'documentSelection' || | ||
type == 'view:selection' || | ||
type == 'view:documentSelection'; | ||
} | ||
@@ -296,0 +302,0 @@ |
@@ -70,9 +70,34 @@ /** | ||
/** | ||
* @inheritDoc | ||
* Checks whether this object is of the given. | ||
* | ||
* editableElement.is( 'editableElement' ); // -> true | ||
* editableElement.is( 'element' ); // -> true | ||
* editableElement.is( 'node' ); // -> true | ||
* editableElement.is( 'view:editableElement' ); // -> true | ||
* editableElement.is( 'view:element' ); // -> true | ||
* editableElement.is( 'view:node' ); // -> true | ||
* | ||
* editableElement.is( 'model:element' ); // -> false | ||
* editableElement.is( 'documentFragment' ); // -> false | ||
* | ||
* Assuming that the object being checked is an editbale element, you can also check its | ||
* {@link module:engine/view/editableelement~EditableElement#name name}: | ||
* | ||
* editableElement.is( 'div' ); // -> true if this is a div element | ||
* editableElement.is( 'editableElement', 'div' ); // -> same as above | ||
* text.is( 'div' ); -> false | ||
* | ||
* {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method. | ||
* | ||
* @param {String} type Type to check when `name` parameter is present. | ||
* Otherwise, it acts like the `name` parameter. | ||
* @param {String} [name] Element name. | ||
* @returns {Boolean} | ||
*/ | ||
is( type, name = null ) { | ||
const cutType = type && type.replace( /^view:/, '' ); | ||
if ( !name ) { | ||
return type == 'editableElement' || super.is( type ); | ||
return cutType == 'editableElement' || super.is( type ); | ||
} else { | ||
return ( type == 'editableElement' && name == this.name ) || super.is( type, name ); | ||
return ( cutType == 'editableElement' && name == this.name ) || super.is( type, name ); | ||
} | ||
@@ -79,0 +104,0 @@ } |
@@ -150,13 +150,23 @@ /** | ||
/** | ||
* Checks whether this view object is of the given type. | ||
* Checks whether this object is of the given. | ||
* | ||
* obj.is( 'element' ); // true | ||
* obj.is( 'li' ); // true | ||
* obj.is( 'element', 'li' ); // true | ||
* obj.is( 'text' ); // false | ||
* obj.is( 'element', 'img' ); // false | ||
* element.is( 'element' ); // -> true | ||
* element.is( 'node' ); // -> true | ||
* element.is( 'view:element' ); // -> true | ||
* element.is( 'view:node' ); // -> true | ||
* | ||
* Read more in {@link module:engine/view/node~Node#is `Node#is()`}. | ||
* element.is( 'model:element' ); // -> false | ||
* element.is( 'documentSelection' ); // -> false | ||
* | ||
* @param {String} type | ||
* Assuming that the object being checked is an element, you can also check its | ||
* {@link module:engine/view/element~Element#name name}: | ||
* | ||
* element.is( 'img' ); // -> true if this is an <img> element | ||
* element.is( 'element', 'img' ); // -> same as above | ||
* text.is( 'img' ); -> false | ||
* | ||
* {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method. | ||
* | ||
* @param {String} type Type to check when `name` parameter is present. | ||
* Otherwise, it acts like the `name` parameter. | ||
* @param {String} [name] Element name. | ||
@@ -166,6 +176,7 @@ * @returns {Boolean} | ||
is( type, name = null ) { | ||
const cutType = type.replace( /^view:/, '' ); | ||
if ( !name ) { | ||
return type == 'element' || type == this.name || super.is( type ); | ||
return cutType == 'element' || cutType == this.name || super.is( type ); | ||
} else { | ||
return type == 'element' && name == this.name; | ||
return cutType == 'element' && name == this.name; | ||
} | ||
@@ -172,0 +183,0 @@ } |
@@ -47,9 +47,34 @@ /** | ||
/** | ||
* @inheritDoc | ||
* Checks whether this object is of the given. | ||
* | ||
* emptyElement.is( 'emptyElement' ); // -> true | ||
* emptyElement.is( 'element' ); // -> true | ||
* emptyElement.is( 'node' ); // -> true | ||
* emptyElement.is( 'view:emptyElement' ); // -> true | ||
* emptyElement.is( 'view:element' ); // -> true | ||
* emptyElement.is( 'view:node' ); // -> true | ||
* | ||
* emptyElement.is( 'model:element' ); // -> false | ||
* emptyElement.is( 'documentFragment' ); // -> false | ||
* | ||
* Assuming that the object being checked is an empty element, you can also check its | ||
* {@link module:engine/view/emptyelement~EmptyElement#name name}: | ||
* | ||
* emptyElement.is( 'img' ); // -> true if this is a img element | ||
* emptyElement.is( 'emptyElement', 'img' ); // -> same as above | ||
* text.is( 'img' ); -> false | ||
* | ||
* {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method. | ||
* | ||
* @param {String} type Type to check when `name` parameter is present. | ||
* Otherwise, it acts like the `name` parameter. | ||
* @param {String} [name] Element name. | ||
* @returns {Boolean} | ||
*/ | ||
is( type, name = null ) { | ||
const cutType = type.replace( /^view:/, '' ); | ||
if ( !name ) { | ||
return type == 'emptyElement' || super.is( type ); | ||
return cutType == 'emptyElement' || super.is( type ); | ||
} else { | ||
return ( type == 'emptyElement' && name == this.name ) || super.is( type, name ); | ||
return ( cutType == 'emptyElement' && name == this.name ) || super.is( type, name ); | ||
} | ||
@@ -56,0 +81,0 @@ } |
@@ -293,21 +293,48 @@ /** | ||
/** | ||
* Checks whether this view object is of the given type. | ||
* Checks whether this object is of the given type. | ||
* | ||
* This method is useful when processing view tree objects that are of unknown type. For example, a function | ||
* may return {@link module:engine/view/documentfragment~DocumentFragment} or {@link module:engine/view/node~Node} | ||
* that can be either text node or element. This method can be used to check what kind of object is returned. | ||
* This method is useful when processing view objects that are of unknown type. For example, a function | ||
* may return a {@link module:engine/view/documentfragment~DocumentFragment} or a {@link module:engine/view/node~Node} | ||
* that can be either a text node or an element. This method can be used to check what kind of object is returned. | ||
* | ||
* obj.is( 'node' ); // true for any node, false for document fragment and text fragment | ||
* obj.is( 'documentFragment' ); // true for document fragment, false for any node | ||
* obj.is( 'element' ); // true for any element, false for text node or document fragment | ||
* obj.is( 'element', 'p' ); // true only for element which name is 'p' | ||
* obj.is( 'p' ); // shortcut for obj.is( 'element', 'p' ) | ||
* obj.is( 'text' ); // true for text node, false for element and document fragment | ||
* someObject.is( 'element' ); // -> true if this is an element | ||
* someObject.is( 'node' ); // -> true if this is a node (a text node or an element) | ||
* someObject.is( 'documentFragment' ); // -> true if this is a document fragment | ||
* | ||
* @param {'element'|'containerElement'|'attributeElement'|'emptyElement'|'uiElement'| | ||
* 'rootElement'|'documentFragment'|'text'|'textProxy'} type | ||
* Since this method is also available on a range of model objects, you can prefix the type of the object with | ||
* `model:` or `view:` to check, for example, if this is the model's or view's element: | ||
* | ||
* viewElement.is( 'view:element' ); // -> true | ||
* viewElement.is( 'model:element' ); // -> false | ||
* | ||
* By using this method it is also possible to check a name of an element: | ||
* | ||
* imgElement.is( 'img' ); // -> true | ||
* imgElement.is( 'element', 'img' ); // -> same as above | ||
* imgElement.is( 'view:element', 'img' ); // -> same as above, but more precise | ||
* | ||
* The list of view objects which implement the `is()` method: | ||
* | ||
* * {@link module:engine/view/attributeelement~AttributeElement#is `AttributeElement#is()`} | ||
* * {@link module:engine/view/containerelement~ContainerElement#is `ContainerElement#is()`} | ||
* * {@link module:engine/view/documentfragment~DocumentFragment#is `DocumentFragment#is()`} | ||
* * {@link module:engine/view/documentselection~DocumentSelection#is `DocumentSelection#is()`} | ||
* * {@link module:engine/view/editableelement~EditableElement#is `EditableElement#is()`} | ||
* * {@link module:engine/view/element~Element#is `Element#is()`} | ||
* * {@link module:engine/view/emptyelement~EmptyElement#is `EmptyElement#is()`} | ||
* * {@link module:engine/view/node~Node#is `Node#is()`} | ||
* * {@link module:engine/view/position~Position#is `Position#is()`} | ||
* * {@link module:engine/view/range~Range#is `Range#is()`} | ||
* * {@link module:engine/view/rooteditableelement~RootEditableElement#is `RootEditableElement#is()`} | ||
* * {@link module:engine/view/selection~Selection#is `Selection#is()`} | ||
* * {@link module:engine/view/text~Text#is `Text#is()`} | ||
* * {@link module:engine/view/textproxy~TextProxy#is `TextProxy#is()`} | ||
* * {@link module:engine/view/uielement~UIElement#is `UIElement#is()`} | ||
* | ||
* @method #is | ||
* @param {String} type | ||
* @returns {Boolean} | ||
*/ | ||
is( type ) { | ||
return type == 'node'; | ||
return type == 'node' || type == 'view:node'; | ||
} | ||
@@ -314,0 +341,0 @@ |
@@ -22,3 +22,3 @@ /** | ||
* | ||
* @extends module:engine/view/observer/observer~Observer.Observer | ||
* @extends module:engine/view/observer/observer~Observer | ||
*/ | ||
@@ -25,0 +25,0 @@ export default class FakeSelectionObserver extends Observer { |
@@ -14,3 +14,2 @@ /** | ||
import MutationObserver from './mutationobserver'; | ||
import log from '@ckeditor/ckeditor5-utils/src/log'; | ||
import { debounce } from 'lodash-es'; | ||
@@ -154,11 +153,8 @@ | ||
if ( ++this._loopbackCounter > 60 ) { | ||
/** | ||
* Selection change observer detected an infinite rendering loop. | ||
* Most probably you try to put the selection in the position which is not allowed | ||
* by the browser and browser fixes it automatically what causes `selectionchange` event on | ||
* which a loopback through a model tries to re-render the wrong selection and again. | ||
* | ||
* @error selectionchange-infinite-loop | ||
*/ | ||
log.warn( 'selectionchange-infinite-loop: Selection change observer detected an infinite rendering loop.' ); | ||
// Selection change observer detected an infinite rendering loop. | ||
// Most probably you try to put the selection in the position which is not allowed | ||
// by the browser and browser fixes it automatically what causes `selectionchange` event on | ||
// which a loopback through a model tries to re-render the wrong selection and again. | ||
// | ||
// @if CK_DEBUG // console.warn( 'Selection change observer detected an infinite rendering loop.' ); | ||
@@ -165,0 +161,0 @@ return; |
@@ -210,2 +210,21 @@ /** | ||
/** | ||
* Checks whether this object is of the given type. | ||
* | ||
* position.is( 'position' ); // -> true | ||
* position.is( 'view:position' ); // -> true | ||
* | ||
* position.is( 'model:position' ); // -> false | ||
* position.is( 'element' ); // -> false | ||
* position.is( 'range' ); // -> false | ||
* | ||
* {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method. | ||
* | ||
* @param {String} type | ||
* @returns {Boolean} | ||
*/ | ||
is( type ) { | ||
return type == 'position' || type == 'view:position'; | ||
} | ||
/** | ||
* Checks whether this position equals given position. | ||
@@ -212,0 +231,0 @@ * |
@@ -398,2 +398,21 @@ /** | ||
/** | ||
* Checks whether this object is of the given type. | ||
* | ||
* range.is( 'range' ); // -> true | ||
* range.is( 'view:range' ); // -> true | ||
* | ||
* range.is( 'model:range' ); // -> false | ||
* range.is( 'element' ); // -> false | ||
* range.is( 'selection' ); // -> false | ||
* | ||
* {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method. | ||
* | ||
* @param {String} type | ||
* @returns {Boolean} | ||
*/ | ||
is( type ) { | ||
return type == 'range' || type == 'view:range'; | ||
} | ||
/** | ||
* Checks and returns whether this range intersects with the given range. | ||
@@ -400,0 +419,0 @@ * |
@@ -41,9 +41,36 @@ /** | ||
/** | ||
* @inheritDoc | ||
* Checks whether this object is of the given. | ||
* | ||
* rootEditableElement.is( 'rootEditableElement' ); // -> true | ||
* rootEditableElement.is( 'editableElement' ); // -> true | ||
* rootEditableElement.is( 'element' ); // -> true | ||
* rootEditableElement.is( 'node' ); // -> true | ||
* rootEditableElement.is( 'view:rootEditableElement' ); // -> true | ||
* rootEditableElement.is( 'view:editableElement' ); // -> true | ||
* rootEditableElement.is( 'view:element' ); // -> true | ||
* rootEditableElement.is( 'view:node' ); // -> true | ||
* | ||
* rootEditableElement.is( 'model:element' ); // -> false | ||
* rootEditableElement.is( 'documentFragment' ); // -> false | ||
* | ||
* Assuming that the object being checked is a root editbale element, you can also check its | ||
* {@link module:engine/view/rooteditableelement~RootEditableElement#name name}: | ||
* | ||
* rootEditableElement.is( 'div' ); // -> true if this is a div root editable element | ||
* rootEditableElement.is( 'rootEditableElement', 'div' ); // -> same as above | ||
* text.is( 'div' ); -> false | ||
* | ||
* {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method. | ||
* | ||
* @param {String} type Type to check when `name` parameter is present. | ||
* Otherwise, it acts like the `name` parameter. | ||
* @param {String} [name] Element name. | ||
* @returns {Boolean} | ||
*/ | ||
is( type, name = null ) { | ||
const cutType = type.replace( /^view:/, '' ); | ||
if ( !name ) { | ||
return type == 'rootElement' || super.is( type ); | ||
return cutType == 'rootElement' || super.is( type ); | ||
} else { | ||
return ( type == 'rootElement' && name == this.name ) || super.is( type, name ); | ||
return ( cutType == 'rootElement' && name == this.name ) || super.is( type, name ); | ||
} | ||
@@ -50,0 +77,0 @@ } |
@@ -601,11 +601,13 @@ /** | ||
/** | ||
* Checks whether object is of given type following the convention set by | ||
* {@link module:engine/view/node~Node#is `Node#is()`}. | ||
* Checks whether this object is of the given type. | ||
* | ||
* const selection = new Selection( ... ); | ||
* selection.is( 'selection' ); // -> true | ||
* selection.is( 'view:selection' ); // -> true | ||
* | ||
* selection.is( 'selection' ); // true | ||
* selection.is( 'node' ); // false | ||
* selection.is( 'element' ); // false | ||
* selection.is( 'model:selection' ); // -> false | ||
* selection.is( 'element' ); // -> false | ||
* selection.is( 'range' ); // -> false | ||
* | ||
* {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method. | ||
* | ||
* @param {String} type | ||
@@ -615,3 +617,3 @@ * @returns {Boolean} | ||
is( type ) { | ||
return type == 'selection'; | ||
return type == 'selection' || type == 'view:selection'; | ||
} | ||
@@ -618,0 +620,0 @@ |
@@ -45,6 +45,20 @@ /** | ||
/** | ||
* @inheritDoc | ||
* Checks whether this object is of the given type. | ||
* | ||
* text.is( 'text' ); // -> true | ||
* text.is( 'node' ); // -> true | ||
* text.is( 'view:text' ); // -> true | ||
* text.is( 'view:node' ); // -> true | ||
* | ||
* text.is( 'model:text' ); // -> false | ||
* text.is( 'element' ); // -> false | ||
* text.is( 'range' ); // -> false | ||
* | ||
* {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method. | ||
* | ||
* @param {String} type | ||
* @returns {Boolean} | ||
*/ | ||
is( type ) { | ||
return type == 'text' || super.is( type ); | ||
return type == 'text' || type == 'view:text' || super.is( type ); | ||
} | ||
@@ -51,0 +65,0 @@ |
@@ -144,6 +144,13 @@ /** | ||
/** | ||
* Checks whether given view tree object is of given type. | ||
* Checks whether this object is of the given type. | ||
* | ||
* Read more in {@link module:engine/view/node~Node#is}. | ||
* textProxy.is( 'textProxy' ); // -> true | ||
* textProxy.is( 'view:textProxy' ); // -> true | ||
* | ||
* textProxy.is( 'model:textProxy' ); // -> false | ||
* textProxy.is( 'element' ); // -> false | ||
* textProxy.is( 'range' ); // -> false | ||
* | ||
* {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method. | ||
* | ||
* @param {String} type | ||
@@ -153,3 +160,3 @@ * @returns {Boolean} | ||
is( type ) { | ||
return type == 'textProxy'; | ||
return type == 'textProxy' || type == 'view:textProxy'; | ||
} | ||
@@ -156,0 +163,0 @@ |
@@ -60,9 +60,34 @@ /** | ||
/** | ||
* @inheritDoc | ||
* Checks whether this object is of the given. | ||
* | ||
* uiElement.is( 'uiElement' ); // -> true | ||
* uiElement.is( 'element' ); // -> true | ||
* uiElement.is( 'node' ); // -> true | ||
* uiElement.is( 'view:uiElement' ); // -> true | ||
* uiElement.is( 'view:element' ); // -> true | ||
* uiElement.is( 'view:node' ); // -> true | ||
* | ||
* uiElement.is( 'model:element' ); // -> false | ||
* uiElement.is( 'documentFragment' ); // -> false | ||
* | ||
* Assuming that the object being checked is an ui element, you can also check its | ||
* {@link module:engine/view/uielement~UIElement#name name}: | ||
* | ||
* uiElement.is( 'span' ); // -> true if this is a span ui element | ||
* uiElement.is( 'uiElement', 'span' ); // -> same as above | ||
* text.is( 'span' ); -> false | ||
* | ||
* {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method. | ||
* | ||
* @param {String} type Type to check when `name` parameter is present. | ||
* Otherwise, it acts like the `name` parameter. | ||
* @param {String} [name] Element name. | ||
* @returns {Boolean} | ||
*/ | ||
is( type, name = null ) { | ||
const cutType = type.replace( /^view:/, '' ); | ||
if ( !name ) { | ||
return type == 'uiElement' || super.is( type ); | ||
return cutType == 'uiElement' || super.is( type ); | ||
} else { | ||
return ( type == 'uiElement' && name == this.name ) || super.is( type, name ); | ||
return ( cutType == 'uiElement' && name == this.name ) || super.is( type, name ); | ||
} | ||
@@ -69,0 +94,0 @@ } |
@@ -30,3 +30,3 @@ /** | ||
* Unlike `DowncastWriter`, which is available in the {@link module:engine/view/view~View#change `View#change()`} block, | ||
* `UpcastWriter` can wherever you need it: | ||
* `UpcastWriter` can be created wherever you need it: | ||
* | ||
@@ -177,2 +177,19 @@ * const writer = new UpcastWriter(); | ||
/** | ||
* Removes given element from view structure and places its children in its position. | ||
* It does nothing if element has no parent. | ||
* | ||
* @param {module:engine/view/element~Element} element Element to unwrap. | ||
*/ | ||
unwrapElement( element ) { | ||
const parent = element.parent; | ||
if ( parent ) { | ||
const index = parent.getChildIndex( element ); | ||
this.remove( element ); | ||
this.insertChild( index, element.getChildren(), parent ); | ||
} | ||
} | ||
/** | ||
* Renames element by creating a copy of a given element but with its name changed and then moving contents of the | ||
@@ -179,0 +196,0 @@ * old element to the new one. |
@@ -27,3 +27,2 @@ /** | ||
import ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin'; | ||
import log from '@ckeditor/ckeditor5-utils/src/log'; | ||
import mix from '@ckeditor/ckeditor5-utils/src/mix'; | ||
@@ -402,10 +401,7 @@ import { scrollViewportToShowTarget } from '@ckeditor/ckeditor5-utils/src/dom/scroll'; | ||
} else { | ||
/** | ||
* Before focusing view document, selection should be placed inside one of the view's editables. | ||
* Normally its selection will be converted from model document (which have default selection), but | ||
* when using view document on its own, we need to manually place selection before focusing it. | ||
* | ||
* @error view-focus-no-selection | ||
*/ | ||
log.warn( 'view-focus-no-selection: There is no selection in any editable to focus.' ); | ||
// Before focusing view document, selection should be placed inside one of the view's editables. | ||
// Normally its selection will be converted from model document (which have default selection), but | ||
// when using view document on its own, we need to manually place selection before focusing it. | ||
// | ||
// @if CK_DEBUG // console.warn( 'There is no selection in any editable to focus.' ); | ||
} | ||
@@ -412,0 +408,0 @@ } |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
1625148
36749
+ Added@ckeditor/ckeditor5-utils@14.0.0(transitive)
- Removed@ckeditor/ckeditor5-utils@13.0.1(transitive)