@ebl-vue/editor-full 2.31.11 → 2.31.12
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.mjs +360 -319
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/Editor/Editor.vue +22 -6
- package/src/plugins/list/ListRenderer/ChecklistRenderer.ts +1 -1
- package/src/plugins/list/ListTabulator/index.ts +1 -1
- package/src/plugins/list/index.ts +118 -123
- package/src/plugins/list/styles/.cdx-list .css +168 -0
- package/src/plugins/list/utils/normalizeData.ts +0 -1
- package/src/plugins/list-bak/ListRenderer/ChecklistRenderer.ts +208 -0
- package/src/plugins/list-bak/ListRenderer/ListRenderer.ts +73 -0
- package/src/plugins/list-bak/ListRenderer/OrderedListRenderer.ts +123 -0
- package/src/plugins/list-bak/ListRenderer/UnorderedListRenderer.ts +123 -0
- package/src/plugins/list-bak/ListRenderer/index.ts +6 -0
- package/src/plugins/list-bak/ListTabulator/index.ts +1179 -0
- package/src/plugins/list-bak/index.ts +485 -0
- package/src/plugins/list-bak/styles/CssPrefix.ts +4 -0
- package/src/plugins/list-bak/styles/input.css +36 -0
- package/src/plugins/list-bak/styles/list.css +165 -0
- package/src/plugins/list-bak/types/Elements.ts +14 -0
- package/src/plugins/list-bak/types/ItemMeta.ts +40 -0
- package/src/plugins/list-bak/types/ListParams.ts +102 -0
- package/src/plugins/list-bak/types/ListRenderer.ts +6 -0
- package/src/plugins/list-bak/types/OlCounterType.ts +63 -0
- package/src/plugins/list-bak/types/index.ts +14 -0
- package/src/plugins/list-bak/utils/focusItem.ts +18 -0
- package/src/plugins/list-bak/utils/getChildItems.ts +40 -0
- package/src/plugins/list-bak/utils/getItemChildWrapper.ts +10 -0
- package/src/plugins/list-bak/utils/getItemContentElement.ts +10 -0
- package/src/plugins/list-bak/utils/getSiblings.ts +52 -0
- package/src/plugins/list-bak/utils/isLastItem.ts +9 -0
- package/src/plugins/list-bak/utils/itemHasSublist.ts +10 -0
- package/src/plugins/list-bak/utils/normalizeData.ts +84 -0
- package/src/plugins/list-bak/utils/removeChildWrapperIfEmpty.ts +31 -0
- package/src/plugins/list-bak/utils/renderToolboxInput.ts +105 -0
- package/src/plugins/list-bak/utils/stripNumbers.ts +7 -0
- package/src/plugins/list-bak/utils/type-guards.ts +8 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { OlCounterType } from './OlCounterType';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Meta information of each list item
|
|
5
|
+
*/
|
|
6
|
+
export interface ItemMetaBase {}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Meta information of checklist item
|
|
10
|
+
*/
|
|
11
|
+
export interface ChecklistItemMeta extends ItemMetaBase {
|
|
12
|
+
/**
|
|
13
|
+
* State of the checkbox of the item
|
|
14
|
+
*/
|
|
15
|
+
checked: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Meta information of ordered list item
|
|
20
|
+
*/
|
|
21
|
+
export interface OrderedListItemMeta extends ItemMetaBase {
|
|
22
|
+
/**
|
|
23
|
+
* If passed, ordered list counters will start with this index
|
|
24
|
+
*/
|
|
25
|
+
start?: number;
|
|
26
|
+
/**
|
|
27
|
+
* Counters type used only in ordered list
|
|
28
|
+
*/
|
|
29
|
+
counterType?: OlCounterType;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Meta information of unordered list item
|
|
34
|
+
*/
|
|
35
|
+
export interface UnorderedListItemMeta extends ItemMetaBase {}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Type that represents all available meta objects for list item
|
|
39
|
+
*/
|
|
40
|
+
export type ItemMeta = ChecklistItemMeta | OrderedListItemMeta | UnorderedListItemMeta;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type { ItemMeta } from './ItemMeta';
|
|
2
|
+
import type { OlCounterType } from './OlCounterType';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* list style to make list as ordered or unordered
|
|
6
|
+
*/
|
|
7
|
+
export type ListDataStyle = 'ordered' | 'unordered' | 'checklist';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Interface that represents data of the List tool
|
|
11
|
+
*/
|
|
12
|
+
export type ListData = Omit<ListItem, 'content'> & {
|
|
13
|
+
/**
|
|
14
|
+
* Style of the list tool
|
|
15
|
+
*/
|
|
16
|
+
style: ListDataStyle;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Interface that represents data of the List tool
|
|
21
|
+
*/
|
|
22
|
+
export interface OldListData {
|
|
23
|
+
/**
|
|
24
|
+
* Style of the List tool
|
|
25
|
+
*/
|
|
26
|
+
style: 'ordered' | 'unordered';
|
|
27
|
+
/**
|
|
28
|
+
* Array of items of the List tool
|
|
29
|
+
*/
|
|
30
|
+
items: string[];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Type that represents data of the List tool
|
|
35
|
+
*/
|
|
36
|
+
export type OldNestedListData = Omit<ListData, 'meta'>;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Interface that represents old checklist data format
|
|
40
|
+
*/
|
|
41
|
+
export interface OldChecklistData {
|
|
42
|
+
/**
|
|
43
|
+
* Checklist items
|
|
44
|
+
*/
|
|
45
|
+
items: OldChecklistItem[];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Interface that represents old checklist item format
|
|
50
|
+
*/
|
|
51
|
+
interface OldChecklistItem {
|
|
52
|
+
/**
|
|
53
|
+
* Text of the checklist item
|
|
54
|
+
*/
|
|
55
|
+
text: string;
|
|
56
|
+
/**
|
|
57
|
+
* Checked state of the checklist item
|
|
58
|
+
*/
|
|
59
|
+
checked: boolean;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* List item within the output data
|
|
64
|
+
*/
|
|
65
|
+
export interface ListItem {
|
|
66
|
+
/**
|
|
67
|
+
* list item text content
|
|
68
|
+
*/
|
|
69
|
+
content: string;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Meta information of each list item
|
|
73
|
+
*/
|
|
74
|
+
meta: ItemMeta;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* sublist items
|
|
78
|
+
*/
|
|
79
|
+
items: ListItem[];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Tool's configuration
|
|
84
|
+
*/
|
|
85
|
+
export interface ListConfig {
|
|
86
|
+
/**
|
|
87
|
+
* default list style: ordered or unordered
|
|
88
|
+
* default is unordered
|
|
89
|
+
*/
|
|
90
|
+
defaultStyle?: ListDataStyle;
|
|
91
|
+
/**
|
|
92
|
+
* Max level of the nesting in list
|
|
93
|
+
* If nesting is not needed, it could be set to 1
|
|
94
|
+
*/
|
|
95
|
+
maxLevel?: number;
|
|
96
|
+
/**
|
|
97
|
+
* Specifies which counter types should be shown in the ordered list style selector.
|
|
98
|
+
* @example ['numeric', 'upper-roman'] // Shows selector with these two options
|
|
99
|
+
* @default undefined // All counter types are available when not specified
|
|
100
|
+
*/
|
|
101
|
+
counterTypes?: OlCounterType[];
|
|
102
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { IconNumber, IconLowerRoman, IconUpperRoman, IconLowerAlpha, IconUpperAlpha } from '../../../icons';
|
|
2
|
+
|
|
3
|
+
export type OlCounterType = 'numeric' | 'upper-roman' | 'lower-roman' | 'upper-alpha' | 'lower-alpha';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Map that represents all of the supported styles of the counters for ordered list
|
|
7
|
+
*/
|
|
8
|
+
export const OlCounterTypesMap = new Map<string, string>([
|
|
9
|
+
/**
|
|
10
|
+
* Value that represents default arabic numbers for counters
|
|
11
|
+
*/
|
|
12
|
+
['Numeric', 'numeric'],
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Value that represents lower roman numbers for counteres
|
|
16
|
+
*/
|
|
17
|
+
['Lower Roman', 'lower-roman'],
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Value that represents upper roman numbers for counters
|
|
21
|
+
*/
|
|
22
|
+
['Upper Roman', 'upper-roman'],
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Value that represents lower alpha characters for counters
|
|
26
|
+
*/
|
|
27
|
+
['Lower Alpha', 'lower-alpha'],
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Value that represents upper alpha characters for counters
|
|
31
|
+
*/
|
|
32
|
+
['Upper Alpha', 'upper-alpha'],
|
|
33
|
+
]);
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Map that represents relation between supported counter types and theirs icons to be displayed in toolbox
|
|
37
|
+
*/
|
|
38
|
+
export const OlCounterIconsMap = new Map<string, string>([
|
|
39
|
+
/**
|
|
40
|
+
* Value that represents Icon for Numeric counter type
|
|
41
|
+
*/
|
|
42
|
+
['numeric', IconNumber],
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Value that represents Icon for Lower Roman counter type
|
|
46
|
+
*/
|
|
47
|
+
['lower-roman', IconLowerRoman],
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Value that represents Icon for Upper Roman counter type
|
|
51
|
+
*/
|
|
52
|
+
['upper-roman', IconUpperRoman],
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Value that represents Icon for Lower Alpha counter type
|
|
56
|
+
*/
|
|
57
|
+
['lower-alpha', IconLowerAlpha],
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Value that represents Icon for Upper Alpha counter type
|
|
61
|
+
*/
|
|
62
|
+
['upper-alpha', IconUpperAlpha],
|
|
63
|
+
]);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Paste event for tag substitution, similar to editor.js PasteEvent but with a different data type
|
|
3
|
+
*/
|
|
4
|
+
export interface PasteEvent extends CustomEvent {
|
|
5
|
+
/**
|
|
6
|
+
* Pasted element
|
|
7
|
+
*/
|
|
8
|
+
detail: {
|
|
9
|
+
/**
|
|
10
|
+
* Supported elements fir the paste event
|
|
11
|
+
*/
|
|
12
|
+
data: HTMLUListElement | HTMLOListElement | HTMLLIElement;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { focus } from '@editorjs/caret';
|
|
2
|
+
import type { ItemElement } from '../types/Elements';
|
|
3
|
+
import { getItemContentElement } from './getItemContentElement';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Sets focus to the item's content
|
|
7
|
+
* @param item - item (<li>) to select
|
|
8
|
+
* @param atStart - where to set focus: at the start or at the end
|
|
9
|
+
*/
|
|
10
|
+
export function focusItem(item: ItemElement, atStart: boolean = true): void {
|
|
11
|
+
const itemContent = getItemContentElement(item);
|
|
12
|
+
|
|
13
|
+
if (!itemContent) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
focus(itemContent, atStart);
|
|
18
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { DefaultListCssClasses } from '../ListRenderer';
|
|
2
|
+
import type { ItemChildWrapperElement, ItemElement } from '../types/Elements';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Get child items of the passed element
|
|
6
|
+
* @param element - child items would be got from this element
|
|
7
|
+
* @param firstLevelChildren - if method should return all level child items or only first level ones
|
|
8
|
+
*/
|
|
9
|
+
// eslint-disable-next-line @typescript-eslint/no-duplicate-type-constituents
|
|
10
|
+
export function getChildItems(element: ItemElement | ItemChildWrapperElement, firstLevelChildren: boolean = true): ItemElement[] {
|
|
11
|
+
let itemChildWrapper: HTMLElement = element;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* If passed element is list item than get item's child wrapper
|
|
15
|
+
*/
|
|
16
|
+
if (element.classList.contains(DefaultListCssClasses.item)) {
|
|
17
|
+
itemChildWrapper = element.querySelector(`.${DefaultListCssClasses.itemChildren}`) as HTMLElement;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Check if itemChildWrapper is not null
|
|
22
|
+
*/
|
|
23
|
+
if (itemChildWrapper === null) {
|
|
24
|
+
return [];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (firstLevelChildren) {
|
|
28
|
+
/**
|
|
29
|
+
* Filter first level child items of the curret child item wrapper
|
|
30
|
+
* In case that child could be not only list item
|
|
31
|
+
*/
|
|
32
|
+
return Array.from(itemChildWrapper.querySelectorAll(`:scope > .${DefaultListCssClasses.item}`));
|
|
33
|
+
} else {
|
|
34
|
+
/**
|
|
35
|
+
* Filter all levels child items of the current child item wrapper
|
|
36
|
+
* In case that child could be not only list item
|
|
37
|
+
*/
|
|
38
|
+
return Array.from(itemChildWrapper.querySelectorAll(`.${DefaultListCssClasses.item}`));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ItemChildWrapperElement, ItemElement } from '../types/Elements';
|
|
2
|
+
import { DefaultListCssClasses } from '../ListRenderer';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Returns child wrapper element of the passed item
|
|
6
|
+
* @param item - wrapper element would be got from this item
|
|
7
|
+
*/
|
|
8
|
+
export function getItemChildWrapper(item: ItemElement): ItemChildWrapperElement | null {
|
|
9
|
+
return item.querySelector(`.${DefaultListCssClasses.itemChildren}`);
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ItemContentElement, ItemElement } from '../types/Elements';
|
|
2
|
+
import { DefaultListCssClasses } from '../ListRenderer';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Returns content element of the passed item
|
|
6
|
+
* @param item - content element would be got from this item
|
|
7
|
+
*/
|
|
8
|
+
export function getItemContentElement(item: ItemElement): ItemContentElement | null {
|
|
9
|
+
return item.querySelector(`.${DefaultListCssClasses.itemContent}`);
|
|
10
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get all siblings before passed element, or after it
|
|
3
|
+
* @param element - html element whose siblings would be returned
|
|
4
|
+
* @param direction - wherever siblings would be returned, after element of before it
|
|
5
|
+
*/
|
|
6
|
+
export function getSiblings(element: HTMLElement, direction: 'after' | 'before' = 'after'): Element[] | null {
|
|
7
|
+
const siblings: Element[] = [];
|
|
8
|
+
|
|
9
|
+
let nextElementSibling: HTMLElement;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Method that is responsible for getting next element sibling responsible to the direction variable
|
|
13
|
+
* @param el - current element
|
|
14
|
+
* @returns HTML element of the sibling
|
|
15
|
+
*/
|
|
16
|
+
function getNextElementSibling(el: HTMLElement): HTMLElement {
|
|
17
|
+
/**
|
|
18
|
+
* Get first sibling element respectfully to passed direction
|
|
19
|
+
*/
|
|
20
|
+
switch (direction) {
|
|
21
|
+
case 'after':
|
|
22
|
+
return el.nextElementSibling as HTMLElement;
|
|
23
|
+
|
|
24
|
+
case 'before':
|
|
25
|
+
return el.previousElementSibling as HTMLElement;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
nextElementSibling = getNextElementSibling(element);
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Iterate by all siblings elements
|
|
33
|
+
*/
|
|
34
|
+
while (nextElementSibling !== null) {
|
|
35
|
+
siblings.push(nextElementSibling);
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Get next element sibling
|
|
39
|
+
*/
|
|
40
|
+
nextElementSibling = getNextElementSibling(nextElementSibling);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Check that formed siblings array is not empty
|
|
45
|
+
* If it is emtpy, return null
|
|
46
|
+
*/
|
|
47
|
+
if (siblings.length !== 0) {
|
|
48
|
+
return siblings;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ItemElement } from '../types/Elements';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Check that passed item element is last item of the list
|
|
5
|
+
* @param item - item to be checked, wherever it has next element sibling
|
|
6
|
+
*/
|
|
7
|
+
export function isLastItem(item: ItemElement): boolean {
|
|
8
|
+
return item.nextElementSibling === null;
|
|
9
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ItemElement } from '../types/Elements';
|
|
2
|
+
import { DefaultListCssClasses } from '../ListRenderer';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Check if passed item has the sublist
|
|
6
|
+
* @param item - item to be checked wherever it has sublist
|
|
7
|
+
*/
|
|
8
|
+
export function itemHasSublist(item: ItemElement): boolean {
|
|
9
|
+
return item.querySelector(`.${DefaultListCssClasses.itemChildren}`) !== null;
|
|
10
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { OldListData, ListData, ListItem, OldChecklistData, OldNestedListData } from '../types/ListParams';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Method that checks if data is result of the Old list tool save mtehod
|
|
5
|
+
* @param data - data of the OldList, Checklist, OldNestedList or Editorjs List tool
|
|
6
|
+
* @returns true if data related to the List tool, false otherwise
|
|
7
|
+
*/
|
|
8
|
+
function instanceOfOldListData(data: ListData | OldListData | OldChecklistData | OldNestedListData): data is OldListData {
|
|
9
|
+
return (typeof data.items[0] === 'string');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Method that checks if data is result of the Old nested list tool save method
|
|
14
|
+
* @param data - data of the OldList, Checklist, OldNestedList or Editorjs List tool
|
|
15
|
+
* @returns true if data is related to the Nested List tool, false otherwise
|
|
16
|
+
*/
|
|
17
|
+
function instanceOfOldNestedListData(data: ListData | OldListData | OldChecklistData | OldNestedListData): data is OldNestedListData {
|
|
18
|
+
return !('meta' in data);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Method that checks if data is result of the Old checklist tool save method
|
|
23
|
+
* @param data - data of the Checklist, OldList, OldNestedList or Editorjs List tool
|
|
24
|
+
* @returns true if data is related to the Checklist tool, false otherwise
|
|
25
|
+
*/
|
|
26
|
+
function instanceOfChecklistData(data: ListData | OldListData | OldChecklistData | OldNestedListData): data is OldChecklistData {
|
|
27
|
+
return (
|
|
28
|
+
typeof data.items[0] !== 'string'
|
|
29
|
+
&& 'text' in data.items[0]
|
|
30
|
+
&& 'checked' in data.items[0]
|
|
31
|
+
&& typeof data.items[0].text === 'string'
|
|
32
|
+
&& typeof data.items[0].checked === 'boolean'
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Method that checks if passed data is related to the legacy format and normalizes it
|
|
38
|
+
* @param data - data to be checked
|
|
39
|
+
* @returns - normalized data, ready to be used by Editorjs List tool
|
|
40
|
+
*/
|
|
41
|
+
export default function normalizeData(data: ListData | OldListData | OldChecklistData): ListData {
|
|
42
|
+
|
|
43
|
+
const normalizedDataItems: ListItem[] = [];
|
|
44
|
+
|
|
45
|
+
if (instanceOfOldListData(data)) {
|
|
46
|
+
data.items.forEach((item) => {
|
|
47
|
+
normalizedDataItems.push({
|
|
48
|
+
content: item,
|
|
49
|
+
meta: {},
|
|
50
|
+
items: [],
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
style: data.style,
|
|
56
|
+
meta: {},
|
|
57
|
+
items: normalizedDataItems,
|
|
58
|
+
};
|
|
59
|
+
} else if (instanceOfChecklistData(data)) {
|
|
60
|
+
data.items.forEach((item) => {
|
|
61
|
+
normalizedDataItems.push({
|
|
62
|
+
content: item.text,
|
|
63
|
+
meta: {
|
|
64
|
+
checked: item.checked,
|
|
65
|
+
},
|
|
66
|
+
items: [],
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
style: 'checklist',
|
|
72
|
+
meta: {},
|
|
73
|
+
items: normalizedDataItems,
|
|
74
|
+
};
|
|
75
|
+
} else if (instanceOfOldNestedListData(data)) {
|
|
76
|
+
return {
|
|
77
|
+
style: data.style,
|
|
78
|
+
meta: {},
|
|
79
|
+
items: data.items,
|
|
80
|
+
};
|
|
81
|
+
} else {
|
|
82
|
+
return structuredClone(data);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { DefaultListCssClasses } from '../ListRenderer';
|
|
2
|
+
import type { ItemChildWrapperElement, ItemElement } from '../types/Elements';
|
|
3
|
+
import { getChildItems } from './getChildItems';
|
|
4
|
+
import { getItemChildWrapper } from './getItemChildWrapper';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Method that will remove passed child wrapper if it has no child items
|
|
8
|
+
* @param element - child wrapper or actual item, from where we get child wrapper
|
|
9
|
+
*/
|
|
10
|
+
// eslint-disable-next-line @typescript-eslint/no-duplicate-type-constituents
|
|
11
|
+
export function removeChildWrapperIfEmpty(element: ItemChildWrapperElement | ItemElement): void {
|
|
12
|
+
let itemChildWrapper: HTMLElement | null = element;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* If passed element is list item than get item's child wrapper
|
|
16
|
+
*/
|
|
17
|
+
if (element.classList.contains(DefaultListCssClasses.item)) {
|
|
18
|
+
itemChildWrapper = getItemChildWrapper(element);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (itemChildWrapper === null) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Check that there is at least one item
|
|
27
|
+
*/
|
|
28
|
+
if (getChildItems(itemChildWrapper).length === 0) {
|
|
29
|
+
itemChildWrapper.remove();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import * as Dom from '@editorjs/dom';
|
|
2
|
+
import { CssPrefix } from '../styles/CssPrefix';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Options used in input rendering
|
|
6
|
+
*/
|
|
7
|
+
interface InputOptions {
|
|
8
|
+
/**
|
|
9
|
+
* Placeholder, that will be displayed in input
|
|
10
|
+
*/
|
|
11
|
+
placeholder: string;
|
|
12
|
+
/**
|
|
13
|
+
* Input will be rendered with this value inside
|
|
14
|
+
*/
|
|
15
|
+
value?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Html attributes, that would be added to the input element
|
|
18
|
+
*/
|
|
19
|
+
attributes?: {
|
|
20
|
+
[key: string]: string;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Flag that represents special behavior that prevents you from entering anything other than numbers
|
|
24
|
+
*/
|
|
25
|
+
sanitize?: (value: string) => string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const css = {
|
|
29
|
+
wrapper: `${CssPrefix}-start-with-field`,
|
|
30
|
+
input: `${CssPrefix}-start-with-field__input`,
|
|
31
|
+
startWithElementWrapperInvalid: `${CssPrefix}-start-with-field--invalid`,
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Method that renders html element for popover start with item
|
|
36
|
+
* @param inputCallback - callback method that could change list attributes on input
|
|
37
|
+
* @param inputOptions - options used in input rendering
|
|
38
|
+
* @param inputOptions.value - input will be rendered with this value inside
|
|
39
|
+
* @param inputOptions.placeholder - placeholder, that will be displayed in input
|
|
40
|
+
* @param inputOptions.attributes - html attributes, that would be added to the input element
|
|
41
|
+
* @returns - rendered html element
|
|
42
|
+
*/
|
|
43
|
+
export function renderToolboxInput(inputCallback: (index: string) => void,
|
|
44
|
+
{ value, placeholder, attributes, sanitize }: InputOptions): HTMLElement {
|
|
45
|
+
const startWithElementWrapper = Dom.make('div', css.wrapper);
|
|
46
|
+
|
|
47
|
+
const input = Dom.make('input', css.input, {
|
|
48
|
+
placeholder,
|
|
49
|
+
/**
|
|
50
|
+
* Used to prevent focusing on the input by Tab key
|
|
51
|
+
* (Popover in the Toolbar lays below the blocks,
|
|
52
|
+
* so Tab in the last block will focus this hidden input if this property is not set)
|
|
53
|
+
*/
|
|
54
|
+
tabIndex: -1,
|
|
55
|
+
/**
|
|
56
|
+
* Value of the start property, if it is not specified, then it is set to one
|
|
57
|
+
*/
|
|
58
|
+
value,
|
|
59
|
+
}) as HTMLInputElement;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Add passed attributes to the input
|
|
63
|
+
*/
|
|
64
|
+
for (const attribute in attributes) {
|
|
65
|
+
input.setAttribute(attribute, attributes[attribute]);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
startWithElementWrapper.appendChild(input);
|
|
69
|
+
|
|
70
|
+
input.addEventListener('input', () => {
|
|
71
|
+
/**
|
|
72
|
+
* If input sanitizer specified, then sanitize input value
|
|
73
|
+
*/
|
|
74
|
+
if (sanitize !== undefined) {
|
|
75
|
+
input.value = sanitize(input.value);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const validInput = input.checkValidity();
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* If input is invalid and classlist does not contain invalid class, add it
|
|
82
|
+
*/
|
|
83
|
+
if (!validInput && !startWithElementWrapper.classList.contains(css.startWithElementWrapperInvalid)) {
|
|
84
|
+
startWithElementWrapper.classList.add(css.startWithElementWrapperInvalid);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* If input is valid and classlist contains invalid class, remove it
|
|
89
|
+
*/
|
|
90
|
+
if (validInput && startWithElementWrapper.classList.contains(css.startWithElementWrapperInvalid)) {
|
|
91
|
+
startWithElementWrapper.classList.remove(css.startWithElementWrapperInvalid);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* If input is invalid, than do not change start with attribute
|
|
96
|
+
*/
|
|
97
|
+
if (!validInput) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
inputCallback(input.value);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
return startWithElementWrapper;
|
|
105
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type guard to check if a node is an HTMLElement, then we can safely use it as an HTMLElement
|
|
3
|
+
* @param node - Node to be checked, wherever it is an HTMLElement
|
|
4
|
+
*/
|
|
5
|
+
export function isHtmlElement(node: Node): node is HTMLElement {
|
|
6
|
+
// node is an HTMLElement if it is an element node
|
|
7
|
+
return node.nodeType === Node.ELEMENT_NODE;
|
|
8
|
+
}
|