@manuscripts/body-editor 3.16.3 → 3.17.1

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.
Files changed (55) hide show
  1. package/dist/cjs/lib/context-menu.js +28 -11
  2. package/dist/cjs/lib/popper.js +18 -3
  3. package/dist/cjs/lib/position-menu.js +175 -100
  4. package/dist/cjs/lib/view.js +10 -1
  5. package/dist/cjs/plugins/detect-inconsistency/index.js +6 -4
  6. package/dist/cjs/plugins/persist.js +3 -0
  7. package/dist/cjs/versions.js +1 -1
  8. package/dist/cjs/views/box_element.js +23 -1
  9. package/dist/cjs/views/caption_title.js +1 -1
  10. package/dist/cjs/views/footnote.js +43 -18
  11. package/dist/cjs/views/general_table_footnote.js +31 -21
  12. package/dist/cjs/views/image_element.js +7 -62
  13. package/dist/cjs/views/pullquote_element.js +23 -1
  14. package/dist/cjs/views/table_element.js +23 -1
  15. package/dist/es/lib/context-menu.js +29 -12
  16. package/dist/es/lib/popper.js +18 -3
  17. package/dist/es/lib/position-menu.js +173 -91
  18. package/dist/es/lib/view.js +8 -0
  19. package/dist/es/plugins/detect-inconsistency/index.js +6 -4
  20. package/dist/es/plugins/persist.js +3 -0
  21. package/dist/es/versions.js +1 -1
  22. package/dist/es/views/box_element.js +23 -1
  23. package/dist/es/views/caption_title.js +1 -1
  24. package/dist/es/views/footnote.js +43 -18
  25. package/dist/es/views/general_table_footnote.js +31 -21
  26. package/dist/es/views/image_element.js +7 -62
  27. package/dist/es/views/pullquote_element.js +23 -1
  28. package/dist/es/views/table_element.js +23 -1
  29. package/dist/types/lib/popper.d.ts +4 -2
  30. package/dist/types/lib/position-menu.d.ts +36 -11
  31. package/dist/types/lib/view.d.ts +3 -1
  32. package/dist/types/versions.d.ts +1 -1
  33. package/dist/types/views/box_element.d.ts +6 -0
  34. package/dist/types/views/footnote.d.ts +5 -2
  35. package/dist/types/views/general_table_footnote.d.ts +2 -2
  36. package/dist/types/views/image_element.d.ts +2 -9
  37. package/dist/types/views/pullquote_element.d.ts +6 -0
  38. package/dist/types/views/table_element.d.ts +6 -0
  39. package/package.json +2 -2
  40. package/src/lib/context-menu.ts +42 -21
  41. package/src/lib/popper.ts +23 -4
  42. package/src/lib/position-menu.ts +243 -137
  43. package/src/lib/view.ts +17 -0
  44. package/src/plugins/detect-inconsistency/index.ts +6 -4
  45. package/src/plugins/persist.ts +3 -0
  46. package/src/versions.ts +1 -1
  47. package/src/views/box_element.ts +34 -1
  48. package/src/views/caption_title.ts +1 -1
  49. package/src/views/footnote.ts +69 -33
  50. package/src/views/general_table_footnote.ts +43 -20
  51. package/src/views/image_element.ts +12 -89
  52. package/src/views/pullquote_element.ts +33 -1
  53. package/src/views/table_element.ts +34 -1
  54. package/styles/AdvancedEditor.css +5 -8
  55. package/styles/Editor.css +9 -5
@@ -27,27 +27,27 @@ const base_node_view_1 = require("./base_node_view");
27
27
  const creators_1 = require("./creators");
28
28
  const ReactSubView_1 = __importDefault(require("./ReactSubView"));
29
29
  const track_changes_plugin_1 = require("@manuscripts/track-changes-plugin");
30
+ const navigation_utils_1 = require("../lib/navigation-utils");
31
+ const view_1 = require("../lib/view");
30
32
  class GeneralTableFootnoteView extends base_node_view_1.BaseNodeView {
31
33
  constructor() {
32
34
  super(...arguments);
35
+ this.isMenuShown = false;
33
36
  this.initialise = () => {
34
37
  this.dom = document.createElement('div');
35
38
  this.dom.classList.add('footnote', 'general-table-footnote');
36
- this.dom.addEventListener('mousedown', this.handleClick);
39
+ this.dom.tabIndex = 0;
40
+ this.dom.addEventListener('keydown', (0, navigation_utils_1.handleEnterKey)(() => {
41
+ const can = this.props.getCapabilities();
42
+ const canShowMenu = can.editArticle && !(0, track_changes_plugin_1.isDeleted)(this.node);
43
+ if (canShowMenu) {
44
+ this.showContextMenu(true);
45
+ }
46
+ }));
37
47
  this.contentDOM = document.createElement('div');
38
48
  this.contentDOM.classList.add('footnote-text');
39
49
  this.updateContents();
40
50
  };
41
- this.handleClick = (e) => {
42
- const element = e.target;
43
- const can = this.props.getCapabilities();
44
- if (can.editArticle) {
45
- const item = element.closest('.general-table-footnote');
46
- if (item) {
47
- this.showContextMenu(item);
48
- }
49
- }
50
- };
51
51
  this.handleDeleteClick = () => {
52
52
  const componentProps = {
53
53
  header: 'Delete table general note',
@@ -80,21 +80,31 @@ class GeneralTableFootnoteView extends base_node_view_1.BaseNodeView {
80
80
  super.updateContents();
81
81
  this.dom.innerHTML = '';
82
82
  this.contentDOM && this.dom.appendChild(this.contentDOM);
83
+ const selectionInsideNode = (0, view_1.isSelectionInsideNode)(this.view, this.node, this.getPos());
84
+ const can = this.props.getCapabilities();
85
+ const canShowMenu = can.editArticle && !(0, track_changes_plugin_1.isDeleted)(this.node);
86
+ if (canShowMenu && selectionInsideNode && !this.isMenuShown) {
87
+ this.showContextMenu(false);
88
+ }
89
+ else if ((!canShowMenu || !selectionInsideNode) && this.isMenuShown) {
90
+ this.props.popper.destroy();
91
+ this.isMenuShown = false;
92
+ }
83
93
  }
84
- showContextMenu(element) {
94
+ showContextMenu(autoFocus = false) {
95
+ this.isMenuShown = true;
85
96
  this.props.popper.destroy();
86
97
  const componentProps = {
87
- actions: [],
98
+ actions: [
99
+ {
100
+ label: 'Delete',
101
+ action: () => this.handleDeleteClick(),
102
+ icon: 'Delete',
103
+ },
104
+ ],
88
105
  };
89
- if (!(0, track_changes_plugin_1.isDeleted)(this.node)) {
90
- componentProps.actions.push({
91
- label: 'Delete',
92
- action: () => this.handleDeleteClick(),
93
- icon: 'Delete',
94
- });
95
- }
96
106
  this.contextMenu = (0, ReactSubView_1.default)(this.props, style_guide_1.ContextMenu, componentProps, this.node, this.getPos, this.view, ['context-menu', 'footnote-context-menu']);
97
- this.props.popper.show(element, this.contextMenu, 'right-start');
107
+ this.props.popper.show(this.dom, this.contextMenu, 'right-start', false, [], autoFocus, false);
98
108
  }
99
109
  }
100
110
  exports.GeneralTableFootnoteView = GeneralTableFootnoteView;
@@ -18,8 +18,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
18
18
  return (mod && mod.__esModule) ? mod : { "default": mod };
19
19
  };
20
20
  Object.defineProperty(exports, "__esModule", { value: true });
21
- exports.ImageElementView = exports.figurePositions = void 0;
22
- const style_guide_1 = require("@manuscripts/style-guide");
21
+ exports.ImageElementView = void 0;
23
22
  const transform_1 = require("@manuscripts/transform");
24
23
  const icons_1 = require("../icons");
25
24
  const media_1 = require("../lib/media");
@@ -27,13 +26,6 @@ const navigation_utils_1 = require("../lib/navigation-utils");
27
26
  const position_menu_1 = require("../lib/position-menu");
28
27
  const block_view_1 = __importDefault(require("./block_view"));
29
28
  const creators_1 = require("./creators");
30
- const ReactSubView_1 = __importDefault(require("./ReactSubView"));
31
- var figurePositions;
32
- (function (figurePositions) {
33
- figurePositions["left"] = "half-left";
34
- figurePositions["right"] = "half-right";
35
- figurePositions["default"] = "";
36
- })(figurePositions || (exports.figurePositions = figurePositions = {}));
37
29
  class ImageElementView extends block_view_1.default {
38
30
  constructor() {
39
31
  super(...arguments);
@@ -48,46 +40,6 @@ class ImageElementView extends block_view_1.default {
48
40
  this.setExtLink({ extLink: result.id });
49
41
  this.updateContents();
50
42
  };
51
- this.showPositionMenu = () => {
52
- const firstFigure = this.getFirstFigure();
53
- if (!firstFigure) {
54
- return;
55
- }
56
- this.props.popper.destroy();
57
- const options = [
58
- {
59
- label: 'Left',
60
- action: () => {
61
- this.props.popper.destroy();
62
- this.updateAllFiguresPosition(figurePositions.left);
63
- },
64
- icon: 'ImageLeft',
65
- selected: this.figurePosition === figurePositions.left,
66
- },
67
- {
68
- label: 'Default',
69
- action: () => {
70
- this.props.popper.destroy();
71
- this.updateAllFiguresPosition(figurePositions.default);
72
- },
73
- icon: 'ImageDefault',
74
- selected: !this.figurePosition,
75
- },
76
- {
77
- label: 'Right',
78
- action: () => {
79
- this.props.popper.destroy();
80
- this.updateAllFiguresPosition(figurePositions.right);
81
- },
82
- icon: 'ImageRight',
83
- selected: this.figurePosition === figurePositions.right,
84
- },
85
- ];
86
- const componentProps = {
87
- actions: options,
88
- };
89
- this.props.popper.show(this.positionMenuWrapper, (0, ReactSubView_1.default)(this.props, style_guide_1.ContextMenu, componentProps, this.node, this.getPos, this.view, ['context-menu', 'position-menu']), 'left', false);
90
- };
91
43
  this.removeExtLink = () => {
92
44
  this.setExtLink({ extLink: '' });
93
45
  };
@@ -133,18 +85,6 @@ class ImageElementView extends block_view_1.default {
133
85
  addTools() {
134
86
  this.addPositionMenu();
135
87
  }
136
- addPositionMenu() {
137
- if (this.props.getCapabilities()?.editArticle) {
138
- const existingMenu = this.container.querySelector('.position-menu');
139
- if (existingMenu) {
140
- existingMenu.remove();
141
- }
142
- const firstFigure = this.getFirstFigure();
143
- this.figurePosition = firstFigure?.attrs.type || figurePositions.default;
144
- this.positionMenuWrapper = (0, position_menu_1.createPositionMenuWrapper)(this.figurePosition, this.showPositionMenu, this.props);
145
- this.container.prepend(this.positionMenuWrapper);
146
- }
147
- }
148
88
  getFirstFigure() {
149
89
  if (this.node.type === transform_1.schema.nodes.image_element) {
150
90
  const figureNode = this.node.firstChild;
@@ -182,6 +122,12 @@ class ImageElementView extends block_view_1.default {
182
122
  }
183
123
  return figures;
184
124
  }
125
+ addPositionMenu() {
126
+ if (!this.positionMenu) {
127
+ this.positionMenu = new position_menu_1.HorizontalPositionMenu(this, this.updateAllFiguresPosition.bind(this), this.container, () => this.getFirstFigure());
128
+ }
129
+ this.positionMenu.create();
130
+ }
185
131
  updateAllFiguresPosition(position) {
186
132
  const figures = this.getAllFigures();
187
133
  const { tr } = this.view.state;
@@ -192,7 +138,6 @@ class ImageElementView extends block_view_1.default {
192
138
  });
193
139
  });
194
140
  this.view.dispatch(tr);
195
- this.figurePosition = position;
196
141
  }
197
142
  createDnDPlaceholder() {
198
143
  const can = this.props.getCapabilities();
@@ -27,6 +27,7 @@ const comments_1 = require("../plugins/comments");
27
27
  const block_view_1 = __importDefault(require("./block_view"));
28
28
  const creators_1 = require("./creators");
29
29
  const ReactSubView_1 = __importDefault(require("./ReactSubView"));
30
+ const position_menu_1 = require("../lib/position-menu");
30
31
  class PullquoteElementView extends block_view_1.default {
31
32
  constructor() {
32
33
  super(...arguments);
@@ -49,7 +50,10 @@ class PullquoteElementView extends block_view_1.default {
49
50
  this.contentDOM = document.createElement(this.elementType);
50
51
  this.contentDOM.className = 'block';
51
52
  this.contentDOM.classList.add('pullquote');
52
- this.dom.appendChild(this.contentDOM);
53
+ this.container = document.createElement('div');
54
+ this.container.classList.add('container');
55
+ this.container.appendChild(this.contentDOM);
56
+ this.dom.appendChild(this.container);
53
57
  this.dom.addEventListener('click', this.handleClick);
54
58
  };
55
59
  this.actionGutterButtons = () => {
@@ -84,6 +88,24 @@ class PullquoteElementView extends block_view_1.default {
84
88
  tr.insert(this.getPos() + 1, transform_1.schema.nodes.quote_image.create());
85
89
  this.view.dispatch(tr);
86
90
  }
91
+ updateContents() {
92
+ super.updateContents();
93
+ this.addTools();
94
+ }
95
+ addTools() {
96
+ this.addPositionMenu();
97
+ }
98
+ addPositionMenu() {
99
+ if (!this.positionMenu) {
100
+ this.positionMenu = new position_menu_1.HorizontalPositionMenu(this, this.updateHorizontalPosition, this.container);
101
+ }
102
+ this.positionMenu.create();
103
+ }
104
+ updateHorizontalPosition(horizontalPosition) {
105
+ const tr = this.view.state.tr;
106
+ tr.setNodeAttribute(this.getPos(), 'type', horizontalPosition);
107
+ this.view.dispatch(tr);
108
+ }
87
109
  }
88
110
  exports.PullquoteElementView = PullquoteElementView;
89
111
  exports.default = (0, creators_1.createNodeOrElementView)(PullquoteElementView, 'aside');
@@ -21,6 +21,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
21
21
  exports.TableElementView = void 0;
22
22
  const block_view_1 = __importDefault(require("./block_view"));
23
23
  const creators_1 = require("./creators");
24
+ const position_menu_1 = require("../lib/position-menu");
24
25
  class TableElementView extends block_view_1.default {
25
26
  constructor() {
26
27
  super(...arguments);
@@ -29,9 +30,30 @@ class TableElementView extends block_view_1.default {
29
30
  this.contentDOM = document.createElement('figure');
30
31
  this.contentDOM.classList.add('block');
31
32
  this.contentDOM.setAttribute('id', this.node.attrs.id);
32
- this.dom.appendChild(this.contentDOM);
33
+ this.container = document.createElement('div');
34
+ this.container.classList.add('container');
35
+ this.container.appendChild(this.contentDOM);
36
+ this.dom.appendChild(this.container);
33
37
  };
34
38
  }
39
+ updateContents() {
40
+ super.updateContents();
41
+ this.addTools();
42
+ }
43
+ addTools() {
44
+ this.addPositionMenu();
45
+ }
46
+ addPositionMenu() {
47
+ if (!this.positionMenu) {
48
+ this.positionMenu = new position_menu_1.HorizontalPositionMenu(this, this.updateHorizontalPosition, this.container);
49
+ }
50
+ this.positionMenu.create();
51
+ }
52
+ updateHorizontalPosition(horizontalPosition) {
53
+ const tr = this.view.state.tr;
54
+ tr.setNodeAttribute(this.getPos(), 'type', horizontalPosition);
55
+ this.view.dispatch(tr);
56
+ }
35
57
  }
36
58
  exports.TableElementView = TableElementView;
37
59
  exports.default = (0, creators_1.createNodeView)(TableElementView);
@@ -22,7 +22,7 @@ import { createElement } from 'react';
22
22
  import { renderToStaticMarkup } from 'react-dom/server';
23
23
  import { addNodeComment, createBlock, findPosBeforeFirstSubsection, insertGeneralTableFootnote, insertInlineTableFootnote, } from '../commands';
24
24
  import { PopperManager } from './popper';
25
- import { createPositionOptions } from './position-menu';
25
+ import { HorizontalPositionMenu } from './position-menu';
26
26
  import { templateAllows } from './template';
27
27
  import { getMatchingChild, isChildOfNodeTypes, isSelectionInNode, } from './utils';
28
28
  const popper = new PopperManager();
@@ -32,8 +32,15 @@ const readonlyTypes = [
32
32
  schema.nodes.bibliography_section,
33
33
  schema.nodes.footnotes_section,
34
34
  ];
35
- const isBoxElementSectionTitle = ($pos, node) => isSectionTitleNode(node) &&
36
- $pos.node($pos.depth - 1).type === schema.nodes.box_element;
35
+ const getBoxElementOfSectionTitle = ($pos, node) => {
36
+ if (isSectionTitleNode(node)) {
37
+ const parent = $pos.node($pos.depth - 1);
38
+ if (parent.type === schema.nodes.box_element) {
39
+ return parent;
40
+ }
41
+ }
42
+ return null;
43
+ };
37
44
  export const sectionLevel = (depth) => {
38
45
  switch (depth) {
39
46
  case 1:
@@ -153,18 +160,28 @@ export class ContextMenu {
153
160
  const menu = document.createElement('div');
154
161
  menu.className = 'menu';
155
162
  const $pos = this.resolvePos();
156
- const isBox = isBoxElementSectionTitle($pos, this.node);
157
- const type = isBox ? schema.nodes.box_element : this.node.type;
158
- if (type === schema.nodes.figure_element ||
159
- type === schema.nodes.image_element) {
163
+ const boxParent = getBoxElementOfSectionTitle($pos, this.node);
164
+ const type = boxParent ? schema.nodes.box_element : this.node.type;
165
+ const positionableTypes = [
166
+ schema.nodes.figure_element,
167
+ schema.nodes.image_element,
168
+ schema.nodes.box_element,
169
+ schema.nodes.pullquote_element,
170
+ schema.nodes.table_element,
171
+ ];
172
+ let nodeBase = this.node;
173
+ if (positionableTypes.includes(type)) {
160
174
  const figure = getMatchingChild(this.node, (node) => node.type === schema.nodes.figure);
161
175
  if (figure) {
162
- const attrType = figure.attrs.type;
163
- const submenuOptions = createPositionOptions(schema.nodes.figure, figure, attrType, this.view, () => popper.destroy());
164
- const submenuLabel = 'Position';
165
- const submenu = this.createSubmenu(submenuLabel, submenuOptions);
166
- menu.appendChild(submenu);
176
+ nodeBase = figure;
177
+ }
178
+ if (boxParent) {
179
+ nodeBase = boxParent;
167
180
  }
181
+ const submenuOptions = HorizontalPositionMenu.createPositionOptions(schema.nodes[nodeBase.type.name], nodeBase, nodeBase.attrs.type, this.view, () => popper.destroy());
182
+ const submenuLabel = 'Position';
183
+ const submenu = this.createSubmenu(submenuLabel, submenuOptions);
184
+ menu.appendChild(submenu);
168
185
  }
169
186
  if (type === schema.nodes.list) {
170
187
  menu.appendChild(this.createMenuSection((section) => {
@@ -19,9 +19,10 @@ export class PopperManager {
19
19
  constructor() {
20
20
  this.isActive = () => !!this.activePopper;
21
21
  }
22
- show(target, contents, placement = 'bottom', showArrow = true, modifiers = [], autoFocus = true) {
22
+ show(target, contents, placement = 'bottom', showArrow = true, modifiers = [], autoFocus = true, autoCloseOnOutsideClick = true, onDestroy = undefined) {
23
23
  this.destroy();
24
24
  this.triggerElement = target;
25
+ this.destructionListener = onDestroy;
25
26
  window.requestAnimationFrame(() => {
26
27
  const container = document.createElement('div');
27
28
  container.className = 'popper';
@@ -81,9 +82,10 @@ export class PopperManager {
81
82
  this.destroy();
82
83
  }
83
84
  };
84
- if (contents.classList.contains('context-menu') ||
85
+ if ((contents.classList.contains('context-menu') ||
85
86
  contents.classList.contains('language') ||
86
- contents.classList.contains('section-category')) {
87
+ contents.classList.contains('section-category')) &&
88
+ autoCloseOnOutsideClick) {
87
89
  window.addEventListener('click', this.handleDocumentClick);
88
90
  }
89
91
  });
@@ -91,6 +93,8 @@ export class PopperManager {
91
93
  destroy() {
92
94
  if (this.activePopper) {
93
95
  this.removeContainerClass(this.activePopper.state.elements.reference);
96
+ this.destructionListener?.(this.activePopper);
97
+ this.destructionListener = undefined;
94
98
  this.activePopper.destroy();
95
99
  this.activePopper.state.elements.popper.remove();
96
100
  if (this.handleDocumentClick) {
@@ -108,6 +112,17 @@ export class PopperManager {
108
112
  this.activePopper.update();
109
113
  }
110
114
  }
115
+ replaceContent(newContent) {
116
+ if (this.container && this.activePopper) {
117
+ const arrow = this.container.querySelector('.popper-arrow');
118
+ this.container.innerHTML = '';
119
+ if (arrow) {
120
+ this.container.appendChild(arrow);
121
+ }
122
+ this.container.appendChild(newContent);
123
+ this.activePopper.update();
124
+ }
125
+ }
111
126
  focusInput(container, autoFocus = true) {
112
127
  const input = container.querySelector('input');
113
128
  if (input) {
@@ -15,100 +15,182 @@
15
15
  */
16
16
  import { ContextMenu } from '@manuscripts/style-guide';
17
17
  import { imageDefaultIcon, imageLeftIcon, imageRightIcon } from '../icons';
18
- import { figurePositions } from '../views/image_element';
19
- import ReactSubView from '../views/ReactSubView';
18
+ import { createSubViewAsync } from '../views/ReactSubView';
20
19
  import { handleEnterKey } from './navigation-utils';
21
20
  import { updateNodeAttrs } from './view';
22
- export const createPositionOptions = (nodeType, node, currentPosition, view, onComplete) => {
23
- const createAction = (position) => () => {
24
- onComplete?.();
25
- updateNodeAttrs(view, nodeType, {
26
- ...node.attrs,
27
- type: position,
28
- });
29
- };
30
- return [
31
- {
32
- title: 'Left',
33
- action: createAction(figurePositions.left),
34
- IconComponent: imageLeftIcon,
35
- iconName: 'ImageLeft',
36
- selected: currentPosition === figurePositions.left,
37
- },
38
- {
39
- title: 'Center',
40
- action: createAction(figurePositions.default),
41
- IconComponent: imageDefaultIcon,
42
- iconName: 'ImageDefault',
43
- selected: !currentPosition,
44
- },
45
- {
46
- title: 'Right',
47
- action: createAction(figurePositions.right),
48
- IconComponent: imageRightIcon,
49
- iconName: 'ImageRight',
50
- selected: currentPosition === figurePositions.right,
51
- },
52
- ];
53
- };
54
- export const createPopperMenuPositionOptions = (nodeType, node, currentPosition, view, onComplete) => {
55
- return createPositionOptions(nodeType, node, currentPosition, view, onComplete).map((option) => ({
56
- label: option.title,
57
- action: option.action,
58
- icon: option.iconName,
59
- selected: option.selected,
60
- }));
61
- };
62
- export const showPositionMenu = (nodeType, node, currentPosition, positionMenuWrapper, view, getPos, props) => {
63
- props.popper.destroy();
64
- const options = createPopperMenuPositionOptions(nodeType, node, currentPosition, view, () => props.popper.destroy());
65
- const componentProps = {
66
- actions: options,
67
- };
68
- props.popper.show(positionMenuWrapper, ReactSubView(props, ContextMenu, componentProps, node, getPos, view, [
69
- 'context-menu',
70
- 'position-menu',
71
- ]), 'left', false);
72
- };
73
- export const setElementPositionAlignment = (element, position) => {
74
- switch (position) {
75
- case figurePositions.left:
76
- element.setAttribute('data-alignment', 'left');
77
- break;
78
- case figurePositions.right:
79
- element.setAttribute('data-alignment', 'right');
80
- break;
81
- default:
82
- element.removeAttribute('data-alignment');
83
- break;
21
+ export var HorizontalPositions;
22
+ (function (HorizontalPositions) {
23
+ HorizontalPositions["left"] = "half-left";
24
+ HorizontalPositions["right"] = "half-right";
25
+ HorizontalPositions["default"] = "";
26
+ })(HorizontalPositions || (HorizontalPositions = {}));
27
+ export class HorizontalPositionMenu {
28
+ constructor(parent, onChange, location, getPositionSource) {
29
+ this.menuOpen = false;
30
+ this.posMenuSelector = 'position-menu';
31
+ this.buttonClass = 'position-menu-button';
32
+ const preSource = getPositionSource?.() || parent.node;
33
+ if (typeof preSource.attrs.type === 'undefined') {
34
+ console.error("This node doesn't support horizontal alignment");
35
+ return;
36
+ }
37
+ this.getPositionSource = getPositionSource;
38
+ this.location = location || parent.dom;
39
+ this.onChange = onChange.bind(parent);
40
+ this.parent = parent;
41
+ }
42
+ static createPositionOptions(nodeType, node, currentPosition, view, onComplete) {
43
+ const createAction = (position) => () => {
44
+ onComplete?.();
45
+ updateNodeAttrs(view, nodeType, {
46
+ ...node.attrs,
47
+ type: position,
48
+ });
49
+ };
50
+ return [
51
+ {
52
+ title: 'Left',
53
+ action: createAction(HorizontalPositions.left),
54
+ IconComponent: imageLeftIcon,
55
+ iconName: 'ImageLeft',
56
+ selected: currentPosition === HorizontalPositions.left,
57
+ },
58
+ {
59
+ title: 'Default',
60
+ action: createAction(HorizontalPositions.default),
61
+ IconComponent: imageDefaultIcon,
62
+ iconName: 'ImageDefault',
63
+ selected: !currentPosition || currentPosition === HorizontalPositions.default,
64
+ },
65
+ {
66
+ title: 'Right',
67
+ action: createAction(HorizontalPositions.right),
68
+ IconComponent: imageRightIcon,
69
+ iconName: 'ImageRight',
70
+ selected: currentPosition === HorizontalPositions.right,
71
+ },
72
+ ];
73
+ }
74
+ createPopperMenuPositionOptions(nodeType, node, currentPosition, view, onComplete) {
75
+ return HorizontalPositionMenu.createPositionOptions(nodeType, node, currentPosition, view, onComplete).map((option) => ({
76
+ label: option.title,
77
+ action: option.action,
78
+ icon: option.iconName,
79
+ selected: option.selected,
80
+ }));
84
81
  }
85
- };
86
- export const createPositionMenuWrapper = (currentPosition, onClick, props) => {
87
- const can = props.getCapabilities();
88
- const positionMenuWrapper = document.createElement('div');
89
- positionMenuWrapper.classList.add('position-menu');
90
- const positionMenuButton = document.createElement('div');
91
- positionMenuButton.classList.add('position-menu-button');
92
- let icon;
93
- switch (currentPosition) {
94
- case figurePositions.left:
95
- icon = imageLeftIcon;
96
- break;
97
- case figurePositions.right:
98
- icon = imageRightIcon;
99
- break;
100
- default:
101
- icon = imageDefaultIcon;
102
- break;
82
+ createPositionMenuWrapper(currentPosition, props) {
83
+ const can = props.getCapabilities();
84
+ const positionMenuWrapper = document.createElement('div');
85
+ positionMenuWrapper.classList.add(this.posMenuSelector);
86
+ const positionMenuButton = document.createElement('div');
87
+ positionMenuButton.classList.add(this.buttonClass);
88
+ let icon;
89
+ switch (currentPosition) {
90
+ case HorizontalPositions.left:
91
+ icon = imageLeftIcon;
92
+ break;
93
+ case HorizontalPositions.right:
94
+ icon = imageRightIcon;
95
+ break;
96
+ default:
97
+ icon = imageDefaultIcon;
98
+ break;
99
+ }
100
+ if (icon) {
101
+ positionMenuButton.innerHTML = icon;
102
+ }
103
+ const onClick = () => {
104
+ this.showPositionMenu();
105
+ };
106
+ if (can.editArticle) {
107
+ positionMenuButton.tabIndex = -1;
108
+ positionMenuButton.addEventListener('click', onClick);
109
+ positionMenuButton.addEventListener('keydown', handleEnterKey(onClick));
110
+ }
111
+ if (this.positionMenuWrapper) {
112
+ const button = this.positionMenuWrapper.querySelector('.' + this.buttonClass);
113
+ if (button) {
114
+ this.positionMenuWrapper.removeChild(button);
115
+ this.positionMenuWrapper.appendChild(positionMenuButton);
116
+ }
117
+ }
118
+ else {
119
+ positionMenuWrapper.appendChild(positionMenuButton);
120
+ this.positionMenuWrapper = positionMenuWrapper;
121
+ this.location.prepend(this.positionMenuWrapper);
122
+ }
103
123
  }
104
- if (icon) {
105
- positionMenuButton.innerHTML = icon;
124
+ getHorizontalPositionOptions(current, onPick, destroy) {
125
+ const componentProps = {
126
+ actions: [
127
+ {
128
+ label: 'Left',
129
+ action: () => {
130
+ destroy();
131
+ this.menuOpen = false;
132
+ onPick(HorizontalPositions.left);
133
+ },
134
+ icon: 'ImageLeft',
135
+ selected: current === HorizontalPositions.left,
136
+ },
137
+ {
138
+ label: 'Default',
139
+ action: () => {
140
+ destroy();
141
+ this.menuOpen = false;
142
+ onPick(HorizontalPositions.default);
143
+ },
144
+ icon: 'ImageDefault',
145
+ selected: !current,
146
+ },
147
+ {
148
+ label: 'Right',
149
+ action: () => {
150
+ destroy();
151
+ this.menuOpen = false;
152
+ onPick(HorizontalPositions.right);
153
+ },
154
+ icon: 'ImageRight',
155
+ selected: current === HorizontalPositions.right,
156
+ },
157
+ ],
158
+ };
159
+ return componentProps;
160
+ }
161
+ showPositionMenu(force = false) {
162
+ const p = this.parent;
163
+ if (this.menuOpen && !force) {
164
+ p.props.popper.destroy();
165
+ this.menuOpen = false;
166
+ return;
167
+ }
168
+ const posSource = this.getPositionSource
169
+ ? this.getPositionSource()
170
+ : this.parent.node;
171
+ const componentProps = this.getHorizontalPositionOptions(posSource?.attrs.type || HorizontalPositions.default, this.onChange, p.props.popper.destroy.bind(p.props.popper));
172
+ createSubViewAsync(p.props, ContextMenu, componentProps, p.node, p.getPos, p.view, ['context-menu', this.posMenuSelector]).then((content) => {
173
+ if (this.menuOpen && p.props.popper.isActive()) {
174
+ p.props.popper.replaceContent(content);
175
+ }
176
+ else {
177
+ p.props.popper.show(this.positionMenuWrapper, content, 'left', false, [], true, true, () => {
178
+ this.menuOpen = false;
179
+ });
180
+ this.menuOpen = true;
181
+ }
182
+ });
106
183
  }
107
- if (can.editArticle) {
108
- positionMenuButton.tabIndex = 0;
109
- positionMenuButton.addEventListener('click', onClick);
110
- positionMenuButton.addEventListener('keydown', handleEnterKey(onClick));
184
+ create() {
185
+ if (!this.parent) {
186
+ return;
187
+ }
188
+ const p = this.parent;
189
+ if (p.props.getCapabilities()?.editArticle) {
190
+ const posSource = this.getPositionSource
191
+ ? this.getPositionSource()
192
+ : this.parent.node;
193
+ this.createPositionMenuWrapper(posSource?.attrs.type || HorizontalPositions.default, p.props);
194
+ }
111
195
  }
112
- positionMenuWrapper.appendChild(positionMenuButton);
113
- return positionMenuWrapper;
114
- };
196
+ }