-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #7861 from ckeditor/i/7801
Feature (list): Introduced the list styles feature that allows customizing the list's marker of the list item elements. Closes #7801. Feature (theme-lark): Creates styles for the `ListStylesUI` plugin (see #7803). MINOR BREAKING CHANGE (ui): It is now possible to override existing components when [adding new ones](https://ckeditor.com/docs/ckeditor5/latest/api/module_ui_componentfactory-ComponentFactory.html#function-add) to the [component factory](https://ckeditor.com/docs/ckeditor5/latest/api/module_ui_componentfactory-ComponentFactory.html) (previously an error was thrown) (see #7803).
- Loading branch information
Showing
31 changed files
with
3,162 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,25 @@ | ||
{ | ||
"Numbered List": "Toolbar button tooltip for the Numbered List feature.", | ||
"Bulleted List": "Toolbar button tooltip for the Bulleted List feature.", | ||
"To-do List": "Toolbar button tooltip for the To-do List feature." | ||
"To-do List": "Toolbar button tooltip for the To-do List feature.", | ||
"Bulleted list styles toolbar": "The ARIA label of the toolbar displaying buttons allowing users to change the bulleted list style.", | ||
"Numbered list styles toolbar": "The ARIA label of the toolbar displaying buttons allowing users to change the numbered list style.", | ||
"Toggle the disc list style": "The ARIA label of the button that toggles the \"disc\" list style.", | ||
"Toggle the circle list style": "The ARIA label of the button that toggles the \"circle\" list style.", | ||
"Toggle the square list style": "The ARIA label of the button that toggles the \"square\" list style.", | ||
"Toggle the decimal list style": "The ARIA label of the button that toggles the \"decimal\" list style.", | ||
"Toggle the decimal with leading zero list style": "The ARIA label of the button that toggles the \"decimal with leading zero\" list style.", | ||
"Toggle the lower–roman list style": "The ARIA label of the button that toggles the \"lower–roman\" list style.", | ||
"Toggle the upper–roman list style": "The ARIA label of the button that toggles the \"upper–roman\" list style.", | ||
"Toggle the lower–latin list style": "The ARIA label of the button that toggles the \"lower–latin\" list style.", | ||
"Toggle the upper–latin list style": "The ARIA label of the button that toggles the \"upper–latin\" list style.", | ||
"Disc": "The tooltip text of the button that toggles the \"disc\" list style.", | ||
"Circle": "The tooltip text of the button that toggles the \"circle\" list style.", | ||
"Square": "The tooltip text of the button that toggles the \"square\" list style.", | ||
"Decimal": "The tooltip text of the button that toggles the \"decimal\" list style.", | ||
"Decimal with leading zero": "The tooltip text of the button that toggles the \"decimal with leading zero\" list style.", | ||
"Lower–roman": "The tooltip text of the button that toggles the \"lower–roman\" list style.", | ||
"Upper-roman": "The tooltip text of the button that toggles the \"upper–roman\" list style.", | ||
"Lower-latin": "The tooltip text of the button that toggles the \"lower–latin\" list style.", | ||
"Upper-latin": "The tooltip text of the button that toggles the \"upper–latin\" list style." | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
/** | ||
* @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. | ||
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license | ||
*/ | ||
|
||
/** | ||
* @module list/liststyle | ||
*/ | ||
|
||
import Plugin from '@ckeditor/ckeditor5-core/src/plugin'; | ||
import ListStyleEditing from './liststyleediting'; | ||
import ListStyleUI from './liststyleui'; | ||
|
||
/** | ||
* The list styles 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}. | ||
* | ||
* @extends module:core/plugin~Plugin | ||
*/ | ||
export default class ListStyle extends Plugin { | ||
/** | ||
* @inheritDoc | ||
*/ | ||
static get requires() { | ||
return [ ListStyleEditing, ListStyleUI ]; | ||
} | ||
|
||
/** | ||
* @inheritDoc | ||
*/ | ||
static get pluginName() { | ||
return 'ListStyle'; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,197 @@ | ||
/** | ||
* @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. | ||
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license | ||
*/ | ||
|
||
/** | ||
* @module list/liststylecommand | ||
*/ | ||
|
||
import Command from '@ckeditor/ckeditor5-core/src/command'; | ||
import TreeWalker from '@ckeditor/ckeditor5-engine/src/model/treewalker'; | ||
|
||
/** | ||
* The list style command. It is used by the {@link module:list/liststyle~ListStyle list styles feature}. | ||
* | ||
* @extends module:core/command~Command | ||
*/ | ||
export default class ListStyleCommand extends Command { | ||
/** | ||
* Creates an instance of the command. | ||
* | ||
* @param {module:core/editor/editor~Editor} editor The editor instance. | ||
* @param {String} defaultType The list type that will be used by default if the value was not specified during | ||
* the command execution. | ||
*/ | ||
constructor( editor, defaultType ) { | ||
super( editor ); | ||
|
||
/** | ||
* The default type of the list style. | ||
* | ||
* @protected | ||
* @member {String} | ||
*/ | ||
this._defaultType = defaultType; | ||
} | ||
|
||
/** | ||
* @inheritDoc | ||
*/ | ||
refresh() { | ||
this.value = this._getValue(); | ||
this.isEnabled = this._checkEnabled(); | ||
} | ||
|
||
/** | ||
* Executes the 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 | ||
* style will be applied. | ||
* @protected | ||
*/ | ||
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 ) ]; | ||
|
||
if ( !listItems.length ) { | ||
return; | ||
} | ||
|
||
model.change( writer => { | ||
for ( const item of listItems ) { | ||
writer.setAttribute( 'listStyle', options.type || this._defaultType, item ); | ||
} | ||
} ); | ||
} | ||
|
||
/** | ||
* Checks the command's {@link #value}. | ||
* | ||
* @private | ||
* @returns {String|null} The current value. | ||
*/ | ||
_getValue() { | ||
const listItem = this.editor.model.document.selection.getFirstPosition().parent; | ||
|
||
if ( listItem && listItem.is( 'element', 'listItem' ) ) { | ||
return listItem.getAttribute( 'listStyle' ); | ||
} | ||
|
||
return null; | ||
} | ||
|
||
/** | ||
* Checks whether the command can be enabled in the current context. | ||
* | ||
* @private | ||
* @returns {Boolean} Whether the command should be enabled. | ||
*/ | ||
_checkEnabled() { | ||
const editor = this.editor; | ||
|
||
const numberedList = editor.commands.get( 'numberedList' ); | ||
const bulletedList = editor.commands.get( 'bulletedList' ); | ||
|
||
return numberedList.isEnabled || bulletedList.isEnabled; | ||
} | ||
} | ||
|
||
// 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; | ||
} |
Oops, something went wrong.