Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@ckeditor/ckeditor5-list

Package Overview
Dependencies
Maintainers
1
Versions
714
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@ckeditor/ckeditor5-list - npm Package Compare versions

Comparing version 22.0.0 to 23.0.0

42

package.json
{
"name": "@ckeditor/ckeditor5-list",
"version": "22.0.0",
"version": "23.0.0",
"description": "Ordered and unordered lists feature to CKEditor 5.",

@@ -13,24 +13,24 @@ "keywords": [

"dependencies": {
"@ckeditor/ckeditor5-core": "^22.0.0",
"@ckeditor/ckeditor5-engine": "^22.0.0",
"@ckeditor/ckeditor5-paragraph": "^22.0.0",
"@ckeditor/ckeditor5-ui": "^22.0.0",
"@ckeditor/ckeditor5-utils": "^22.0.0"
"@ckeditor/ckeditor5-core": "^23.0.0",
"@ckeditor/ckeditor5-engine": "^23.0.0",
"@ckeditor/ckeditor5-paragraph": "^23.0.0",
"@ckeditor/ckeditor5-ui": "^23.0.0",
"@ckeditor/ckeditor5-utils": "^23.0.0"
},
"devDependencies": {
"@ckeditor/ckeditor5-basic-styles": "^22.0.0",
"@ckeditor/ckeditor5-block-quote": "^22.0.0",
"@ckeditor/ckeditor5-clipboard": "^22.0.0",
"@ckeditor/ckeditor5-essentials": "^22.0.0",
"@ckeditor/ckeditor5-editor-classic": "^22.0.0",
"@ckeditor/ckeditor5-enter": "^22.0.0",
"@ckeditor/ckeditor5-font": "^22.0.0",
"@ckeditor/ckeditor5-heading": "^22.0.0",
"@ckeditor/ckeditor5-highlight": "^22.0.0",
"@ckeditor/ckeditor5-indent": "^22.0.0",
"@ckeditor/ckeditor5-link": "^22.0.0",
"@ckeditor/ckeditor5-remove-format": "^22.0.0",
"@ckeditor/ckeditor5-table": "^22.0.0",
"@ckeditor/ckeditor5-typing": "^22.0.0",
"@ckeditor/ckeditor5-undo": "^22.0.0"
"@ckeditor/ckeditor5-basic-styles": "^23.0.0",
"@ckeditor/ckeditor5-block-quote": "^23.0.0",
"@ckeditor/ckeditor5-clipboard": "^23.0.0",
"@ckeditor/ckeditor5-essentials": "^23.0.0",
"@ckeditor/ckeditor5-editor-classic": "^23.0.0",
"@ckeditor/ckeditor5-enter": "^23.0.0",
"@ckeditor/ckeditor5-font": "^23.0.0",
"@ckeditor/ckeditor5-heading": "^23.0.0",
"@ckeditor/ckeditor5-highlight": "^23.0.0",
"@ckeditor/ckeditor5-indent": "^23.0.0",
"@ckeditor/ckeditor5-link": "^23.0.0",
"@ckeditor/ckeditor5-remove-format": "^23.0.0",
"@ckeditor/ckeditor5-table": "^23.0.0",
"@ckeditor/ckeditor5-typing": "^23.0.0",
"@ckeditor/ckeditor5-undo": "^23.0.0"
},

@@ -37,0 +37,0 @@ "engines": {

@@ -98,3 +98,3 @@ /**

*
* It allows to execute an action after executing the {@link ~IndentCommand#execute} method, e.g. adjusting
* It allows to execute an action after executing the {@link ~IndentCommand#execute} method, for example adjusting
* attributes of changed list items.

@@ -101,0 +101,0 @@ *

@@ -218,3 +218,3 @@ /**

*
* It allows to execute an action after executing the {@link ~ListCommand#execute} method, e.g. adjusting
* It allows to execute an action after executing the {@link ~ListCommand#execute} method, for example adjusting
* attributes of changed blocks.

@@ -221,0 +221,0 @@ *

@@ -15,6 +15,6 @@ /**

/**
* The list styles feature.
* The list style feature.
*
* This is a "glue" plugin that loads the {@link module:list/liststyleediting~ListStyleEditing list styles editing feature}
* and the {@link module:list/liststyleui~ListStyleUI list styles UI feature}.
* This is a "glue" plugin that loads the {@link module:list/liststyleediting~ListStyleEditing list style editing feature}
* and the {@link module:list/liststyleui~ListStyleUI list style UI feature}.
*

@@ -21,0 +21,0 @@ * @extends module:core/plugin~Plugin

@@ -11,6 +11,6 @@ /**

import Command from '@ckeditor/ckeditor5-core/src/command';
import TreeWalker from '@ckeditor/ckeditor5-engine/src/model/treewalker';
import { getSiblingNodes } from './utils';
/**
* The list style command. It is used by the {@link module:list/liststyle~ListStyle list styles feature}.
* The list style command. It is used by the {@link module:list/liststyle~ListStyle list style feature}.
*

@@ -51,3 +51,3 @@ * @extends module:core/command~Command

* @param {Object} options
* @param {String|null} options.type The type of the list styles, e.g. 'disc' or 'square'. If `null` specified, the default
* @param {String|null} options.type The type of the list style, e.g. `'disc'` or `'square'`. If `null` is specified, the default
* style will be applied.

@@ -120,81 +120,1 @@ * @protected

}
// Returns an array with all `listItem` elements that represents the same list.
//
// It means that values for `listIndent`, `listType`, and `listStyle` for all items
// are equal.
//
// @param {module:engine/model/position~Position} position Starting position.
// @param {'forward'|'backward'} direction Walking direction.
// @returns {Array.<module:engine/model/element~Element>
function getSiblingNodes( position, direction ) {
const items = [];
const listItem = position.parent;
const walkerOptions = {
ignoreElementEnd: true,
startPosition: position,
shallow: true,
direction
};
const limitIndent = listItem.getAttribute( 'listIndent' );
const nodes = [ ...new TreeWalker( walkerOptions ) ]
.filter( value => value.item.is( 'element' ) )
.map( value => value.item );
for ( const element of nodes ) {
// If found something else than `listItem`, we're out of the list scope.
if ( !element.is( 'element', 'listItem' ) ) {
break;
}
// If current parsed item has lower indent that element that the element that was a starting point,
// it means we left a nested list. Abort searching items.
//
// ■ List item 1. [listIndent=0]
// ○ List item 2.[] [listIndent=1], limitIndent = 1,
// ○ List item 3. [listIndent=1]
// ■ List item 4. [listIndent=0]
//
// Abort searching when leave nested list.
if ( element.getAttribute( 'listIndent' ) < limitIndent ) {
break;
}
// ■ List item 1.[] [listIndent=0] limitIndent = 0,
// ○ List item 2. [listIndent=1]
// ○ List item 3. [listIndent=1]
// ■ List item 4. [listIndent=0]
//
// Ignore nested lists.
if ( element.getAttribute( 'listIndent' ) > limitIndent ) {
continue;
}
// ■ List item 1.[] [listType=bulleted]
// 1. List item 2. [listType=numbered]
// 2.List item 3. [listType=numbered]
//
// Abort searching when found a different kind of a list.
if ( element.getAttribute( 'listType' ) !== listItem.getAttribute( 'listType' ) ) {
break;
}
// ■ List item 1.[] [listType=bulleted]
// ■ List item 2. [listType=bulleted]
// ○ List item 3. [listType=bulleted]
// ○ List item 4. [listType=bulleted]
//
// Abort searching when found a different list style.
if ( element.getAttribute( 'listStyle' ) !== listItem.getAttribute( 'listStyle' ) ) {
break;
}
if ( direction === 'backward' ) {
items.unshift( element );
} else {
items.push( element );
}
}
return items;
}

@@ -13,3 +13,3 @@ /**

import ListStyleCommand from './liststylecommand';
import { getSiblingListItem } from './utils';
import { getSiblingListItem, getSiblingNodes } from './utils';

@@ -19,6 +19,6 @@ const DEFAULT_LIST_TYPE = 'default';

/**
* The list styles engine feature.
* The list style engine feature.
*
* It sets value for the `listItem` attribute for the {@link module:list/list~List `<listItem>`} element that
* allows modifying list style type.
* It sets the value for the `listItem` attribute of the {@link module:list/list~List `<listItem>`} element that
* allows modifying the list style type.
*

@@ -71,2 +71,5 @@ * It registers the `'listStyle'` command.

editor.conversion.for( 'downcast' ).add( downcastListStyleAttribute() );
// Handle merging two separated lists into the single one.
this._mergeListStyleAttributeWhileMergingLists();
}

@@ -86,8 +89,126 @@

}
/**
* Starts listening to {@link module:engine/model/model~Model#deleteContent} checks whether two lists will be merged into a single one
* after deleting the content.
*
* The purpose of this action is to adjust the `listStyle` value for the list that was merged.
*
* Consider the following model's content:
*
* <listItem listIndent="0" listType="bulleted" listStyle="square">UL List item 1</listItem>
* <listItem listIndent="0" listType="bulleted" listStyle="square">UL List item 2</listItem>
* <paragraph>[A paragraph.]</paragraph>
* <listItem listIndent="0" listType="bulleted" listStyle="circle">UL List item 1</listItem>
* <listItem listIndent="0" listType="bulleted" listStyle="circle">UL List item 2</listItem>
*
* After removing the paragraph element, the second list will be merged into the first one.
* We want to inherit the `listStyle` attribute for the second list from the first one.
*
* <listItem listIndent="0" listType="bulleted" listStyle="square">UL List item 1</listItem>
* <listItem listIndent="0" listType="bulleted" listStyle="square">UL List item 2</listItem>
* <listItem listIndent="0" listType="bulleted" listStyle="square">UL List item 1</listItem>
* <listItem listIndent="0" listType="bulleted" listStyle="square">UL List item 2</listItem>
*
* See https://github.com/ckeditor/ckeditor5/issues/7879.
*
* @private
*/
_mergeListStyleAttributeWhileMergingLists() {
const editor = this.editor;
const model = editor.model;
// First the most-outer `listItem` in the first list reference.
// If found, lists should be merged and this `listItem` provides the `listStyle` attribute
// and it' also a starting point when searching for items in the second list.
let firstMostOuterItem;
// Check whether the removed content is between two lists.
this.listenTo( model, 'deleteContent', ( evt, [ selection ] ) => {
const firstPosition = selection.getFirstPosition();
const lastPosition = selection.getLastPosition();
// Typing or removing content in a single item. Aborting.
if ( firstPosition.parent === lastPosition.parent ) {
return;
}
// An element before the content that will be removed is not a list.
if ( !firstPosition.parent.is( 'element', 'listItem' ) ) {
return;
}
const nextSibling = lastPosition.parent.nextSibling;
// An element after the content that will be removed is not a list.
if ( !nextSibling || !nextSibling.is( 'element', 'listItem' ) ) {
return;
}
// Find the outermost list item based on the `listIndent` attribute. We can't assume that `listIndent=0`
// because the selection can be hooked in nested lists.
//
// <listItem listIndent="0" listType="bulleted" listStyle="square">UL List item 1</listItem>
// <listItem listIndent="1" listType="bulleted" listStyle="square">UL List [item 1.1</listItem>
// <listItem listIndent="0" listType="bulleted" listStyle="circle">[]UL List item 1.</listItem>
// <listItem listIndent="1" listType="bulleted" listStyle="circle">UL List ]item 1.1</listItem>
//
// After deleting the content, we would like to inherit the "square" attribute for the last element:
//
// <listItem listIndent="0" listType="bulleted" listStyle="square">UL List item 1</listItem>
// <listItem listIndent="1" listType="bulleted" listStyle="square">UL List []item 1.1</listItem>
const mostOuterItemList = getSiblingListItem( firstPosition.parent, {
sameIndent: true,
listIndent: nextSibling.getAttribute( 'listIndent' )
} );
// The outermost list item may not exist while removing elements between lists with different value
// of the `listIndent` attribute. In such a case we don't want to update anything. See: #8073.
if ( !mostOuterItemList ) {
return;
}
if ( mostOuterItemList.getAttribute( 'listType' ) === nextSibling.getAttribute( 'listType' ) ) {
firstMostOuterItem = mostOuterItemList;
}
}, { priority: 'high' } );
// If so, update the `listStyle` attribute for the second list.
this.listenTo( model, 'deleteContent', () => {
if ( !firstMostOuterItem ) {
return;
}
model.change( writer => {
// Find the first most-outer item list in the merged list.
// A case when the first list item in the second list was merged into the last item in the first list.
//
// <listItem listIndent="0" listType="bulleted" listStyle="square">UL List item 1</listItem>
// <listItem listIndent="0" listType="bulleted" listStyle="square">UL List item 2</listItem>
// <listItem listIndent="0" listType="bulleted" listStyle="circle">[]UL List item 1</listItem>
// <listItem listIndent="0" listType="bulleted" listStyle="circle">UL List item 2</listItem>
const secondListMostOuterItem = getSiblingListItem( firstMostOuterItem.nextSibling, {
sameIndent: true,
listIndent: firstMostOuterItem.getAttribute( 'listIndent' ),
direction: 'forward'
} );
const items = [
secondListMostOuterItem,
...getSiblingNodes( writer.createPositionAt( secondListMostOuterItem, 0 ), 'forward' )
];
for ( const listItem of items ) {
writer.setAttribute( 'listStyle', firstMostOuterItem.getAttribute( 'listStyle' ), listItem );
}
} );
firstMostOuterItem = null;
}, { priority: 'low' } );
}
}
// Returns a converter that consumes the `style` attribute and search for `list-style-type` definition.
// Returns a converter that consumes the `style` attribute and searches for the `list-style-type` definition.
// If not found, the `"default"` value will be used.
//
// @private
// @returns {Function}

@@ -109,3 +230,2 @@ function upcastListItemStyle() {

//
// @private
// @returns {Function}

@@ -117,3 +237,2 @@ function downcastListStyleAttribute() {

const currentElement = data.item;
const listStyle = data.attributeNewValue;

@@ -128,11 +247,8 @@ const previousElement = getSiblingListItem( currentElement.previousSibling, {

// Single item list.
if ( !previousElement ) {
setListStyle( viewWriter, listStyle, viewItem.parent );
} else if ( !areRepresentingSameList( previousElement, currentElement ) ) {
// A case when elements represent different lists. We need to separate their container.
if ( !areRepresentingSameList( currentElement, previousElement ) ) {
viewWriter.breakContainer( viewWriter.createPositionBefore( viewItem ) );
viewWriter.breakContainer( viewWriter.createPositionAfter( viewItem ) );
}
setListStyle( viewWriter, listStyle, viewItem.parent );
}
setListStyle( viewWriter, data.attributeNewValue, viewItem.parent );
}, { priority: 'low' } );

@@ -144,6 +260,7 @@ };

// @param {module:engine/model/element~Element} listItem1 The first list item to check.
// @param {module:engine/model/element~Element} listItem2 The second list item to check.
// @param {module:engine/model/element~Element|null} listItem2 The second list item to check.
// @returns {Boolean}
function areRepresentingSameList( listItem1, listItem2 ) {
return listItem1.getAttribute( 'listType' ) === listItem2.getAttribute( 'listType' ) &&
return listItem2 &&
listItem1.getAttribute( 'listType' ) === listItem2.getAttribute( 'listType' ) &&
listItem1.getAttribute( 'listIndent' ) === listItem2.getAttribute( 'listIndent' ) &&

@@ -178,3 +295,2 @@ listItem1.getAttribute( 'listStyle' ) === listItem2.getAttribute( 'listStyle' );

//
// @private
// @param {module:core/editor/editor~Editor} editor

@@ -231,3 +347,2 @@ // @returns {Function}

//
// @private
// @param {module:core/editor/editor~Editor} editor

@@ -332,3 +447,2 @@ // @returns {Function}

//
// @private
// @param {module:core/editor/editor~Editor} editor

@@ -339,13 +453,9 @@ // @returns {Function}

let wasFixed = false;
let insertedListItems = [];
for ( const change of editor.model.document.differ.getChanges() ) {
if ( change.type == 'insert' && change.name == 'listItem' ) {
insertedListItems.push( change.position.nodeAfter );
}
}
const insertedListItems = getChangedListItems( editor.model.document.differ.getChanges() )
.filter( item => {
// Don't touch todo lists. They are handled in another post-fixer.
return item.getAttribute( 'listType' ) !== 'todo';
} );
// Don't touch todo lists.
insertedListItems = insertedListItems.filter( item => item.getAttribute( 'listType' ) !== 'todo' );
if ( !insertedListItems.length ) {

@@ -379,2 +489,7 @@ return wasFixed;

existingListItem = existingListItem.previousSibling;
// If the item does not exist, most probably there is no other content in the editor. See: #8072.
if ( !existingListItem ) {
break;
}
}

@@ -386,3 +501,3 @@ }

if ( !item.hasAttribute( 'listStyle' ) ) {
if ( shouldInheritListType( existingListItem ) ) {
if ( shouldInheritListType( existingListItem, item ) ) {
writer.setAttribute( 'listStyle', existingListItem.getAttribute( 'listStyle' ), item );

@@ -406,4 +521,5 @@ } else {

// @param {module:engine/model/element~Element|null} baseItem
// @param {module:engine/model/element~Element} itemToChange
// @returns {Boolean}
function shouldInheritListType( baseItem ) {
function shouldInheritListType( baseItem, itemToChange ) {
if ( !baseItem ) {

@@ -423,2 +539,6 @@ return false;

if ( baseItem.getAttribute( 'listType' ) !== itemToChange.getAttribute( 'listType' ) ) {
return false;
}
return true;

@@ -430,3 +550,2 @@ }

//
// @private
// @param {module:core/editor/editor~Editor} editor

@@ -436,14 +555,8 @@ // @returns {Function}

return writer => {
let todoListItems = [];
const todoListItems = getChangedListItems( editor.model.document.differ.getChanges() )
.filter( item => {
// Handle the todo lists only. The rest is handled in another post-fixer.
return item.getAttribute( 'listType' ) === 'todo' && item.hasAttribute( 'listStyle' );
} );
for ( const change of editor.model.document.differ.getChanges() ) {
const item = getItemFromChange( change );
if ( item && item.is( 'element', 'listItem' ) && item.getAttribute( 'listType' ) === 'todo' ) {
todoListItems.push( item );
}
}
todoListItems = todoListItems.filter( item => item.hasAttribute( 'listStyle' ) );
if ( !todoListItems.length ) {

@@ -459,14 +572,2 @@ return false;

};
function getItemFromChange( change ) {
if ( change.type === 'attribute' ) {
return change.range.start.nodeAfter;
}
if ( change.type === 'insert' ) {
return change.position.nodeAfter;
}
return null;
}
}

@@ -476,3 +577,2 @@

//
// @private
// @param {module:core/editor/editor~Editor} editor

@@ -492,1 +592,32 @@ // @returns {Function}

}
// Returns `listItem` that were inserted or changed.
//
// @param {Array.<Object>} changes The changes list returned by the differ.
// @returns {Array.<module:engine/model/element~Element>}
function getChangedListItems( changes ) {
const items = [];
for ( const change of changes ) {
const item = getItemFromChange( change );
if ( item && item.is( 'element', 'listItem' ) ) {
items.push( item );
}
}
return items;
}
function getItemFromChange( change ) {
if ( change.type === 'attribute' ) {
return change.range.start.nodeAfter;
}
if ( change.type === 'insert' ) {
return change.position.nodeAfter;
}
return null;
}

@@ -34,6 +34,6 @@ /**

/**
* The list styles UI plugin. It introduces the extended `'bulletedList'` and `'numberedList'` toolbar
* buttons that allow users change styles of individual lists in the content.
* The list style UI plugin. It introduces the extended `'bulletedList'` and `'numberedList'` toolbar
* buttons that allow users to change styles of individual lists in the content.
*
* **Note**: Buttons introduces by this plugin override implementations from the {@link module:list/listui~ListUI}
* **Note**: Buttons introduced by this plugin override implementations from the {@link module:list/listui~ListUI}
* (because they share the same names).

@@ -40,0 +40,0 @@ *

@@ -12,2 +12,3 @@ /**

import ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';
import TreeWalker from '@ckeditor/ckeditor5-engine/src/model/treewalker';

@@ -211,2 +212,3 @@ /**

* @param {Number} [options.listIndent] The reference indentation.
* @param {'forward'|'backward'} [options.direction='backward'] Walking direction.
* @returns {module:engine/model/item~Item|null}

@@ -228,3 +230,7 @@ */

item = item.previousSibling;
if ( options.direction === 'forward' ) {
item = item.nextSibling;
} else {
item = item.previousSibling;
}
}

@@ -285,2 +291,83 @@

/**
* Returns an array with all `listItem` elements that represents the same list.
*
* It means that values for `listIndent`, `listType`, and `listStyle` for all items are equal.
*
* @param {module:engine/model/position~Position} position Starting position.
* @param {'forward'|'backward'} direction Walking direction.
* @returns {Array.<module:engine/model/element~Element>}
*/
export function getSiblingNodes( position, direction ) {
const items = [];
const listItem = position.parent;
const walkerOptions = {
ignoreElementEnd: true,
startPosition: position,
shallow: true,
direction
};
const limitIndent = listItem.getAttribute( 'listIndent' );
const nodes = [ ...new TreeWalker( walkerOptions ) ]
.filter( value => value.item.is( 'element' ) )
.map( value => value.item );
for ( const element of nodes ) {
// If found something else than `listItem`, we're out of the list scope.
if ( !element.is( 'element', 'listItem' ) ) {
break;
}
// If current parsed item has lower indent that element that the element that was a starting point,
// it means we left a nested list. Abort searching items.
//
// ■ List item 1. [listIndent=0]
// ○ List item 2.[] [listIndent=1], limitIndent = 1,
// ○ List item 3. [listIndent=1]
// ■ List item 4. [listIndent=0]
//
// Abort searching when leave nested list.
if ( element.getAttribute( 'listIndent' ) < limitIndent ) {
break;
}
// ■ List item 1.[] [listIndent=0] limitIndent = 0,
// ○ List item 2. [listIndent=1]
// ○ List item 3. [listIndent=1]
// ■ List item 4. [listIndent=0]
//
// Ignore nested lists.
if ( element.getAttribute( 'listIndent' ) > limitIndent ) {
continue;
}
// ■ List item 1.[] [listType=bulleted]
// 1. List item 2. [listType=numbered]
// 2.List item 3. [listType=numbered]
//
// Abort searching when found a different kind of a list.
if ( element.getAttribute( 'listType' ) !== listItem.getAttribute( 'listType' ) ) {
break;
}
// ■ List item 1.[] [listType=bulleted]
// ■ List item 2. [listType=bulleted]
// ○ List item 3. [listType=bulleted]
// ○ List item 4. [listType=bulleted]
//
// Abort searching when found a different list style.
if ( element.getAttribute( 'listStyle' ) !== listItem.getAttribute( 'listStyle' ) ) {
break;
}
if ( direction === 'backward' ) {
items.unshift( element );
} else {
items.push( element );
}
}
return items;
}
// Implementation of getFillerOffset for view list item element.

@@ -287,0 +374,0 @@ //

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc