From 0405843a0f420812a10c79ff58ddd2f3c9d0419f Mon Sep 17 00:00:00 2001 From: Alexandre Date: Wed, 3 Jul 2024 17:24:04 -0300 Subject: [PATCH] Migrate to TS to get better code completion --- .gitattributes | 1 + demo/assets/bundle.js | 118 +++++----- package-lock.json | 142 ++++++++++++ package.json | 2 + src/commands/command-factory.js | 16 +- src/common/JCircularLinkedList.js | 62 ------ src/common/JCircularLinkedList.ts | 46 ++++ src/common/JLinkedList.js | 60 ----- src/common/JLinkedList.ts | 40 ++++ src/common/JNode.js | 81 ------- src/common/JNode.ts | 46 ++++ src/components/common/SVGIcon.ts | 24 ++ src/components/quick-menu/QuickMenu.js | 206 ------------------ src/components/quick-menu/QuickMenu.ts | 186 ++++++++++++++++ src/components/quick-menu/QuickMenuItem.js | 81 ------- src/components/quick-menu/QuickMenuItem.ts | 70 ++++++ src/components/quick-menu/QuickMenuSection.js | 95 -------- src/components/quick-menu/QuickMenuSection.ts | 52 +++++ .../quick-menu/{helperDOM.js => helperDOM.ts} | 2 +- src/{index.js => index.ts} | 0 src/triggers/keypress-events.js | 12 +- src/triggers/load-events.js | 3 +- tsconfig.json | 25 +++ webpack.config.js | 12 +- 24 files changed, 722 insertions(+), 660 deletions(-) create mode 100644 .gitattributes delete mode 100644 src/common/JCircularLinkedList.js create mode 100644 src/common/JCircularLinkedList.ts delete mode 100644 src/common/JLinkedList.js create mode 100644 src/common/JLinkedList.ts delete mode 100644 src/common/JNode.js create mode 100644 src/common/JNode.ts create mode 100644 src/components/common/SVGIcon.ts delete mode 100644 src/components/quick-menu/QuickMenu.js create mode 100644 src/components/quick-menu/QuickMenu.ts delete mode 100644 src/components/quick-menu/QuickMenuItem.js create mode 100644 src/components/quick-menu/QuickMenuItem.ts delete mode 100644 src/components/quick-menu/QuickMenuSection.js create mode 100644 src/components/quick-menu/QuickMenuSection.ts rename src/components/quick-menu/{helperDOM.js => helperDOM.ts} (87%) rename src/{index.js => index.ts} (100%) create mode 100644 tsconfig.json diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..94f480d --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf \ No newline at end of file diff --git a/demo/assets/bundle.js b/demo/assets/bundle.js index 3589f8e..64df4e9 100644 --- a/demo/assets/bundle.js +++ b/demo/assets/bundle.js @@ -20,102 +20,113 @@ eval("__webpack_require__.r(__webpack_exports__);\n// extracted by mini-css-extr /***/ }), -/***/ "./src/block-operation.js": -/*!********************************!*\ - !*** ./src/block-operation.js ***! - \********************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ createListItem: () => (/* binding */ createListItem),\n/* harmony export */ createNewElement: () => (/* binding */ createNewElement),\n/* harmony export */ deleteAndFocusOnNext: () => (/* binding */ deleteAndFocusOnNext),\n/* harmony export */ deleteAndFocusOnPrevious: () => (/* binding */ deleteAndFocusOnPrevious),\n/* harmony export */ deleteDraggableParentBlock: () => (/* binding */ deleteDraggableParentBlock),\n/* harmony export */ duplicateSelectedBlock: () => (/* binding */ duplicateSelectedBlock),\n/* harmony export */ moveDownBlock: () => (/* binding */ moveDownBlock),\n/* harmony export */ moveUpBlock: () => (/* binding */ moveUpBlock),\n/* harmony export */ transformBlock: () => (/* binding */ transformBlock)\n/* harmony export */ });\n/* harmony import */ var _element_factory__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./element-factory */ \"./src/element-factory.js\");\n/* harmony import */ var _j_selection__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./j-selection */ \"./src/j-selection.js\");\n/* harmony import */ var _j_window__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./j-window */ \"./src/j-window.js\");\n/* harmony import */ var _components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./components/text-formatting-bar/text-formatting-bar */ \"./src/components/text-formatting-bar/text-formatting-bar.js\");\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n//** Create a default block or a element list */\r\nfunction createNewElement(event) {\r\n\r\n const element = event.target;\r\n\r\n const contentElement = element.closest('.johannes-content-element');\r\n\r\n if (contentElement && contentElement.classList.contains('list')) {\r\n createListItem(contentElement);\r\n } else {\r\n createADefaultBlock(contentElement);\r\n }\r\n}\r\n\r\n//** Just create a new paragraph draggable block and insert in the DOM */\r\nfunction createADefaultBlock(eventParagraph) {\r\n\r\n const newBlock = _element_factory__WEBPACK_IMPORTED_MODULE_0__.createNewDraggableParagraphElement();\r\n\r\n if (eventParagraph && eventParagraph.closest('.draggable-block')) {\r\n const sibling = eventParagraph.closest('.draggable-block');\r\n sibling.insertAdjacentElement('afterend', newBlock);\r\n } else {\r\n document.querySelector('.johannes-editor > .content').appendChild(newBlock);\r\n }\r\n\r\n const focusable = newBlock.querySelector('.johannes-content-element');\r\n // focusable.focus();\r\n\r\n (0,_j_window__WEBPACK_IMPORTED_MODULE_2__.focusOnTheEndOfTheText)(focusable);\r\n}\r\n\r\nfunction createListItem(element) {\r\n\r\n let newContentElement = null;\r\n\r\n let activeElement = document.activeElement;\r\n let contentElement = element.closest('.johannes-content-element');\r\n\r\n if (contentElement.classList.contains('checkbox-list')) {\r\n newContentElement = (0,_element_factory__WEBPACK_IMPORTED_MODULE_0__.createNewCheckboxLiElement)();\r\n } else if (contentElement.classList.contains('list')) {\r\n newContentElement = (0,_element_factory__WEBPACK_IMPORTED_MODULE_0__.createNewLiElement)();\r\n } else {\r\n newContentElement = (0,_element_factory__WEBPACK_IMPORTED_MODULE_0__.createNewDraggableParagraphElement)();\r\n }\r\n\r\n let parentBlock = null;\r\n\r\n if (contentElement.classList.contains('list')) {\r\n\r\n parentBlock = contentElement;\r\n\r\n const textContent = activeElement.textContent.trim();\r\n\r\n if (textContent === '') {\r\n\r\n parentBlock = element.closest('.draggable-block');\r\n\r\n element.closest('.deletable').remove();\r\n\r\n newContentElement = (0,_element_factory__WEBPACK_IMPORTED_MODULE_0__.createNewDraggableParagraphElement)();\r\n parentBlock.insertAdjacentElement('afterend', newContentElement);\r\n\r\n } else {\r\n const activeElement = document.activeElement.closest('.list-item');\r\n activeElement.insertAdjacentElement('afterend', newContentElement);\r\n }\r\n\r\n } else {\r\n parentBlock = element.closest('.draggable-block');\r\n\r\n if (parentBlock) {\r\n if (parentBlock.nextSibling) {\r\n parentBlock.parentNode.insertBefore(newContentElement, parentBlock.nextSibling);\r\n } else {\r\n parentBlock.parentNode.appendChild(newContentElement);\r\n }\r\n }\r\n }\r\n\r\n (0,_j_window__WEBPACK_IMPORTED_MODULE_2__.focusOnTheEndOfTheText)(newContentElement);\r\n}\r\n\r\n//** Delete the closest draggable-block parent of a child. Take the current selection if a child is not passed. */\r\nfunction deleteDraggableParentBlock(child) {\r\n\r\n let draggableBlockToRemove = null;\r\n\r\n if (child && child instanceof HTMLElement && child.closest('.draggable-block')) {\r\n draggableBlockToRemove = child.closest('.draggable-block');\r\n } else {\r\n draggableBlockToRemove = _j_selection__WEBPACK_IMPORTED_MODULE_1__.getCurrentDraggableBlockFocused();\r\n }\r\n\r\n if (draggableBlockToRemove) {\r\n draggableBlockToRemove.remove();\r\n } else {\r\n throw new Error('Focusable Element Not Found Exception');\r\n }\r\n\r\n clearAllAfterDelete();\r\n}\r\n\r\nfunction deleteAndFocusOnPrevious() {\r\n\r\n const currentActiveElement = document.activeElement;\r\n\r\n (0,_j_window__WEBPACK_IMPORTED_MODULE_2__.focusOnPrevious)(currentActiveElement);\r\n deleteTheCurrentElementAndTheDraggableBlockIfEmpty(currentActiveElement);\r\n}\r\n\r\nfunction deleteAndFocusOnNext() {\r\n\r\n const currentActiveElement = document.activeElement;\r\n\r\n (0,_j_window__WEBPACK_IMPORTED_MODULE_2__.focusOnNext)(currentActiveElement);\r\n deleteTheCurrentElementAndTheDraggableBlockIfEmpty(currentActiveElement);\r\n}\r\n\r\n\r\n//** Delete the current element and the draggable-block parent if empty. A block is empty if has no editable element inside. */\r\nfunction deleteTheCurrentElementAndTheDraggableBlockIfEmpty(currentElement) {\r\n\r\n const parentBlock = currentElement.closest('.draggable-block');\r\n const actual = currentElement.closest('.deletable');\r\n\r\n actual.remove();\r\n\r\n if (parentBlock && parentBlock.querySelectorAll('.editable').length == 0) {\r\n parentBlock.remove();\r\n }\r\n}\r\n\r\n/** Transform a block type into another */\r\nfunction transformBlock(blockElement, type) {\r\n\r\n //blockElement, type\r\n\r\n\r\n let contentElement = blockElement.querySelector('.swittable');\r\n let content = contentElement.innerText;\r\n\r\n // if (content.endsWith('/')) {\r\n // content = content.slice(0, -1); // Remove the last '/'\r\n // }\r\n\r\n let newContentBlock;\r\n\r\n switch (type) {\r\n case 'p':\r\n {\r\n newContentBlock = _element_factory__WEBPACK_IMPORTED_MODULE_0__.createNewParagraphElement();\r\n newContentBlock.innerText = content;\r\n break;\r\n }\r\n case 'h1':\r\n {\r\n newContentBlock = _element_factory__WEBPACK_IMPORTED_MODULE_0__.createNewHeadingElement(1);\r\n newContentBlock.innerText = content;\r\n break;\r\n }\r\n case 'h2':\r\n {\r\n newContentBlock = _element_factory__WEBPACK_IMPORTED_MODULE_0__.createNewHeadingElement(2);\r\n newContentBlock.innerText = content;\r\n break;\r\n }\r\n case 'h3':\r\n {\r\n newContentBlock = _element_factory__WEBPACK_IMPORTED_MODULE_0__.createNewHeadingElement(3);\r\n newContentBlock.innerText = content;\r\n break;\r\n }\r\n case 'h4':\r\n {\r\n newContentBlock = _element_factory__WEBPACK_IMPORTED_MODULE_0__.createNewHeadingElement(4);\r\n newContentBlock.innerText = content;\r\n break;\r\n }\r\n case 'h5':\r\n {\r\n newContentBlock = _element_factory__WEBPACK_IMPORTED_MODULE_0__.createNewHeadingElement(5);\r\n newContentBlock.innerText = content;\r\n break;\r\n }\r\n case 'h6':\r\n {\r\n newContentBlock = _element_factory__WEBPACK_IMPORTED_MODULE_0__.createNewHeadingElement(6);\r\n newContentBlock.innerText = content;\r\n break;\r\n }\r\n case 'code':\r\n newContentBlock = document.createElement('pre');\r\n const code = document.createElement('code');\r\n code.innerText = content;\r\n newContentBlock.appendChild(code);\r\n break;\r\n case 'image':\r\n newContentBlock = document.createElement('img');\r\n newContentBlock.src = content;\r\n newContentBlock.alt = \"Descriptive text\";\r\n break;\r\n case 'quote':\r\n {\r\n newContentBlock = _element_factory__WEBPACK_IMPORTED_MODULE_0__.createNewQuoteElement(content);\r\n\r\n break;\r\n }\r\n case 'bulleted-list':\r\n {\r\n newContentBlock = _element_factory__WEBPACK_IMPORTED_MODULE_0__.createNewListElement(content);\r\n\r\n break;\r\n }\r\n\r\n case 'numbered-list':\r\n {\r\n newContentBlock = _element_factory__WEBPACK_IMPORTED_MODULE_0__.createNewListElement(content, 'ol');\r\n\r\n break;\r\n }\r\n case 'todo-list':\r\n {\r\n newContentBlock = _element_factory__WEBPACK_IMPORTED_MODULE_0__.createNewTodoListElement(content, 'ul');\r\n\r\n break;\r\n }\r\n\r\n case 'separator':\r\n {\r\n newContentBlock = _element_factory__WEBPACK_IMPORTED_MODULE_0__.createNewSeparatorElement();\r\n break;\r\n }\r\n\r\n default:\r\n console.error('Unsupported type');\r\n return;\r\n }\r\n\r\n blockElement.replaceChild(newContentBlock, contentElement);\r\n\r\n const focusable = newContentBlock.closest('.focusable') || blockElement.querySelector('.focusable');\r\n\r\n (0,_j_window__WEBPACK_IMPORTED_MODULE_2__.focusOnTheEndOfTheText)(focusable);\r\n}\r\n\r\n\r\nfunction moveDownBlock() {\r\n\r\n}\r\n\r\nfunction moveUpBlock() {\r\n\r\n}\r\n\r\nfunction duplicateSelectedBlock() {\r\n\r\n let element = _j_selection__WEBPACK_IMPORTED_MODULE_1__.getCurrentDraggableBlockFocused();\r\n\r\n if (!element || !element.parentNode) {\r\n console.error('O elemento fornecido é inválido ou não está no DOM.');\r\n return;\r\n }\r\n\r\n const clone = element.cloneNode(true);\r\n\r\n // Obtem o próximo elemento irmão\r\n const nextElement = element.nextSibling;\r\n\r\n // Insere o clone antes do próximo elemento irmão no pai\r\n // Se o próximo elemento irmão não existir, 'insertBefore' funcionará como 'appendChild'\r\n element.parentNode.insertBefore(clone, nextElement);\r\n\r\n\r\n (0,_components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_3__.hideAllDependentBox)();\r\n (0,_components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_3__.hideTextFormattingBar)();\r\n\r\n (0,_j_window__WEBPACK_IMPORTED_MODULE_2__.focusOnTheEndOfTheText)(clone);\r\n}\r\n\r\nfunction clearAllAfterDelete() {\r\n _j_selection__WEBPACK_IMPORTED_MODULE_1__.clearAllSelection();\r\n\r\n (0,_components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_3__.hideAllDependentBox)();\r\n (0,_components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_3__.hideTextFormattingBar)();\r\n}\n\n//# sourceURL=webpack://johannes/./src/block-operation.js?"); - -/***/ }), - -/***/ "./src/commands/command-factory.js": -/*!*****************************************!*\ - !*** ./src/commands/command-factory.js ***! - \*****************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ OPERATIONS: () => (/* binding */ OPERATIONS),\n/* harmony export */ createCommand: () => (/* binding */ createCommand),\n/* harmony export */ getBlockOperationFunction: () => (/* binding */ getBlockOperationFunction),\n/* harmony export */ operationMap: () => (/* binding */ operationMap)\n/* harmony export */ });\n/* harmony import */ var _block_operation__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../block-operation */ \"./src/block-operation.js\");\n/* harmony import */ var _components_quick_menu_quick_insert_menu__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../components/quick-menu/quick-insert-menu */ \"./src/components/quick-menu/quick-insert-menu.js\");\n/* harmony import */ var _j_window__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../j-window */ \"./src/j-window.js\");\n/* harmony import */ var _components_quick_menu_QuickMenu__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../components/quick-menu/QuickMenu */ \"./src/components/quick-menu/QuickMenu.js\");\n/* harmony import */ var _components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../components/text-formatting-bar/text-formatting-bar */ \"./src/components/text-formatting-bar/text-formatting-bar.js\");\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nfunction createCommand(operationName, elements = null) {\r\n return new Command(operationName, elements);\r\n}\r\n\r\nclass Command {\r\n\r\n constructor(operationName, elements) {\r\n this.elements = elements;\r\n this.operation = getBlockOperationFunction(operationName);\r\n }\r\n\r\n execute() {\r\n if (this.elements !== null) {\r\n this.operation(...this.elements);\r\n } else {\r\n this.operation();\r\n }\r\n }\r\n}\r\n\r\nconst OPERATIONS = {\r\n BLOCK: {\r\n CREATE_LIST_ELEMENT: 'create-list-element',\r\n CREATE_NEW_ELEMENT: 'create-new-element',\r\n DELETE_DRAGGABLE_BLOCK: 'delete-draggable-block',\r\n DELETE_AND_FOCUS_ON_NEXT: 'delete-and-focus-on-next',\r\n DELETE_AND_FOCUS_ON_PREVIOUS: 'delete-and-focus-on-previous',\r\n DUPLICATE_SELECTED_BLOCK: 'duplicate-selected-block',\r\n TRANSFORM_BLOCK: 'transform-block',\r\n MOVE_UP_BLOCK: 'move-up-block',\r\n MOVE_DOWN_BLOCK: 'move-down-block',\r\n SHOW_TURN_INTO_BOX: 'show-turn-into-box',\r\n SHOW_COLOR_BOX: 'show-color-box',\r\n SHOW_MORE_OPTIONS_BOX: 'show-more-options-box'\r\n },\r\n BLOCK_OPTIONS: {\r\n SHOW_BLOCK_OPTIONS: 'show-block-options',\r\n HIDE_CLEAR_BLOCK_OPTIONS: 'hide-clear-block-options',\r\n MOVE_FAKE_FOCUS_TO_NEXT_OPTION: 'move-fake-focus-to-next-option',\r\n MOVE_FAKE_FOCUS_TO_PREVIOUS_OPTION: 'move-fake-focus-to-previous-option',\r\n APPLY_SELECTED_BLOCK_TYPE: 'apply-selected-block-type',\r\n FILTER_CONCAT: 'filter-contact',\r\n FILTER_REMOVE_LAST: 'filter-remove-last',\r\n },\r\n FORMATTING_BAR: {\r\n SHOW_TEXT_FORMATTING_BAR: 'show-text-formatting-bar',\r\n HIDE_TEXT_FORMATTING_BAR: 'hide-text-formatting-bar',\r\n TOGGLE_MORE_OPTIONS_BOX: 'toggle-more-options-box',\r\n TOGGLE_CHANGE_COLOR_BOX: 'toggle-change-color-box',\r\n TOGGLE_TURN_INTO_BOX: 'toggle-turn-into-box',\r\n TOGGLE_INPUT_LINK_BOX: 'toggle-input-link-box',\r\n INPUT_LINK_URL: 'input-link-url', \r\n TOGGLE_ENCLOSE_SELECTED_TEXT_TO: 'toggle-enclose-selected-text-to',\r\n },\r\n\r\n};\r\n\r\nconst operationMap = {\r\n [OPERATIONS.BLOCK.CREATE_LIST_ELEMENT]: _block_operation__WEBPACK_IMPORTED_MODULE_0__.createListItem,\r\n [OPERATIONS.BLOCK.CREATE_NEW_ELEMENT]: _block_operation__WEBPACK_IMPORTED_MODULE_0__.createNewElement,\r\n [OPERATIONS.BLOCK.DELETE_DRAGGABLE_BLOCK]: _block_operation__WEBPACK_IMPORTED_MODULE_0__.deleteDraggableParentBlock,\r\n [OPERATIONS.BLOCK.DELETE_AND_FOCUS_ON_NEXT]: _block_operation__WEBPACK_IMPORTED_MODULE_0__.deleteAndFocusOnNext,\r\n [OPERATIONS.BLOCK.DELETE_AND_FOCUS_ON_PREVIOUS]: _block_operation__WEBPACK_IMPORTED_MODULE_0__.deleteAndFocusOnPrevious,\r\n [OPERATIONS.BLOCK.DUPLICATE_SELECTED_BLOCK]: _block_operation__WEBPACK_IMPORTED_MODULE_0__.duplicateSelectedBlock,\r\n [OPERATIONS.BLOCK.TRANSFORM_BLOCK]: _block_operation__WEBPACK_IMPORTED_MODULE_0__.transformBlock,\r\n [OPERATIONS.BLOCK.MOVE_UP_BLOCK]: _block_operation__WEBPACK_IMPORTED_MODULE_0__.moveUpBlock,\r\n [OPERATIONS.BLOCK.MOVE_DOWN_BLOCK]: _block_operation__WEBPACK_IMPORTED_MODULE_0__.moveDownBlock,\r\n [OPERATIONS.BLOCK_OPTIONS.SHOW_BLOCK_OPTIONS]: _components_quick_menu_quick_insert_menu__WEBPACK_IMPORTED_MODULE_1__.showMainBlockOptions,\r\n [OPERATIONS.BLOCK_OPTIONS.HIDE_CLEAR_BLOCK_OPTIONS]: _components_quick_menu_quick_insert_menu__WEBPACK_IMPORTED_MODULE_1__.hideAndClearBlockOptions,\r\n [OPERATIONS.BLOCK_OPTIONS.MOVE_FAKE_FOCUS_TO_NEXT_OPTION]: _components_quick_menu_QuickMenu__WEBPACK_IMPORTED_MODULE_3__[\"default\"].moveTheFakeFocusToTheNextMenuItem, // blockOptionOperation.moveTheFakeFocusToTheNextBlockOption,\r\n [OPERATIONS.BLOCK_OPTIONS.MOVE_FAKE_FOCUS_TO_PREVIOUS_OPTION]: _components_quick_menu_quick_insert_menu__WEBPACK_IMPORTED_MODULE_1__.moveTheFakeFocusToPreviousBlockOption,\r\n [OPERATIONS.BLOCK_OPTIONS.APPLY_SELECTED_BLOCK_TYPE]: _components_quick_menu_quick_insert_menu__WEBPACK_IMPORTED_MODULE_1__.applySelectedBlockType,\r\n [OPERATIONS.BLOCK_OPTIONS.FILTER_CONCAT]: _components_quick_menu_quick_insert_menu__WEBPACK_IMPORTED_MODULE_1__.filterContact,\r\n [OPERATIONS.BLOCK_OPTIONS.FILTER_REMOVE_LAST]: _components_quick_menu_quick_insert_menu__WEBPACK_IMPORTED_MODULE_1__.filterRemoveLast,\r\n [OPERATIONS.FORMATTING_BAR.SHOW_TEXT_FORMATTING_BAR]: _components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_4__.showTextFormattingBar,\r\n [OPERATIONS.FORMATTING_BAR.HIDE_TEXT_FORMATTING_BAR]: _components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_4__.hideTextFormattingBar,\r\n [OPERATIONS.FORMATTING_BAR.TOGGLE_MORE_OPTIONS_BOX]: _components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_4__.toggleMoreOptionsBox,\r\n [OPERATIONS.FORMATTING_BAR.TOGGLE_CHANGE_COLOR_BOX]: _components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_4__.toggleChangeColorBox,\r\n [OPERATIONS.FORMATTING_BAR.TOGGLE_TURN_INTO_BOX]: _components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_4__.toggleTurnIntoBox,\r\n [OPERATIONS.FORMATTING_BAR.TOGGLE_INPUT_LINK_BOX]: _components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_4__.toggleInputLinkBox,\r\n [OPERATIONS.FORMATTING_BAR.INPUT_LINK_URL]: _components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_4__.inputLinkUrl,\r\n [OPERATIONS.FORMATTING_BAR.TOGGLE_ENCLOSE_SELECTED_TEXT_TO]: _components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_4__.toggleEncloseSelectedTextTo,\r\n [OPERATIONS.SHOW_TURN_INTO_BOX]: _block_operation__WEBPACK_IMPORTED_MODULE_0__.transformBlock,\r\n [OPERATIONS.SHOW_COLOR_BOX]: _block_operation__WEBPACK_IMPORTED_MODULE_0__.transformBlock,\r\n [OPERATIONS.SHOW_MORE_OPTIONS_BOX]: _block_operation__WEBPACK_IMPORTED_MODULE_0__.transformBlock\r\n};\r\n\r\nfunction getBlockOperationFunction(blockOperation) {\r\n const operationFunction = operationMap[blockOperation];\r\n if (!operationFunction) {\r\n throw new Error('Operation Not Found Exception');\r\n }\r\n return operationFunction;\r\n}\n\n//# sourceURL=webpack://johannes/./src/commands/command-factory.js?"); - -/***/ }), - -/***/ "./src/common/JCircularLinkedList.js": +/***/ "./src/common/JCircularLinkedList.ts": /*!*******************************************!*\ - !*** ./src/common/JCircularLinkedList.js ***! + !*** ./src/common/JCircularLinkedList.ts ***! \*******************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _JNode__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./JNode */ \"./src/common/JNode.js\");\n\r\n\r\n/**\r\n * Lista ligada que pode trabalhar com qualquer tipo de dados.\r\n * @template T - O tipo de elementos que a lista armazenará.\r\n */\r\nclass JCircularLinkedList {\r\n\r\n constructor() {\r\n\r\n /** @type {T|null} */\r\n this.head = null;\r\n\r\n /** @type {T|null} */\r\n this.tail = null;\r\n\r\n this.length = 0;\r\n }\r\n\r\n /**\r\n * Append a new node with the given value to the end of the list.\r\n * @param {T} node - The node to append.\r\n */\r\n append(node) {\r\n if (!(node instanceof _JNode__WEBPACK_IMPORTED_MODULE_0__[\"default\"])) {\r\n throw new TypeError(\"Expected an instance of JNode.\");\r\n }\r\n\r\n if (this.length === 0) {\r\n this.head = node;\r\n this.tail = node;\r\n\r\n this.head.setNext(this.tail);\r\n this.head.setPrevious(this.tail);\r\n } else {\r\n node.setPrevious(this.tail);\r\n node.setNext(this.head);\r\n\r\n this.tail.setNext(node);\r\n this.head.setPrevious(node);\r\n\r\n this.tail = node;\r\n }\r\n this.length++;\r\n }\r\n\r\n /**\r\n * @returns {T|null} The first node.\r\n */\r\n getFirst() {\r\n return this.head;\r\n }\r\n\r\n /**\r\n * @returns {T|null} The last node.\r\n */\r\n getLast() {\r\n return this.tail;\r\n }\r\n}\r\n\r\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (JCircularLinkedList);\n\n//# sourceURL=webpack://johannes/./src/common/JCircularLinkedList.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\nclass JCircularLinkedList {\n head = null;\n tail = null;\n length = 0;\n constructor() {\n }\n append(node) {\n if (!this.head || !this.tail) {\n this.head = node;\n this.tail = node;\n this.head.setNext(this.tail);\n this.head.setPrevious(this.tail);\n }\n else {\n node.setPrevious(this.tail);\n node.setNext(this.head);\n this.tail.setNext(node);\n this.head.setPrevious(node);\n this.tail = node;\n }\n this.length++;\n }\n getFirst() {\n return this.head;\n }\n getLast() {\n return this.tail;\n }\n}\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (JCircularLinkedList);\n\n\n//# sourceURL=webpack://johannes/./src/common/JCircularLinkedList.ts?"); /***/ }), -/***/ "./src/common/JLinkedList.js": +/***/ "./src/common/JLinkedList.ts": /*!***********************************!*\ - !*** ./src/common/JLinkedList.js ***! + !*** ./src/common/JLinkedList.ts ***! \***********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _JNode__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./JNode */ \"./src/common/JNode.js\");\n\r\n\r\n/**\r\n * Lista ligada que pode trabalhar com qualquer tipo de dados.\r\n * @template T - O tipo de elementos que a lista armazenará.\r\n */\r\nclass JLinkedList {\r\n\r\n constructor() {\r\n /** @type {T|null} */\r\n this.head = null;\r\n\r\n /** @type {T|null} */\r\n this.tail = null;\r\n\r\n \r\n this.length = 0;\r\n }\r\n\r\n /**\r\n * Append a new node with the given value to the end of the list.\r\n * @param {*} HTMLElement - The value to store in the new node.\r\n */\r\n append(node) {\r\n\r\n if (!(node instanceof _JNode__WEBPACK_IMPORTED_MODULE_0__[\"default\"])) {\r\n throw new TypeError(\"Expected an instance of JNode.\");\r\n }\r\n\r\n if (this.length === 0) {\r\n this.head = node;\r\n this.tail = node;\r\n } else {\r\n\r\n this.tail.setNext(node);\r\n node.setPrevious(this.tail);\r\n\r\n this.tail = node;\r\n }\r\n\r\n this.length++;\r\n\r\n\r\n /**\r\n * @returns {T} node.\r\n */\r\n this.getFirst = () => {\r\n return this.head;\r\n }\r\n\r\n /**\r\n * @returns {T} node.\r\n */\r\n this.getLast = () => {\r\n return this.tail;\r\n }\r\n }\r\n}\r\n\r\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (JLinkedList);\n\n//# sourceURL=webpack://johannes/./src/common/JLinkedList.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\nclass JLinkedList {\n head = null;\n tail = null;\n length = 0;\n constructor() {\n }\n append(node) {\n if (!this.head || !this.tail) {\n this.head = node;\n this.tail = node;\n }\n else {\n this.tail.setNext(node);\n node.setPrevious(this.tail);\n this.tail = node;\n }\n this.length++;\n }\n getFirst() {\n return this.head;\n }\n getLast() {\n return this.tail;\n }\n}\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (JLinkedList);\n\n\n//# sourceURL=webpack://johannes/./src/common/JLinkedList.ts?"); /***/ }), -/***/ "./src/common/JNode.js": +/***/ "./src/common/JNode.ts": /*!*****************************!*\ - !*** ./src/common/JNode.js ***! + !*** ./src/common/JNode.ts ***! \*****************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/**\r\n * @class\r\n * Classe abstrata JNode. Deve ser estendida e o tipo do nó deve ser especificado na extensão.\r\n * @template T O tipo de nó que estende JNode, usado para indicar os tipos de previousNode e nextNode.\r\n * @example\r\n * //Assume we have a class QuickMenuItem that extends JNode.\r\n* class QuickMenuItem extends JNode {\r\n* constructor() {\r\n* super();\r\n* }\r\n* }\r\n* let menuList = new JLinkedList();\r\n* let item = new QuickMenuItem(\"Item 1\");\r\n* menuList.append(item);\r\n */\r\nclass JNode {\r\n\r\n constructor() {\r\n\r\n if (new.target === JNode) {\r\n throw new Error(\"JNode is an abstract class and cannot be instantiated directly.\");\r\n }\r\n\r\n /** @type {T|null} */\r\n this.previousNode;\r\n\r\n /** @type {T|null} */\r\n this.nextNode;\r\n\r\n // /**\r\n // * The HTML element of the component in the DOM.\r\n // * @type {HTMLElement}\r\n // */\r\n // this.htmlElement = htmlElement;\r\n\r\n\r\n /**\r\n * Sets the next node.\r\n * If the input is not a JNode, an error is thrown.\r\n *\r\n * @param {T} node - The node to be set as the next item.\r\n * @throws {TypeError} Throws an error if the provided node is not an instance of JNode.\r\n */\r\n this.setNext = (node) => {\r\n if (!(node instanceof JNode)) {\r\n throw new TypeError(\"Expected an instance of JNode.\");\r\n }\r\n\r\n this.nextNode = node;\r\n }\r\n\r\n /**\r\n * Sets the previous node.\r\n * If the input is not a JNode, an error is thrown.\r\n *\r\n * @param {T} node - The node to be set as the previous item.\r\n * @throws {TypeError} Throws an error if the provided node is not an instance of JNode.\r\n */\r\n this.setPrevious = (node) => {\r\n if (!(node instanceof JNode)) {\r\n throw new TypeError(\"Expected an instance of JNode.\");\r\n }\r\n\r\n this.previousNode = node;\r\n }\r\n }\r\n}\r\n\r\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (JNode);\r\n\r\n\r\n// Example usage:\r\n// Assume we have a class QuickMenuItem that extends JNode.\r\n// class QuickMenuItem extends JNode {\r\n// constructor(value) {\r\n// super(value);\r\n// }\r\n// }\r\n// let menuList = new JLinkedList();\r\n// let item = new QuickMenuItem(\"Item 1\");\r\n// menuList.append(item);\n\n//# sourceURL=webpack://johannes/./src/common/JNode.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/**\n * @class\n * Classe abstrata JNode. Deve ser estendida e o tipo do nó deve ser especificado na extensão.\n * @template T O tipo de nó que estende JNode, usado para indicar os tipos de previousNode e nextNode.\n * @example\n * //Assume we have a class QuickMenuItem that extends JNode.\n* class QuickMenuItem extends JNode {\n* constructor() {\n* super();\n* }\n* }\n* let menuList = new JLinkedList();\n* let item = new QuickMenuItem(\"Item 1\");\n* menuList.append(item);\n */\nclass JNode {\n previousNode = null;\n nextNode = null;\n constructor() {\n }\n setNext(node) {\n this.nextNode = node;\n }\n setPrevious(node) {\n this.previousNode = node;\n }\n}\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (JNode);\n// Example usage:\n// Assume we have a class QuickMenuItem that extends JNode.\n// class QuickMenuItem extends JNode {\n// constructor(value) {\n// super(value);\n// }\n// }\n// let menuList = new JLinkedList();\n// let item = new QuickMenuItem(\"Item 1\");\n// menuList.append(item);\n\n\n//# sourceURL=webpack://johannes/./src/common/JNode.ts?"); /***/ }), -/***/ "./src/components/quick-menu/QuickMenu.js": +/***/ "./src/components/common/SVGIcon.ts": +/*!******************************************!*\ + !*** ./src/components/common/SVGIcon.ts ***! + \******************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\nclass SVGIcon {\n htmlElement;\n constructor(hrefUseId, classList = \"\", width = \"16\", height = \"16\") {\n this.htmlElement = document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\");\n if (classList && classList.trim() !== \"\") {\n const classes = classList.split(',');\n this.htmlElement.classList.add(...classes);\n }\n let use = document.createElementNS(\"http://www.w3.org/2000/svg\", \"use\");\n use.setAttributeNS(\"http://www.w3.org/1999/xlink\", \"href\", `#${hrefUseId}`);\n this.htmlElement.appendChild(use);\n this.htmlElement.setAttribute('width', width);\n this.htmlElement.setAttribute('height', height);\n this.htmlElement.setAttribute('fill', 'currentColor');\n }\n}\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (SVGIcon);\n\n\n//# sourceURL=webpack://johannes/./src/components/common/SVGIcon.ts?"); + +/***/ }), + +/***/ "./src/components/quick-menu/QuickMenu.ts": /*!************************************************!*\ - !*** ./src/components/quick-menu/QuickMenu.js ***! + !*** ./src/components/quick-menu/QuickMenu.ts ***! \************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _QuickMenuSection__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./QuickMenuSection */ \"./src/components/quick-menu/QuickMenuSection.js\");\n/* harmony import */ var _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./QuickMenuItem */ \"./src/components/quick-menu/QuickMenuItem.js\");\n/* harmony import */ var _common_JCircularLinkedList__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../common/JCircularLinkedList */ \"./src/common/JCircularLinkedList.js\");\n\r\n\r\n\r\n\r\nclass QuickMenu {\r\n\r\n constructor() {\r\n\r\n /**\r\n * The QuickMenu element of the component in the DOM.\r\n * @type {HTMLElement}\r\n */\r\n this.htmlElement = document.createElement('div');\r\n this.htmlElement.id = 'blockOptionsWrapper';\r\n\r\n this.isShowing = false;\r\n\r\n /**\r\n * The QuickMenuItem current focused.\r\n * @type {QuickMenuItem|null}\r\n */\r\n this.currentFocusedMenuItem = null;\r\n\r\n /**\r\n * The QuickMenuSection elements in a CircularLinkedList.\r\n * @type {JCircularLinkedList}\r\n */\r\n this.menuSections = new _common_JCircularLinkedList__WEBPACK_IMPORTED_MODULE_2__[\"default\"]();\r\n\r\n this.htmlElement.classList.add('block-options-wrapper', 'soft-box-shadow');\r\n this.htmlElement.style.display = 'none';\r\n\r\n const blockOptions = document.createElement('div');\r\n blockOptions.classList.add('block-options');\r\n blockOptions.style.position = 'relative';\r\n\r\n this.htmlElement.appendChild(blockOptions);\r\n\r\n const basicBlocksSection = new _QuickMenuSection__WEBPACK_IMPORTED_MODULE_0__[\"default\"](this, 'Basic blocks', 'basic-section');\r\n\r\n basicBlocksSection.appendQuickMenuItem([\r\n new _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"](basicBlocksSection, 'Paragraph', 'Just start writing with plain text.', 'icon-wordpress-paragraph', 'p'),\r\n new _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"](basicBlocksSection, 'Image', 'Just start writing with plain text.', 'icon-wordpress-paragraph', 'image'),\r\n new _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"](basicBlocksSection, 'Bulleted list', 'Organize items with bullet points.', 'icon-wordpress-bulleted-list', 'bulleted-list'),\r\n new _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"](basicBlocksSection, 'Numbered list', 'List items in a numbered format.', 'icon-wordpress-numbered-list', 'numbered-list'),\r\n new _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"](basicBlocksSection, 'Code', 'Insert code snippets with syntax highlighting.', 'icon-wordpress-code-mark', 'code'),\r\n new _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"](basicBlocksSection, 'Quote', 'Highlight text as a significant quote.', 'icon-wordpress-quote', 'quote'),\r\n new _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"](basicBlocksSection, 'Heading 2', 'Medium header for subsections.', 'icon-julia-head-2', 'h2'),\r\n new _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"](basicBlocksSection, 'Heading 3', 'Small header for detailed sections.', 'icon-julia-head-2', 'h3'),\r\n new _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"](basicBlocksSection, 'Separator', 'Visually divide blocks.', 'icon-wordpress-separator', 'separator')\r\n ]);\r\n\r\n this.menuSections.append(basicBlocksSection);\r\n blockOptions.appendChild(basicBlocksSection.htmlElement);\r\n\r\n\r\n const headingBlocksSection = new _QuickMenuSection__WEBPACK_IMPORTED_MODULE_0__[\"default\"](this, 'Heading', 'heading-section');\r\n\r\n headingBlocksSection.appendQuickMenuItem([\r\n new _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"](headingBlocksSection, 'Heading 1', 'Large header to organize content.', 'icon-julia-head-1', 'h1'),\r\n new _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"](headingBlocksSection, 'Heading 2', 'Medium header for subsections.', 'icon-julia-head-2', 'h2'),\r\n new _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"](headingBlocksSection, 'Heading 3', 'Small header for detailed sections.', 'icon-julia-head-3', 'h3'),\r\n new _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"](headingBlocksSection, 'Heading 4', 'Small header for detailed sections.', 'icon-julia-head-4', 'h4'),\r\n new _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"](headingBlocksSection, 'Heading 5', 'Small header for detailed sections.', 'icon-julia-head-5', 'h5'),\r\n new _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"](headingBlocksSection, 'Heading 6', 'Small header for detailed sections.', 'icon-julia-head-6', 'h6'),\r\n ]);\r\n\r\n this.menuSections.append(headingBlocksSection);\r\n blockOptions.appendChild(headingBlocksSection.htmlElement);\r\n\r\n\r\n const listBlocksSection = new _QuickMenuSection__WEBPACK_IMPORTED_MODULE_0__[\"default\"](this, 'List', 'list-section');\r\n\r\n listBlocksSection.appendQuickMenuItem([\r\n new _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"](listBlocksSection, 'Todo list', 'Organize items with bullet points.', 'icon-material-check-list', 'todo-list'),\r\n new _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"](listBlocksSection, 'Bulleted list', 'Organize items with bullet points.', 'icon-wordpress-bulleted-list', 'bulleted-list'),\r\n new _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"](listBlocksSection, 'Numbered list', 'List items in a numbered format.', 'icon-wordpress-numbered-list', 'numbered-list')\r\n ]);\r\n\r\n this.menuSections.append(listBlocksSection);\r\n blockOptions.appendChild(listBlocksSection.htmlElement);\r\n\r\n\r\n /**\r\n * Change the current fake focus and remove the current fake focus.\r\n * If the input is not a QuickMenuItem or contains an item that is not a QuickMenuItem, an error is thrown.\r\n *\r\n * @param {QuickMenuItem} menuItems The item(s) to be focused.\r\n * @throws {TypeError} Throws an 'Expected an instance of QuickMenuItem. if item is not a QuickMenuItem.\r\n */\r\n this.changeFocus = (item) => {\r\n\r\n if (!(item instanceof _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"])) {\r\n throw new TypeError(\"Expected an instance of QuickMenuItem.\");\r\n }\r\n\r\n if (this.currentFocusedMenuItem == item) {\r\n return;\r\n }\r\n\r\n if (this.currentFocusedMenuItem) {\r\n this.currentFocusedMenuItem.removeFocus();\r\n }\r\n\r\n this.currentFocusedMenuItem = item;\r\n this.currentFocusedMenuItem.focus();\r\n }\r\n\r\n /**\r\n * Move the fake focus menu indication to the next element.\r\n * If no element is currently focused the first QuickMenuItem is used.\r\n */\r\n this.moveTheFakeFocusToTheNextMenuItem = () => {\r\n\r\n let nextItem;\r\n\r\n if (!this.currentFocusedMenuItem) {\r\n\r\n nextItem = this.menuSections.getFirst().getFirstMenuItem();\r\n } else {\r\n\r\n nextItem = this.currentFocusedMenuItem.nextNode;\r\n\r\n if (!nextItem) {\r\n nextItem = this.currentFocusedMenuItem.quickMenuSectionInstance.nextNode.getFirstMenuItem();\r\n }\r\n }\r\n\r\n this.changeFocus(nextItem);\r\n }\r\n\r\n /**\r\n * Get the QuickMenu HTML Element.\r\n * @returns {HTMLElement} htmlElement.\r\n */\r\n this.getMenuElement = () => {\r\n return this.htmlElement;\r\n }\r\n\r\n this.attachEvents = () => {\r\n\r\n document.addEventListener('keydown', (event) => {\r\n if (event.key === '/' && !event.ctrlKey && !event.shiftKey && !event.altKey) {\r\n alert('show the Quick Insert Menu');\r\n }\r\n });\r\n }\r\n\r\n this.attachEvents();\r\n }\r\n\r\n\r\n showMenu() {\r\n\r\n // The timeout in necessary to wait the browser process the selection before show the Block Options\r\n setTimeout(() => {\r\n\r\n const realFocusedElement = document.activeElement;\r\n const currentDraggableBlock = realFocusedElement.closest('.draggable-block');\r\n const firstBlockOption = getTheFirstVisibleBlockOption();\r\n\r\n setRealFocusedElement(realFocusedElement);\r\n setCurrentDraggableBlock(currentDraggableBlock);\r\n setCurrentFakeFocusElement(firstBlockOption);\r\n\r\n applyVisualFakeFocus(realFocusedElement, firstBlockOption);\r\n\r\n\r\n //TODO: create a clear filter\r\n // removeDisplayNoneFromAllBlockOptions();\r\n\r\n const range = document.getSelection().getRangeAt(0);\r\n const cursorPos = range.getBoundingClientRect();\r\n\r\n const remSize = parseFloat(getComputedStyle(document.documentElement).fontSize);\r\n const menuWidth = 19 * remSize;\r\n\r\n let xPosition = cursorPos.right;\r\n let yPosition = cursorPos.bottom + window.scrollY;\r\n\r\n const margin = remSize * 1.25;\r\n\r\n blockOptionsWrapper.style.display = 'block';\r\n\r\n let blockWidth = blockOptionsWrapper.offsetWidth;\r\n\r\n\r\n if (xPosition + blockWidth + margin > window.innerWidth) {\r\n xPosition = cursorPos.left - menuWidth;\r\n if (xPosition < 0) xPosition = 0;\r\n }\r\n\r\n blockOptionsWrapper.style.left = `${xPosition}px`;\r\n blockOptionsWrapper.style.top = `${yPosition}px`;\r\n\r\n\r\n }, 10);\r\n }\r\n\r\n\r\n\r\n\r\n}\r\n\r\nconst instance = new QuickMenu();\r\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (instance);\n\n//# sourceURL=webpack://johannes/./src/components/quick-menu/QuickMenu.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _QuickMenuSection__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./QuickMenuSection */ \"./src/components/quick-menu/QuickMenuSection.ts\");\n/* harmony import */ var _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./QuickMenuItem */ \"./src/components/quick-menu/QuickMenuItem.ts\");\n/* harmony import */ var _common_JCircularLinkedList__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../common/JCircularLinkedList */ \"./src/common/JCircularLinkedList.ts\");\n\n\n\nclass QuickMenu {\n static instance = null;\n htmlElement;\n menuSections;\n isShowing;\n currentFocusedMenuItem = null;\n constructor() {\n this.htmlElement = document.createElement('div');\n this.htmlElement.id = 'blockOptionsWrapper';\n this.isShowing = false;\n this.menuSections = new _common_JCircularLinkedList__WEBPACK_IMPORTED_MODULE_2__[\"default\"]();\n this.htmlElement.classList.add('block-options-wrapper', 'soft-box-shadow');\n this.htmlElement.style.display = 'none';\n const blockOptions = document.createElement('div');\n blockOptions.classList.add('block-options');\n blockOptions.style.position = 'relative';\n this.htmlElement.appendChild(blockOptions);\n const basicBlocksSection = new _QuickMenuSection__WEBPACK_IMPORTED_MODULE_0__[\"default\"](this, 'Basic blocks', 'basic-section');\n basicBlocksSection.appendQuickMenuItems([\n new _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"](basicBlocksSection, 'Paragraph', 'Just start writing with plain text.', 'icon-wordpress-paragraph', 'p'),\n new _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"](basicBlocksSection, 'Image', 'Just start writing with plain text.', 'icon-wordpress-paragraph', 'image'),\n new _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"](basicBlocksSection, 'Bulleted list', 'Organize items with bullet points.', 'icon-wordpress-bulleted-list', 'bulleted-list'),\n new _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"](basicBlocksSection, 'Numbered list', 'List items in a numbered format.', 'icon-wordpress-numbered-list', 'numbered-list'),\n new _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"](basicBlocksSection, 'Code', 'Insert code snippets with syntax highlighting.', 'icon-wordpress-code-mark', 'code'),\n new _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"](basicBlocksSection, 'Quote', 'Highlight text as a significant quote.', 'icon-wordpress-quote', 'quote'),\n new _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"](basicBlocksSection, 'Heading 2', 'Medium header for subsections.', 'icon-julia-head-2', 'h2'),\n new _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"](basicBlocksSection, 'Heading 3', 'Small header for detailed sections.', 'icon-julia-head-2', 'h3'),\n new _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"](basicBlocksSection, 'Separator', 'Visually divide blocks.', 'icon-wordpress-separator', 'separator')\n ]);\n this.menuSections.append(basicBlocksSection);\n blockOptions.appendChild(basicBlocksSection.htmlElement);\n const headingBlocksSection = new _QuickMenuSection__WEBPACK_IMPORTED_MODULE_0__[\"default\"](this, 'Heading', 'heading-section');\n headingBlocksSection.appendQuickMenuItems([\n new _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"](headingBlocksSection, 'Heading 1', 'Large header to organize content.', 'icon-julia-head-1', 'h1'),\n new _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"](headingBlocksSection, 'Heading 2', 'Medium header for subsections.', 'icon-julia-head-2', 'h2'),\n new _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"](headingBlocksSection, 'Heading 3', 'Small header for detailed sections.', 'icon-julia-head-3', 'h3'),\n new _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"](headingBlocksSection, 'Heading 4', 'Small header for detailed sections.', 'icon-julia-head-4', 'h4'),\n new _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"](headingBlocksSection, 'Heading 5', 'Small header for detailed sections.', 'icon-julia-head-5', 'h5'),\n new _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"](headingBlocksSection, 'Heading 6', 'Small header for detailed sections.', 'icon-julia-head-6', 'h6'),\n ]);\n this.menuSections.append(headingBlocksSection);\n blockOptions.appendChild(headingBlocksSection.htmlElement);\n const listBlocksSection = new _QuickMenuSection__WEBPACK_IMPORTED_MODULE_0__[\"default\"](this, 'List', 'list-section');\n listBlocksSection.appendQuickMenuItems([\n new _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"](listBlocksSection, 'Todo list', 'Organize items with bullet points.', 'icon-material-check-list', 'todo-list'),\n new _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"](listBlocksSection, 'Bulleted list', 'Organize items with bullet points.', 'icon-wordpress-bulleted-list', 'bulleted-list'),\n new _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"](listBlocksSection, 'Numbered list', 'List items in a numbered format.', 'icon-wordpress-numbered-list', 'numbered-list')\n ]);\n this.menuSections.append(listBlocksSection);\n blockOptions.appendChild(listBlocksSection.htmlElement);\n // this.attachEvents();\n }\n static getInstance() {\n if (!QuickMenu.instance) {\n QuickMenu.instance = new QuickMenu();\n }\n return QuickMenu.instance;\n }\n changeFocus(item) {\n if (this.currentFocusedMenuItem == item) {\n return;\n }\n if (this.currentFocusedMenuItem) {\n this.currentFocusedMenuItem.removeFocus();\n }\n this.currentFocusedMenuItem = item;\n this.currentFocusedMenuItem.focus();\n }\n moveTheFakeFocusToTheNextMenuItem() {\n let nextItem;\n if (!this.currentFocusedMenuItem) {\n nextItem = this.menuSections.getFirst().getFirstMenuItem();\n }\n else {\n nextItem = this.currentFocusedMenuItem.nextNode;\n if (!nextItem) {\n nextItem = this.currentFocusedMenuItem.quickMenuSectionInstance.nextNode.getFirstMenuItem();\n }\n }\n this.changeFocus(nextItem);\n }\n getMenuElement() {\n return this.htmlElement;\n }\n attachEvents = () => {\n document.addEventListener('keydown', (event) => {\n if (event.key === '/' && !event.ctrlKey && !event.shiftKey && !event.altKey) {\n alert('show the Quick Insert Menu');\n }\n });\n };\n showMenu() {\n // The timeout in necessary to wait the browser process the selection before show the Block Options\n // setTimeout(() => {\n // const realFocusedElement = document.activeElement;\n // const currentDraggableBlock = realFocusedElement.closest('.draggable-block');\n // const firstBlockOption = getTheFirstVisibleBlockOption();\n // setRealFocusedElement(realFocusedElement);\n // setCurrentDraggableBlock(currentDraggableBlock);\n // setCurrentFakeFocusElement(firstBlockOption);\n // applyVisualFakeFocus(realFocusedElement, firstBlockOption);\n // //TODO: create a clear filter\n // // removeDisplayNoneFromAllBlockOptions();\n // const range = document.getSelection().getRangeAt(0);\n // const cursorPos = range.getBoundingClientRect();\n // const remSize = parseFloat(getComputedStyle(document.documentElement).fontSize);\n // const menuWidth = 19 * remSize;\n // let xPosition = cursorPos.right;\n // let yPosition = cursorPos.bottom + window.scrollY;\n // const margin = remSize * 1.25;\n // blockOptionsWrapper.style.display = 'block';\n // let blockWidth = blockOptionsWrapper.offsetWidth;\n // if (xPosition + blockWidth + margin > window.innerWidth) {\n // xPosition = cursorPos.left - menuWidth;\n // if (xPosition < 0) xPosition = 0;\n // }\n // blockOptionsWrapper.style.left = `${xPosition}px`;\n // blockOptionsWrapper.style.top = `${yPosition}px`;\n // }, 10);\n }\n}\n// const instance = new QuickMenu();\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (QuickMenu);\n\n\n//# sourceURL=webpack://johannes/./src/components/quick-menu/QuickMenu.ts?"); /***/ }), -/***/ "./src/components/quick-menu/QuickMenuItem.js": +/***/ "./src/components/quick-menu/QuickMenuItem.ts": /*!****************************************************!*\ - !*** ./src/components/quick-menu/QuickMenuItem.js ***! + !*** ./src/components/quick-menu/QuickMenuItem.ts ***! \****************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _helperDOM__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./helperDOM */ \"./src/components/quick-menu/helperDOM.js\");\n/* harmony import */ var _common_JNode__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../common/JNode */ \"./src/common/JNode.js\");\n/* harmony import */ var _QuickMenuSection__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./QuickMenuSection */ \"./src/components/quick-menu/QuickMenuSection.js\");\n\r\n\r\n\r\n\r\nclass QuickMenuItem extends _common_JNode__WEBPACK_IMPORTED_MODULE_1__[\"default\"] {\r\n\r\n constructor(quickMenuSectionInstance, itemName, itemDescription, SVGHrefUseId, dataType) {\r\n\r\n super();\r\n\r\n // if (!(QuickMenuSectionInstance instanceof QuickMenuSection)) {\r\n // throw new TypeError(\"Expected an instance of QuickMenuSection.\");\r\n // }\r\n\r\n /**\r\n * The QuickMenu element of the component in the DOM.\r\n * @type {HTMLElement}\r\n */\r\n this.htmlElement = document.createElement('div');\r\n htmlElement.classList.add('option', 'option-hover', 'block-operation');\r\n\r\n /**\r\n * The QuickMenuSection parent.\r\n * @type {QuickMenuSection}\r\n */\r\n this.quickMenuSectionInstance = quickMenuSectionInstance;\r\n\r\n htmlElement.setAttribute('data-block-operation', 'apply-selected-block-type');\r\n htmlElement.setAttribute('data-type', dataType);\r\n htmlElement.setAttribute('tabindex', '0');\r\n htmlElement.setAttribute('role', 'option');\r\n\r\n const optionImage = document.createElement('div');\r\n optionImage.classList.add('option-image');\r\n\r\n const svg = _helperDOM__WEBPACK_IMPORTED_MODULE_0__.createSVG(SVGHrefUseId, '', '100%', '100%');\r\n\r\n optionImage.appendChild(svg);\r\n\r\n htmlElement.appendChild(optionImage);\r\n\r\n\r\n const optionText = document.createElement('div');\r\n optionText.classList.add('option-text');\r\n\r\n const blockTitle = document.createElement('p');\r\n blockTitle.classList.add('block-title');\r\n blockTitle.innerText = itemName;\r\n\r\n optionText.appendChild(blockTitle);\r\n\r\n const blockDescription = document.createElement('p');\r\n blockDescription.classList.add('block-description');\r\n blockDescription.innerText = itemDescription;\r\n\r\n optionText.appendChild(blockDescription);\r\n\r\n htmlElement.appendChild(optionText);\r\n\r\n\r\n /** Apply a fake focus in the element */\r\n this.focus = () => {\r\n this.htmlElement.classList.add('block-options-focused');\r\n this.htmlElement.focus();\r\n }\r\n\r\n this.removeFocus = () => {\r\n this.htmlElement.classList.remove('block-options-focused');\r\n }\r\n\r\n this.attachEvents = () => {\r\n this.htmlElement.addEventListener('mousemove', () => {\r\n this.quickMenuSectionInstance.quickMenuInstance.changeFocus(this);\r\n });\r\n }\r\n\r\n this.attachEvents();\r\n }\r\n}\r\n\r\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (QuickMenuItem);\n\n//# sourceURL=webpack://johannes/./src/components/quick-menu/QuickMenuItem.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _common_SVGIcon__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../common/SVGIcon */ \"./src/components/common/SVGIcon.ts\");\n/* harmony import */ var _common_JNode__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../common/JNode */ \"./src/common/JNode.ts\");\n\n\nclass QuickMenuItem extends _common_JNode__WEBPACK_IMPORTED_MODULE_1__[\"default\"] {\n htmlElement;\n quickMenuSectionInstance;\n constructor(quickMenuSectionInstance, itemName, itemDescription, SVGHrefUseId, dataType) {\n super();\n this.htmlElement = document.createElement('div');\n this.htmlElement.classList.add('option', 'option-hover', 'block-operation');\n this.quickMenuSectionInstance = quickMenuSectionInstance;\n this.htmlElement.setAttribute('data-block-operation', 'apply-selected-block-type');\n this.htmlElement.setAttribute('data-type', dataType);\n this.htmlElement.setAttribute('tabindex', '0');\n this.htmlElement.setAttribute('role', 'option');\n const optionImage = document.createElement('div');\n optionImage.classList.add('option-image');\n const svg = new _common_SVGIcon__WEBPACK_IMPORTED_MODULE_0__[\"default\"](SVGHrefUseId, '', '100%', '100%');\n optionImage.appendChild(svg.htmlElement);\n this.htmlElement.appendChild(optionImage);\n const optionText = document.createElement('div');\n optionText.classList.add('option-text');\n const blockTitle = document.createElement('p');\n blockTitle.classList.add('block-title');\n blockTitle.innerText = itemName;\n optionText.appendChild(blockTitle);\n const blockDescription = document.createElement('p');\n blockDescription.classList.add('block-description');\n blockDescription.innerText = itemDescription;\n optionText.appendChild(blockDescription);\n this.htmlElement.appendChild(optionText);\n this.attachEvents();\n }\n focus() {\n this.htmlElement.classList.add('block-options-focused');\n this.htmlElement.focus();\n }\n removeFocus() {\n this.htmlElement.classList.remove('block-options-focused');\n }\n attachEvents() {\n this.htmlElement.addEventListener('mousemove', () => {\n this.quickMenuSectionInstance.quickMenuInstance.changeFocus(this);\n });\n }\n}\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (QuickMenuItem);\n\n\n//# sourceURL=webpack://johannes/./src/components/quick-menu/QuickMenuItem.ts?"); /***/ }), -/***/ "./src/components/quick-menu/QuickMenuSection.js": +/***/ "./src/components/quick-menu/QuickMenuSection.ts": /*!*******************************************************!*\ - !*** ./src/components/quick-menu/QuickMenuSection.js ***! + !*** ./src/components/quick-menu/QuickMenuSection.ts ***! \*******************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _QuickMenu__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./QuickMenu */ \"./src/components/quick-menu/QuickMenu.js\");\n/* harmony import */ var _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./QuickMenuItem */ \"./src/components/quick-menu/QuickMenuItem.js\");\n/* harmony import */ var _common_JLinkedList__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../common/JLinkedList */ \"./src/common/JLinkedList.js\");\n/* harmony import */ var _common_JNode__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../common/JNode */ \"./src/common/JNode.js\");\n\r\n\r\n\r\n\r\n\r\n/**\r\n * Represents a section within a QuickMenu, acting as a node in a doubly-linked list.\r\n * Each section contains a collection of QuickMenuItem nodes, managed as a linked list with references to both the head and tail of the list.\r\n * This setup facilitates efficient addition and removal of items at both ends of the list.\r\n *\r\n * @class QuickMenuSection\r\n * @property {HTMLElement} htmlElement - The DOM element representing the section in the UI.\r\n * @property {QuickMenuItem[]} menuItems - An array of menu items contained within the section.\r\n * @property {QuickMenuItem} #head - Private field holding a reference to the first QuickMenuItem in the section.\r\n * @property {QuickMenuItem} #tail - Private field holding a reference to the last QuickMenuItem in the section.\r\n */\r\nclass QuickMenuSection extends _common_JNode__WEBPACK_IMPORTED_MODULE_3__[\"default\"] {\r\n\r\n constructor(quickMenuInstance, sectionName, classList) {\r\n\r\n super();\r\n\r\n // if (!(QuickMenuInstance instanceof QuickMenu)) {\r\n // throw new TypeError(\"Expected an instance of QuickMenu.\");\r\n // }\r\n\r\n /**\r\n * The QuickMenuSection element of the component in the DOM.\r\n * @type {HTMLElement}\r\n */\r\n this.htmlElement = document.createElement('section');\r\n htmlElement.classList.add(classList);\r\n\r\n /**\r\n * The QuickMenu parent.\r\n * @type {QuickMenu}\r\n */\r\n this.quickMenuInstance = quickMenuInstance;\r\n\r\n let heading = document.createElement('h2');\r\n heading.textContent = sectionName;\r\n\r\n /**\r\n * The QuickMenuItem elements in a LinkedList.\r\n * @type {JLinkedList}\r\n */\r\n this.menuItems = new _common_JLinkedList__WEBPACK_IMPORTED_MODULE_2__[\"default\"]();\r\n\r\n htmlElement.appendChild(heading);\r\n\r\n /**\r\n * Inserts a QuickMenuItem or an array of QuickMenuItems into the menu.\r\n * If the input is not a QuickMenuItem or contains an item that is not a QuickMenuItem, an error is thrown.\r\n *\r\n * @param {QuickMenuItem|QuickMenuItem[]} menuItems The item(s) to be inserted.\r\n * @throws {Error} Throws an 'Out Of Range Exception' if any item is not a QuickMenuItem.\r\n */\r\n this.appendQuickMenuItem = (menuItems) => {\r\n\r\n if (Array.isArray(menuItems)) {\r\n menuItems.forEach(item => {\r\n\r\n if (!(item instanceof _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"])) {\r\n throw new Error('Out Of Range Exception');\r\n }\r\n\r\n this.menuItems.append(item);\r\n this.htmlElement.appendChild(item.htmlElement);\r\n });\r\n } else {\r\n\r\n if (!(item instanceof _QuickMenuItem__WEBPACK_IMPORTED_MODULE_1__[\"default\"])) {\r\n throw new Error('Out Of Range Exception');\r\n }\r\n\r\n this.menuItems.append(menuItems);\r\n this.htmlElement.appendChild(menuItems.htmlElement);\r\n }\r\n }\r\n\r\n /**\r\n * Gets the first item from the list of menu items.\r\n * @returns {QuickMenuItem|null} The first menu item if the list is not empty, or null if it is empty.\r\n */\r\n this.getFirstMenuItem = () => {\r\n if (this.menuItems.length) {\r\n return this.menuItems.getFirst();\r\n } else {\r\n return null;\r\n }\r\n }\r\n }\r\n}\r\n\r\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (QuickMenuSection);\n\n//# sourceURL=webpack://johannes/./src/components/quick-menu/QuickMenuSection.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _common_JLinkedList__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../common/JLinkedList */ \"./src/common/JLinkedList.ts\");\n/* harmony import */ var _common_JNode__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../common/JNode */ \"./src/common/JNode.ts\");\n\n\nclass QuickMenuSection extends _common_JNode__WEBPACK_IMPORTED_MODULE_1__[\"default\"] {\n htmlElement;\n quickMenuInstance;\n menuItems = new _common_JLinkedList__WEBPACK_IMPORTED_MODULE_0__[\"default\"]();\n constructor(quickMenuInstance, sectionName, classList) {\n super();\n this.htmlElement = document.createElement('section');\n this.htmlElement.classList.add(classList);\n this.quickMenuInstance = quickMenuInstance;\n let heading = document.createElement('h2');\n heading.textContent = sectionName;\n this.htmlElement.appendChild(heading);\n }\n appendQuickMenuItems(menuItems) {\n menuItems.forEach(item => {\n this.appendQuickMenuItem(item);\n });\n }\n appendQuickMenuItem(menuItem) {\n this.menuItems.append(menuItem);\n this.htmlElement.appendChild(menuItem.htmlElement);\n }\n getFirstMenuItem() {\n if (this.menuItems.length) {\n return this.menuItems.getFirst();\n }\n else {\n return null;\n }\n }\n}\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (QuickMenuSection);\n\n\n//# sourceURL=webpack://johannes/./src/components/quick-menu/QuickMenuSection.ts?"); /***/ }), -/***/ "./src/components/quick-menu/helperDOM.js": -/*!************************************************!*\ - !*** ./src/components/quick-menu/helperDOM.js ***! - \************************************************/ +/***/ "./src/index.ts": +/*!**********************!*\ + !*** ./src/index.ts ***! + \**********************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _triggers_load_events_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./triggers/load-events.js */ \"./src/triggers/load-events.js\");\n/* harmony import */ var _triggers_keypress_events_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./triggers/keypress-events.js */ \"./src/triggers/keypress-events.js\");\n/* harmony import */ var _triggers_click_events_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./triggers/click-events.js */ \"./src/triggers/click-events.js\");\n/* harmony import */ var _block_operation_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./block-operation.js */ \"./src/block-operation.js\");\n/* harmony import */ var _drag_and_drop_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./drag-and-drop.js */ \"./src/drag-and-drop.js\");\n/* harmony import */ var _drag_and_drop_js__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_drag_and_drop_js__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var _switch_block_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./switch-block.js */ \"./src/switch-block.js\");\n/* harmony import */ var _switch_block_js__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_switch_block_js__WEBPACK_IMPORTED_MODULE_5__);\n/* harmony import */ var _keyboard_navigation_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./keyboard-navigation.js */ \"./src/keyboard-navigation.js\");\n/* harmony import */ var _keyboard_navigation_js__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(_keyboard_navigation_js__WEBPACK_IMPORTED_MODULE_6__);\n/* harmony import */ var _text_blocks_from_newlines_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./text-blocks-from-newlines.js */ \"./src/text-blocks-from-newlines.js\");\n/* harmony import */ var _memento_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./memento.js */ \"./src/memento.js\");\n/* harmony import */ var _memento_js__WEBPACK_IMPORTED_MODULE_8___default = /*#__PURE__*/__webpack_require__.n(_memento_js__WEBPACK_IMPORTED_MODULE_8__);\n/* harmony import */ var _style_css__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./style.css */ \"./src/style.css\");\n// listen events in keyboard, mouse and document load\n\n\n\n\n\n\n\n\n\n// default style\n\n\n\n//# sourceURL=webpack://johannes/./src/index.ts?"); + +/***/ }), + +/***/ "./src/block-operation.js": +/*!********************************!*\ + !*** ./src/block-operation.js ***! + \********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ createSVG: () => (/* binding */ createSVG)\n/* harmony export */ });\nfunction createSVG(hrefUseId, classList = \"\", width = 16, height = 16) {\r\n\r\n if (!hrefUseId) {\r\n throw new Error('Invalid Argument Exception');\r\n }\r\n\r\n let svg = document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\");\r\n\r\n if (classList && classList.trim() !== \"\") {\r\n const classes = classList.split(',');\r\n svg.classList.add(...classes);\r\n }\r\n\r\n let use = document.createElementNS(\"http://www.w3.org/2000/svg\", \"use\");\r\n use.setAttributeNS(\"http://www.w3.org/1999/xlink\", \"href\", `#${hrefUseId}`);\r\n\r\n svg.appendChild(use);\r\n svg.setAttribute('width', width);\r\n svg.setAttribute('height', height);\r\n svg.setAttribute('fill', 'currentColor');\r\n\r\n return svg;\r\n}\n\n//# sourceURL=webpack://johannes/./src/components/quick-menu/helperDOM.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ createListItem: () => (/* binding */ createListItem),\n/* harmony export */ createNewElement: () => (/* binding */ createNewElement),\n/* harmony export */ deleteAndFocusOnNext: () => (/* binding */ deleteAndFocusOnNext),\n/* harmony export */ deleteAndFocusOnPrevious: () => (/* binding */ deleteAndFocusOnPrevious),\n/* harmony export */ deleteDraggableParentBlock: () => (/* binding */ deleteDraggableParentBlock),\n/* harmony export */ duplicateSelectedBlock: () => (/* binding */ duplicateSelectedBlock),\n/* harmony export */ moveDownBlock: () => (/* binding */ moveDownBlock),\n/* harmony export */ moveUpBlock: () => (/* binding */ moveUpBlock),\n/* harmony export */ transformBlock: () => (/* binding */ transformBlock)\n/* harmony export */ });\n/* harmony import */ var _element_factory__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./element-factory */ \"./src/element-factory.js\");\n/* harmony import */ var _j_selection__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./j-selection */ \"./src/j-selection.js\");\n/* harmony import */ var _j_window__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./j-window */ \"./src/j-window.js\");\n/* harmony import */ var _components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./components/text-formatting-bar/text-formatting-bar */ \"./src/components/text-formatting-bar/text-formatting-bar.js\");\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n//** Create a default block or a element list */\r\nfunction createNewElement(event) {\r\n\r\n const element = event.target;\r\n\r\n const contentElement = element.closest('.johannes-content-element');\r\n\r\n if (contentElement && contentElement.classList.contains('list')) {\r\n createListItem(contentElement);\r\n } else {\r\n createADefaultBlock(contentElement);\r\n }\r\n}\r\n\r\n//** Just create a new paragraph draggable block and insert in the DOM */\r\nfunction createADefaultBlock(eventParagraph) {\r\n\r\n const newBlock = _element_factory__WEBPACK_IMPORTED_MODULE_0__.createNewDraggableParagraphElement();\r\n\r\n if (eventParagraph && eventParagraph.closest('.draggable-block')) {\r\n const sibling = eventParagraph.closest('.draggable-block');\r\n sibling.insertAdjacentElement('afterend', newBlock);\r\n } else {\r\n document.querySelector('.johannes-editor > .content').appendChild(newBlock);\r\n }\r\n\r\n const focusable = newBlock.querySelector('.johannes-content-element');\r\n // focusable.focus();\r\n\r\n (0,_j_window__WEBPACK_IMPORTED_MODULE_2__.focusOnTheEndOfTheText)(focusable);\r\n}\r\n\r\nfunction createListItem(element) {\r\n\r\n let newContentElement = null;\r\n\r\n let activeElement = document.activeElement;\r\n let contentElement = element.closest('.johannes-content-element');\r\n\r\n if (contentElement.classList.contains('checkbox-list')) {\r\n newContentElement = (0,_element_factory__WEBPACK_IMPORTED_MODULE_0__.createNewCheckboxLiElement)();\r\n } else if (contentElement.classList.contains('list')) {\r\n newContentElement = (0,_element_factory__WEBPACK_IMPORTED_MODULE_0__.createNewLiElement)();\r\n } else {\r\n newContentElement = (0,_element_factory__WEBPACK_IMPORTED_MODULE_0__.createNewDraggableParagraphElement)();\r\n }\r\n\r\n let parentBlock = null;\r\n\r\n if (contentElement.classList.contains('list')) {\r\n\r\n parentBlock = contentElement;\r\n\r\n const textContent = activeElement.textContent.trim();\r\n\r\n if (textContent === '') {\r\n\r\n parentBlock = element.closest('.draggable-block');\r\n\r\n element.closest('.deletable').remove();\r\n\r\n newContentElement = (0,_element_factory__WEBPACK_IMPORTED_MODULE_0__.createNewDraggableParagraphElement)();\r\n parentBlock.insertAdjacentElement('afterend', newContentElement);\r\n\r\n } else {\r\n const activeElement = document.activeElement.closest('.list-item');\r\n activeElement.insertAdjacentElement('afterend', newContentElement);\r\n }\r\n\r\n } else {\r\n parentBlock = element.closest('.draggable-block');\r\n\r\n if (parentBlock) {\r\n if (parentBlock.nextSibling) {\r\n parentBlock.parentNode.insertBefore(newContentElement, parentBlock.nextSibling);\r\n } else {\r\n parentBlock.parentNode.appendChild(newContentElement);\r\n }\r\n }\r\n }\r\n\r\n (0,_j_window__WEBPACK_IMPORTED_MODULE_2__.focusOnTheEndOfTheText)(newContentElement);\r\n}\r\n\r\n//** Delete the closest draggable-block parent of a child. Take the current selection if a child is not passed. */\r\nfunction deleteDraggableParentBlock(child) {\r\n\r\n let draggableBlockToRemove = null;\r\n\r\n if (child && child instanceof HTMLElement && child.closest('.draggable-block')) {\r\n draggableBlockToRemove = child.closest('.draggable-block');\r\n } else {\r\n draggableBlockToRemove = _j_selection__WEBPACK_IMPORTED_MODULE_1__.getCurrentDraggableBlockFocused();\r\n }\r\n\r\n if (draggableBlockToRemove) {\r\n draggableBlockToRemove.remove();\r\n } else {\r\n throw new Error('Focusable Element Not Found Exception');\r\n }\r\n\r\n clearAllAfterDelete();\r\n}\r\n\r\nfunction deleteAndFocusOnPrevious() {\r\n\r\n const currentActiveElement = document.activeElement;\r\n\r\n (0,_j_window__WEBPACK_IMPORTED_MODULE_2__.focusOnPrevious)(currentActiveElement);\r\n deleteTheCurrentElementAndTheDraggableBlockIfEmpty(currentActiveElement);\r\n}\r\n\r\nfunction deleteAndFocusOnNext() {\r\n\r\n const currentActiveElement = document.activeElement;\r\n\r\n (0,_j_window__WEBPACK_IMPORTED_MODULE_2__.focusOnNext)(currentActiveElement);\r\n deleteTheCurrentElementAndTheDraggableBlockIfEmpty(currentActiveElement);\r\n}\r\n\r\n\r\n//** Delete the current element and the draggable-block parent if empty. A block is empty if has no editable element inside. */\r\nfunction deleteTheCurrentElementAndTheDraggableBlockIfEmpty(currentElement) {\r\n\r\n const parentBlock = currentElement.closest('.draggable-block');\r\n const actual = currentElement.closest('.deletable');\r\n\r\n actual.remove();\r\n\r\n if (parentBlock && parentBlock.querySelectorAll('.editable').length == 0) {\r\n parentBlock.remove();\r\n }\r\n}\r\n\r\n/** Transform a block type into another */\r\nfunction transformBlock(blockElement, type) {\r\n\r\n //blockElement, type\r\n\r\n\r\n let contentElement = blockElement.querySelector('.swittable');\r\n let content = contentElement.innerText;\r\n\r\n // if (content.endsWith('/')) {\r\n // content = content.slice(0, -1); // Remove the last '/'\r\n // }\r\n\r\n let newContentBlock;\r\n\r\n switch (type) {\r\n case 'p':\r\n {\r\n newContentBlock = _element_factory__WEBPACK_IMPORTED_MODULE_0__.createNewParagraphElement();\r\n newContentBlock.innerText = content;\r\n break;\r\n }\r\n case 'h1':\r\n {\r\n newContentBlock = _element_factory__WEBPACK_IMPORTED_MODULE_0__.createNewHeadingElement(1);\r\n newContentBlock.innerText = content;\r\n break;\r\n }\r\n case 'h2':\r\n {\r\n newContentBlock = _element_factory__WEBPACK_IMPORTED_MODULE_0__.createNewHeadingElement(2);\r\n newContentBlock.innerText = content;\r\n break;\r\n }\r\n case 'h3':\r\n {\r\n newContentBlock = _element_factory__WEBPACK_IMPORTED_MODULE_0__.createNewHeadingElement(3);\r\n newContentBlock.innerText = content;\r\n break;\r\n }\r\n case 'h4':\r\n {\r\n newContentBlock = _element_factory__WEBPACK_IMPORTED_MODULE_0__.createNewHeadingElement(4);\r\n newContentBlock.innerText = content;\r\n break;\r\n }\r\n case 'h5':\r\n {\r\n newContentBlock = _element_factory__WEBPACK_IMPORTED_MODULE_0__.createNewHeadingElement(5);\r\n newContentBlock.innerText = content;\r\n break;\r\n }\r\n case 'h6':\r\n {\r\n newContentBlock = _element_factory__WEBPACK_IMPORTED_MODULE_0__.createNewHeadingElement(6);\r\n newContentBlock.innerText = content;\r\n break;\r\n }\r\n case 'code':\r\n newContentBlock = document.createElement('pre');\r\n const code = document.createElement('code');\r\n code.innerText = content;\r\n newContentBlock.appendChild(code);\r\n break;\r\n case 'image':\r\n newContentBlock = document.createElement('img');\r\n newContentBlock.src = content;\r\n newContentBlock.alt = \"Descriptive text\";\r\n break;\r\n case 'quote':\r\n {\r\n newContentBlock = _element_factory__WEBPACK_IMPORTED_MODULE_0__.createNewQuoteElement(content);\r\n\r\n break;\r\n }\r\n case 'bulleted-list':\r\n {\r\n newContentBlock = _element_factory__WEBPACK_IMPORTED_MODULE_0__.createNewListElement(content);\r\n\r\n break;\r\n }\r\n\r\n case 'numbered-list':\r\n {\r\n newContentBlock = _element_factory__WEBPACK_IMPORTED_MODULE_0__.createNewListElement(content, 'ol');\r\n\r\n break;\r\n }\r\n case 'todo-list':\r\n {\r\n newContentBlock = _element_factory__WEBPACK_IMPORTED_MODULE_0__.createNewTodoListElement(content, 'ul');\r\n\r\n break;\r\n }\r\n\r\n case 'separator':\r\n {\r\n newContentBlock = _element_factory__WEBPACK_IMPORTED_MODULE_0__.createNewSeparatorElement();\r\n break;\r\n }\r\n\r\n default:\r\n console.error('Unsupported type');\r\n return;\r\n }\r\n\r\n blockElement.replaceChild(newContentBlock, contentElement);\r\n\r\n const focusable = newContentBlock.closest('.focusable') || blockElement.querySelector('.focusable');\r\n\r\n (0,_j_window__WEBPACK_IMPORTED_MODULE_2__.focusOnTheEndOfTheText)(focusable);\r\n}\r\n\r\n\r\nfunction moveDownBlock() {\r\n\r\n}\r\n\r\nfunction moveUpBlock() {\r\n\r\n}\r\n\r\nfunction duplicateSelectedBlock() {\r\n\r\n let element = _j_selection__WEBPACK_IMPORTED_MODULE_1__.getCurrentDraggableBlockFocused();\r\n\r\n if (!element || !element.parentNode) {\r\n console.error('O elemento fornecido é inválido ou não está no DOM.');\r\n return;\r\n }\r\n\r\n const clone = element.cloneNode(true);\r\n\r\n // Obtem o próximo elemento irmão\r\n const nextElement = element.nextSibling;\r\n\r\n // Insere o clone antes do próximo elemento irmão no pai\r\n // Se o próximo elemento irmão não existir, 'insertBefore' funcionará como 'appendChild'\r\n element.parentNode.insertBefore(clone, nextElement);\r\n\r\n\r\n (0,_components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_3__.hideAllDependentBox)();\r\n (0,_components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_3__.hideTextFormattingBar)();\r\n\r\n (0,_j_window__WEBPACK_IMPORTED_MODULE_2__.focusOnTheEndOfTheText)(clone);\r\n}\r\n\r\nfunction clearAllAfterDelete() {\r\n _j_selection__WEBPACK_IMPORTED_MODULE_1__.clearAllSelection();\r\n\r\n (0,_components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_3__.hideAllDependentBox)();\r\n (0,_components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_3__.hideTextFormattingBar)();\r\n}\n\n//# sourceURL=webpack://johannes/./src/block-operation.js?"); + +/***/ }), + +/***/ "./src/commands/command-factory.js": +/*!*****************************************!*\ + !*** ./src/commands/command-factory.js ***! + \*****************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ OPERATIONS: () => (/* binding */ OPERATIONS),\n/* harmony export */ createCommand: () => (/* binding */ createCommand),\n/* harmony export */ getBlockOperationFunction: () => (/* binding */ getBlockOperationFunction),\n/* harmony export */ operationMap: () => (/* binding */ operationMap)\n/* harmony export */ });\n/* harmony import */ var _block_operation__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../block-operation */ \"./src/block-operation.js\");\n/* harmony import */ var _components_quick_menu_quick_insert_menu__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../components/quick-menu/quick-insert-menu */ \"./src/components/quick-menu/quick-insert-menu.js\");\n/* harmony import */ var _j_window__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../j-window */ \"./src/j-window.js\");\n/* harmony import */ var _components_quick_menu_QuickMenu__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../components/quick-menu/QuickMenu */ \"./src/components/quick-menu/QuickMenu.ts\");\n/* harmony import */ var _components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../components/text-formatting-bar/text-formatting-bar */ \"./src/components/text-formatting-bar/text-formatting-bar.js\");\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nfunction createCommand(operationName, elements = null) {\r\n return new Command(operationName, elements);\r\n}\r\n\r\nclass Command {\r\n\r\n constructor(operationName, elements) {\r\n this.elements = elements;\r\n this.operation = getBlockOperationFunction(operationName);\r\n }\r\n\r\n execute() {\r\n\r\n setTimeout(() => {\r\n if (this.elements !== null) {\r\n this.operation(...this.elements);\r\n } else {\r\n this.operation();\r\n }\r\n }, 0);\r\n\r\n }\r\n}\r\n\r\nconst OPERATIONS = {\r\n BLOCK: {\r\n CREATE_LIST_ELEMENT: 'create-list-element',\r\n CREATE_NEW_ELEMENT: 'create-new-element',\r\n DELETE_DRAGGABLE_BLOCK: 'delete-draggable-block',\r\n DELETE_AND_FOCUS_ON_NEXT: 'delete-and-focus-on-next',\r\n DELETE_AND_FOCUS_ON_PREVIOUS: 'delete-and-focus-on-previous',\r\n DUPLICATE_SELECTED_BLOCK: 'duplicate-selected-block',\r\n TRANSFORM_BLOCK: 'transform-block',\r\n MOVE_UP_BLOCK: 'move-up-block',\r\n MOVE_DOWN_BLOCK: 'move-down-block',\r\n SHOW_TURN_INTO_BOX: 'show-turn-into-box',\r\n SHOW_COLOR_BOX: 'show-color-box',\r\n SHOW_MORE_OPTIONS_BOX: 'show-more-options-box'\r\n },\r\n BLOCK_OPTIONS: {\r\n SHOW_BLOCK_OPTIONS: 'show-block-options',\r\n HIDE_CLEAR_BLOCK_OPTIONS: 'hide-clear-block-options',\r\n MOVE_FAKE_FOCUS_TO_NEXT_OPTION: 'move-fake-focus-to-next-option',\r\n MOVE_FAKE_FOCUS_TO_PREVIOUS_OPTION: 'move-fake-focus-to-previous-option',\r\n APPLY_SELECTED_BLOCK_TYPE: 'apply-selected-block-type',\r\n FILTER_CONCAT: 'filter-contact',\r\n FILTER_REMOVE_LAST: 'filter-remove-last',\r\n },\r\n FORMATTING_BAR: {\r\n SHOW_TEXT_FORMATTING_BAR: 'show-text-formatting-bar',\r\n HIDE_TEXT_FORMATTING_BAR: 'hide-text-formatting-bar',\r\n TOGGLE_MORE_OPTIONS_BOX: 'toggle-more-options-box',\r\n TOGGLE_CHANGE_COLOR_BOX: 'toggle-change-color-box',\r\n TOGGLE_TURN_INTO_BOX: 'toggle-turn-into-box',\r\n TOGGLE_INPUT_LINK_BOX: 'toggle-input-link-box',\r\n INPUT_LINK_URL: 'input-link-url',\r\n TOGGLE_ENCLOSE_SELECTED_TEXT_TO: 'toggle-enclose-selected-text-to',\r\n },\r\n\r\n};\r\n\r\nconst operationMap = {\r\n [OPERATIONS.BLOCK.CREATE_LIST_ELEMENT]: _block_operation__WEBPACK_IMPORTED_MODULE_0__.createListItem,\r\n [OPERATIONS.BLOCK.CREATE_NEW_ELEMENT]: _block_operation__WEBPACK_IMPORTED_MODULE_0__.createNewElement,\r\n [OPERATIONS.BLOCK.DELETE_DRAGGABLE_BLOCK]: _block_operation__WEBPACK_IMPORTED_MODULE_0__.deleteDraggableParentBlock,\r\n [OPERATIONS.BLOCK.DELETE_AND_FOCUS_ON_NEXT]: _block_operation__WEBPACK_IMPORTED_MODULE_0__.deleteAndFocusOnNext,\r\n [OPERATIONS.BLOCK.DELETE_AND_FOCUS_ON_PREVIOUS]: _block_operation__WEBPACK_IMPORTED_MODULE_0__.deleteAndFocusOnPrevious,\r\n [OPERATIONS.BLOCK.DUPLICATE_SELECTED_BLOCK]: _block_operation__WEBPACK_IMPORTED_MODULE_0__.duplicateSelectedBlock,\r\n [OPERATIONS.BLOCK.TRANSFORM_BLOCK]: _block_operation__WEBPACK_IMPORTED_MODULE_0__.transformBlock,\r\n [OPERATIONS.BLOCK.MOVE_UP_BLOCK]: _block_operation__WEBPACK_IMPORTED_MODULE_0__.moveUpBlock,\r\n [OPERATIONS.BLOCK.MOVE_DOWN_BLOCK]: _block_operation__WEBPACK_IMPORTED_MODULE_0__.moveDownBlock,\r\n [OPERATIONS.BLOCK_OPTIONS.SHOW_BLOCK_OPTIONS]: _components_quick_menu_quick_insert_menu__WEBPACK_IMPORTED_MODULE_1__.showMainBlockOptions,\r\n [OPERATIONS.BLOCK_OPTIONS.HIDE_CLEAR_BLOCK_OPTIONS]: _components_quick_menu_quick_insert_menu__WEBPACK_IMPORTED_MODULE_1__.hideAndClearBlockOptions,\r\n [OPERATIONS.BLOCK_OPTIONS.MOVE_FAKE_FOCUS_TO_NEXT_OPTION]: _components_quick_menu_QuickMenu__WEBPACK_IMPORTED_MODULE_3__[\"default\"].moveTheFakeFocusToTheNextMenuItem, // blockOptionOperation.moveTheFakeFocusToTheNextBlockOption,\r\n [OPERATIONS.BLOCK_OPTIONS.MOVE_FAKE_FOCUS_TO_PREVIOUS_OPTION]: _components_quick_menu_quick_insert_menu__WEBPACK_IMPORTED_MODULE_1__.moveTheFakeFocusToPreviousBlockOption,\r\n [OPERATIONS.BLOCK_OPTIONS.APPLY_SELECTED_BLOCK_TYPE]: _components_quick_menu_quick_insert_menu__WEBPACK_IMPORTED_MODULE_1__.applySelectedBlockType,\r\n [OPERATIONS.BLOCK_OPTIONS.FILTER_CONCAT]: _components_quick_menu_quick_insert_menu__WEBPACK_IMPORTED_MODULE_1__.filterContact,\r\n [OPERATIONS.BLOCK_OPTIONS.FILTER_REMOVE_LAST]: _components_quick_menu_quick_insert_menu__WEBPACK_IMPORTED_MODULE_1__.filterRemoveLast,\r\n [OPERATIONS.FORMATTING_BAR.SHOW_TEXT_FORMATTING_BAR]: _components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_4__.showTextFormattingBar,\r\n [OPERATIONS.FORMATTING_BAR.HIDE_TEXT_FORMATTING_BAR]: _components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_4__.hideTextFormattingBar,\r\n [OPERATIONS.FORMATTING_BAR.TOGGLE_MORE_OPTIONS_BOX]: _components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_4__.toggleMoreOptionsBox,\r\n [OPERATIONS.FORMATTING_BAR.TOGGLE_CHANGE_COLOR_BOX]: _components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_4__.toggleChangeColorBox,\r\n [OPERATIONS.FORMATTING_BAR.TOGGLE_TURN_INTO_BOX]: _components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_4__.toggleTurnIntoBox,\r\n [OPERATIONS.FORMATTING_BAR.TOGGLE_INPUT_LINK_BOX]: _components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_4__.toggleInputLinkBox,\r\n [OPERATIONS.FORMATTING_BAR.INPUT_LINK_URL]: _components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_4__.inputLinkUrl,\r\n [OPERATIONS.FORMATTING_BAR.TOGGLE_ENCLOSE_SELECTED_TEXT_TO]: _components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_4__.toggleEncloseSelectedTextTo,\r\n [OPERATIONS.SHOW_TURN_INTO_BOX]: _block_operation__WEBPACK_IMPORTED_MODULE_0__.transformBlock,\r\n [OPERATIONS.SHOW_COLOR_BOX]: _block_operation__WEBPACK_IMPORTED_MODULE_0__.transformBlock,\r\n [OPERATIONS.SHOW_MORE_OPTIONS_BOX]: _block_operation__WEBPACK_IMPORTED_MODULE_0__.transformBlock\r\n};\r\n\r\nfunction getBlockOperationFunction(blockOperation) {\r\n const operationFunction = operationMap[blockOperation];\r\n if (!operationFunction) {\r\n throw new Error('Operation Not Found Exception');\r\n }\r\n return operationFunction;\r\n}\n\n//# sourceURL=webpack://johannes/./src/commands/command-factory.js?"); /***/ }), @@ -173,17 +184,6 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac /***/ }), -/***/ "./src/index.js": -/*!**********************!*\ - !*** ./src/index.js ***! - \**********************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _triggers_load_events_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./triggers/load-events.js */ \"./src/triggers/load-events.js\");\n/* harmony import */ var _triggers_keypress_events_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./triggers/keypress-events.js */ \"./src/triggers/keypress-events.js\");\n/* harmony import */ var _triggers_click_events_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./triggers/click-events.js */ \"./src/triggers/click-events.js\");\n/* harmony import */ var _block_operation_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./block-operation.js */ \"./src/block-operation.js\");\n/* harmony import */ var _drag_and_drop_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./drag-and-drop.js */ \"./src/drag-and-drop.js\");\n/* harmony import */ var _drag_and_drop_js__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_drag_and_drop_js__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var _switch_block_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./switch-block.js */ \"./src/switch-block.js\");\n/* harmony import */ var _switch_block_js__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_switch_block_js__WEBPACK_IMPORTED_MODULE_5__);\n/* harmony import */ var _keyboard_navigation_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./keyboard-navigation.js */ \"./src/keyboard-navigation.js\");\n/* harmony import */ var _keyboard_navigation_js__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(_keyboard_navigation_js__WEBPACK_IMPORTED_MODULE_6__);\n/* harmony import */ var _text_blocks_from_newlines_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./text-blocks-from-newlines.js */ \"./src/text-blocks-from-newlines.js\");\n/* harmony import */ var _memento_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./memento.js */ \"./src/memento.js\");\n/* harmony import */ var _memento_js__WEBPACK_IMPORTED_MODULE_8___default = /*#__PURE__*/__webpack_require__.n(_memento_js__WEBPACK_IMPORTED_MODULE_8__);\n/* harmony import */ var _style_css__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./style.css */ \"./src/style.css\");\n// listen events in keyboard, mouse and document load\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n// default style\r\n\n\n//# sourceURL=webpack://johannes/./src/index.js?"); - -/***/ }), - /***/ "./src/j-anchor.js": /*!*************************!*\ !*** ./src/j-anchor.js ***! @@ -276,7 +276,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _com /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../commands/command-factory */ \"./src/commands/command-factory.js\");\n/* harmony import */ var _components_quick_menu_quick_insert_menu__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../components/quick-menu/quick-insert-menu */ \"./src/components/quick-menu/quick-insert-menu.js\");\n/* harmony import */ var _helper__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../helper */ \"./src/helper.js\");\n/* harmony import */ var _components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../components/text-formatting-bar/text-formatting-bar */ \"./src/components/text-formatting-bar/text-formatting-bar.js\");\n//The start point for key press events\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n// Block operations is operations related to the block it self. Create a block, delete a block, change the block type, etc...\r\ndocument.addEventListener('DOMContentLoaded', function () {\r\n\r\n\r\n document.addEventListener('keydown', function (event) {\r\n\r\n if ((0,_helper__WEBPACK_IMPORTED_MODULE_2__.isTriggable)(event) && !(0,_components_quick_menu_quick_insert_menu__WEBPACK_IMPORTED_MODULE_1__.isShowingBlockOptions)()) {\r\n\r\n if (event.key === 'Enter' && !(0,_components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_3__.isShowingTextFormattingSelectableDependentBox)() && !(0,_components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_3__.isShowingTextFormattingBar)() && !event.ctrlKey && !event.shiftKey && !event.altKey) {\r\n\r\n event.preventDefault();\r\n event.stopPropagation();\r\n\r\n //TODO: pass the event not event.target/it`s more simple to deal with event when create a click eventListener\r\n const command = _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.createCommand(_commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.OPERATIONS.BLOCK.CREATE_NEW_ELEMENT, [event]);\r\n command.execute();\r\n\r\n } else if (event.key === 'Backspace' && isActiveContentBlank(event) && !event.ctrlKey && !event.shiftKey && !event.altKey) {\r\n\r\n event.preventDefault();\r\n\r\n const command = _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.createCommand(_commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.OPERATIONS.BLOCK.DELETE_AND_FOCUS_ON_PREVIOUS);\r\n command.execute();\r\n\r\n } else if (event.key === 'Delete' && isActiveContentBlank() && !event.ctrlKey && !event.shiftKey && !event.altKey) {\r\n\r\n event.preventDefault();\r\n\r\n const command = _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.createCommand(_commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.OPERATIONS.BLOCK.DELETE_AND_FOCUS_ON_NEXT);\r\n command.execute();\r\n\r\n }\r\n }\r\n });\r\n\r\n document.addEventListener('keyup', function (event) {\r\n\r\n if ((0,_helper__WEBPACK_IMPORTED_MODULE_2__.isTriggable)(event) && !(0,_components_quick_menu_quick_insert_menu__WEBPACK_IMPORTED_MODULE_1__.isShowingBlockOptions)()) {\r\n if (event.key === 'Escape' && isActiveContentBlank() && !event.ctrlKey && !event.shiftKey && !event.altKey) {\r\n\r\n //TODO: write the code to select the all text\r\n\r\n }\r\n }\r\n });\r\n});\r\n\r\n// Block options operations is operations related to the Block Options. Show the block options, hide the block options, filter, ...\r\ndocument.addEventListener('DOMContentLoaded', function () {\r\n\r\n document.addEventListener('keydown', function (event) {\r\n\r\n // if (isTriggable(event) && !isShowingBlockOptions()) {\r\n\r\n // if (event.key === '/' && !event.ctrlKey && !event.shiftKey && !event.altKey) {\r\n\r\n // const command = commandFactory.createCommand(commandFactory.OPERATIONS.BLOCK_OPTIONS.SHOW_BLOCK_OPTIONS);\r\n // command.execute();\r\n // }\r\n // }\r\n\r\n if ((0,_components_quick_menu_quick_insert_menu__WEBPACK_IMPORTED_MODULE_1__.isShowingBlockOptions)()) {\r\n\r\n if (event.key === 'Escape' && !event.ctrlKey && !event.shiftKey && !event.altKey) {\r\n\r\n event.preventDefault();\r\n\r\n const elementToFocusAfterHide = event.target;\r\n\r\n //TODO: pass the event not event.target/it`s more simple to deal with event when create a click eventListener\r\n const command = _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.createCommand(_commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.OPERATIONS.BLOCK_OPTIONS.HIDE_CLEAR_BLOCK_OPTIONS, [elementToFocusAfterHide]);\r\n command.execute();\r\n\r\n } else if (event.key === 'ArrowDown' && !event.ctrlKey && !event.shiftKey && !event.altKey) {\r\n\r\n event.preventDefault();\r\n\r\n const command = _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.createCommand(_commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.OPERATIONS.BLOCK_OPTIONS.MOVE_FAKE_FOCUS_TO_NEXT_OPTION);\r\n command.execute();\r\n\r\n } else if (event.key === 'ArrowUp' && !event.ctrlKey && !event.shiftKey && !event.altKey) {\r\n\r\n event.preventDefault();\r\n\r\n const command = _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.createCommand(_commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.OPERATIONS.BLOCK_OPTIONS.MOVE_FAKE_FOCUS_TO_PREVIOUS_OPTION);\r\n command.execute();\r\n\r\n } else if (event.key === 'Enter' && !event.ctrlKey && !event.shiftKey && !event.altKey) {\r\n\r\n event.preventDefault();\r\n event.stopPropagation();\r\n\r\n const command = _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.createCommand(_commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.OPERATIONS.BLOCK_OPTIONS.APPLY_SELECTED_BLOCK_TYPE, [event]);\r\n command.execute();\r\n\r\n } else if (/^[a-z0-9]$/i.test(event.key) && !event.ctrlKey && !event.shiftKey && !event.altKey) {\r\n\r\n const command = _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.createCommand(_commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.OPERATIONS.BLOCK_OPTIONS.FILTER_CONCAT, [event]);\r\n command.execute();\r\n\r\n } else if (event.key === 'Backspace') {\r\n\r\n const command = _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.createCommand(_commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.OPERATIONS.BLOCK_OPTIONS.FILTER_REMOVE_LAST);\r\n command.execute();\r\n }\r\n }\r\n\r\n\r\n if ((0,_components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_3__.isShowingTextFormattingSelectableDependentBox)()) {\r\n\r\n if (event.key === 'Escape' && !event.ctrlKey && !event.shiftKey && !event.altKey) {\r\n\r\n event.preventDefault();\r\n\r\n const command = _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.createCommand(_commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.OPERATIONS.BLOCK_OPTIONS.HIDE_TEXT_FORMATTING_BAR, [event]);\r\n command.execute();\r\n\r\n } else if (event.key === 'ArrowDown' && !event.ctrlKey && !event.shiftKey && !event.altKey) {\r\n\r\n event.preventDefault();\r\n\r\n const command = _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.createCommand(_commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.OPERATIONS.BLOCK_OPTIONS.MOVE_FAKE_FOCUS_TO_NEXT_OPTION);\r\n command.execute();\r\n\r\n } else if (event.key === 'ArrowUp' && !event.ctrlKey && !event.shiftKey && !event.altKey) {\r\n\r\n event.preventDefault();\r\n\r\n const command = _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.createCommand(_commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.OPERATIONS.BLOCK_OPTIONS.MOVE_FAKE_FOCUS_TO_PREVIOUS_OPTION);\r\n command.execute();\r\n\r\n } else if (event.key === 'Enter' && !event.ctrlKey && !event.shiftKey && !event.altKey) {\r\n\r\n event.preventDefault();\r\n event.stopPropagation();\r\n\r\n const command = _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.createCommand(_commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.OPERATIONS.BLOCK_OPTIONS.APPLY_SELECTED_BLOCK_TYPE, [event]);\r\n command.execute();\r\n\r\n }\r\n }\r\n });\r\n});\r\n\r\n\r\n// Text formatting bar operations is operations related to text presentation, color, show or hide text formatting dependent boxes,...\r\ndocument.addEventListener('keyup', function (event) {\r\n if (event.key === 'Shift' && (0,_helper__WEBPACK_IMPORTED_MODULE_2__.isTriggable)(event)) {\r\n\r\n setTimeout(() => {\r\n if (window.getSelection().toString().trim() !== '') {\r\n const command = _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.createCommand(_commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.OPERATIONS.FORMATTING_BAR.SHOW_TEXT_FORMATTING_BAR, [event]);\r\n command.execute();\r\n }\r\n }, 10);\r\n\r\n }\r\n});\r\n\r\ndocument.addEventListener('keydown', function (event) {\r\n if (event.ctrlKey && event.key.toLowerCase() === 'a' && (0,_helper__WEBPACK_IMPORTED_MODULE_2__.isTriggable)(event)) {\r\n\r\n setTimeout(() => {\r\n if (window.getSelection().toString().trim() !== '') {\r\n const command = _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.createCommand(_commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.OPERATIONS.FORMATTING_BAR.SHOW_TEXT_FORMATTING_BAR, [event]);\r\n command.execute();\r\n }\r\n }, 10);\r\n\r\n } else if (event.key === 'Escape' && (0,_components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_3__.canHideTextFormattingBar)() && (0,_components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_3__.isShowingTextFormattingBar)()) {\r\n\r\n const command = _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.createCommand(_commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.OPERATIONS.FORMATTING_BAR.HIDE_TEXT_FORMATTING_BAR, [event]);\r\n command.execute();\r\n }\r\n});\r\n\r\n\r\n\r\nfunction isActiveContentBlank() {\r\n return document.activeElement.textContent.trim() === '';\r\n}\r\n\r\n\r\n// Listen a input link\r\ndocument.addEventListener('DOMContentLoaded', function () {\r\n linkBoxInput.addEventListener('keydown', function (event) {\r\n if (event.key === 'Enter') {\r\n\r\n event.preventDefault();\r\n event.stopPropagation();\r\n\r\n const command = _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.createCommand(_commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.OPERATIONS.FORMATTING_BAR.INPUT_LINK_URL);\r\n command.execute();\r\n }\r\n });\r\n});\r\n\r\n\r\n// Lock left and right key when is showing the dependent box\r\ndocument.addEventListener('keydown', function (event) {\r\n if ((0,_components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_3__.isShowingTextFormattingSelectableDependentBox)() &&\r\n (event.key === 'ArrowLeft' || event.key === 'ArrowRight')) {\r\n\r\n event.preventDefault();\r\n event.stopPropagation();\r\n }\r\n});\r\n\r\n\r\ndocument.addEventListener('keyup', function (event) {\r\n if ((0,_components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_3__.isShowingTextFormattingBar)() && (0,_components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_3__.canHideTextFormattingBar)() && !(0,_components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_3__.isShowingTextFormattingSelectableDependentBox)() &&\r\n (event.key === 'ArrowLeft' || event.key === 'ArrowRight' || event.key === 'ArrowUp' || event.key === 'ArrowDown')) {\r\n\r\n setTimeout(() => {\r\n if (window.getSelection().toString().trim() == '') {\r\n const command = _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.createCommand(_commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.OPERATIONS.FORMATTING_BAR.HIDE_TEXT_FORMATTING_BAR, [event]);\r\n command.execute();\r\n }\r\n }, 10);\r\n }\r\n});\n\n//# sourceURL=webpack://johannes/./src/triggers/keypress-events.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../commands/command-factory */ \"./src/commands/command-factory.js\");\n/* harmony import */ var _components_quick_menu_quick_insert_menu__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../components/quick-menu/quick-insert-menu */ \"./src/components/quick-menu/quick-insert-menu.js\");\n/* harmony import */ var _helper__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../helper */ \"./src/helper.js\");\n/* harmony import */ var _components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../components/text-formatting-bar/text-formatting-bar */ \"./src/components/text-formatting-bar/text-formatting-bar.js\");\n//The start point for key press events\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n// Block operations is operations related to the block it self. Create a block, delete a block, change the block type, etc...\r\ndocument.addEventListener('DOMContentLoaded', function () {\r\n\r\n\r\n document.addEventListener('keydown', function (event) {\r\n\r\n if ((0,_helper__WEBPACK_IMPORTED_MODULE_2__.isTriggable)(event) && !(0,_components_quick_menu_quick_insert_menu__WEBPACK_IMPORTED_MODULE_1__.isShowingBlockOptions)()) {\r\n\r\n if (event.key === 'Enter' && !(0,_components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_3__.isShowingTextFormattingSelectableDependentBox)() && !(0,_components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_3__.isShowingTextFormattingBar)() && !event.ctrlKey && !event.shiftKey && !event.altKey) {\r\n\r\n event.preventDefault();\r\n event.stopPropagation();\r\n\r\n //TODO: pass the event not event.target/it`s more simple to deal with event when create a click eventListener\r\n const command = _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.createCommand(_commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.OPERATIONS.BLOCK.CREATE_NEW_ELEMENT, [event]);\r\n command.execute();\r\n\r\n } else if (event.key === 'Backspace' && isActiveContentBlank(event) && !event.ctrlKey && !event.shiftKey && !event.altKey) {\r\n\r\n event.preventDefault();\r\n\r\n const command = _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.createCommand(_commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.OPERATIONS.BLOCK.DELETE_AND_FOCUS_ON_PREVIOUS);\r\n command.execute();\r\n\r\n } else if (event.key === 'Delete' && isActiveContentBlank() && !event.ctrlKey && !event.shiftKey && !event.altKey) {\r\n\r\n event.preventDefault();\r\n\r\n const command = _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.createCommand(_commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.OPERATIONS.BLOCK.DELETE_AND_FOCUS_ON_NEXT);\r\n command.execute();\r\n\r\n }\r\n }\r\n });\r\n\r\n document.addEventListener('keyup', function (event) {\r\n\r\n if ((0,_helper__WEBPACK_IMPORTED_MODULE_2__.isTriggable)(event) && !(0,_components_quick_menu_quick_insert_menu__WEBPACK_IMPORTED_MODULE_1__.isShowingBlockOptions)()) {\r\n if (event.key === 'Escape' && isActiveContentBlank() && !event.ctrlKey && !event.shiftKey && !event.altKey) {\r\n\r\n //TODO: write the code to select the all text\r\n\r\n }\r\n }\r\n });\r\n});\r\n\r\n// Block options operations is operations related to the Block Options. Show the block options, hide the block options, filter, ...\r\ndocument.addEventListener('DOMContentLoaded', function () {\r\n\r\n document.addEventListener('keydown', function (event) {\r\n\r\n if ((0,_helper__WEBPACK_IMPORTED_MODULE_2__.isTriggable)(event) && !(0,_components_quick_menu_quick_insert_menu__WEBPACK_IMPORTED_MODULE_1__.isShowingBlockOptions)()) {\r\n\r\n if (event.key === '/' && !event.ctrlKey && !event.shiftKey && !event.altKey) {\r\n\r\n const command = _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.createCommand(_commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.OPERATIONS.BLOCK_OPTIONS.SHOW_BLOCK_OPTIONS);\r\n command.execute();\r\n }\r\n }\r\n\r\n if ((0,_components_quick_menu_quick_insert_menu__WEBPACK_IMPORTED_MODULE_1__.isShowingBlockOptions)()) {\r\n\r\n if (event.key === 'Escape' && !event.ctrlKey && !event.shiftKey && !event.altKey) {\r\n\r\n event.preventDefault();\r\n\r\n const elementToFocusAfterHide = event.target;\r\n\r\n //TODO: pass the event not event.target/it`s more simple to deal with event when create a click eventListener\r\n const command = _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.createCommand(_commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.OPERATIONS.BLOCK_OPTIONS.HIDE_CLEAR_BLOCK_OPTIONS, [elementToFocusAfterHide]);\r\n command.execute();\r\n\r\n } else if (event.key === 'ArrowDown' && !event.ctrlKey && !event.shiftKey && !event.altKey) {\r\n\r\n event.preventDefault();\r\n\r\n const command = _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.createCommand(_commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.OPERATIONS.BLOCK_OPTIONS.MOVE_FAKE_FOCUS_TO_NEXT_OPTION);\r\n command.execute();\r\n\r\n } else if (event.key === 'ArrowUp' && !event.ctrlKey && !event.shiftKey && !event.altKey) {\r\n\r\n event.preventDefault();\r\n\r\n const command = _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.createCommand(_commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.OPERATIONS.BLOCK_OPTIONS.MOVE_FAKE_FOCUS_TO_PREVIOUS_OPTION);\r\n command.execute();\r\n\r\n } else if (event.key === 'Enter' && !event.ctrlKey && !event.shiftKey && !event.altKey) {\r\n\r\n event.preventDefault();\r\n event.stopPropagation();\r\n\r\n const command = _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.createCommand(_commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.OPERATIONS.BLOCK_OPTIONS.APPLY_SELECTED_BLOCK_TYPE, [event]);\r\n command.execute();\r\n\r\n } else if (/^[a-z0-9]$/i.test(event.key) && !event.ctrlKey && !event.shiftKey && !event.altKey) {\r\n\r\n const command = _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.createCommand(_commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.OPERATIONS.BLOCK_OPTIONS.FILTER_CONCAT, [event]);\r\n command.execute();\r\n\r\n } else if (event.key === 'Backspace') {\r\n\r\n const command = _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.createCommand(_commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.OPERATIONS.BLOCK_OPTIONS.FILTER_REMOVE_LAST);\r\n command.execute();\r\n }\r\n }\r\n\r\n\r\n if ((0,_components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_3__.isShowingTextFormattingSelectableDependentBox)()) {\r\n\r\n if (event.key === 'Escape' && !event.ctrlKey && !event.shiftKey && !event.altKey) {\r\n\r\n event.preventDefault();\r\n\r\n const command = _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.createCommand(_commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.OPERATIONS.BLOCK_OPTIONS.HIDE_TEXT_FORMATTING_BAR, [event]);\r\n command.execute();\r\n\r\n } else if (event.key === 'ArrowDown' && !event.ctrlKey && !event.shiftKey && !event.altKey) {\r\n\r\n event.preventDefault();\r\n\r\n const command = _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.createCommand(_commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.OPERATIONS.BLOCK_OPTIONS.MOVE_FAKE_FOCUS_TO_NEXT_OPTION);\r\n command.execute();\r\n\r\n } else if (event.key === 'ArrowUp' && !event.ctrlKey && !event.shiftKey && !event.altKey) {\r\n\r\n event.preventDefault();\r\n\r\n const command = _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.createCommand(_commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.OPERATIONS.BLOCK_OPTIONS.MOVE_FAKE_FOCUS_TO_PREVIOUS_OPTION);\r\n command.execute();\r\n\r\n } else if (event.key === 'Enter' && !event.ctrlKey && !event.shiftKey && !event.altKey) {\r\n\r\n event.preventDefault();\r\n event.stopPropagation();\r\n\r\n const command = _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.createCommand(_commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.OPERATIONS.BLOCK_OPTIONS.APPLY_SELECTED_BLOCK_TYPE, [event]);\r\n command.execute();\r\n\r\n }\r\n }\r\n });\r\n});\r\n\r\n\r\n// Text formatting bar operations is operations related to text presentation, color, show or hide text formatting dependent boxes,...\r\ndocument.addEventListener('keyup', function (event) {\r\n if (event.key === 'Shift' && (0,_helper__WEBPACK_IMPORTED_MODULE_2__.isTriggable)(event)) {\r\n\r\n setTimeout(() => {\r\n if (window.getSelection().toString().trim() !== '') {\r\n const command = _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.createCommand(_commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.OPERATIONS.FORMATTING_BAR.SHOW_TEXT_FORMATTING_BAR, [event]);\r\n command.execute();\r\n }\r\n }, 10);\r\n\r\n }\r\n});\r\n\r\ndocument.addEventListener('keydown', function (event) {\r\n if (event.ctrlKey && event.key.toLowerCase() === 'a' && (0,_helper__WEBPACK_IMPORTED_MODULE_2__.isTriggable)(event)) {\r\n\r\n setTimeout(() => {\r\n if (window.getSelection().toString().trim() !== '') {\r\n const command = _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.createCommand(_commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.OPERATIONS.FORMATTING_BAR.SHOW_TEXT_FORMATTING_BAR, [event]);\r\n command.execute();\r\n }\r\n }, 10);\r\n\r\n } else if (event.key === 'Escape' && (0,_components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_3__.canHideTextFormattingBar)() && (0,_components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_3__.isShowingTextFormattingBar)()) {\r\n\r\n const command = _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.createCommand(_commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.OPERATIONS.FORMATTING_BAR.HIDE_TEXT_FORMATTING_BAR, [event]);\r\n command.execute();\r\n }\r\n});\r\n\r\n\r\n\r\nfunction isActiveContentBlank() {\r\n return document.activeElement.textContent.trim() === '';\r\n}\r\n\r\n\r\n// Listen a input link\r\ndocument.addEventListener('DOMContentLoaded', function () {\r\n linkBoxInput.addEventListener('keydown', function (event) {\r\n if (event.key === 'Enter') {\r\n\r\n event.preventDefault();\r\n event.stopPropagation();\r\n\r\n const command = _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.createCommand(_commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.OPERATIONS.FORMATTING_BAR.INPUT_LINK_URL);\r\n command.execute();\r\n }\r\n });\r\n});\r\n\r\n\r\n// Lock left and right key when is showing the dependent box\r\ndocument.addEventListener('keydown', function (event) {\r\n if ((0,_components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_3__.isShowingTextFormattingSelectableDependentBox)() &&\r\n (event.key === 'ArrowLeft' || event.key === 'ArrowRight')) {\r\n\r\n event.preventDefault();\r\n event.stopPropagation();\r\n }\r\n});\r\n\r\n\r\ndocument.addEventListener('keyup', function (event) {\r\n if ((0,_components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_3__.isShowingTextFormattingBar)() && (0,_components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_3__.canHideTextFormattingBar)() && !(0,_components_text_formatting_bar_text_formatting_bar__WEBPACK_IMPORTED_MODULE_3__.isShowingTextFormattingSelectableDependentBox)() &&\r\n (event.key === 'ArrowLeft' || event.key === 'ArrowRight' || event.key === 'ArrowUp' || event.key === 'ArrowDown')) {\r\n\r\n setTimeout(() => {\r\n if (window.getSelection().toString().trim() == '') {\r\n const command = _commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.createCommand(_commands_command_factory__WEBPACK_IMPORTED_MODULE_0__.OPERATIONS.FORMATTING_BAR.HIDE_TEXT_FORMATTING_BAR, [event]);\r\n command.execute();\r\n }\r\n }, 10);\r\n }\r\n});\n\n//# sourceURL=webpack://johannes/./src/triggers/keypress-events.js?"); /***/ }), @@ -287,7 +287,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _com /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _components_quick_menu_QuickMenu__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../components/quick-menu/QuickMenu */ \"./src/components/quick-menu/QuickMenu.js\");\n//TODO use commands\r\n\r\n\r\n//Focus on P when load\r\ndocument.addEventListener('DOMContentLoaded', function () {\r\n const editor = document.querySelector('.johannes-editor');\r\n\r\n if (editor) {\r\n let blocks = editor.querySelectorAll('.draggable-block');\r\n\r\n if (blocks.length == 1) {\r\n\r\n const p = blocks[0].querySelector('.johannes-content-element');\r\n if (p.innerText == '') {\r\n p.focus();\r\n }\r\n }\r\n }\r\n});\r\n\r\n// Clear text when paste\r\ndocument.addEventListener('DOMContentLoaded', function () {\r\n\r\n const editor = document.querySelector('.johannes-editor');\r\n\r\n if (editor) {\r\n document.addEventListener('paste', function (e) {\r\n if (e.target.getAttribute('contenteditable') === 'true') {\r\n e.preventDefault();\r\n const text = (e.clipboardData || window.clipboardData).getData('text/plain');\r\n insertTextAtCursor(text);\r\n }\r\n }, true);\r\n\r\n function insertTextAtCursor(text) {\r\n const sel = window.getSelection();\r\n if (sel.rangeCount > 0) {\r\n const range = sel.getRangeAt(0);\r\n range.deleteContents();\r\n\r\n const textNode = document.createTextNode(text);\r\n range.insertNode(textNode);\r\n\r\n range.setStartAfter(textNode);\r\n range.setEndAfter(textNode);\r\n sel.removeAllRanges();\r\n sel.addRange(range);\r\n }\r\n }\r\n }\r\n});\r\n\r\n\r\ndocument.addEventListener('DOMContentLoaded', function () {\r\n\r\n\r\n johannesEditor.appendChild(_components_quick_menu_QuickMenu__WEBPACK_IMPORTED_MODULE_0__[\"default\"].getMenuElement());\r\n});\n\n//# sourceURL=webpack://johannes/./src/triggers/load-events.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _components_quick_menu_QuickMenu__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../components/quick-menu/QuickMenu */ \"./src/components/quick-menu/QuickMenu.ts\");\n//TODO use commands\r\n\r\n\r\n//Focus on P when load\r\ndocument.addEventListener('DOMContentLoaded', function () {\r\n const editor = document.querySelector('.johannes-editor');\r\n\r\n if (editor) {\r\n let blocks = editor.querySelectorAll('.draggable-block');\r\n\r\n if (blocks.length == 1) {\r\n\r\n const p = blocks[0].querySelector('.johannes-content-element');\r\n if (p.innerText == '') {\r\n p.focus();\r\n }\r\n }\r\n }\r\n});\r\n\r\n// Clear text when paste\r\ndocument.addEventListener('DOMContentLoaded', function () {\r\n\r\n const editor = document.querySelector('.johannes-editor');\r\n\r\n if (editor) {\r\n document.addEventListener('paste', function (e) {\r\n if (e.target.getAttribute('contenteditable') === 'true') {\r\n e.preventDefault();\r\n const text = (e.clipboardData || window.clipboardData).getData('text/plain');\r\n insertTextAtCursor(text);\r\n }\r\n }, true);\r\n\r\n function insertTextAtCursor(text) {\r\n const sel = window.getSelection();\r\n if (sel.rangeCount > 0) {\r\n const range = sel.getRangeAt(0);\r\n range.deleteContents();\r\n\r\n const textNode = document.createTextNode(text);\r\n range.insertNode(textNode);\r\n\r\n range.setStartAfter(textNode);\r\n range.setEndAfter(textNode);\r\n sel.removeAllRanges();\r\n sel.addRange(range);\r\n }\r\n }\r\n }\r\n});\r\n\r\n\r\ndocument.addEventListener('DOMContentLoaded', function () {\r\n\r\n let instance = _components_quick_menu_QuickMenu__WEBPACK_IMPORTED_MODULE_0__[\"default\"].getInstance();\r\n\r\n johannesEditor.appendChild(instance.getMenuElement());\r\n});\n\n//# sourceURL=webpack://johannes/./src/triggers/load-events.js?"); /***/ }) @@ -363,7 +363,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _com /******/ // startup /******/ // Load entry module and return exports /******/ // This entry module can't be inlined because the eval devtool is used. -/******/ var __webpack_exports__ = __webpack_require__("./src/index.js"); +/******/ var __webpack_exports__ = __webpack_require__("./src/index.ts"); /******/ /******/ })() ; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index aabcefe..770568a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,8 @@ "copyfiles": "^2.4.1", "css-loader": "^7.1.2", "mini-css-extract-plugin": "^2.9.0", + "ts-loader": "^9.5.1", + "typescript": "^5.5.3", "webpack": "^5.92.0", "webpack-cli": "^5.1.4" } @@ -451,6 +453,18 @@ "concat-map": "0.0.1" } }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/browserslist": { "version": "4.23.1", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.1.tgz", @@ -509,6 +523,34 @@ } ] }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/chrome-trace-event": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", @@ -790,6 +832,18 @@ "node": ">= 4.9.1" } }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -968,6 +1022,15 @@ "node": ">=8" } }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", @@ -1063,6 +1126,19 @@ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true }, + "node_modules/micromatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "dev": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -1305,6 +1381,18 @@ "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", "dev": true }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/pkg-dir": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", @@ -1813,6 +1901,60 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-loader": { + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz", + "integrity": "sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4", + "source-map": "^0.7.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "*", + "webpack": "^5.0.0" + } + }, + "node_modules/ts-loader/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/typescript": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", + "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", diff --git a/package.json b/package.json index 40a18c8..f67a604 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,8 @@ "copyfiles": "^2.4.1", "css-loader": "^7.1.2", "mini-css-extract-plugin": "^2.9.0", + "ts-loader": "^9.5.1", + "typescript": "^5.5.3", "webpack": "^5.92.0", "webpack-cli": "^5.1.4" } diff --git a/src/commands/command-factory.js b/src/commands/command-factory.js index 20101e5..1e6d045 100644 --- a/src/commands/command-factory.js +++ b/src/commands/command-factory.js @@ -18,11 +18,15 @@ class Command { } execute() { - if (this.elements !== null) { - this.operation(...this.elements); - } else { - this.operation(); - } + + setTimeout(() => { + if (this.elements !== null) { + this.operation(...this.elements); + } else { + this.operation(); + } + }, 0); + } } @@ -57,7 +61,7 @@ export const OPERATIONS = { TOGGLE_CHANGE_COLOR_BOX: 'toggle-change-color-box', TOGGLE_TURN_INTO_BOX: 'toggle-turn-into-box', TOGGLE_INPUT_LINK_BOX: 'toggle-input-link-box', - INPUT_LINK_URL: 'input-link-url', + INPUT_LINK_URL: 'input-link-url', TOGGLE_ENCLOSE_SELECTED_TEXT_TO: 'toggle-enclose-selected-text-to', }, diff --git a/src/common/JCircularLinkedList.js b/src/common/JCircularLinkedList.js deleted file mode 100644 index e4ae921..0000000 --- a/src/common/JCircularLinkedList.js +++ /dev/null @@ -1,62 +0,0 @@ -import JNode from './JNode'; - -/** - * Lista ligada que pode trabalhar com qualquer tipo de dados. - * @template T - O tipo de elementos que a lista armazenará. - */ -class JCircularLinkedList { - - constructor() { - - /** @type {T|null} */ - this.head = null; - - /** @type {T|null} */ - this.tail = null; - - this.length = 0; - } - - /** - * Append a new node with the given value to the end of the list. - * @param {T} node - The node to append. - */ - append(node) { - if (!(node instanceof JNode)) { - throw new TypeError("Expected an instance of JNode."); - } - - if (this.length === 0) { - this.head = node; - this.tail = node; - - this.head.setNext(this.tail); - this.head.setPrevious(this.tail); - } else { - node.setPrevious(this.tail); - node.setNext(this.head); - - this.tail.setNext(node); - this.head.setPrevious(node); - - this.tail = node; - } - this.length++; - } - - /** - * @returns {T|null} The first node. - */ - getFirst() { - return this.head; - } - - /** - * @returns {T|null} The last node. - */ - getLast() { - return this.tail; - } -} - -export default JCircularLinkedList; \ No newline at end of file diff --git a/src/common/JCircularLinkedList.ts b/src/common/JCircularLinkedList.ts new file mode 100644 index 0000000..fa84501 --- /dev/null +++ b/src/common/JCircularLinkedList.ts @@ -0,0 +1,46 @@ +import JNode from './JNode'; + +class JCircularLinkedList> { + + head: T | null = null; + tail: T | null = null; + + length: number = 0; + + constructor() { + + } + + append(node: T): void { + + if (!this.head || !this.tail) { + + this.head = node; + this.tail = node; + + this.head.setNext(this.tail); + this.head.setPrevious(this.tail); + + } else { + node.setPrevious(this.tail); + node.setNext(this.head); + + this.tail.setNext(node); + this.head.setPrevious(node); + + this.tail = node; + } + + this.length++; + } + + getFirst(): T | null { + return this.head; + } + + getLast(): T | null { + return this.tail; + } +} + +export default JCircularLinkedList; \ No newline at end of file diff --git a/src/common/JLinkedList.js b/src/common/JLinkedList.js deleted file mode 100644 index e1eb7b3..0000000 --- a/src/common/JLinkedList.js +++ /dev/null @@ -1,60 +0,0 @@ -import JNode from './JNode'; - -/** - * Lista ligada que pode trabalhar com qualquer tipo de dados. - * @template T - O tipo de elementos que a lista armazenará. - */ -class JLinkedList { - - constructor() { - /** @type {T|null} */ - this.head = null; - - /** @type {T|null} */ - this.tail = null; - - - this.length = 0; - } - - /** - * Append a new node with the given value to the end of the list. - * @param {*} HTMLElement - The value to store in the new node. - */ - append(node) { - - if (!(node instanceof JNode)) { - throw new TypeError("Expected an instance of JNode."); - } - - if (this.length === 0) { - this.head = node; - this.tail = node; - } else { - - this.tail.setNext(node); - node.setPrevious(this.tail); - - this.tail = node; - } - - this.length++; - - - /** - * @returns {T} node. - */ - this.getFirst = () => { - return this.head; - } - - /** - * @returns {T} node. - */ - this.getLast = () => { - return this.tail; - } - } -} - -export default JLinkedList; \ No newline at end of file diff --git a/src/common/JLinkedList.ts b/src/common/JLinkedList.ts new file mode 100644 index 0000000..52e89d7 --- /dev/null +++ b/src/common/JLinkedList.ts @@ -0,0 +1,40 @@ +import JNode from './JNode'; + +class JLinkedList> { + + head: T | null = null; + tail: T | null = null; + + length: number = 0; + + constructor() { + + } + + append(node: T): void { + + if (!this.head || !this.tail) { + + this.head = node; + this.tail = node; + + } else { + this.tail.setNext(node); + node.setPrevious(this.tail); + + this.tail = node; + } + + this.length++; + } + + getFirst(): T | null { + return this.head; + } + + getLast(): T | null { + return this.tail; + } +} + +export default JLinkedList; \ No newline at end of file diff --git a/src/common/JNode.js b/src/common/JNode.js deleted file mode 100644 index b824424..0000000 --- a/src/common/JNode.js +++ /dev/null @@ -1,81 +0,0 @@ -/** - * @class - * Classe abstrata JNode. Deve ser estendida e o tipo do nó deve ser especificado na extensão. - * @template T O tipo de nó que estende JNode, usado para indicar os tipos de previousNode e nextNode. - * @example - * //Assume we have a class QuickMenuItem that extends JNode. -* class QuickMenuItem extends JNode { -* constructor() { -* super(); -* } -* } -* let menuList = new JLinkedList(); -* let item = new QuickMenuItem("Item 1"); -* menuList.append(item); - */ -class JNode { - - constructor() { - - if (new.target === JNode) { - throw new Error("JNode is an abstract class and cannot be instantiated directly."); - } - - /** @type {T|null} */ - this.previousNode; - - /** @type {T|null} */ - this.nextNode; - - // /** - // * The HTML element of the component in the DOM. - // * @type {HTMLElement} - // */ - // this.htmlElement = htmlElement; - - - /** - * Sets the next node. - * If the input is not a JNode, an error is thrown. - * - * @param {T} node - The node to be set as the next item. - * @throws {TypeError} Throws an error if the provided node is not an instance of JNode. - */ - this.setNext = (node) => { - if (!(node instanceof JNode)) { - throw new TypeError("Expected an instance of JNode."); - } - - this.nextNode = node; - } - - /** - * Sets the previous node. - * If the input is not a JNode, an error is thrown. - * - * @param {T} node - The node to be set as the previous item. - * @throws {TypeError} Throws an error if the provided node is not an instance of JNode. - */ - this.setPrevious = (node) => { - if (!(node instanceof JNode)) { - throw new TypeError("Expected an instance of JNode."); - } - - this.previousNode = node; - } - } -} - -export default JNode; - - -// Example usage: -// Assume we have a class QuickMenuItem that extends JNode. -// class QuickMenuItem extends JNode { -// constructor(value) { -// super(value); -// } -// } -// let menuList = new JLinkedList(); -// let item = new QuickMenuItem("Item 1"); -// menuList.append(item); \ No newline at end of file diff --git a/src/common/JNode.ts b/src/common/JNode.ts new file mode 100644 index 0000000..8e815e1 --- /dev/null +++ b/src/common/JNode.ts @@ -0,0 +1,46 @@ +/** + * @class + * Classe abstrata JNode. Deve ser estendida e o tipo do nó deve ser especificado na extensão. + * @template T O tipo de nó que estende JNode, usado para indicar os tipos de previousNode e nextNode. + * @example + * //Assume we have a class QuickMenuItem that extends JNode. +* class QuickMenuItem extends JNode { +* constructor() { +* super(); +* } +* } +* let menuList = new JLinkedList(); +* let item = new QuickMenuItem("Item 1"); +* menuList.append(item); + */ +abstract class JNode> { + + previousNode: T | null = null; + nextNode: T | null = null; + + constructor() { + + } + + setNext(node: T): void { + this.nextNode = node; + } + + setPrevious(node: T): void { + this.previousNode = node; + } +} + +export default JNode; + + +// Example usage: +// Assume we have a class QuickMenuItem that extends JNode. +// class QuickMenuItem extends JNode { +// constructor(value) { +// super(value); +// } +// } +// let menuList = new JLinkedList(); +// let item = new QuickMenuItem("Item 1"); +// menuList.append(item); \ No newline at end of file diff --git a/src/components/common/SVGIcon.ts b/src/components/common/SVGIcon.ts new file mode 100644 index 0000000..53152e4 --- /dev/null +++ b/src/components/common/SVGIcon.ts @@ -0,0 +1,24 @@ +class SVGIcon { + + htmlElement: SVGSVGElement; + + constructor(hrefUseId: string, classList = "", width = "16", height = "16") { + + this.htmlElement = document.createElementNS("http://www.w3.org/2000/svg", "svg"); + + if (classList && classList.trim() !== "") { + const classes = classList.split(','); + this.htmlElement.classList.add(...classes); + } + + let use = document.createElementNS("http://www.w3.org/2000/svg", "use"); + use.setAttributeNS("http://www.w3.org/1999/xlink", "href", `#${hrefUseId}`); + + this.htmlElement.appendChild(use); + this.htmlElement.setAttribute('width', width); + this.htmlElement.setAttribute('height', height); + this.htmlElement.setAttribute('fill', 'currentColor'); + } +} + +export default SVGIcon; \ No newline at end of file diff --git a/src/components/quick-menu/QuickMenu.js b/src/components/quick-menu/QuickMenu.js deleted file mode 100644 index 0ec4e72..0000000 --- a/src/components/quick-menu/QuickMenu.js +++ /dev/null @@ -1,206 +0,0 @@ -import QuickMenuSection from './QuickMenuSection'; -import QuickMenuItem from './QuickMenuItem'; -import JCircularLinkedList from '../../common/JCircularLinkedList'; - -class QuickMenu { - - constructor() { - - /** - * The QuickMenu element of the component in the DOM. - * @type {HTMLElement} - */ - this.htmlElement = document.createElement('div'); - this.htmlElement.id = 'blockOptionsWrapper'; - - this.isShowing = false; - - /** - * The QuickMenuItem current focused. - * @type {QuickMenuItem|null} - */ - this.currentFocusedMenuItem = null; - - /** - * The QuickMenuSection elements in a CircularLinkedList. - * @type {JCircularLinkedList} - */ - this.menuSections = new JCircularLinkedList(); - - this.htmlElement.classList.add('block-options-wrapper', 'soft-box-shadow'); - this.htmlElement.style.display = 'none'; - - const blockOptions = document.createElement('div'); - blockOptions.classList.add('block-options'); - blockOptions.style.position = 'relative'; - - this.htmlElement.appendChild(blockOptions); - - const basicBlocksSection = new QuickMenuSection(this, 'Basic blocks', 'basic-section'); - - basicBlocksSection.appendQuickMenuItem([ - new QuickMenuItem(basicBlocksSection, 'Paragraph', 'Just start writing with plain text.', 'icon-wordpress-paragraph', 'p'), - new QuickMenuItem(basicBlocksSection, 'Image', 'Just start writing with plain text.', 'icon-wordpress-paragraph', 'image'), - new QuickMenuItem(basicBlocksSection, 'Bulleted list', 'Organize items with bullet points.', 'icon-wordpress-bulleted-list', 'bulleted-list'), - new QuickMenuItem(basicBlocksSection, 'Numbered list', 'List items in a numbered format.', 'icon-wordpress-numbered-list', 'numbered-list'), - new QuickMenuItem(basicBlocksSection, 'Code', 'Insert code snippets with syntax highlighting.', 'icon-wordpress-code-mark', 'code'), - new QuickMenuItem(basicBlocksSection, 'Quote', 'Highlight text as a significant quote.', 'icon-wordpress-quote', 'quote'), - new QuickMenuItem(basicBlocksSection, 'Heading 2', 'Medium header for subsections.', 'icon-julia-head-2', 'h2'), - new QuickMenuItem(basicBlocksSection, 'Heading 3', 'Small header for detailed sections.', 'icon-julia-head-2', 'h3'), - new QuickMenuItem(basicBlocksSection, 'Separator', 'Visually divide blocks.', 'icon-wordpress-separator', 'separator') - ]); - - this.menuSections.append(basicBlocksSection); - blockOptions.appendChild(basicBlocksSection.htmlElement); - - - const headingBlocksSection = new QuickMenuSection(this, 'Heading', 'heading-section'); - - headingBlocksSection.appendQuickMenuItem([ - new QuickMenuItem(headingBlocksSection, 'Heading 1', 'Large header to organize content.', 'icon-julia-head-1', 'h1'), - new QuickMenuItem(headingBlocksSection, 'Heading 2', 'Medium header for subsections.', 'icon-julia-head-2', 'h2'), - new QuickMenuItem(headingBlocksSection, 'Heading 3', 'Small header for detailed sections.', 'icon-julia-head-3', 'h3'), - new QuickMenuItem(headingBlocksSection, 'Heading 4', 'Small header for detailed sections.', 'icon-julia-head-4', 'h4'), - new QuickMenuItem(headingBlocksSection, 'Heading 5', 'Small header for detailed sections.', 'icon-julia-head-5', 'h5'), - new QuickMenuItem(headingBlocksSection, 'Heading 6', 'Small header for detailed sections.', 'icon-julia-head-6', 'h6'), - ]); - - this.menuSections.append(headingBlocksSection); - blockOptions.appendChild(headingBlocksSection.htmlElement); - - - const listBlocksSection = new QuickMenuSection(this, 'List', 'list-section'); - - listBlocksSection.appendQuickMenuItem([ - new QuickMenuItem(listBlocksSection, 'Todo list', 'Organize items with bullet points.', 'icon-material-check-list', 'todo-list'), - new QuickMenuItem(listBlocksSection, 'Bulleted list', 'Organize items with bullet points.', 'icon-wordpress-bulleted-list', 'bulleted-list'), - new QuickMenuItem(listBlocksSection, 'Numbered list', 'List items in a numbered format.', 'icon-wordpress-numbered-list', 'numbered-list') - ]); - - this.menuSections.append(listBlocksSection); - blockOptions.appendChild(listBlocksSection.htmlElement); - - - /** - * Change the current fake focus and remove the current fake focus. - * If the input is not a QuickMenuItem or contains an item that is not a QuickMenuItem, an error is thrown. - * - * @param {QuickMenuItem} menuItems The item(s) to be focused. - * @throws {TypeError} Throws an 'Expected an instance of QuickMenuItem. if item is not a QuickMenuItem. - */ - this.changeFocus = (item) => { - - if (!(item instanceof QuickMenuItem)) { - throw new TypeError("Expected an instance of QuickMenuItem."); - } - - if (this.currentFocusedMenuItem == item) { - return; - } - - if (this.currentFocusedMenuItem) { - this.currentFocusedMenuItem.removeFocus(); - } - - this.currentFocusedMenuItem = item; - this.currentFocusedMenuItem.focus(); - } - - /** - * Move the fake focus menu indication to the next element. - * If no element is currently focused the first QuickMenuItem is used. - */ - this.moveTheFakeFocusToTheNextMenuItem = () => { - - let nextItem; - - if (!this.currentFocusedMenuItem) { - - nextItem = this.menuSections.getFirst().getFirstMenuItem(); - } else { - - nextItem = this.currentFocusedMenuItem.nextNode; - - if (!nextItem) { - nextItem = this.currentFocusedMenuItem.quickMenuSectionInstance.nextNode.getFirstMenuItem(); - } - } - - this.changeFocus(nextItem); - } - - /** - * Get the QuickMenu HTML Element. - * @returns {HTMLElement} htmlElement. - */ - this.getMenuElement = () => { - return this.htmlElement; - } - - this.attachEvents = () => { - - document.addEventListener('keydown', (event) => { - if (event.key === '/' && !event.ctrlKey && !event.shiftKey && !event.altKey) { - alert('show the Quick Insert Menu'); - } - }); - } - - this.attachEvents(); - } - - - showMenu() { - - // The timeout in necessary to wait the browser process the selection before show the Block Options - setTimeout(() => { - - const realFocusedElement = document.activeElement; - const currentDraggableBlock = realFocusedElement.closest('.draggable-block'); - const firstBlockOption = getTheFirstVisibleBlockOption(); - - setRealFocusedElement(realFocusedElement); - setCurrentDraggableBlock(currentDraggableBlock); - setCurrentFakeFocusElement(firstBlockOption); - - applyVisualFakeFocus(realFocusedElement, firstBlockOption); - - - //TODO: create a clear filter - // removeDisplayNoneFromAllBlockOptions(); - - const range = document.getSelection().getRangeAt(0); - const cursorPos = range.getBoundingClientRect(); - - const remSize = parseFloat(getComputedStyle(document.documentElement).fontSize); - const menuWidth = 19 * remSize; - - let xPosition = cursorPos.right; - let yPosition = cursorPos.bottom + window.scrollY; - - const margin = remSize * 1.25; - - blockOptionsWrapper.style.display = 'block'; - - let blockWidth = blockOptionsWrapper.offsetWidth; - - - if (xPosition + blockWidth + margin > window.innerWidth) { - xPosition = cursorPos.left - menuWidth; - if (xPosition < 0) xPosition = 0; - } - - blockOptionsWrapper.style.left = `${xPosition}px`; - blockOptionsWrapper.style.top = `${yPosition}px`; - - - }, 10); - } - - - - -} - -const instance = new QuickMenu(); -export default instance; \ No newline at end of file diff --git a/src/components/quick-menu/QuickMenu.ts b/src/components/quick-menu/QuickMenu.ts new file mode 100644 index 0000000..3fc7002 --- /dev/null +++ b/src/components/quick-menu/QuickMenu.ts @@ -0,0 +1,186 @@ +import QuickMenuSection from './QuickMenuSection'; +import QuickMenuItem from './QuickMenuItem'; +import JCircularLinkedList from '../../common/JCircularLinkedList'; + +class QuickMenu { + + private static instance: QuickMenu | null = null; + + htmlElement: HTMLElement; + menuSections: JCircularLinkedList; + + isShowing: boolean; + currentFocusedMenuItem: QuickMenuItem | null = null; + + private constructor() { + + this.htmlElement = document.createElement('div'); + this.htmlElement.id = 'blockOptionsWrapper'; + + this.isShowing = false; + + this.menuSections = new JCircularLinkedList(); + + this.htmlElement.classList.add('block-options-wrapper', 'soft-box-shadow'); + this.htmlElement.style.display = 'none'; + + const blockOptions = document.createElement('div'); + blockOptions.classList.add('block-options'); + blockOptions.style.position = 'relative'; + + this.htmlElement.appendChild(blockOptions); + + const basicBlocksSection = new QuickMenuSection(this, 'Basic blocks', 'basic-section'); + + basicBlocksSection.appendQuickMenuItems([ + new QuickMenuItem(basicBlocksSection, 'Paragraph', 'Just start writing with plain text.', 'icon-wordpress-paragraph', 'p'), + new QuickMenuItem(basicBlocksSection, 'Image', 'Just start writing with plain text.', 'icon-wordpress-paragraph', 'image'), + new QuickMenuItem(basicBlocksSection, 'Bulleted list', 'Organize items with bullet points.', 'icon-wordpress-bulleted-list', 'bulleted-list'), + new QuickMenuItem(basicBlocksSection, 'Numbered list', 'List items in a numbered format.', 'icon-wordpress-numbered-list', 'numbered-list'), + new QuickMenuItem(basicBlocksSection, 'Code', 'Insert code snippets with syntax highlighting.', 'icon-wordpress-code-mark', 'code'), + new QuickMenuItem(basicBlocksSection, 'Quote', 'Highlight text as a significant quote.', 'icon-wordpress-quote', 'quote'), + new QuickMenuItem(basicBlocksSection, 'Heading 2', 'Medium header for subsections.', 'icon-julia-head-2', 'h2'), + new QuickMenuItem(basicBlocksSection, 'Heading 3', 'Small header for detailed sections.', 'icon-julia-head-2', 'h3'), + new QuickMenuItem(basicBlocksSection, 'Separator', 'Visually divide blocks.', 'icon-wordpress-separator', 'separator') + ]); + + this.menuSections.append(basicBlocksSection); + blockOptions.appendChild(basicBlocksSection.htmlElement); + + + const headingBlocksSection = new QuickMenuSection(this, 'Heading', 'heading-section'); + + headingBlocksSection.appendQuickMenuItems([ + new QuickMenuItem(headingBlocksSection, 'Heading 1', 'Large header to organize content.', 'icon-julia-head-1', 'h1'), + new QuickMenuItem(headingBlocksSection, 'Heading 2', 'Medium header for subsections.', 'icon-julia-head-2', 'h2'), + new QuickMenuItem(headingBlocksSection, 'Heading 3', 'Small header for detailed sections.', 'icon-julia-head-3', 'h3'), + new QuickMenuItem(headingBlocksSection, 'Heading 4', 'Small header for detailed sections.', 'icon-julia-head-4', 'h4'), + new QuickMenuItem(headingBlocksSection, 'Heading 5', 'Small header for detailed sections.', 'icon-julia-head-5', 'h5'), + new QuickMenuItem(headingBlocksSection, 'Heading 6', 'Small header for detailed sections.', 'icon-julia-head-6', 'h6'), + ]); + + this.menuSections.append(headingBlocksSection); + blockOptions.appendChild(headingBlocksSection.htmlElement); + + + const listBlocksSection = new QuickMenuSection(this, 'List', 'list-section'); + + listBlocksSection.appendQuickMenuItems([ + new QuickMenuItem(listBlocksSection, 'Todo list', 'Organize items with bullet points.', 'icon-material-check-list', 'todo-list'), + new QuickMenuItem(listBlocksSection, 'Bulleted list', 'Organize items with bullet points.', 'icon-wordpress-bulleted-list', 'bulleted-list'), + new QuickMenuItem(listBlocksSection, 'Numbered list', 'List items in a numbered format.', 'icon-wordpress-numbered-list', 'numbered-list') + ]); + + this.menuSections.append(listBlocksSection); + blockOptions.appendChild(listBlocksSection.htmlElement); + + // this.attachEvents(); + } + + public static getInstance(): QuickMenu { + if (!QuickMenu.instance) { + QuickMenu.instance = new QuickMenu(); + } + + return QuickMenu.instance; + } + + changeFocus(item: QuickMenuItem): void { + + if (this.currentFocusedMenuItem == item) { + return; + } + + if (this.currentFocusedMenuItem) { + this.currentFocusedMenuItem.removeFocus(); + } + + this.currentFocusedMenuItem = item; + this.currentFocusedMenuItem.focus(); + } + + + moveTheFakeFocusToTheNextMenuItem(): void { + + let nextItem: QuickMenuItem | null; + + if (!this.currentFocusedMenuItem) { + + nextItem = this.menuSections.getFirst()!.getFirstMenuItem(); + + } else { + + nextItem = this.currentFocusedMenuItem.nextNode; + + if (!nextItem) { + nextItem = this.currentFocusedMenuItem.quickMenuSectionInstance!.nextNode!.getFirstMenuItem(); + } + } + + this.changeFocus(nextItem!); + } + + getMenuElement(): HTMLElement { + return this.htmlElement; + } + + attachEvents = () => { + + document.addEventListener('keydown', (event) => { + if (event.key === '/' && !event.ctrlKey && !event.shiftKey && !event.altKey) { + alert('show the Quick Insert Menu'); + } + }); + } + + showMenu() { + + // The timeout in necessary to wait the browser process the selection before show the Block Options + // setTimeout(() => { + + // const realFocusedElement = document.activeElement; + // const currentDraggableBlock = realFocusedElement.closest('.draggable-block'); + // const firstBlockOption = getTheFirstVisibleBlockOption(); + + // setRealFocusedElement(realFocusedElement); + // setCurrentDraggableBlock(currentDraggableBlock); + // setCurrentFakeFocusElement(firstBlockOption); + + // applyVisualFakeFocus(realFocusedElement, firstBlockOption); + + + // //TODO: create a clear filter + // // removeDisplayNoneFromAllBlockOptions(); + + // const range = document.getSelection().getRangeAt(0); + // const cursorPos = range.getBoundingClientRect(); + + // const remSize = parseFloat(getComputedStyle(document.documentElement).fontSize); + // const menuWidth = 19 * remSize; + + // let xPosition = cursorPos.right; + // let yPosition = cursorPos.bottom + window.scrollY; + + // const margin = remSize * 1.25; + + // blockOptionsWrapper.style.display = 'block'; + + // let blockWidth = blockOptionsWrapper.offsetWidth; + + + // if (xPosition + blockWidth + margin > window.innerWidth) { + // xPosition = cursorPos.left - menuWidth; + // if (xPosition < 0) xPosition = 0; + // } + + // blockOptionsWrapper.style.left = `${xPosition}px`; + // blockOptionsWrapper.style.top = `${yPosition}px`; + + + // }, 10); + } + +} + +// const instance = new QuickMenu(); +export default QuickMenu; \ No newline at end of file diff --git a/src/components/quick-menu/QuickMenuItem.js b/src/components/quick-menu/QuickMenuItem.js deleted file mode 100644 index f345c25..0000000 --- a/src/components/quick-menu/QuickMenuItem.js +++ /dev/null @@ -1,81 +0,0 @@ -import * as helperDOM from './helperDOM'; -import JNode from '../../common/JNode'; -import QuickMenuSection from './QuickMenuSection'; - -class QuickMenuItem extends JNode { - - constructor(quickMenuSectionInstance, itemName, itemDescription, SVGHrefUseId, dataType) { - - super(); - - // if (!(QuickMenuSectionInstance instanceof QuickMenuSection)) { - // throw new TypeError("Expected an instance of QuickMenuSection."); - // } - - /** - * The QuickMenu element of the component in the DOM. - * @type {HTMLElement} - */ - this.htmlElement = document.createElement('div'); - htmlElement.classList.add('option', 'option-hover', 'block-operation'); - - /** - * The QuickMenuSection parent. - * @type {QuickMenuSection} - */ - this.quickMenuSectionInstance = quickMenuSectionInstance; - - htmlElement.setAttribute('data-block-operation', 'apply-selected-block-type'); - htmlElement.setAttribute('data-type', dataType); - htmlElement.setAttribute('tabindex', '0'); - htmlElement.setAttribute('role', 'option'); - - const optionImage = document.createElement('div'); - optionImage.classList.add('option-image'); - - const svg = helperDOM.createSVG(SVGHrefUseId, '', '100%', '100%'); - - optionImage.appendChild(svg); - - htmlElement.appendChild(optionImage); - - - const optionText = document.createElement('div'); - optionText.classList.add('option-text'); - - const blockTitle = document.createElement('p'); - blockTitle.classList.add('block-title'); - blockTitle.innerText = itemName; - - optionText.appendChild(blockTitle); - - const blockDescription = document.createElement('p'); - blockDescription.classList.add('block-description'); - blockDescription.innerText = itemDescription; - - optionText.appendChild(blockDescription); - - htmlElement.appendChild(optionText); - - - /** Apply a fake focus in the element */ - this.focus = () => { - this.htmlElement.classList.add('block-options-focused'); - this.htmlElement.focus(); - } - - this.removeFocus = () => { - this.htmlElement.classList.remove('block-options-focused'); - } - - this.attachEvents = () => { - this.htmlElement.addEventListener('mousemove', () => { - this.quickMenuSectionInstance.quickMenuInstance.changeFocus(this); - }); - } - - this.attachEvents(); - } -} - -export default QuickMenuItem; \ No newline at end of file diff --git a/src/components/quick-menu/QuickMenuItem.ts b/src/components/quick-menu/QuickMenuItem.ts new file mode 100644 index 0000000..5f4506c --- /dev/null +++ b/src/components/quick-menu/QuickMenuItem.ts @@ -0,0 +1,70 @@ +import SVGIcon from '../common/SVGIcon'; +import JNode from '../../common/JNode'; +import QuickMenuSection from './QuickMenuSection'; + +class QuickMenuItem extends JNode { + + htmlElement: HTMLElement; + quickMenuSectionInstance: QuickMenuSection; + + constructor(quickMenuSectionInstance: QuickMenuSection, itemName: string, itemDescription: string, SVGHrefUseId: string, dataType: string) { + + super(); + + this.htmlElement = document.createElement('div'); + this.htmlElement.classList.add('option', 'option-hover', 'block-operation'); + + this.quickMenuSectionInstance = quickMenuSectionInstance; + + this.htmlElement.setAttribute('data-block-operation', 'apply-selected-block-type'); + this.htmlElement.setAttribute('data-type', dataType); + this.htmlElement.setAttribute('tabindex', '0'); + this.htmlElement.setAttribute('role', 'option'); + + const optionImage = document.createElement('div'); + optionImage.classList.add('option-image'); + + const svg = new SVGIcon(SVGHrefUseId, '', '100%', '100%'); + + optionImage.appendChild(svg.htmlElement); + + this.htmlElement.appendChild(optionImage); + + + const optionText = document.createElement('div'); + optionText.classList.add('option-text'); + + const blockTitle = document.createElement('p'); + blockTitle.classList.add('block-title'); + blockTitle.innerText = itemName; + + optionText.appendChild(blockTitle); + + const blockDescription = document.createElement('p'); + blockDescription.classList.add('block-description'); + blockDescription.innerText = itemDescription; + + optionText.appendChild(blockDescription); + + this.htmlElement.appendChild(optionText); + + this.attachEvents(); + } + + focus(): void { + this.htmlElement.classList.add('block-options-focused'); + this.htmlElement.focus(); + } + + removeFocus(): void { + this.htmlElement.classList.remove('block-options-focused'); + } + + attachEvents(): void { + this.htmlElement.addEventListener('mousemove', () => { + this.quickMenuSectionInstance.quickMenuInstance.changeFocus(this); + }); + } +} + +export default QuickMenuItem; \ No newline at end of file diff --git a/src/components/quick-menu/QuickMenuSection.js b/src/components/quick-menu/QuickMenuSection.js deleted file mode 100644 index 95ec249..0000000 --- a/src/components/quick-menu/QuickMenuSection.js +++ /dev/null @@ -1,95 +0,0 @@ -import QuickMenu from './QuickMenu'; -import QuickMenuItem from "./QuickMenuItem"; -import JLinkedList from '../../common/JLinkedList'; -import JNode from "../../common/JNode"; - -/** - * Represents a section within a QuickMenu, acting as a node in a doubly-linked list. - * Each section contains a collection of QuickMenuItem nodes, managed as a linked list with references to both the head and tail of the list. - * This setup facilitates efficient addition and removal of items at both ends of the list. - * - * @class QuickMenuSection - * @property {HTMLElement} htmlElement - The DOM element representing the section in the UI. - * @property {QuickMenuItem[]} menuItems - An array of menu items contained within the section. - * @property {QuickMenuItem} #head - Private field holding a reference to the first QuickMenuItem in the section. - * @property {QuickMenuItem} #tail - Private field holding a reference to the last QuickMenuItem in the section. - */ -class QuickMenuSection extends JNode { - - constructor(quickMenuInstance, sectionName, classList) { - - super(); - - // if (!(QuickMenuInstance instanceof QuickMenu)) { - // throw new TypeError("Expected an instance of QuickMenu."); - // } - - /** - * The QuickMenuSection element of the component in the DOM. - * @type {HTMLElement} - */ - this.htmlElement = document.createElement('section'); - htmlElement.classList.add(classList); - - /** - * The QuickMenu parent. - * @type {QuickMenu} - */ - this.quickMenuInstance = quickMenuInstance; - - let heading = document.createElement('h2'); - heading.textContent = sectionName; - - /** - * The QuickMenuItem elements in a LinkedList. - * @type {JLinkedList} - */ - this.menuItems = new JLinkedList(); - - htmlElement.appendChild(heading); - - /** - * Inserts a QuickMenuItem or an array of QuickMenuItems into the menu. - * If the input is not a QuickMenuItem or contains an item that is not a QuickMenuItem, an error is thrown. - * - * @param {QuickMenuItem|QuickMenuItem[]} menuItems The item(s) to be inserted. - * @throws {Error} Throws an 'Out Of Range Exception' if any item is not a QuickMenuItem. - */ - this.appendQuickMenuItem = (menuItems) => { - - if (Array.isArray(menuItems)) { - menuItems.forEach(item => { - - if (!(item instanceof QuickMenuItem)) { - throw new Error('Out Of Range Exception'); - } - - this.menuItems.append(item); - this.htmlElement.appendChild(item.htmlElement); - }); - } else { - - if (!(item instanceof QuickMenuItem)) { - throw new Error('Out Of Range Exception'); - } - - this.menuItems.append(menuItems); - this.htmlElement.appendChild(menuItems.htmlElement); - } - } - - /** - * Gets the first item from the list of menu items. - * @returns {QuickMenuItem|null} The first menu item if the list is not empty, or null if it is empty. - */ - this.getFirstMenuItem = () => { - if (this.menuItems.length) { - return this.menuItems.getFirst(); - } else { - return null; - } - } - } -} - -export default QuickMenuSection; \ No newline at end of file diff --git a/src/components/quick-menu/QuickMenuSection.ts b/src/components/quick-menu/QuickMenuSection.ts new file mode 100644 index 0000000..099e2fe --- /dev/null +++ b/src/components/quick-menu/QuickMenuSection.ts @@ -0,0 +1,52 @@ + +import QuickMenu from './QuickMenu'; +import QuickMenuItem from "./QuickMenuItem"; +import JLinkedList from '../../common/JLinkedList'; +import JNode from "../../common/JNode"; + +class QuickMenuSection extends JNode { + + htmlElement: HTMLElement; + quickMenuInstance: QuickMenu; + + menuItems = new JLinkedList(); + + constructor(quickMenuInstance: QuickMenu, sectionName: string, classList: string) { + + super(); + + this.htmlElement = document.createElement('section'); + this.htmlElement.classList.add(classList); + + this.quickMenuInstance = quickMenuInstance; + + let heading = document.createElement('h2'); + heading.textContent = sectionName; + + this.htmlElement.appendChild(heading); + } + + appendQuickMenuItems(menuItems: QuickMenuItem[]) { + + menuItems.forEach(item => { + + this.appendQuickMenuItem(item) + }); + } + + appendQuickMenuItem(menuItem: QuickMenuItem): void { + + this.menuItems.append(menuItem); + this.htmlElement.appendChild(menuItem.htmlElement); + } + + getFirstMenuItem() { + if (this.menuItems.length) { + return this.menuItems.getFirst(); + } else { + return null; + } + } +} + +export default QuickMenuSection; \ No newline at end of file diff --git a/src/components/quick-menu/helperDOM.js b/src/components/quick-menu/helperDOM.ts similarity index 87% rename from src/components/quick-menu/helperDOM.js rename to src/components/quick-menu/helperDOM.ts index 51450ba..6b8e7b4 100644 --- a/src/components/quick-menu/helperDOM.js +++ b/src/components/quick-menu/helperDOM.ts @@ -1,4 +1,4 @@ -export function createSVG(hrefUseId, classList = "", width = 16, height = 16) { +export function createSVG(hrefUseId: string, classList = "", width = "16", height = "16") { if (!hrefUseId) { throw new Error('Invalid Argument Exception'); diff --git a/src/index.js b/src/index.ts similarity index 100% rename from src/index.js rename to src/index.ts diff --git a/src/triggers/keypress-events.js b/src/triggers/keypress-events.js index 60f6114..cc071e2 100644 --- a/src/triggers/keypress-events.js +++ b/src/triggers/keypress-events.js @@ -58,14 +58,14 @@ document.addEventListener('DOMContentLoaded', function () { document.addEventListener('keydown', function (event) { - // if (isTriggable(event) && !isShowingBlockOptions()) { + if (isTriggable(event) && !isShowingBlockOptions()) { - // if (event.key === '/' && !event.ctrlKey && !event.shiftKey && !event.altKey) { + if (event.key === '/' && !event.ctrlKey && !event.shiftKey && !event.altKey) { - // const command = commandFactory.createCommand(commandFactory.OPERATIONS.BLOCK_OPTIONS.SHOW_BLOCK_OPTIONS); - // command.execute(); - // } - // } + const command = commandFactory.createCommand(commandFactory.OPERATIONS.BLOCK_OPTIONS.SHOW_BLOCK_OPTIONS); + command.execute(); + } + } if (isShowingBlockOptions()) { diff --git a/src/triggers/load-events.js b/src/triggers/load-events.js index 3856380..ac52233 100644 --- a/src/triggers/load-events.js +++ b/src/triggers/load-events.js @@ -1,5 +1,5 @@ //TODO use commands -import instance from '../components/quick-menu/QuickMenu' +import QuickInsertMenu from '../components/quick-menu/QuickMenu' //Focus on P when load document.addEventListener('DOMContentLoaded', function () { @@ -53,6 +53,7 @@ document.addEventListener('DOMContentLoaded', function () { document.addEventListener('DOMContentLoaded', function () { + let instance = QuickInsertMenu.getInstance(); johannesEditor.appendChild(instance.getMenuElement()); }); \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..ba7cf09 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "esnext", // Compila para a última versão do ECMAScript + "module": "esnext", // Usa ES Modules + "moduleResolution": "node", // Estratégia de resolução de módulos + "strict": true, // Ativa verificações estritas de tipo + "esModuleInterop": true, // Permite interoperabilidade de módulos padrão ES com módulos CommonJS + "allowSyntheticDefaultImports": true, // Permite importações default sintéticas + "outDir": "./dist", // Diretório para arquivos compilados + "baseUrl": "./", // Base para resolução de módulos + "paths": { // Mapeamento de caminhos para módulos + "*": [ + "node_modules/*", + "src/*" + ] + }, + "sourceMap": true // Gera mapas de código fonte para debugging + }, + "include": [ + "src/**/*" + ], // Inclui todos os arquivos TypeScript na pasta src + "exclude": [ + "node_modules" + ] // Exclui a pasta node_modules +} \ No newline at end of file diff --git a/webpack.config.js b/webpack.config.js index 6b0a568..b344cd0 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -2,13 +2,21 @@ const path = require('path'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); module.exports = { - entry: './src/index.js', + entry: './src/index.ts', // Alterado para apontar para o arquivo TypeScript output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist'), }, + resolve: { + extensions: ['.ts', '.js'], // Webpack agora resolve arquivos .ts e .js + }, module: { rules: [ + { + test: /\.ts$/, // Regra para compilar arquivos TypeScript + use: 'ts-loader', + exclude: /node_modules/ + }, { test: /\.css$/, use: [ @@ -23,4 +31,4 @@ module.exports = { filename: 'style.css', }), ] -}; \ No newline at end of file +};