mirror of
https://github.com/codex-team/editor.js
synced 2024-05-19 06:47:16 +02:00
ac93017c70
* 2.16.0 * [Refactor] Separate internal and external settings (#845) * Enable flipping tools via standalone class (#830) * Enable flipping tools via standalone class * use flipper to refactor (#842) * use flipper to refactor * save changes * update * fix flipper on inline toolbar * ready for testing * requested changes * update doc * updates * destroy flippers * some requested changes * update * update * ready * update * last changes * update docs * Hghl active button of CT, simplify activate/deactivate * separate dom iterator * unhardcode directions * fixed a link in readme.md (#856) * Fix Block selection via CMD+A (#829) * Fix Block selection via CMD+A * Delete editor.js.map * update * update * Update CHANGELOG.md * Improve style of selected blocks (#858) * Cross-block-selection style improved * Update CHANGELOG.md * Fix case when property 'observer' in modificationObserver is not defined (#866) * Bump lodash.template from 4.4.0 to 4.5.0 (#885) Bumps [lodash.template](https://github.com/lodash/lodash) from 4.4.0 to 4.5.0. - [Release notes](https://github.com/lodash/lodash/releases) - [Commits](https://github.com/lodash/lodash/compare/4.4.0...4.5.0) Signed-off-by: dependabot[bot] <support@github.com> * Bump eslint-utils from 1.3.1 to 1.4.2 (#886) Bumps [eslint-utils](https://github.com/mysticatea/eslint-utils) from 1.3.1 to 1.4.2. - [Release notes](https://github.com/mysticatea/eslint-utils/releases) - [Commits](https://github.com/mysticatea/eslint-utils/compare/v1.3.1...v1.4.2) Signed-off-by: dependabot[bot] <support@github.com> * Bump mixin-deep from 1.3.1 to 1.3.2 (#887) Bumps [mixin-deep](https://github.com/jonschlinkert/mixin-deep) from 1.3.1 to 1.3.2. - [Release notes](https://github.com/jonschlinkert/mixin-deep/releases) - [Commits](https://github.com/jonschlinkert/mixin-deep/compare/1.3.1...1.3.2) Signed-off-by: dependabot[bot] <support@github.com> * update bundle and readme * Update README.md * upd codeowners, fix funding * Minor Docs Fix according to main Readme (#916) * Inline Toolbar now contains Conversion Toolbar (#932) * Block lifecycle hooks (#906) * [Fix] Arrow selection (#964) * Fix arrow selection * Add docs * [issue-926]: fix dom iterator leafing when items are empty (#958) * [issue-926]: fix dom iterator leafing when items are empty * update Changelog * Issue 869 (#963) * Fix issue 943 (#965) * [Draft] Feature/tooltip enhancements (#907) * initial * update * make module standalone * use tooltips as external module * update * build via prod mode * add tooltips as external module * add declaration file and options param * add api tooltip * update * removed submodule * removed due to the incorrect setip * setup tooltips again * wip * update tooltip module * toolbox, inline toolbar * Tooltips in block tunes not uses shorthand * shorthand in a plus and block settings * fix doc * Update tools-inline.md * Delete tooltip.css * Update CHANGELOG.md * Update codex.tooltips * Update api.md * [issue-779]: Grammarly conflicts (#956) * grammarly conflicts * update * upd bundle * Submodule Header now on master * Submodule Marker now on master * Submodule Paragraph now on master * Submodule InlineCode now on master * Submodule Simple Image now on master * [issue-868]: Deleting multiple blocks triggers back button in Firefox (#967) * Deleting multiple blocks triggers back button in Firefox @evgenusov * Update editor.js * Update CHANGELOG.md * pass options on removeEventListener (#904) * pass options on removeEventListener by removeAll * rebuild * Merge branch 'release/2.16' into pr/904 * Update CHANGELOG.md * Update inline.ts * [Fix] Selection rangecount (#968) * Fix #952 (#969) * Update codex.tooltips * Selection bugfix (#970) * Selection bugfix * fix cross block selection * close inline toolbar when blocks selected via shift * remove inline toolbar closing on cross block selection mouse up due to the bug (#972) * [Feature] Log levels (#971) * Decrease margins (#973) * Decrease margins * Update editor.licenses.txt * Update src/components/domIterator.ts Co-Authored-By: Murod Khaydarov <murod.haydarov@gmail.com> * [Fix] Fix delete blocks api method (#974) * Update docs/usage.md Co-Authored-By: Murod Khaydarov <murod.haydarov@gmail.com> * rm unused * Update yarn.lock file * upd bundle, changelog
324 lines
8.3 KiB
TypeScript
324 lines
8.3 KiB
TypeScript
import Module from '../../__module';
|
|
import $ from '../../dom';
|
|
import * as _ from '../../utils';
|
|
import {BlockToolConstructable} from '../../../../types';
|
|
import Flipper from '../../flipper';
|
|
import {BlockToolAPI} from '../../block';
|
|
|
|
/**
|
|
* @class Toolbox
|
|
* @classdesc Holder for Tools
|
|
*
|
|
* @typedef {Toolbox} Toolbox
|
|
* @property {Boolean} opened - opening state
|
|
* @property {Object} nodes - Toolbox nodes
|
|
* @property {Object} CSS - CSS class names
|
|
*
|
|
*/
|
|
export default class Toolbox extends Module {
|
|
|
|
/**
|
|
* CSS styles
|
|
* @return {{toolbox: string, toolboxButton string, toolboxButtonActive: string,
|
|
* toolboxOpened: string, tooltip: string, tooltipShown: string, tooltipShortcut: string}}
|
|
*/
|
|
get CSS() {
|
|
return {
|
|
toolbox: 'ce-toolbox',
|
|
toolboxButton: 'ce-toolbox__button',
|
|
toolboxButtonActive : 'ce-toolbox__button--active',
|
|
toolboxOpened: 'ce-toolbox--opened',
|
|
openedToolbarHolderModifier: 'codex-editor--toolbox-opened',
|
|
|
|
buttonTooltip: 'ce-toolbox-button-tooltip',
|
|
buttonShortcut: 'ce-toolbox-button-tooltip__shortcut',
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Returns True if Toolbox is Empty and nothing to show
|
|
* @return {boolean}
|
|
*/
|
|
public get isEmpty(): boolean {
|
|
return this.displayedToolsCount === 0;
|
|
}
|
|
|
|
/**
|
|
* Opening state
|
|
* @type {boolean}
|
|
*/
|
|
public opened: boolean = false;
|
|
|
|
/**
|
|
* HTMLElements used for Toolbox UI
|
|
*/
|
|
public nodes: {
|
|
toolbox: HTMLElement,
|
|
buttons: HTMLElement[],
|
|
} = {
|
|
toolbox: null,
|
|
buttons: [],
|
|
};
|
|
|
|
/**
|
|
* How many tools displayed in Toolbox
|
|
* @type {number}
|
|
*/
|
|
private displayedToolsCount: number = 0;
|
|
|
|
/**
|
|
* Instance of class that responses for leafing buttons by arrows/tab
|
|
* @type {Flipper|null}
|
|
*/
|
|
private flipper: Flipper = null;
|
|
|
|
/**
|
|
* Makes the Toolbox
|
|
*/
|
|
public make(): void {
|
|
this.nodes.toolbox = $.make('div', this.CSS.toolbox);
|
|
$.append(this.Editor.Toolbar.nodes.content, this.nodes.toolbox);
|
|
|
|
this.addTools();
|
|
this.enableFlipper();
|
|
}
|
|
|
|
/**
|
|
* Toolbox Tool's button click handler
|
|
*
|
|
* @param {MouseEvent|KeyboardEvent} event
|
|
* @param {string} toolName
|
|
*/
|
|
public toolButtonActivate(event: MouseEvent|KeyboardEvent, toolName: string): void {
|
|
const tool = this.Editor.Tools.toolsClasses[toolName] as BlockToolConstructable;
|
|
|
|
this.insertNewBlock(tool, toolName);
|
|
}
|
|
|
|
/**
|
|
* Open Toolbox with Tools
|
|
*/
|
|
public open(): void {
|
|
if (this.isEmpty) {
|
|
return;
|
|
}
|
|
|
|
this.Editor.UI.nodes.wrapper.classList.add(this.CSS.openedToolbarHolderModifier);
|
|
this.nodes.toolbox.classList.add(this.CSS.toolboxOpened);
|
|
|
|
this.opened = true;
|
|
this.flipper.activate();
|
|
}
|
|
|
|
/**
|
|
* Close Toolbox
|
|
*/
|
|
public close(): void {
|
|
this.nodes.toolbox.classList.remove(this.CSS.toolboxOpened);
|
|
this.Editor.UI.nodes.wrapper.classList.remove(this.CSS.openedToolbarHolderModifier);
|
|
|
|
this.opened = false;
|
|
this.flipper.deactivate();
|
|
}
|
|
|
|
/**
|
|
* Close Toolbox
|
|
*/
|
|
public toggle(): void {
|
|
if (!this.opened) {
|
|
this.open();
|
|
} else {
|
|
this.close();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Iterates available tools and appends them to the Toolbox
|
|
*/
|
|
private addTools(): void {
|
|
const tools = this.Editor.Tools.available;
|
|
|
|
for (const toolName in tools) {
|
|
if (tools.hasOwnProperty(toolName)) {
|
|
this.addTool(toolName, tools[toolName] as BlockToolConstructable);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Append Tool to the Toolbox
|
|
*
|
|
* @param {string} toolName - tool name
|
|
* @param {BlockToolConstructable} tool - tool class
|
|
*/
|
|
private addTool(toolName: string, tool: BlockToolConstructable): void {
|
|
const internalSettings = this.Editor.Tools.INTERNAL_SETTINGS;
|
|
const userSettings = this.Editor.Tools.USER_SETTINGS;
|
|
|
|
const toolToolboxSettings = tool[internalSettings.TOOLBOX];
|
|
|
|
/**
|
|
* Skip tools that don't pass 'toolbox' property
|
|
*/
|
|
if (_.isEmpty(toolToolboxSettings)) {
|
|
return;
|
|
}
|
|
|
|
if (toolToolboxSettings && !toolToolboxSettings.icon) {
|
|
_.log('Toolbar icon is missed. Tool %o skipped', 'warn', toolName);
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* @todo Add checkup for the render method
|
|
*/
|
|
// if (typeof tool.render !== 'function') {
|
|
// _.log('render method missed. Tool %o skipped', 'warn', tool);
|
|
// return;
|
|
// }
|
|
|
|
const userToolboxSettings = this.Editor.Tools.getToolSettings(toolName)[userSettings.TOOLBOX] || {};
|
|
|
|
const button = $.make('li', [ this.CSS.toolboxButton ]);
|
|
|
|
button.dataset.tool = toolName;
|
|
button.innerHTML = userToolboxSettings.icon || toolToolboxSettings.icon;
|
|
|
|
$.append(this.nodes.toolbox, button);
|
|
|
|
this.nodes.toolbox.appendChild(button);
|
|
this.nodes.buttons.push(button);
|
|
|
|
/**
|
|
* Add click listener
|
|
*/
|
|
this.Editor.Listeners.on(button, 'click', (event: KeyboardEvent|MouseEvent) => {
|
|
this.toolButtonActivate(event, toolName);
|
|
});
|
|
|
|
/**
|
|
* Add listeners to show/hide toolbox tooltip
|
|
*/
|
|
const tooltipContent = this.drawTooltip(toolName);
|
|
|
|
this.Editor.Tooltip.onHover(button, tooltipContent, {
|
|
placement: 'bottom',
|
|
hidingDelay: 200,
|
|
});
|
|
|
|
/**
|
|
* Enable shortcut
|
|
*/
|
|
const toolSettings = this.Editor.Tools.getToolSettings(toolName);
|
|
|
|
if (toolSettings && toolSettings[this.Editor.Tools.USER_SETTINGS.SHORTCUT]) {
|
|
this.enableShortcut(tool, toolName, toolSettings[this.Editor.Tools.USER_SETTINGS.SHORTCUT]);
|
|
}
|
|
|
|
/** Increment Tools count */
|
|
this.displayedToolsCount++;
|
|
}
|
|
|
|
/**
|
|
* Draw tooltip for toolbox tools
|
|
*
|
|
* @param {String} toolName - toolbox tool name
|
|
* @return { HTMLElement }
|
|
*/
|
|
private drawTooltip(toolName: string): HTMLElement {
|
|
const toolSettings = this.Editor.Tools.getToolSettings(toolName);
|
|
const toolboxSettings = this.Editor.Tools.available[toolName][this.Editor.Tools.INTERNAL_SETTINGS.TOOLBOX] || {};
|
|
const userToolboxSettings = toolSettings.toolbox || {};
|
|
const name = userToolboxSettings.title || toolboxSettings.title || toolName;
|
|
|
|
let shortcut = toolSettings[this.Editor.Tools.USER_SETTINGS.SHORTCUT];
|
|
|
|
const tooltip = $.make('div', this.CSS.buttonTooltip);
|
|
const hint = document.createTextNode(_.capitalize(name));
|
|
|
|
tooltip.appendChild(hint);
|
|
|
|
if (shortcut) {
|
|
shortcut = _.beautifyShortcut(shortcut);
|
|
|
|
tooltip.appendChild($.make('div', this.CSS.buttonShortcut, {
|
|
textContent: shortcut,
|
|
}));
|
|
}
|
|
|
|
return tooltip;
|
|
}
|
|
|
|
/**
|
|
* Enable shortcut Block Tool implemented shortcut
|
|
* @param {BlockToolConstructable} tool - Tool class
|
|
* @param {String} toolName - Tool name
|
|
* @param {String} shortcut - shortcut according to the ShortcutData Module format
|
|
*/
|
|
private enableShortcut(tool: BlockToolConstructable, toolName: string, shortcut: string) {
|
|
this.Editor.Shortcuts.add({
|
|
name: shortcut,
|
|
handler: (event: KeyboardEvent) => {
|
|
event.preventDefault();
|
|
this.insertNewBlock(tool, toolName);
|
|
},
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Creates Flipper instance to be able to leaf tools
|
|
*/
|
|
private enableFlipper(): void {
|
|
const tools = Array.from(this.nodes.toolbox.childNodes) as HTMLElement[];
|
|
this.flipper = new Flipper({
|
|
items: tools,
|
|
focusedItemClass: this.CSS.toolboxButtonActive,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Inserts new block
|
|
* Can be called when button clicked on Toolbox or by ShortcutData
|
|
*
|
|
* @param {BlockToolConstructable} tool - Tool Class
|
|
* @param {String} toolName - Tool name
|
|
*/
|
|
private insertNewBlock(tool: BlockToolConstructable, toolName: string) {
|
|
const {BlockManager, Caret} = this.Editor;
|
|
/**
|
|
* @type {Block}
|
|
*/
|
|
const {currentBlock} = BlockManager;
|
|
|
|
let newBlock;
|
|
|
|
if (currentBlock.isEmpty) {
|
|
newBlock = BlockManager.replace(toolName);
|
|
} else {
|
|
newBlock = BlockManager.insert(toolName);
|
|
}
|
|
|
|
/**
|
|
* Apply callback before inserting html
|
|
*/
|
|
newBlock.call(BlockToolAPI.APPEND_CALLBACK);
|
|
|
|
this.Editor.Caret.setToBlock(newBlock);
|
|
|
|
/** If new block doesn't contain inpus, insert new paragraph above */
|
|
if (newBlock.inputs.length === 0) {
|
|
if (newBlock === BlockManager.lastBlock) {
|
|
BlockManager.insertAtEnd();
|
|
Caret.setToBlock(BlockManager.lastBlock);
|
|
} else {
|
|
Caret.setToBlock(BlockManager.nextBlock);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* close toolbar when node is changed
|
|
*/
|
|
this.Editor.Toolbar.close();
|
|
}
|
|
}
|