Implement children and attributes disallowing in Schema
📝 Provide a description of the new feature
Right now when defining the schema, you can register() new elements or extend() how existing elements behave. When you do it, you can directly specify which children/attributes are allowed on the new/updated element. Or you can set that a new element should allow the same children/attributes as another element. Or you can do both.
But you can't exclude.
There's no way to disallow children/attributes for already specified element (if you want to modify its behavior).
There's no way to disallow for a new element if you want to base it on existing element (e.g. "allow all children of root, except of tables").
This is crucial for creating more complex integrations, especially if you want to structure the document (e.g. root should only include a title and structure-containers).
I haven't gone into technical details when researching this issue, so I might be missing something. Here are general guides. The way the schema extensions work is that we have a set of rules for each item. Some are direct ("allow child Z"), some are inherited ("allow same children as Y"). When the schema is changed, these rules are "compiled". For example, for element Y, we resolve all children it can have. Then we go to element X, and e.g. we take all resolved children of Y ("allow same children as Y") and add specific children declared for element X.
Finally, SchemaCompiledItemDefinition has only resolved items in allowIn, allowChildren, and allowAttributes.
Given this flow, I think it should be possible to implement disallowChildren and disallowAttributes property. You would first resolve allowed children and then remove disallowed ones. Disallows will always take precedence over allows.
For example, let's have such configuration:
-
$blockallows attributelistItemId, -
paragraphallows attributes of block and alsotextAlign, -
myCustomParagraphallows attributes of paragraph but disallowslistItemId.
When compiling, $block is topmost (I wonder if we solved problem with recursion?), it allows listItemId. Then paragraph is resolved, takes listItemId and adds textAlign. Then myCustomParagraph is resolved, takes listItemId, textAlign and removes listItemId. If some other element would allowAttributesOf: 'myCustomParagraph' then it would only get textAlign.
@scofalik is there any more context to this, for instance, previous kinda related issues, or customer requests? Trying to understand the impact on this.
I think the issue is pretty straightforward and says it all. We need to have disallowChildren and disallowAttributes available when using register() and extend() so that you can e.g. add a new element type that disallows specific children or attributes, as in the example in the original post.
What about this, has it been solved, what is the problem with it and can it impact this?
(I wonder if we solved problem with recursion?)
That was actually a bit off-topic, and I meant situation when element X allows all children of Y while element Y allows all children of X. I wonder if we solve it all.