Skip to content
This repository was archived by the owner on Jun 26, 2020. It is now read-only.

Commit d776c71

Browse files
authored
Merge pull request #1124 from ckeditor/t/1120b
Feature: Introduced `Schema#removeDisallowedAttributes` method to filter out disallowed by schema attributes from given nodes. Closes #1120.
2 parents 32016a6 + 5837e68 commit d776c71

File tree

4 files changed

+215
-82
lines changed

4 files changed

+215
-82
lines changed

src/controller/deletecontent.js

Lines changed: 8 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,11 @@ export default function deleteContent( selection, batch, options = {} ) {
4141
return;
4242
}
4343

44+
const schema = batch.document.schema;
45+
4446
// 1. Replace the entire content with paragraph.
4547
// See: https://github.com/ckeditor/ckeditor5-engine/issues/1012#issuecomment-315017594.
46-
if ( !options.doNotResetEntireContent && shouldEntireContentBeReplacedWithParagraph( batch.document.schema, selection ) ) {
48+
if ( !options.doNotResetEntireContent && shouldEntireContentBeReplacedWithParagraph( schema, selection ) ) {
4749
replaceEntireContentWithParagraph( batch, selection );
4850

4951
return;
@@ -74,14 +76,14 @@ export default function deleteContent( selection, batch, options = {} ) {
7476
//
7577
// e.g. bold is disallowed for <H1>
7678
// <h1>Fo{o</h1><p>b}a<b>r</b><p> -> <h1>Fo{}a<b>r</b><h1> -> <h1>Fo{}ar<h1>.
77-
removeDisallowedAttributes( startPos.parent.getChildren(), startPos, batch );
79+
schema.removeDisallowedAttributes( startPos.parent.getChildren(), startPos, batch );
7880
}
7981

8082
selection.setCollapsedAt( startPos );
8183

8284
// 4. Autoparagraphing.
8385
// Check if a text is allowed in the new container. If not, try to create a new paragraph (if it's allowed here).
84-
if ( shouldAutoparagraph( batch.document, startPos ) ) {
86+
if ( shouldAutoparagraph( schema, startPos ) ) {
8587
insertParagraph( batch, startPos, selection );
8688
}
8789

@@ -158,9 +160,9 @@ function mergeBranches( batch, startPos, endPos ) {
158160
mergeBranches( batch, startPos, endPos );
159161
}
160162

161-
function shouldAutoparagraph( doc, position ) {
162-
const isTextAllowed = doc.schema.check( { name: '$text', inside: position } );
163-
const isParagraphAllowed = doc.schema.check( { name: 'paragraph', inside: position } );
163+
function shouldAutoparagraph( schema, position ) {
164+
const isTextAllowed = schema.check( { name: '$text', inside: position } );
165+
const isParagraphAllowed = schema.check( { name: 'paragraph', inside: position } );
164166

165167
return !isTextAllowed && isParagraphAllowed;
166168
}
@@ -217,39 +219,3 @@ function shouldEntireContentBeReplacedWithParagraph( schema, selection ) {
217219

218220
return schema.check( { name: 'paragraph', inside: limitElement.name } );
219221
}
220-
221-
// Gets a name under which we should check this node in the schema.
222-
//
223-
// @param {module:engine/model/node~Node} node The node.
224-
// @returns {String} node name.
225-
function getNodeSchemaName( node ) {
226-
return node.is( 'text' ) ? '$text' : node.name;
227-
}
228-
229-
// Creates AttributeDeltas that removes attributes that are disallowed by schema on given node and its children.
230-
//
231-
// @param {Array<module:engine/model/node~Node>} nodes Nodes that will be filtered.
232-
// @param {module:engine/model/schema~SchemaPath} inside Path inside which schema will be checked.
233-
// @param {module:engine/model/batch~Batch} batch Batch to which the deltas will be added.
234-
function removeDisallowedAttributes( nodes, inside, batch ) {
235-
const schema = batch.document.schema;
236-
237-
for ( const node of nodes ) {
238-
const name = getNodeSchemaName( node );
239-
240-
// When node with attributes is not allowed in current position.
241-
if ( !schema.check( { name, inside, attributes: Array.from( node.getAttributeKeys() ) } ) ) {
242-
// Let's remove attributes one by one.
243-
// This should be improved to check all combination of attributes.
244-
for ( const attribute of node.getAttributeKeys() ) {
245-
if ( !schema.check( { name, inside, attributes: attribute } ) ) {
246-
batch.removeAttribute( node, attribute );
247-
}
248-
}
249-
}
250-
251-
if ( node.is( 'element' ) ) {
252-
removeDisallowedAttributes( node.getChildren(), Position.createAt( node ), batch );
253-
}
254-
}
255-
}

src/controller/insertcontent.js

Lines changed: 5 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ class Insertion {
229229
// If the node is a text and bare text is allowed in current position it means that the node
230230
// contains disallowed attributes and we have to remove them.
231231
else if ( this.schema.check( { name: '$text', inside: this.position } ) ) {
232-
removeDisallowedAttributes( [ node ], this.position, this.schema );
232+
this.schema.removeDisallowedAttributes( [ node ], this.position );
233233
this._handleNode( node, context );
234234
}
235235
// If text is not allowed, try autoparagraphing.
@@ -291,7 +291,7 @@ class Insertion {
291291
// We need to check and strip disallowed attributes in all nested nodes because after merge
292292
// some attributes could end up in a path where are disallowed.
293293
const parent = position.nodeBefore;
294-
removeDisallowedAttributes( parent.getChildren(), Position.createAt( parent ), this.schema, this.batch );
294+
this.schema.removeDisallowedAttributes( parent.getChildren(), Position.createAt( parent ), this.batch );
295295

296296
this.position = Position.createFromPosition( position );
297297
position.detach();
@@ -318,7 +318,7 @@ class Insertion {
318318

319319
// We need to check and strip disallowed attributes in all nested nodes because after merge
320320
// some attributes could end up in a place where are disallowed.
321-
removeDisallowedAttributes( position.parent.getChildren(), position, this.schema, this.batch );
321+
this.schema.removeDisallowedAttributes( position.parent.getChildren(), position, this.batch );
322322

323323
this.position = Position.createFromPosition( position );
324324
position.detach();
@@ -330,7 +330,7 @@ class Insertion {
330330
// When there was no merge we need to check and strip disallowed attributes in all nested nodes of
331331
// just inserted node because some attributes could end up in a place where are disallowed.
332332
if ( !mergeLeft && !mergeRight ) {
333-
removeDisallowedAttributes( node.getChildren(), Position.createAt( node ), this.schema, this.batch );
333+
this.schema.removeDisallowedAttributes( node.getChildren(), Position.createAt( node ), this.batch );
334334
}
335335
}
336336

@@ -350,7 +350,7 @@ class Insertion {
350350
// When node is a text and is disallowed by schema it means that contains disallowed attributes
351351
// and we need to remove them.
352352
if ( node.is( 'text' ) && !this._checkIsAllowed( node, [ paragraph ] ) ) {
353-
removeDisallowedAttributes( [ node ], [ paragraph ], this.schema );
353+
this.schema.removeDisallowedAttributes( [ node ], [ paragraph ] );
354354
}
355355

356356
if ( this._checkIsAllowed( node, [ paragraph ] ) ) {
@@ -453,36 +453,3 @@ class Insertion {
453453
function getNodeSchemaName( node ) {
454454
return node.is( 'text' ) ? '$text' : node.name;
455455
}
456-
457-
// Removes disallowed by schema attributes from given nodes. When batch parameter is provided then
458-
// attributes will be removed by creating AttributeDeltas otherwise attributes will be removed
459-
// directly from provided nodes.
460-
//
461-
// @param {Array<module:engine/model/node~Node>} nodes Nodes that will be filtered.
462-
// @param {module:engine/model/schema~SchemaPath} inside Path inside which schema will be checked.
463-
// @param {module:engine/model/schema~Schema} schema Schema instance uses for element validation.
464-
// @param {module:engine/model/batch~Batch} [batch] Batch to which the deltas will be added.
465-
function removeDisallowedAttributes( nodes, inside, schema, batch ) {
466-
for ( const node of nodes ) {
467-
const name = getNodeSchemaName( node );
468-
469-
// When node with attributes is not allowed in current position.
470-
if ( !schema.check( { name, inside, attributes: Array.from( node.getAttributeKeys() ) } ) ) {
471-
// Let's remove attributes one by one.
472-
// This should be improved to check all combination of attributes.
473-
for ( const attribute of node.getAttributeKeys() ) {
474-
if ( !schema.check( { name, inside, attributes: attribute } ) ) {
475-
if ( batch ) {
476-
batch.removeAttribute( node, attribute );
477-
} else {
478-
node.removeAttribute( attribute );
479-
}
480-
}
481-
}
482-
}
483-
484-
if ( node.is( 'element' ) ) {
485-
removeDisallowedAttributes( node.getChildren(), Position.createAt( node ), schema, batch );
486-
}
487-
}
488-
}

src/model/schema.js

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@
99

1010
import Position from './position';
1111
import Element from './element';
12+
import Range from './range';
1213
import clone from '@ckeditor/ckeditor5-utils/src/lib/lodash/clone';
1314
import isArray from '@ckeditor/ckeditor5-utils/src/lib/lodash/isArray';
1415
import isString from '@ckeditor/ckeditor5-utils/src/lib/lodash/isString';
1516
import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
16-
import Range from './range';
1717

1818
/**
1919
* Schema is a definition of the structure of the document. It allows to define which tree model items (element, text, etc.)
@@ -415,6 +415,43 @@ export default class Schema {
415415
return element;
416416
}
417417

418+
/**
419+
* Removes disallowed by {@link module:engine/model/schema~Schema schema} attributes from given nodes.
420+
* When {@link module:engine/model/batch~Batch batch} parameter is provided then attributes will be removed
421+
* using that batch, by creating {@link module:engine/model/delta/attributedelta~AttributeDelta attribute deltas}.
422+
* Otherwise, attributes will be removed directly from provided nodes using {@link module:engine/model/node~Node node} API.
423+
*
424+
* @param {Iterable.<module:engine/model/node~Node>} nodes Nodes that will be filtered.
425+
* @param {module:engine/model/schema~SchemaPath} inside Path inside which schema will be checked.
426+
* @param {module:engine/model/batch~Batch} [batch] Batch to which the deltas will be added.
427+
*/
428+
removeDisallowedAttributes( nodes, inside, batch ) {
429+
for ( const node of nodes ) {
430+
const name = node.is( 'text' ) ? '$text' : node.name;
431+
const attributes = Array.from( node.getAttributeKeys() );
432+
const queryPath = Schema._normalizeQueryPath( inside );
433+
434+
// When node with attributes is not allowed in current position.
435+
if ( !this.check( { name, attributes, inside: queryPath } ) ) {
436+
// Let's remove attributes one by one.
437+
// TODO: this should be improved to check all combination of attributes.
438+
for ( const attribute of node.getAttributeKeys() ) {
439+
if ( !this.check( { name, attributes: attribute, inside: queryPath } ) ) {
440+
if ( batch ) {
441+
batch.removeAttribute( node, attribute );
442+
} else {
443+
node.removeAttribute( attribute );
444+
}
445+
}
446+
}
447+
}
448+
449+
if ( node.is( 'element' ) ) {
450+
this.removeDisallowedAttributes( node.getChildren(), queryPath.concat( node.name ), batch );
451+
}
452+
}
453+
}
454+
418455
/**
419456
* Returns {@link module:engine/model/schema~SchemaItem schema item} that was registered in the schema under given name.
420457
* If item has not been found, throws error.

0 commit comments

Comments
 (0)