Skip to content

Commit e960bc2

Browse files
authored
Merge pull request #458 from Harbour-Enterprises/nick/har-8863-lists-v1
HAR-8863 - Lists v1
2 parents 9cb3137 + ff5b170 commit e960bc2

47 files changed

Lines changed: 6316 additions & 531 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

package-lock.json

Lines changed: 395 additions & 347 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/super-editor/src/core/Editor.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ export class Editor extends EventEmitter {
7171
annotations: false,
7272
isInternal: false,
7373
externalExtensions: [],
74+
numbering: {},
7475
onBeforeCreate: () => null,
7576
onCreate: () => null,
7677
onUpdate: () => null,
@@ -500,11 +501,11 @@ export class Editor extends EventEmitter {
500501
* Load the data from DOCX to be used in the schema.
501502
* Expects a DOCX file.
502503
*/
503-
static async loadXmlData(fileSource) {
504+
static async loadXmlData(fileSource, isNode = false) {
504505
if (!fileSource) return;
505506

506507
const zipper = new DocxZipper();
507-
const xmlFiles = await zipper.getDocxData(fileSource);
508+
const xmlFiles = await zipper.getDocxData(fileSource, isNode);
508509
const mediaFiles = zipper.media;
509510

510511
return [xmlFiles, mediaFiles, zipper.mediaFiles, zipper.fonts];
@@ -983,11 +984,14 @@ export class Editor extends EventEmitter {
983984
const rels = this.converter.schemaToXml(this.converter.convertedXml['word/_rels/document.xml.rels'].elements[0]);
984985
const media = this.converter.addedMedia;
985986

987+
const numberingData = this.converter.convertedXml['word/numbering.xml'];
988+
const numbering = this.converter.schemaToXml(numberingData.elements[0]);
986989
const updatedDocs = {
987990
'word/document.xml': String(documentXml),
988991
'docProps/custom.xml': String(customXml),
989992
'word/settings.xml': String(customSettings),
990993
'word/_rels/document.xml.rels': String(rels),
994+
'word/numbering.xml': String(numbering),
991995

992996
// Replace & with & in styles.xml as DOCX viewers can't handle it
993997
'word/styles.xml': String(styles).replace(/&/gi, '&'),

packages/super-editor/src/core/commands/toggleList.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { canJoin } from 'prosemirror-transform';
22
import { getNodeType } from '../helpers/getNodeType.js';
33
import { findParentNode } from '../helpers/findParentNode.js';
44
import { isList } from '../helpers/isList.js';
5+
import { baseBulletList, baseOrderedListDef } from '../helpers/baseListDefinitions';
56

67
/**
78
* Join list backwards.
@@ -67,12 +68,15 @@ export const toggleList =
6768
if (!range) return false;
6869

6970
const parentList = findParentNode((node) => isList(node.type.name, extensions))(selection);
71+
const { numbering } = editor.converter;
7072

7173
// This is the case when we toggle an existing list.
7274
if (range.depth >= 1 && parentList && range.depth - parentList.depth <= 1) {
7375
// If we toggle to the same list type,
7476
// then execute `liftListItem` command.
7577
if (parentList.node.type === listType) {
78+
const { listId } = parentList.node.attrs;
79+
editor.converter.numbering = removeListDefinitions(listId, numbering);
7680
return commands.liftListItem(itemType);
7781
}
7882

@@ -103,6 +107,11 @@ export const toggleList =
103107
};
104108
};
105109

110+
// Update the numbering definition for this document
111+
const newListId = getNewListId(numbering.definitions);
112+
editor.converter.numbering = generateNewListDefinition(newListId, numbering, listType);
113+
attributes.listId = newListId;
114+
106115
// This is the case when there is no need to ensureMarks.
107116
if (!keepMarks || !marks || !dispatch) {
108117
const result = chain()
@@ -128,3 +137,48 @@ export const toggleList =
128137

129138
return result;
130139
};
140+
141+
142+
const getNewListId = (definitions) => Math.max(...Object.keys(definitions).map(Number)) + 1;
143+
144+
const generateNewListDefinition = (newListId, numbering, listType) => {
145+
// Generate a new numId to add to numbering.xml
146+
const definition = listType.name === 'orderedList' ? baseOrderedListDef : baseBulletList;
147+
const newNumbering = { ...numbering };
148+
149+
// Generate the new abstractNum definition
150+
const newAbstractId = getNewListId(newNumbering.abstracts);
151+
const newAbstractDef = {
152+
...definition,
153+
attributes: {
154+
...definition.attributes,
155+
'w:abstractNumId': String(newAbstractId),
156+
}
157+
};
158+
newNumbering.abstracts[newAbstractId] = newAbstractDef;
159+
160+
// Generate the new numId definition
161+
const newNumDef = {
162+
type: 'element',
163+
name: 'w:num',
164+
attributes: {
165+
'w:numId': String(newListId),
166+
'w16cid:durableId': '485517411'
167+
},
168+
elements: [
169+
{ name: 'w:abstractNumId', attributes: { 'w:val': String(newAbstractId) } },
170+
]
171+
};
172+
newNumbering.definitions[newListId] = newNumDef;
173+
return newNumbering;
174+
};
175+
176+
const removeListDefinitions = (listId, numbering) => {
177+
const { definitions, abstracts } = numbering;
178+
179+
const abstractId = definitions[listId].elements[0].attributes['w:val'];
180+
delete definitions[listId];
181+
delete abstracts[abstractId];
182+
183+
return numbering;
184+
};

packages/super-editor/src/core/extensions/keymap.js

Lines changed: 42 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,36 @@ import { Extension } from '../Extension.js';
22
import { isIOS } from '../utilities/isIOS.js';
33
import { isMacOS } from '../utilities/isMacOS.js';
44

5+
export const handleEnter = (editor) => {
6+
editor.commands.first(({ commands }) => [
7+
() => commands.newlineInCode(),
8+
() => commands.createParagraphNear(),
9+
() => commands.liftEmptyBlock(),
10+
() => commands.splitBlock(),
11+
]);
12+
};
13+
14+
export const handleBackspace = (editor) => {
15+
editor.commands.first(({ commands, tr }) => [
16+
() => commands.undoInputRule(),
17+
() => {
18+
tr.setMeta('inputType', 'deleteContentBackward');
19+
return false;
20+
},
21+
() => commands.deleteSelection(),
22+
() => commands.joinBackward(),
23+
() => commands.selectNodeBackward(),
24+
]);
25+
};
26+
27+
export const handleDelete = (editor) => {
28+
editor.commands.first(({ commands }) => [
29+
() => commands.deleteSelection(),
30+
() => commands.joinForward(),
31+
() => commands.selectNodeForward(),
32+
]);
33+
};
34+
535
/**
636
* For reference.
737
* https://github.com/ProseMirror/prosemirror-commands/blob/master/src/commands.ts
@@ -10,41 +40,14 @@ export const Keymap = Extension.create({
1040
name: 'keymap',
1141

1242
addShortcuts() {
13-
const handleEnter = () =>
14-
this.editor.commands.first(({ commands }) => [
15-
() => commands.newlineInCode(),
16-
() => commands.createParagraphNear(),
17-
() => commands.liftEmptyBlock(),
18-
() => commands.splitBlock(),
19-
]);
20-
21-
const handleBackspace = () =>
22-
this.editor.commands.first(({ commands, tr }) => [
23-
() => commands.undoInputRule(),
24-
() => {
25-
tr.setMeta('inputType', 'deleteContentBackward');
26-
return false;
27-
},
28-
() => commands.deleteSelection(),
29-
() => commands.joinBackward(),
30-
() => commands.selectNodeBackward(),
31-
]);
32-
33-
const handleDelete = () =>
34-
this.editor.commands.first(({ commands }) => [
35-
() => commands.deleteSelection(),
36-
() => commands.joinForward(),
37-
() => commands.selectNodeForward(),
38-
]);
39-
4043
const baseKeymap = {
41-
Enter: handleEnter,
44+
Enter: () => handleEnter(this.editor),
4245
'Mod-Enter': () => this.editor.commands.exitCode(),
43-
Backspace: handleBackspace,
44-
'Mod-Backspace': handleBackspace,
45-
'Shift-Backspace': handleBackspace,
46-
Delete: handleDelete,
47-
'Mod-Delete': handleDelete,
46+
Backspace: () => handleBackspace(this.editor),
47+
'Mod-Backspace': () => handleBackspace(this.editor),
48+
'Shift-Backspace': () => handleBackspace(this.editor),
49+
Delete: () => handleDelete(this.editor),
50+
'Mod-Delete': () => handleDelete(this.editor),
4851
'Mod-a': () => this.editor.commands.selectAll(),
4952
Tab: () => this.editor.commands.insertTabNode(),
5053
};
@@ -55,12 +58,12 @@ export const Keymap = Extension.create({
5558

5659
const macBaseKeymap = {
5760
...baseKeymap,
58-
'Ctrl-h': handleBackspace,
59-
'Alt-Backspace': handleBackspace,
60-
'Ctrl-d': handleDelete,
61-
'Ctrl-Alt-Backspace': handleDelete,
62-
'Alt-Delete': handleDelete,
63-
'Alt-d': handleDelete,
61+
'Ctrl-h': () => handleBackspace(this.editor),
62+
'Alt-Backspace': () => handleBackspace(this.editor),
63+
'Ctrl-d': () => handleDelete(this.editor),
64+
'Ctrl-Alt-Backspace': () => handleDelete(this.editor),
65+
'Alt-Delete': () => handleDelete(this.editor),
66+
'Alt-d': () => handleDelete(this.editor),
6467
'Ctrl-a': () => this.editor.commands.selectTextblockStart(),
6568
'Ctrl-e': () => this.editor.commands.selectTextblockEnd(),
6669
'Ctrl-t': () => this.editor.commands.insertTabChar(),

0 commit comments

Comments
 (0)