Skip to content

Commit

Permalink
Merge pull request #10973 from ckeditor/ck/10673-reversed-and-indexed…
Browse files Browse the repository at this point in the history
…-lists

Feature (list): Added support for reversed lists and list start index (`reversed` and `start` HTML attributes). Closes #10673.
  • Loading branch information
oleq authored Dec 16, 2021
2 parents 065e421 + b5de719 commit d080639
Show file tree
Hide file tree
Showing 11 changed files with 6,471 additions and 1,405 deletions.
12 changes: 12 additions & 0 deletions packages/ckeditor5-list/src/converters.js
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,18 @@ export function modelChangePostFixer( model, writer ) {
applied = true;
}

if ( item.hasAttribute( 'listReversed' ) ) {
writer.removeAttribute( 'listReversed', item );

applied = true;
}

if ( item.hasAttribute( 'listStart' ) ) {
writer.removeAttribute( 'listStart', item );

applied = true;
}

for ( const innerItem of Array.from( model.createRangeIn( item ) ).filter( e => e.item.is( 'element', 'listItem' ) ) ) {
_addListToFix( innerItem.previousPosition );
}
Expand Down
23 changes: 23 additions & 0 deletions packages/ckeditor5-list/src/list.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,26 @@ export default class List extends Plugin {
return 'List';
}
}

/**
* The configuration of the {@link module:list/list~List list} feature.
*
* ClassicEditor
* .create( editorElement, {
* list: ... // The list feature configuration.
* } )
* .then( ... )
* .catch( ... );
*
* See {@link module:core/editor/editorconfig~EditorConfig all editor options}.
*
* @interface ListConfig
*/

/**
* The configuration of the {@link module:list/list~List} feature.
*
* Read more in {@link module:list/list~ListConfig}.
*
* @member {module:module:list/list~ListConfig} module:core/editor/editorconfig~EditorConfig#list
*/
63 changes: 63 additions & 0 deletions packages/ckeditor5-list/src/listreversedcommand.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/**
* @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/

/**
* @module list/listreversedcommand
*/

import { Command } from 'ckeditor5/src/core';
import { getSelectedListItems } from './utils';

/**
* The list reversed command. It changes `listReversed` attribute of the selected list items.
* It is used by the {@link module:list/liststyle~ListStyle list style feature}.
*
* @extends module:core/command~Command
*/
export default class ListReversedCommand extends Command {
/**
* @inheritDoc
*/
refresh() {
const value = this._getValue();
this.value = value;
this.isEnabled = value != null;
}

/**
* Executes the command.
*
* @param {Object} options
* @param {Boolean} [options.reversed=false] Whether the list should be reversed.
* @protected
*/
execute( options = {} ) {
const model = this.editor.model;
const listItems = getSelectedListItems( model )
.filter( item => item.getAttribute( 'listType' ) == 'numbered' );

model.change( writer => {
for ( const item of listItems ) {
writer.setAttribute( 'listReversed', !!options.reversed, item );
}
} );
}

/**
* Checks the command's {@link #value}.
*
* @private
* @returns {Boolean|null} The current value.
*/
_getValue() {
const listItem = this.editor.model.document.selection.getFirstPosition().parent;

if ( listItem && listItem.is( 'element', 'listItem' ) && listItem.getAttribute( 'listType' ) == 'numbered' ) {
return listItem.getAttribute( 'listReversed' );
}

return null;
}
}
63 changes: 63 additions & 0 deletions packages/ckeditor5-list/src/liststartcommand.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/**
* @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/

/**
* @module list/liststartcommand
*/

import { Command } from 'ckeditor5/src/core';
import { getSelectedListItems } from './utils';

/**
* The list start index command. It changes `listStart` attribute of the selected list items.
* It is used by the {@link module:list/liststyle~ListStyle list style feature}.
*
* @extends module:core/command~Command
*/
export default class ListStartCommand extends Command {
/**
* @inheritDoc
*/
refresh() {
const value = this._getValue();
this.value = value;
this.isEnabled = value != null;
}

/**
* Executes the command.
*
* @param {Object} options
* @param {Number} [options.startIndex=1] Whether the list should be reversed.
* @protected
*/
execute( options = {} ) {
const model = this.editor.model;
const listItems = getSelectedListItems( model )
.filter( item => item.getAttribute( 'listType' ) == 'numbered' );

model.change( writer => {
for ( const item of listItems ) {
writer.setAttribute( 'listStart', options.startIndex || 1, item );
}
} );
}

/**
* Checks the command's {@link #value}.
*
* @private
* @returns {Boolean|null} The current value.
*/
_getValue() {
const listItem = this.editor.model.document.selection.getFirstPosition().parent;

if ( listItem && listItem.is( 'element', 'listItem' ) && listItem.getAttribute( 'listType' ) == 'numbered' ) {
return listItem.getAttribute( 'listStart' );
}

return null;
}
}
58 changes: 58 additions & 0 deletions packages/ckeditor5-list/src/liststyle.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,61 @@ export default class ListStyle extends Plugin {
return 'ListStyle';
}
}

/**
* The configuration of the {@link module:list/liststyle~ListStyle list properties} feature.
*
* This configuration controls the individual list properties. For instance, it enables or disables specific editor commands
* operating on lists ({@link module:list/liststylecommand~ListStyleCommand `'listStyle'`},
* {@link module:list/liststartcommand~ListStartCommand `'listStart'`},
* {@link module:list/listreversedcommand~ListReversedCommand `'listReversed'`}), the look of the UI
* (`'numberedList'` and `'bulletedList'` dropdowns), and editor data pipeline (allowed HTML attributes).
*
* ClassicEditor
* .create( editorElement, {
* list: {
* properties: {
* styles: true,
* startIndex: true,
* reversed: true
* }
* }
* } )
* .then( ... )
* .catch( ... );
*
* @interface ListPropertiesConfig
*/

/**
* When set, the list style feature will be enabled. It allows changing the `list-style-type` HTML attribute of the lists.
*
* @default true
* @member {Boolean} module:list/liststyle~ListPropertiesConfig#styles
*/

/**
* When set, the list start index feature will be enabled. It allows changing the `start` HTML attribute of the numbered lists.
*
* **Note**: This configuration doesn't affect bulleted and todo lists.
*
* @default false
* @member {Boolean} module:list/liststyle~ListPropertiesConfig#startIndex
*/

/**
* When set, the list reversed feature will be enabled. It allows changing the `reversed` HTML attribute of the numbered lists.
*
* **Note**: This configuration doesn't affect bulleted and todo lists.
*
* @default false
* @member {Boolean} module:list/liststyle~ListPropertiesConfig#reversed
*/

/**
* The configuration of the {@link module:list/liststyle~ListStyle} feature.
*
* Read more in {@link module:list/liststyle~ListPropertiesConfig}.
*
* @member {module:list/liststyle~ListPropertiesConfig} module:list/list~ListConfig#properties
*/
25 changes: 4 additions & 21 deletions packages/ckeditor5-list/src/liststylecommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@
*/

import { Command } from 'ckeditor5/src/core';
import { getSiblingNodes } from './utils';
import { getSelectedListItems } from './utils';

/**
* The list style command. It is used by the {@link module:list/liststyle~ListStyle list style feature}.
* The list style command. It changes `listStyle` attribute of the selected list items.
* It is used by the {@link module:list/liststyle~ListStyle list style feature}.
*
* @extends module:core/command~Command
*/
Expand Down Expand Up @@ -53,25 +54,7 @@ export default class ListStyleCommand extends Command {
*/
execute( options = {} ) {
const model = this.editor.model;
const document = model.document;

// For all selected blocks find all list items that are being selected
// and update the `listStyle` attribute in those lists.
let listItems = [ ...document.selection.getSelectedBlocks() ]
.filter( element => element.is( 'element', 'listItem' ) )
.map( element => {
const position = model.change( writer => writer.createPositionAt( element, 0 ) );

return [
...getSiblingNodes( position, 'backward' ),
...getSiblingNodes( position, 'forward' )
];
} )
.flat();

// Since `getSelectedBlocks()` can return items that belong to the same list, and
// `getSiblingNodes()` returns the entire list, we need to remove duplicated items.
listItems = [ ...new Set( listItems ) ];
const listItems = getSelectedListItems( model );

if ( !listItems.length ) {
return;
Expand Down
Loading

0 comments on commit d080639

Please sign in to comment.