Skip to content

Commit

Permalink
Merge pull request #16614 from ckeditor/ck/15554
Browse files Browse the repository at this point in the history
Feature (List): The list styles can be enabled for selected list types. Closes #15554.
  • Loading branch information
niegowski authored Jul 18, 2024
2 parents e4bf767 + 6ead07c commit 248e072
Show file tree
Hide file tree
Showing 10 changed files with 710 additions and 61 deletions.
33 changes: 32 additions & 1 deletion packages/ckeditor5-list/src/listconfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
* @module list/listconfig
*/

import { type ArrayOrItem } from 'ckeditor5/src/utils.js';

/**
* The configuration of the {@link module:list/list~List list} feature
* and the {@link module:list/legacylist~LegacyList legacy list} feature.
Expand Down Expand Up @@ -86,7 +88,7 @@ export interface ListPropertiesConfig {
*
* @default true
*/
styles?: boolean | ListPropertiesStyleConfig;
styles?: boolean | ListPropertiesStyleConfig | ArrayOrItem<ListPropertiesStyleListType>;

/**
* When set, the list start index feature will be enabled. It allows changing the `start` HTML attribute of the numbered lists. As a
Expand All @@ -111,6 +113,33 @@ export interface ListPropertiesConfig {

export interface ListPropertiesStyleConfig {

/**
* Enable style feature for the given list type only.
*
* ```ts
* {
* list: {
* properties: {
* styles: {
* listTypes: 'numbered'
* }
*
* // ...
* }
* },
*
* // ...
* }
* ```
*
*
* **Note**: This configuration works only with
* {@link module:list/listproperties~ListProperties list properties}.
*
* @default ['bulleted','numbered']
*/
listTypes?: ArrayOrItem<ListPropertiesStyleListType>;

/**
* When set `true`, the list style feature will use the `type` attribute of `<ul>` and `<ol>` elements instead of the `list-style-type`
* style.
Expand Down Expand Up @@ -140,3 +169,5 @@ export interface ListPropertiesStyleConfig {
*/
useAttribute?: boolean;
}

export type ListPropertiesStyleListType = 'numbered' | 'bulleted';
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import {

import type { ListIndentCommandAfterExecuteEvent } from '../list/listindentcommand.js';
import type { ListPropertiesConfig } from '../listconfig.js';
import { getNormalizedConfig } from './utils/config.js';

const DEFAULT_LIST_TYPE = 'default';

Expand Down Expand Up @@ -256,9 +257,10 @@ export interface AttributeStrategy {
*/
function createAttributeStrategies( enabledProperties: ListPropertiesConfig ) {
const strategies: Array<AttributeStrategy> = [];
const normalizedConfig = getNormalizedConfig( enabledProperties );

if ( enabledProperties.styles ) {
const useAttribute = typeof enabledProperties.styles == 'object' && enabledProperties.styles.useAttribute;
const useAttribute = normalizedConfig.styles.useAttribute;

strategies.push( {
attributeName: 'listStyle',
Expand Down
60 changes: 32 additions & 28 deletions packages/ckeditor5-list/src/listproperties/listpropertiesui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ import type ListStartCommand from '../listproperties/liststartcommand.js';
import type LegacyListReversedCommand from '../legacylistproperties/legacylistreversedcommand.js';
import type ListReversedCommand from '../listproperties/listreversedcommand.js';

import { getNormalizedConfig, type NormalizedListPropertiesConfig } from './utils/config.js';
import { type ListPropertiesStyleListType } from '../listconfig.js';

import listStyleDiscIcon from '../../theme/icons/liststyledisc.svg';
import listStyleCircleIcon from '../../theme/icons/liststylecircle.svg';
import listStyleSquareIcon from '../../theme/icons/liststylesquare.svg';
Expand All @@ -40,7 +43,6 @@ import listStyleLowerLatinIcon from '../../theme/icons/liststylelowerlatin.svg';
import listStyleUpperLatinIcon from '../../theme/icons/liststyleupperlatin.svg';

import '../../theme/liststyles.css';
import type { ListPropertiesConfig } from '../listconfig.js';

/**
* The list properties UI plugin. It introduces the extended `'bulletedList'` and `'numberedList'` toolbar
Expand All @@ -61,11 +63,13 @@ export default class ListPropertiesUI extends Plugin {
const editor = this.editor;
const t = editor.locale.t;
const propertiesConfig = editor.config.get( 'list.properties' )!;
const normalizedConfig = getNormalizedConfig( propertiesConfig );
const stylesListTypes = normalizedConfig.styles.listTypes;

// Note: When this plugin does not register the "bulletedList" dropdown due to properties configuration,
// a simple button will be still registered under the same name by ListUI as a fallback. This should happen
// in most editor configuration because the List plugin automatically requires ListUI.
if ( propertiesConfig.styles ) {
if ( stylesListTypes.includes( 'bulleted' ) ) {
const styleDefinitions = [
{
label: t( 'Toggle the disc list style' ),
Expand All @@ -92,7 +96,7 @@ export default class ListPropertiesUI extends Plugin {

editor.ui.componentFactory.add( commandName, getDropdownViewCreator( {
editor,
propertiesConfig,
normalizedConfig,
parentCommandName: commandName,
buttonLabel,
buttonIcon: icons.bulletedList,
Expand All @@ -103,7 +107,7 @@ export default class ListPropertiesUI extends Plugin {
// Add the menu bar item for bulleted list.
editor.ui.componentFactory.add( `menuBar:${ commandName }`, getMenuBarStylesMenuCreator( {
editor,
propertiesConfig,
normalizedConfig,
parentCommandName: commandName,
buttonLabel,
styleGridAriaLabel,
Expand All @@ -114,7 +118,7 @@ export default class ListPropertiesUI extends Plugin {
// Note: When this plugin does not register the "numberedList" dropdown due to properties configuration,
// a simple button will be still registered under the same name by ListUI as a fallback. This should happen
// in most editor configuration because the List plugin automatically requires ListUI.
if ( propertiesConfig.styles || propertiesConfig.startIndex || propertiesConfig.reversed ) {
if ( stylesListTypes.includes( 'numbered' ) || propertiesConfig.startIndex || propertiesConfig.reversed ) {
const styleDefinitions = [
{
label: t( 'Toggle the decimal list style' ),
Expand Down Expand Up @@ -159,7 +163,7 @@ export default class ListPropertiesUI extends Plugin {

editor.ui.componentFactory.add( commandName, getDropdownViewCreator( {
editor,
propertiesConfig,
normalizedConfig,
parentCommandName: commandName,
buttonLabel,
buttonIcon: icons.numberedList,
Expand All @@ -169,10 +173,10 @@ export default class ListPropertiesUI extends Plugin {

// Menu bar menu does not display list start index or reverse UI. If there are no styles enabled,
// the menu makes no sense and should be omitted.
if ( propertiesConfig.styles ) {
if ( stylesListTypes.includes( 'numbered' ) ) {
editor.ui.componentFactory.add( `menuBar:${ commandName }`, getMenuBarStylesMenuCreator( {
editor,
propertiesConfig,
normalizedConfig,
parentCommandName: commandName,
buttonLabel,
styleGridAriaLabel,
Expand All @@ -188,7 +192,7 @@ export default class ListPropertiesUI extends Plugin {
* which in turn contains buttons allowing users to change list styles in the context of the current selection.
*
* @param options.editor
* @param options.propertiesConfig List properties configuration.
* @param options.normalizedConfig List properties configuration.
* @param options.parentCommandName The name of the higher-order editor command associated with
* the set of particular list styles (e.g. "bulletedList" for "disc", "circle", and "square" styles).
* @param options.buttonLabel Label of the main part of the split button.
Expand All @@ -199,15 +203,15 @@ export default class ListPropertiesUI extends Plugin {
*/
function getDropdownViewCreator( {
editor,
propertiesConfig,
normalizedConfig,
parentCommandName,
buttonLabel,
buttonIcon,
styleGridAriaLabel,
styleDefinitions
}: {
editor: Editor;
propertiesConfig: Readonly<ListPropertiesConfig>;
normalizedConfig: Readonly<NormalizedListPropertiesConfig>;
parentCommandName: string;
buttonLabel: string;
buttonIcon: string;
Expand Down Expand Up @@ -241,7 +245,7 @@ function getDropdownViewCreator( {
dropdownView.once( 'change:isOpen', () => {
const listPropertiesView = createListPropertiesView( {
editor,
propertiesConfig,
normalizedConfig,
dropdownView,
parentCommandName,
styleGridAriaLabel,
Expand Down Expand Up @@ -321,7 +325,7 @@ function getStyleButtonCreator( {
* A helper that creates the properties view for the individual style dropdown.
*
* @param options.editor Editor instance.
* @param options.propertiesConfig List properties configuration.
* @param options.normalizedConfig List properties configuration.
* @param options.dropdownView Styles dropdown view that hosts the properties view.
* @param options.parentCommandName The name of the higher-order editor command associated with
* the set of particular list styles (e.g. "bulletedList" for "disc", "circle", and "square" styles).
Expand All @@ -330,32 +334,33 @@ function getStyleButtonCreator( {
*/
function createListPropertiesView( {
editor,
propertiesConfig,
normalizedConfig,
dropdownView,
parentCommandName,
styleDefinitions,
styleGridAriaLabel
}: {
editor: Editor;
propertiesConfig: Readonly<ListPropertiesConfig>;
normalizedConfig: Readonly<NormalizedListPropertiesConfig>;
dropdownView: DropdownView;
parentCommandName: string;
styleDefinitions: Array<StyleDefinition>;
styleGridAriaLabel: string;
} ) {
const locale = editor.locale;
const enabledProperties = {
...propertiesConfig
};
...normalizedConfig,

if ( parentCommandName != 'numberedList' ) {
enabledProperties.startIndex = false;
enabledProperties.reversed = false;
}
...( parentCommandName != 'numberedList' ? {
startIndex: false,
reversed: false
} : null )
};
const listType = parentCommandName.replace( 'List', '' ) as ListPropertiesStyleListType;

let styleButtonViews = null;

if ( enabledProperties.styles ) {
if ( normalizedConfig.styles.listTypes.includes( listType ) ) {
const listStyleCommand: LegacyListStyleCommand | ListStyleCommand = editor.commands.get( 'listStyle' )!;

const styleButtonCreator = getStyleButtonCreator( {
Expand All @@ -376,7 +381,7 @@ function createListPropertiesView( {
styleButtonViews
} );

if ( enabledProperties.styles ) {
if ( normalizedConfig.styles.listTypes.includes( listType ) ) {
// Accessibility: focus the first active style when opening the dropdown.
focusChildOnDropdownOpen( dropdownView, () => {
return listPropertiesView.stylesView!.children.find( ( child: any ) => child.isOn );
Expand Down Expand Up @@ -413,23 +418,22 @@ function createListPropertiesView( {
* A helper that creates the list style submenu for menu bar.
*
* @param editor Editor instance.
* @param propertiesConfig List properties configuration.
* @param normalizedConfig List properties configuration.
* @param parentCommandName Name of the list command.
* @param buttonLabel Label of the menu button.
* @param styleGridAriaLabel ARIA label of the styles grid.
* @param styleDefinitions Array of available styles for processed list type.
*/
function getMenuBarStylesMenuCreator(
{
editor,
propertiesConfig,
normalizedConfig,
parentCommandName,
buttonLabel,
styleGridAriaLabel,
styleDefinitions
}: {
editor: Editor;
propertiesConfig: Readonly<ListPropertiesConfig>;
normalizedConfig: Readonly<NormalizedListPropertiesConfig>;
parentCommandName: 'bulletedList' | 'numberedList';
buttonLabel: string;
styleGridAriaLabel: string;
Expand All @@ -450,7 +454,7 @@ function getMenuBarStylesMenuCreator(
const listPropertiesView = new ListPropertiesView( locale, {
styleGridAriaLabel,
enabledProperties: {
...propertiesConfig,
...normalizedConfig,

// Disable list start index and reversed in the menu bar.
startIndex: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import {
type Locale
} from 'ckeditor5/src/utils.js';

import type { ListPropertiesConfig } from '../../listconfig.js';
import type { NormalizedListPropertiesConfig } from '../utils/config.js';

import '../../../theme/listproperties.css';

Expand Down Expand Up @@ -120,7 +120,7 @@ export default class ListPropertiesView extends View {
constructor(
locale: Locale,
{ enabledProperties, styleButtonViews, styleGridAriaLabel }: {
enabledProperties: ListPropertiesConfig;
enabledProperties: NormalizedListPropertiesConfig;
styleButtonViews: Array<ButtonView> | null;
styleGridAriaLabel: string;
}
Expand Down Expand Up @@ -149,7 +149,7 @@ export default class ListPropertiesView extends View {

// The rendering of the styles grid is conditional. When there is no styles grid, the view will render without collapsible
// for numbered list properties, hence simplifying the layout.
if ( enabledProperties.styles ) {
if ( styleButtonViews && styleButtonViews.length ) {
this.stylesView = this._createStylesView( styleButtonViews!, styleGridAriaLabel );
this.children.add( this.stylesView );
} else {
Expand Down Expand Up @@ -302,7 +302,7 @@ export default class ListPropertiesView extends View {
* @param enabledProperties An object containing the configuration of enabled list property names
* (see {@link #constructor}).
*/
private _addNumberedListPropertyViews( enabledProperties: ListPropertiesConfig ) {
private _addNumberedListPropertyViews( enabledProperties: NormalizedListPropertiesConfig ) {
const t = this.locale.t;
const numberedPropertyViews = [];

Expand All @@ -317,7 +317,7 @@ export default class ListPropertiesView extends View {
}

// When there are some style buttons, pack the numbered list properties into a collapsible to separate them.
if ( enabledProperties.styles ) {
if ( this.stylesView ) {
this.additionalPropertiesCollapsibleView = new CollapsibleView( this.locale, numberedPropertyViews );

this.additionalPropertiesCollapsibleView.set( {
Expand Down
Loading

0 comments on commit 248e072

Please sign in to comment.