@ckeditor/ckeditor5-engine
Advanced tools
Comparing version 31.0.0 to 31.1.0
{ | ||
"name": "@ckeditor/ckeditor5-engine", | ||
"version": "31.0.0", | ||
"version": "31.1.0", | ||
"description": "The editing engine of CKEditor 5 – the best browser-based rich text editor.", | ||
@@ -26,26 +26,26 @@ "keywords": [ | ||
"dependencies": { | ||
"@ckeditor/ckeditor5-utils": "^31.0.0", | ||
"@ckeditor/ckeditor5-utils": "^31.1.0", | ||
"lodash-es": "^4.17.15" | ||
}, | ||
"devDependencies": { | ||
"@ckeditor/ckeditor5-basic-styles": "^31.0.0", | ||
"@ckeditor/ckeditor5-block-quote": "^31.0.0", | ||
"@ckeditor/ckeditor5-clipboard": "^31.0.0", | ||
"@ckeditor/ckeditor5-cloud-services": "^31.0.0", | ||
"@ckeditor/ckeditor5-core": "^31.0.0", | ||
"@ckeditor/ckeditor5-editor-classic": "^31.0.0", | ||
"@ckeditor/ckeditor5-enter": "^31.0.0", | ||
"@ckeditor/ckeditor5-essentials": "^31.0.0", | ||
"@ckeditor/ckeditor5-heading": "^31.0.0", | ||
"@ckeditor/ckeditor5-image": "^31.0.0", | ||
"@ckeditor/ckeditor5-link": "^31.0.0", | ||
"@ckeditor/ckeditor5-list": "^31.0.0", | ||
"@ckeditor/ckeditor5-mention": "^31.0.0", | ||
"@ckeditor/ckeditor5-paragraph": "^31.0.0", | ||
"@ckeditor/ckeditor5-table": "^31.0.0", | ||
"@ckeditor/ckeditor5-theme-lark": "^31.0.0", | ||
"@ckeditor/ckeditor5-typing": "^31.0.0", | ||
"@ckeditor/ckeditor5-ui": "^31.0.0", | ||
"@ckeditor/ckeditor5-undo": "^31.0.0", | ||
"@ckeditor/ckeditor5-widget": "^31.0.0", | ||
"@ckeditor/ckeditor5-basic-styles": "^31.1.0", | ||
"@ckeditor/ckeditor5-block-quote": "^31.1.0", | ||
"@ckeditor/ckeditor5-clipboard": "^31.1.0", | ||
"@ckeditor/ckeditor5-cloud-services": "^31.1.0", | ||
"@ckeditor/ckeditor5-core": "^31.1.0", | ||
"@ckeditor/ckeditor5-editor-classic": "^31.1.0", | ||
"@ckeditor/ckeditor5-enter": "^31.1.0", | ||
"@ckeditor/ckeditor5-essentials": "^31.1.0", | ||
"@ckeditor/ckeditor5-heading": "^31.1.0", | ||
"@ckeditor/ckeditor5-image": "^31.1.0", | ||
"@ckeditor/ckeditor5-link": "^31.1.0", | ||
"@ckeditor/ckeditor5-list": "^31.1.0", | ||
"@ckeditor/ckeditor5-mention": "^31.1.0", | ||
"@ckeditor/ckeditor5-paragraph": "^31.1.0", | ||
"@ckeditor/ckeditor5-table": "^31.1.0", | ||
"@ckeditor/ckeditor5-theme-lark": "^31.1.0", | ||
"@ckeditor/ckeditor5-typing": "^31.1.0", | ||
"@ckeditor/ckeditor5-ui": "^31.1.0", | ||
"@ckeditor/ckeditor5-undo": "^31.1.0", | ||
"@ckeditor/ckeditor5-widget": "^31.1.0", | ||
"webpack": "^4.43.0", | ||
@@ -52,0 +52,0 @@ "webpack-cli": "^3.3.11" |
@@ -530,3 +530,3 @@ /** | ||
/** | ||
* Event fired after {@link #get get() method} has been run. | ||
* Event fired after the {@link #get get() method} has been run. | ||
* | ||
@@ -574,14 +574,14 @@ * The `get` event is fired by decorated {@link #get} method. | ||
// Sort the markers in a stable fashion to ensure that the order that they are | ||
// Sort the markers in a stable fashion to ensure that the order in which they are | ||
// added to the model's marker collection does not affect how they are | ||
// downcast. One particular use case that we're targeting here is one where | ||
// downcast. One particular use case that we are targeting here, is one where | ||
// two markers are adjacent but not overlapping, such as an insertion/deletion | ||
// suggestion pair represting the replacement of a range of text. In this | ||
// suggestion pair representing the replacement of a range of text. In this | ||
// case, putting the markers in DOM order causes the first marker's end to be | ||
// serialized right after the second marker's start, while putting the markers | ||
// in reverse DOM order causes it to be right before the second marker's | ||
// start. So, we sort in a way that ensures non-intersecting ranges are in | ||
// start. So, we sort these in a way that ensures non-intersecting ranges are in | ||
// reverse DOM order, and intersecting ranges are in something approximating | ||
// reverse DOM order (since reverse DOM order doesn't have a precise meaning | ||
// when working with intersectng ranges). | ||
// when working with intersecting ranges). | ||
return result.sort( ( [ n1, r1 ], [ n2, r2 ] ) => { | ||
@@ -588,0 +588,0 @@ if ( r1.end.compareWith( r2.start ) !== 'after' ) { |
@@ -70,4 +70,4 @@ /** | ||
* @param {Object} [options.domConverter=null] When set to an actual {@link module:engine/view/domconverter~DomConverter DomConverter} | ||
* instance it lets the conversion go through exactly the same flow the editing view is going, i.e. with view data | ||
* filtering. Otherwise the simple stub is used. | ||
* instance, it lets the conversion go through exactly the same flow the editing view is going through, | ||
* i.e. with view data filtering. Otherwise the simple stub is used. | ||
* @returns {String} The stringified data. | ||
@@ -257,4 +257,4 @@ */ | ||
* @param {Object} [options.domConverter={}] When set to an actual {@link module:engine/view/domconverter~DomConverter DomConverter} | ||
* instance it lets the conversion go through exactly the same flow the editing view is going, i.e. with view data | ||
* filtering. Otherwise the simple stub is used. | ||
* instance, it lets the conversion go through exactly the same flow the editing view is going through, | ||
* i.e. with view data filtering. Otherwise the simple stub is used. | ||
* @returns {String} An HTML-like string representing the view. | ||
@@ -650,4 +650,4 @@ */ | ||
* @param {Object} [options.domConverter={}] When set to an actual {@link module:engine/view/domconverter~DomConverter DomConverter} | ||
* instance it lets the conversion go through exactly the same flow the editing view is going, i.e. with view data | ||
* filtering. Otherwise the simple stub is used. | ||
* instance, it lets the conversion go through exactly the same flow the editing view is going through, | ||
* i.e. with view data filtering. Otherwise the simple stub is used. | ||
* {@link module:engine/view/rawelement~RawElement} will be printed. | ||
@@ -654,0 +654,0 @@ */ |
@@ -131,6 +131,6 @@ /** | ||
// This might be null ie when editor data is empty or the selection is inside limit element | ||
// This might be null, i.e. when the editor data is empty or the selection is inside a limit element | ||
// that doesn't allow text inside. | ||
// In the first case there is no need to fix the selection range. | ||
// In the second let's go up to the outer selectable element | ||
// In the first case, there is no need to fix the selection range. | ||
// In the second, let's go up to the outer selectable element | ||
if ( !nearestSelectionRange ) { | ||
@@ -267,31 +267,38 @@ const ancestorObject = originalPosition.getAncestors().reverse().find( item => schema.isObject( item ) ); | ||
// Returns a minimal non-intersecting array of ranges. | ||
// | ||
// @param {Array.<module:engine/model/range~Range>} ranges | ||
// @returns {Array.<module:engine/model/range~Range>} | ||
function mergeIntersectingRanges( ranges ) { | ||
const nonIntersectingRanges = []; | ||
/** | ||
* Returns a minimal non-intersecting array of ranges without duplicates. | ||
* | ||
* @param {Array.<module:engine/model/range~Range>} Ranges to merge. | ||
* @returns {Array.<module:engine/model/range~Range>} Array of unique and nonIntersecting ranges. | ||
*/ | ||
export function mergeIntersectingRanges( ranges ) { | ||
const rangesToMerge = [ ...ranges ]; | ||
const rangeIndexesToRemove = new Set(); | ||
let currentRangeIndex = 1; | ||
// First range will always be fine. | ||
nonIntersectingRanges.push( ranges.shift() ); | ||
while ( currentRangeIndex < rangesToMerge.length ) { | ||
const currentRange = rangesToMerge[ currentRangeIndex ]; | ||
const previousRanges = rangesToMerge.slice( 0, currentRangeIndex ); | ||
for ( const range of ranges ) { | ||
const previousRange = nonIntersectingRanges.pop(); | ||
for ( const [ previousRangeIndex, previousRange ] of previousRanges.entries() ) { | ||
if ( rangeIndexesToRemove.has( previousRangeIndex ) ) { | ||
continue; | ||
} | ||
if ( range.isEqual( previousRange ) ) { | ||
// Use only one of two identical ranges. | ||
nonIntersectingRanges.push( previousRange ); | ||
} else if ( range.isIntersecting( previousRange ) ) { | ||
// Get the sum of two ranges. | ||
const start = previousRange.start.isAfter( range.start ) ? range.start : previousRange.start; | ||
const end = previousRange.end.isAfter( range.end ) ? previousRange.end : range.end; | ||
if ( currentRange.isEqual( previousRange ) ) { | ||
rangeIndexesToRemove.add( previousRangeIndex ); | ||
} else if ( currentRange.isIntersecting( previousRange ) ) { | ||
rangeIndexesToRemove.add( previousRangeIndex ); | ||
rangeIndexesToRemove.add( currentRangeIndex ); | ||
const merged = new Range( start, end ); | ||
nonIntersectingRanges.push( merged ); | ||
} else { | ||
nonIntersectingRanges.push( previousRange ); | ||
nonIntersectingRanges.push( range ); | ||
const mergedRange = currentRange.getJoined( previousRange ); | ||
rangesToMerge.push( mergedRange ); | ||
} | ||
} | ||
currentRangeIndex++; | ||
} | ||
const nonIntersectingRanges = rangesToMerge.filter( ( _, index ) => !rangeIndexesToRemove.has( index ) ); | ||
return nonIntersectingRanges; | ||
@@ -298,0 +305,0 @@ } |
@@ -27,2 +27,3 @@ /** | ||
import global from '@ckeditor/ckeditor5-utils/src/dom/global'; | ||
import { logWarning } from '@ckeditor/ckeditor5-utils/src/ckeditorerror'; | ||
import indexOf from '@ckeditor/ckeditor5-utils/src/dom/indexof'; | ||
@@ -35,2 +36,4 @@ import getAncestors from '@ckeditor/ckeditor5-utils/src/dom/getancestors'; | ||
const MARKED_NBSP_FILLER_REF = MARKED_NBSP_FILLER( document ); // eslint-disable-line new-cap | ||
const UNSAFE_ATTRIBUTE_NAME_PREFIX = 'data-ck-unsafe-attribute-'; | ||
const UNSAFE_ELEMENT_REPLACEMENT_ATTRIBUTE = 'data-ck-unsafe-element'; | ||
@@ -78,10 +81,2 @@ /** | ||
/** | ||
* Main switch for new rendering approach in the editing view. | ||
* | ||
* @protected | ||
* @member {Boolean} | ||
*/ | ||
this.experimentalRenderingMode = false; | ||
/** | ||
* The mode of a block filler used by the DOM converter. | ||
@@ -248,17 +243,43 @@ * | ||
/** | ||
* Decides whether given pair of attribute key and value should be passed further down the pipeline. | ||
* Decides whether a given pair of attribute key and value should be passed further down the pipeline. | ||
* | ||
* @param {String} attributeKey | ||
* @param {String} attributeValue | ||
* @param {String} elementName Element name in lower case. | ||
* @returns {Boolean} | ||
*/ | ||
shouldRenderAttribute( attributeKey, attributeValue ) { | ||
if ( !this.experimentalRenderingMode || this.renderingMode === 'data' ) { | ||
shouldRenderAttribute( attributeKey, attributeValue, elementName ) { | ||
if ( this.renderingMode === 'data' ) { | ||
return true; | ||
} | ||
return !( attributeKey.toLowerCase().startsWith( 'on' ) || | ||
attributeValue.match( /(\b)(on\S+)(\s*)=|javascript:|(<\s*)(\/*)script/i ) || | ||
attributeValue.match( /data:(?!image\/(png|jpeg|gif|webp))/i ) | ||
); | ||
attributeKey = attributeKey.toLowerCase(); | ||
if ( attributeKey.startsWith( 'on' ) ) { | ||
return false; | ||
} | ||
if ( | ||
attributeKey === 'srcdoc' && | ||
attributeValue.match( /\bon\S+\s*=|javascript:|<\s*\/*script/i ) | ||
) { | ||
return false; | ||
} | ||
if ( | ||
elementName === 'img' && | ||
( attributeKey === 'src' || attributeKey === 'srcset' ) | ||
) { | ||
return true; | ||
} | ||
if ( elementName === 'source' && attributeKey === 'srcset' ) { | ||
return true; | ||
} | ||
if ( attributeValue.match( /^\s*(javascript:|data:(image\/svg|text\/x?html))/i ) ) { | ||
return false; | ||
} | ||
return true; | ||
} | ||
@@ -274,3 +295,3 @@ | ||
// For data pipeline we pass the HTML as-is. | ||
if ( !this.experimentalRenderingMode || this.renderingMode === 'data' ) { | ||
if ( this.renderingMode === 'data' ) { | ||
domElement.innerHTML = html; | ||
@@ -302,7 +323,3 @@ | ||
for ( const attributeName of currentNode.getAttributeNames() ) { | ||
const attributeValue = currentNode.getAttribute( attributeName ); | ||
if ( !this.shouldRenderAttribute( attributeName, attributeValue ) ) { | ||
currentNode.removeAttribute( attributeName ); | ||
} | ||
this.setDomElementAttribute( currentNode, attributeName, currentNode.getAttribute( attributeName ) ); | ||
} | ||
@@ -314,2 +331,4 @@ | ||
if ( this._shouldRenameElement( elementName ) ) { | ||
logWarning( 'domconverter-unsafe-element-detected', { unsafeElement: currentNode } ); | ||
currentNode.replaceWith( this._createReplacementDomElement( elementName, currentNode ) ); | ||
@@ -374,2 +393,4 @@ } | ||
if ( this._shouldRenameElement( viewNode.name ) ) { | ||
logWarning( 'domconverter-unsafe-element-detected', { unsafeElement: viewNode } ); | ||
domElement = this._createReplacementDomElement( viewNode.name ); | ||
@@ -394,9 +415,3 @@ } else if ( viewNode.hasAttribute( 'xmlns' ) ) { | ||
for ( const key of viewNode.getAttributeKeys() ) { | ||
const value = viewNode.getAttribute( key ); | ||
if ( !this.shouldRenderAttribute( key, value ) ) { | ||
continue; | ||
} | ||
domElement.setAttribute( key, value ); | ||
this.setDomElementAttribute( domElement, key, viewNode.getAttribute( key ), viewNode ); | ||
} | ||
@@ -416,2 +431,56 @@ } | ||
/** | ||
* Sets the attribute on a DOM element. | ||
* | ||
* **Note**: To remove the attribute, use {@link #removeDomElementAttribute}. | ||
* | ||
* @param {HTMLElement} domElement The DOM element the attribute should be set on. | ||
* @param {String} key The name of the attribute | ||
* @param {String} value The value of the attribute | ||
* @param {module:engine/view/element~Element} [relatedViewElement] The view element related to the `domElement` (if there is any). | ||
* It helps decide whether the attribute set is unsafe. For instance, view elements created via | ||
* {@link module:engine/view/downcastwriter~DowncastWriter} methods can allow certain attributes that would normally be filtered out. | ||
*/ | ||
setDomElementAttribute( domElement, key, value, relatedViewElement = null ) { | ||
const shouldRenderAttribute = this.shouldRenderAttribute( key, value, domElement.tagName.toLowerCase() ) || | ||
relatedViewElement && relatedViewElement.shouldRenderUnsafeAttribute( key ); | ||
if ( !shouldRenderAttribute ) { | ||
logWarning( 'domconverter-unsafe-attribute-detected', { domElement, key, value } ); | ||
} | ||
// The old value was safe but the new value is unsafe. | ||
if ( domElement.hasAttribute( key ) && !shouldRenderAttribute ) { | ||
domElement.removeAttribute( key ); | ||
} | ||
// The old value was unsafe (but prefixed) but the new value will be safe (will be unprefixed). | ||
else if ( domElement.hasAttribute( UNSAFE_ATTRIBUTE_NAME_PREFIX + key ) && shouldRenderAttribute ) { | ||
domElement.removeAttribute( UNSAFE_ATTRIBUTE_NAME_PREFIX + key ); | ||
} | ||
// If the attribute should not be rendered, rename it (instead of removing) to give developers some idea of what | ||
// is going on (https://github.com/ckeditor/ckeditor5/issues/10801). | ||
domElement.setAttribute( shouldRenderAttribute ? key : UNSAFE_ATTRIBUTE_NAME_PREFIX + key, value ); | ||
} | ||
/** | ||
* Removes an attribute from a DOM element. | ||
* | ||
* **Note**: To set the attribute, use {@link #setDomElementAttribute}. | ||
* | ||
* @param {HTMLElement} domElement The DOM element the attribute should be removed from. | ||
* @param {String} key The name of the attribute. | ||
*/ | ||
removeDomElementAttribute( domElement, key ) { | ||
// See #_createReplacementDomElement() to learn what this is. | ||
if ( key == UNSAFE_ELEMENT_REPLACEMENT_ATTRIBUTE ) { | ||
return; | ||
} | ||
domElement.removeAttribute( key ); | ||
// See setDomElementAttribute() to learn what this is. | ||
domElement.removeAttribute( UNSAFE_ATTRIBUTE_NAME_PREFIX + key ); | ||
} | ||
/** | ||
* Converts children of the view element to DOM using the | ||
@@ -1492,3 +1561,3 @@ * {@link module:engine/view/domconverter~DomConverter#viewToDom} method. | ||
/** | ||
* Checks whether given element name should be renamed in a current rendering mode. | ||
* Checks whether a given element name should be renamed in a current rendering mode. | ||
* | ||
@@ -1500,7 +1569,7 @@ * @private | ||
_shouldRenameElement( elementName ) { | ||
return this.experimentalRenderingMode && this.renderingMode == 'editing' && elementName == 'script'; | ||
return this.renderingMode == 'editing' && elementName.toLowerCase() == 'script'; | ||
} | ||
/** | ||
* Return a <span> element with special attribute holding the name of the original element. | ||
* Return a <span> element with a special attribute holding the name of the original element. | ||
* Optionally, copy all the attributes of the original element if that element is provided. | ||
@@ -1517,3 +1586,3 @@ * | ||
// Mark the span replacing a script as hidden. | ||
newDomElement.setAttribute( 'data-ck-hidden', elementName ); | ||
newDomElement.setAttribute( UNSAFE_ELEMENT_REPLACEMENT_ATTRIBUTE, elementName ); | ||
@@ -1594,1 +1663,42 @@ if ( originalDomElement ) { | ||
*/ | ||
/** | ||
* The {@link module:engine/view/domconverter~DomConverter} detected a `<script>` element that may disrupt the | ||
* {@glink framework/guides/architecture/editing-engine#editing-pipeline editing pipeline} of the editor. To avoid this, | ||
* the `<script>` element was renamed to `<span data-ck-unsafe-element="script"></span>`. | ||
* | ||
* @error domconverter-unsafe-element-detected | ||
* @param {module:engine/model/element~Element|HTMLElement} unsafeElement The editing view or DOM element | ||
* that was renamed. | ||
*/ | ||
/** | ||
* The {@link module:engine/view/domconverter~DomConverter} detected an interactive attribute in the | ||
* {@glink framework/guides/architecture/editing-engine#editing-pipeline editing pipeline}. For the best | ||
* editing experience, the attribute was renamed to `data-ck-unsafe-attribute-[original attribute name]`. | ||
* | ||
* If you are the author of the plugin that generated this attribute and you want it to be preserved | ||
* in the editing pipeline, you can configure this when creating the element | ||
* using {@link module:engine/view/downcastwriter~DowncastWriter} during the | ||
* {@glink framework/guides/architecture/editing-engine#conversion model–view conversion}. Methods such as | ||
* {@link module:engine/view/downcastwriter~DowncastWriter#createContainerElement}, | ||
* {@link module:engine/view/downcastwriter~DowncastWriter#createAttributeElement}, or | ||
* {@link module:engine/view/downcastwriter~DowncastWriter#createEmptyElement} | ||
* accept an option that will disable filtering of specific attributes: | ||
* | ||
* const paragraph = writer.createContainerElement( 'p', | ||
* { | ||
* class: 'clickable-paragraph', | ||
* onclick: 'alert( "Paragraph clicked!" )' | ||
* }, | ||
* { | ||
* // Make sure the "onclick" attribute will pass through. | ||
* renderUnsafeAttributes: [ 'onclick' ] | ||
* } | ||
* ); | ||
* | ||
* @error domconverter-unsafe-attribute-detected | ||
* @param {HTMLElement} domElement The DOM element the attribute was set on. | ||
* @param {String} key The original name of the attribute | ||
* @param {String} value The value of the original attribute | ||
*/ |
@@ -141,2 +141,17 @@ /** | ||
this._isAllowedInsideAttributeElement = false; | ||
/** | ||
* A list of attribute names that should be rendered in the editing pipeline even though filtering mechanisms | ||
* implemented in the {@link module:engine/view/domconverter~DomConverter} (for instance, | ||
* {@link module:engine/view/domconverter~DomConverter#shouldRenderAttribute}) would filter them out. | ||
* | ||
* These attributes can be specified as an option when the element is created by | ||
* the {@link module:engine/view/downcastwriter~DowncastWriter}. To check whether an unsafe an attribute should | ||
* be permitted, use the {@link #shouldRenderUnsafeAttribute} method. | ||
* | ||
* @private | ||
* @readonly | ||
* @member {Array.<String>} | ||
*/ | ||
this._unsafeAttributesToRender = []; | ||
} | ||
@@ -577,2 +592,15 @@ | ||
/** | ||
* Decides whether an unsafe attribute is whitelisted and should be rendered in the editing pipeline even though filtering mechanisms | ||
* like {@link module:engine/view/domconverter~DomConverter#shouldRenderAttribute} say it should not. | ||
* | ||
* Unsafe attribute names can be specified when creating an element via {@link module:engine/view/downcastwriter~DowncastWriter}. | ||
* | ||
* @param {String} attributeName The name of the attribute to be checked. | ||
* @returns {Boolean} | ||
*/ | ||
shouldRenderUnsafeAttribute( attributeName ) { | ||
return this._unsafeAttributesToRender.includes( attributeName ); | ||
} | ||
/** | ||
* Clones provided element. | ||
@@ -579,0 +607,0 @@ * |
@@ -534,3 +534,3 @@ /** | ||
* 'title', // Match `title` attribute (can be empty). | ||
* /^data-*$/, // Match attributes starting with `data-` e.g. `data-foo` with any value (can be empty). | ||
* /^data-*$/ // Match attributes starting with `data-` e.g. `data-foo` with any value (can be empty). | ||
* ] | ||
@@ -545,3 +545,4 @@ * }; | ||
* key: 'type', // Match `type` as an attribute key. | ||
* value: /^(text|number|date)$/ }, // Match `text`, `number` or `date` values. | ||
* value: /^(text|number|date)$/ // Match `text`, `number` or `date` values. | ||
* }, | ||
* { | ||
@@ -577,3 +578,3 @@ * key: /^data-.*$/, // Match attributes starting with `data-` e.g. `data-foo`. | ||
* name: 'p', | ||
* attributes: { | ||
* styles: { | ||
* color: /rgb\((\d{1,3}), (\d{1,3}), (\d{1,3})\)/, // Match `color` in RGB format only. | ||
@@ -588,5 +589,5 @@ * 'font-weight': 600, // Match `font-weight` only if it's `600`. | ||
* name: 'p', | ||
* attributes: [ | ||
* styles: [ | ||
* 'color', // Match `color` with any value. | ||
* /^border.*$/, // Match all border properties. | ||
* /^border.*$/ // Match all border properties. | ||
* ] | ||
@@ -598,6 +599,7 @@ * }; | ||
* name: 'p', | ||
* attributes: [ | ||
* styles: [ | ||
* { | ||
* key: 'color', // Match `color` as an property key. | ||
* value: /rgb\((\d{1,3}), (\d{1,3}), (\d{1,3})\)/, // Match RGB format only. | ||
* key: 'color', // Match `color` as an property key. | ||
* value: /rgb\((\d{1,3}), (\d{1,3}), (\d{1,3})\)/ // Match RGB format only. | ||
* }, | ||
* { | ||
@@ -655,2 +657,3 @@ * key: /^border.*$/, // Match any border style. | ||
* value: true | ||
* }, | ||
* { | ||
@@ -709,7 +712,5 @@ * key: /^image-side-(left|right)$/, // Match `image-side-left` or `image-side-right` class. | ||
* @property {String|RegExp} [name] View element name to match. | ||
* @property {String|RegExp|Array.<String|RegExp>} [classes] View element's class name(s) to match. | ||
* @property {Object} [styles] Object with key-value pairs representing styles to match. | ||
* Each object key represents style name. Value can be given as `String` or `RegExp`. | ||
* @property {Object} [attributes] Object with key-value pairs representing attributes to match. | ||
* Each object key represents attribute name. Value can be given as `String` or `RegExp`. | ||
* @property {Boolean|String|RegExp|Object|Array.<String|RegExp|Object>} [classes] View element's classes to match. | ||
* @property {Boolean|String|RegExp|Object|Array.<String|RegExp|Object>} [styles] View element's styles to match. | ||
* @property {Boolean|String|RegExp|Object|Array.<String|RegExp|Object>} [attributes] View element's attributes to match. | ||
*/ | ||
@@ -716,0 +717,0 @@ |
@@ -84,3 +84,3 @@ /** | ||
/** | ||
* When called, starts clearing the {@link #_loopbackCounter} counter in intervals of time. When the number of selection | ||
* When called, starts clearing the {@link #_loopbackCounter} counter in time intervals. When the number of selection | ||
* changes exceeds a certain limit within the interval of time, the observer will not fire `selectionChange` but warn about | ||
@@ -96,3 +96,3 @@ * possible infinite selection loop. | ||
* Unlocks the `isSelecting` state of the view document in case the selection observer did not record this fact | ||
* correctly (for whatever the reason). It is a safeguard (paranoid check) that returns document to the normal state | ||
* correctly (for whatever reason). It is a safeguard (paranoid check), that returns document to the normal state | ||
* after a certain period of time (debounced, postponed by each selectionchange event). | ||
@@ -99,0 +99,0 @@ * |
@@ -123,3 +123,3 @@ /** | ||
// (https://github.com/ckeditor/ckeditor5/issues/10562, https://github.com/ckeditor/ckeditor5/issues/10723). | ||
// When the user stops, selecting, all pending changes should be rendered ASAP, though. | ||
// When the user stops selecting, all pending changes should be rendered ASAP, though. | ||
if ( env.isBlink && !env.isAndroid ) { | ||
@@ -559,9 +559,3 @@ this.on( 'change:isSelecting', () => { | ||
for ( const key of viewAttrKeys ) { | ||
const value = viewElement.getAttribute( key ); | ||
if ( !this.domConverter.shouldRenderAttribute( key, value ) ) { | ||
domElement.removeAttribute( key ); | ||
} else { | ||
domElement.setAttribute( key, value ); | ||
} | ||
this.domConverter.setDomElementAttribute( domElement, key, viewElement.getAttribute( key ), viewElement ); | ||
} | ||
@@ -571,10 +565,5 @@ | ||
for ( const key of domAttrKeys ) { | ||
// Do not remove attributes on `script` elements with special data attributes `data-ck-hidden`. | ||
if ( viewElement.name === 'script' && key === 'data-ck-hidden' ) { | ||
continue; | ||
} | ||
// All other attributes not present in the DOM should be removed. | ||
if ( !viewElement.hasAttribute( key ) ) { | ||
domElement.removeAttribute( key ); | ||
this.domConverter.removeDomElementAttribute( domElement, key ); | ||
} | ||
@@ -748,3 +737,3 @@ } | ||
// Note: Structural changes in DOM must trigger selection rendering, though. Nodes the selection was anchored | ||
// to may disappear in DOM which would break the selection (e.g. in real-time collaboration scenarios). | ||
// to, may disappear in DOM which would break the selection (e.g. in real-time collaboration scenarios). | ||
// https://github.com/ckeditor/ckeditor5/issues/10562, https://github.com/ckeditor/ckeditor5/issues/10723 | ||
@@ -751,0 +740,0 @@ if ( env.isBlink && !env.isAndroid && this.isSelecting && !this.markedChildren.size ) { |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
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
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
1758533
41896