@ckeditor/ckeditor5-html-support 48.2.0-alpha.5 → 48.2.0-alpha.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2425,6 +2425,11 @@ function modifyGhsAttribute(writer, item, ghsAttributeName, subject, callback) {
2425
2425
  if (!viewPreElement || !viewPreElement.is('element', 'pre')) {
2426
2426
  return;
2427
2427
  }
2428
+ // The `<code>` was not converted to a model `codeBlock` element (e.g. an inline root only allows
2429
+ // inline content), so there is no model range to set the preserved attributes on.
2430
+ if (!data.modelRange) {
2431
+ return;
2432
+ }
2428
2433
  preserveElementAttributes(viewPreElement, 'htmlPreAttributes');
2429
2434
  preserveElementAttributes(viewCodeElement, 'htmlContentAttributes');
2430
2435
  function preserveElementAttributes(viewElement, attributeName) {
@@ -3368,13 +3373,13 @@ const STYLE_ATTRIBUTES_TO_PROPAGATE = [
3368
3373
  allowAttributes
3369
3374
  });
3370
3375
  conversion.for('upcast').add((dispatcher)=>{
3371
- dispatcher.on('element:ul', viewToModelListAttributeConverter('htmlUlAttributes', dataFilter), {
3376
+ dispatcher.on('element:ul', viewToModelListAttributeConverter('htmlUlAttributes', 'list', dataFilter), {
3372
3377
  priority: 'low'
3373
3378
  });
3374
- dispatcher.on('element:ol', viewToModelListAttributeConverter('htmlOlAttributes', dataFilter), {
3379
+ dispatcher.on('element:ol', viewToModelListAttributeConverter('htmlOlAttributes', 'list', dataFilter), {
3375
3380
  priority: 'low'
3376
3381
  });
3377
- dispatcher.on('element:li', viewToModelListAttributeConverter('htmlLiAttributes', dataFilter), {
3382
+ dispatcher.on('element:li', viewToModelListAttributeConverter('htmlLiAttributes', 'item', dataFilter), {
3378
3383
  priority: 'low'
3379
3384
  });
3380
3385
  });
@@ -3390,14 +3395,22 @@ const STYLE_ATTRIBUTES_TO_PROPAGATE = [
3390
3395
  const attribute = getAttributeFromListType(previousNodeInList.getAttribute('listType'));
3391
3396
  const value = previousNodeInList.getAttribute(attribute);
3392
3397
  if (!isEqual(node.getAttribute(attribute), value) && writer.model.schema.checkAttribute(node, attribute)) {
3393
- writer.setAttribute(attribute, value, node);
3398
+ if (value === undefined) {
3399
+ writer.removeAttribute(attribute, node);
3400
+ } else {
3401
+ writer.setAttribute(attribute, value, node);
3402
+ }
3394
3403
  evt.return = true;
3395
3404
  }
3396
3405
  }
3397
3406
  if (previousNodeInList.getAttribute('listItemId') == node.getAttribute('listItemId')) {
3398
3407
  const value = previousNodeInList.getAttribute('htmlLiAttributes');
3399
3408
  if (!isEqual(node.getAttribute('htmlLiAttributes'), value) && writer.model.schema.checkAttribute(node, 'htmlLiAttributes')) {
3400
- writer.setAttribute('htmlLiAttributes', value, node);
3409
+ if (value === undefined) {
3410
+ writer.removeAttribute('htmlLiAttributes', node);
3411
+ } else {
3412
+ writer.setAttribute('htmlLiAttributes', value, node);
3413
+ }
3401
3414
  evt.return = true;
3402
3415
  }
3403
3416
  }
@@ -3434,10 +3447,9 @@ const STYLE_ATTRIBUTES_TO_PROPAGATE = [
3434
3447
  if (!editor.model.schema.checkAttribute(node, attribute)) {
3435
3448
  continue;
3436
3449
  }
3437
- // Just reset the attribute.
3438
- // If there is a previous indented list that this node should be merged into,
3439
- // the postfixer will unify all the attributes of both sub-lists.
3440
- writer.setAttribute(attribute, {}, node);
3450
+ // Clear any attribute inherited from the outer list. If the indented item joins an
3451
+ // existing nested list, the postfixer will copy the right value from a sibling.
3452
+ writer.removeAttribute(attribute, node);
3441
3453
  }
3442
3454
  });
3443
3455
  });
@@ -3448,31 +3460,59 @@ const STYLE_ATTRIBUTES_TO_PROPAGATE = [
3448
3460
  * feature model element.
3449
3461
  *
3450
3462
  * @returns Returns a conversion callback.
3451
- */ function viewToModelListAttributeConverter(attributeName, dataFilter) {
3463
+ */ function viewToModelListAttributeConverter(attributeName, scope, dataFilter) {
3452
3464
  return (evt, data, conversionApi)=>{
3453
3465
  const viewElement = data.viewItem;
3454
3466
  if (!data.modelRange) {
3455
3467
  Object.assign(data, conversionApi.convertChildren(data.viewItem, data.modelCursor));
3456
3468
  }
3457
3469
  const viewAttributes = dataFilter.processViewAttributes(viewElement, conversionApi);
3470
+ if (scope === 'list' && !viewAttributes) {
3471
+ return;
3472
+ }
3473
+ const store = conversionApi.store;
3474
+ store.htmlSupportItemToClosestList ??= new Map();
3475
+ const itemToClosestList = store.htmlSupportItemToClosestList;
3476
+ const closestList = scope === 'item' ? findClosestListAncestor(viewElement) : null;
3458
3477
  for (const item of data.modelRange.getItems({
3459
3478
  shallow: true
3460
3479
  })){
3461
- // Apply only to list item blocks.
3462
3480
  if (!item.hasAttribute('listItemId')) {
3463
3481
  continue;
3464
3482
  }
3465
- // Set list attributes only on same level items, those nested deeper are already handled
3466
- // by the recursive conversion.
3467
- if (item.hasAttribute('htmlUlAttributes') || item.hasAttribute('htmlOlAttributes')) {
3468
- continue;
3483
+ if (scope === 'item') {
3484
+ // Converting `<li>`.
3485
+ if (itemToClosestList.has(item)) {
3486
+ continue;
3487
+ }
3488
+ // Mark that this list item was already visited.
3489
+ itemToClosestList.set(item, closestList);
3490
+ } else {
3491
+ // Converting `<ul>`/`<ol>`.
3492
+ if (itemToClosestList.get(item) !== viewElement) {
3493
+ continue;
3494
+ }
3469
3495
  }
3470
- if (conversionApi.writer.model.schema.checkAttribute(item, attributeName)) {
3471
- conversionApi.writer.setAttribute(attributeName, viewAttributes || {}, item);
3496
+ // Set `<ul>`/`<ol>`/`<li>` custom attributes if any.
3497
+ if (viewAttributes && conversionApi.writer.model.schema.checkAttribute(item, attributeName)) {
3498
+ conversionApi.writer.setAttribute(attributeName, viewAttributes, item);
3472
3499
  }
3473
3500
  }
3474
3501
  };
3475
3502
  }
3503
+ /**
3504
+ * Walks up the view tree from the given element and returns the first `<ul>`/`<ol>` ancestor,
3505
+ * or `null` if there isn't one.
3506
+ */ function findClosestListAncestor(viewElement) {
3507
+ let node = viewElement.parent;
3508
+ while(node){
3509
+ if (node.is('element', 'ul') || node.is('element', 'ol')) {
3510
+ return node;
3511
+ }
3512
+ node = node.parent;
3513
+ }
3514
+ return null;
3515
+ }
3476
3516
  /**
3477
3517
  * Returns HTML attribute name based on provided list type.
3478
3518
  */ function getAttributeFromListType(listType) {