mirror of
https://github.com/codex-team/editor.js
synced 2024-05-27 02:52:35 +02:00
[Improvements] ESLint action (#1099)
* TSLint -> ESLint, GitHub Action * Update eslint.yml * Autofix * more autofix * fix * manually fix some issues * Update CHANGELOG.md
This commit is contained in:
parent
be6f9b78f2
commit
f5e9a6648e
4
.eslintignore
Normal file
4
.eslintignore
Normal file
|
@ -0,0 +1,4 @@
|
|||
node_modules
|
||||
*.d.ts
|
||||
src/components/tools/paragraph
|
||||
src/polyfills.ts
|
106
.eslintrc
106
.eslintrc
|
@ -1,92 +1,18 @@
|
|||
{
|
||||
/** Enable ES6 features */
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2017,
|
||||
"sourceType": "module"
|
||||
},
|
||||
"rules": {
|
||||
|
||||
"arrow-spacing": [2, {
|
||||
"before": true,
|
||||
"after": true
|
||||
}],
|
||||
|
||||
/** Variables */
|
||||
"no-catch-shadow": 2,
|
||||
"no-delete-var": 2,
|
||||
"no-label-var": 2,
|
||||
"no-shadow-restricted-names": 2,
|
||||
"no-shadow": 2,
|
||||
"no-undef-init": 2,
|
||||
"no-undef": 2,
|
||||
"no-unused-vars": 0,
|
||||
|
||||
/** Style */
|
||||
"array-bracket-spacing": [2, "never", {
|
||||
"singleValue": true,
|
||||
"objectsInArrays": true,
|
||||
"arraysInArrays": true
|
||||
}],
|
||||
"quotes": [2, "single", {
|
||||
"avoidEscape": true,
|
||||
"allowTemplateLiterals": true
|
||||
}],
|
||||
"eqeqeq": 0,
|
||||
"brace-style": [2, "1tbs"],
|
||||
"comma-spacing": [2, {
|
||||
"before": false,
|
||||
"after": true
|
||||
}],
|
||||
"comma-style": [2, "last"],
|
||||
"eol-last": 0,
|
||||
"no-nested-ternary": 1,
|
||||
"no-trailing-spaces": 2,
|
||||
"no-mixed-spaces-and-tabs": 2,
|
||||
"padded-blocks": [2, "never"],
|
||||
"space-before-blocks": 1,
|
||||
"space-before-function-paren": [1, {
|
||||
"anonymous": "always",
|
||||
"named": "never"
|
||||
}],
|
||||
"spaced-comment": [2, "always", {
|
||||
"exceptions": ["-", "+"],
|
||||
"markers": ["=", "!"]
|
||||
}],
|
||||
"semi": [2, "always"],
|
||||
"indent": [2, 2, {
|
||||
"SwitchCase": 1
|
||||
}],
|
||||
"camelcase": [2, {
|
||||
"properties": "always"
|
||||
}],
|
||||
"newline-after-var": [1, "always"]
|
||||
|
||||
},
|
||||
"globals":{
|
||||
"document": true,
|
||||
"module": true,
|
||||
"require": true,
|
||||
"window": true,
|
||||
"console" : true,
|
||||
"codex": true,
|
||||
"VERSION" : true,
|
||||
"Promise" : true,
|
||||
"MutationObserver": true,
|
||||
"FormData": true,
|
||||
"XMLHttpRequest": true,
|
||||
"ActiveXObject": true,
|
||||
"RegExp": true,
|
||||
"Module": true,
|
||||
"Node": true,
|
||||
"Element": true,
|
||||
"DocumentFragment": true,
|
||||
"Proxy": true,
|
||||
"Symbol": true,
|
||||
"$": true,
|
||||
"_": true,
|
||||
"setTimeout": true,
|
||||
"process": true,
|
||||
"__dirname": true,
|
||||
"Map": true
|
||||
}
|
||||
"extends": [
|
||||
"codex"
|
||||
],
|
||||
"rules": {
|
||||
/**
|
||||
* Temporary suppress some errors. We need to fix them partially in next patches
|
||||
*/
|
||||
"@typescript-eslint/explicit-function-return-type": ["warn"],
|
||||
"@typescript-eslint/explicit-member-accessibility": ["warn"],
|
||||
"@typescript-eslint/member-ordering": ["warn"],
|
||||
"@typescript-eslint/no-empty-function": ["warn"],
|
||||
"no-prototype-builtins": ["warn"],
|
||||
"no-mixed-operators": ["warn"],
|
||||
"import/no-duplicates": ["warn"],
|
||||
"no-case-declarations": ["warn"]
|
||||
}
|
||||
}
|
||||
|
|
24
.github/workflows/eslint.yml
vendored
Normal file
24
.github/workflows/eslint.yml
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
name: ESLint CodeX
|
||||
|
||||
on: [pull_request]
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: ESlint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: node_modules
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.OS }}-build-${{ env.cache-name }}-
|
||||
${{ runner.OS }}-build-
|
||||
${{ runner.OS }}-
|
||||
|
||||
- run: yarn install
|
||||
|
||||
- run: yarn lint
|
2
dist/editor.js
vendored
2
dist/editor.js
vendored
File diff suppressed because one or more lines are too long
1
dist/editor.js.LICENSE
vendored
1
dist/editor.js.LICENSE
vendored
|
@ -25,6 +25,7 @@
|
|||
* Editor.js
|
||||
*
|
||||
* Short Description (눈_눈;)
|
||||
*
|
||||
* @version 2.0
|
||||
*
|
||||
* @licence Apache-2.0
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
# Changelog
|
||||
|
||||
### 2.18
|
||||
|
||||
- `Improvements` - Deprecated TSLint replaced with ESLint, old config changed to [CodeX ESLint Config](https://github.com/codex-team/eslint-config).
|
||||
- `Improvements` - Adjusted GitHub action for ESLint.
|
||||
|
||||
### 2.17
|
||||
|
||||
- `Improvements` - Editor's [onchange callback](https://editorjs.io/configuration#editor-modifications-callback) now accepts an API as a parameter
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
"build:win": "rimraf dist && yarn svg:win && yarn build:prod",
|
||||
"build:dev": "webpack --mode development --progress --display-error-details --display-entrypoints --watch",
|
||||
"build:prod": "webpack --mode production",
|
||||
"lint": "eslint src/ --ext .ts",
|
||||
"lint:errors": "eslint src/ --ext .ts --quiet",
|
||||
"lint:fix": "eslint src/ --ext .ts --fix",
|
||||
"svg:win": "if not exist dist md dist && yarn svg",
|
||||
"svg": "svg-sprite-generate -d src/assets/ -o dist/sprite.svg",
|
||||
"pull_tools": "git submodule update --init --recursive",
|
||||
|
@ -43,7 +46,8 @@
|
|||
"core-js": "3",
|
||||
"css-loader": "^3.2.1",
|
||||
"cssnano": "^4.1.10",
|
||||
"eslint": "^6.7.2",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-config-codex": "^1.3.2",
|
||||
"eslint-loader": "^3.0.3",
|
||||
"extract-text-webpack-plugin": "^3.0.2",
|
||||
"html-janitor": "^2.0.4",
|
||||
|
@ -61,7 +65,6 @@
|
|||
"terser-webpack-plugin": "^2.2.2",
|
||||
"ts-loader": "^6.2.1",
|
||||
"tslint": "^5.14.0",
|
||||
"tslint-loader": "^3.5.4",
|
||||
"typescript": "^3.7.3",
|
||||
"webpack": "^4.29.6",
|
||||
"webpack-cli": "^3.2.3"
|
||||
|
|
13
src/codex.ts
13
src/codex.ts
|
@ -1,7 +1,6 @@
|
|||
'use strict';
|
||||
import {EditorConfig} from '../types';
|
||||
|
||||
declare const VERSION: string;
|
||||
import { EditorConfig } from '../types';
|
||||
|
||||
/**
|
||||
* Apply polyfills
|
||||
|
@ -11,10 +10,13 @@ import '@babel/register';
|
|||
import 'components/polyfills';
|
||||
import Core from './components/core';
|
||||
|
||||
declare const VERSION: string;
|
||||
|
||||
/**
|
||||
* Editor.js
|
||||
*
|
||||
* Short Description (눈_눈;)
|
||||
*
|
||||
* @version 2.0
|
||||
*
|
||||
* @licence Apache-2.0
|
||||
|
@ -38,11 +40,9 @@ export default class EditorJS {
|
|||
}
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*
|
||||
* @param {EditorConfig|String|undefined} [configuration] - user configuration
|
||||
* @param {EditorConfig|string|undefined} [configuration] - user configuration
|
||||
*/
|
||||
public constructor(configuration?: EditorConfig|string) {
|
||||
constructor(configuration?: EditorConfig|string) {
|
||||
/**
|
||||
* Set default onReady function
|
||||
*/
|
||||
|
@ -63,6 +63,7 @@ export default class EditorJS {
|
|||
/**
|
||||
* We need to export isReady promise in the constructor
|
||||
* as it can be used before other API methods are exported
|
||||
*
|
||||
* @type {Promise<void>}
|
||||
*/
|
||||
this.isReady = editor.isReady.then(() => {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import {EditorModules} from '../types-internal/editor-modules';
|
||||
import {EditorConfig} from '../../types';
|
||||
import {ModuleConfig} from '../types-internal/module-config';
|
||||
import { EditorModules } from '../types-internal/editor-modules';
|
||||
import { EditorConfig } from '../../types';
|
||||
import { ModuleConfig } from '../types-internal/module-config';
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
|
@ -8,28 +8,29 @@ import {ModuleConfig} from '../types-internal/module-config';
|
|||
* @classdesc All modules inherits from this class.
|
||||
*
|
||||
* @typedef {Module} Module
|
||||
* @property {Object} config - Editor user settings
|
||||
* @property {object} config - Editor user settings
|
||||
* @property {EditorModules} Editor - List of Editor modules
|
||||
*/
|
||||
export default class Module {
|
||||
|
||||
/**
|
||||
* Editor modules list
|
||||
*
|
||||
* @type {EditorModules}
|
||||
*/
|
||||
protected Editor: EditorModules;
|
||||
|
||||
/**
|
||||
* Editor configuration object
|
||||
*
|
||||
* @type {EditorConfig}
|
||||
*/
|
||||
protected config: EditorConfig;
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @class
|
||||
* @param {EditorConfig}
|
||||
*/
|
||||
constructor({config}: ModuleConfig) {
|
||||
constructor({ config }: ModuleConfig) {
|
||||
if (new.target === Module) {
|
||||
throw new TypeError('Constructors for abstract class Module are not allowed.');
|
||||
}
|
||||
|
@ -39,6 +40,7 @@ export default class Module {
|
|||
|
||||
/**
|
||||
* Editor modules setter
|
||||
*
|
||||
* @param {EditorModules} Editor
|
||||
*/
|
||||
set state(Editor: EditorModules) {
|
||||
|
|
|
@ -4,13 +4,16 @@
|
|||
*
|
||||
* @copyright <CodeX Team> 2018
|
||||
*/
|
||||
import {API, BlockTune} from '../../../types';
|
||||
import { API, BlockTune } from '../../../types';
|
||||
import $ from '../dom';
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export default class DeleteTune implements BlockTune {
|
||||
|
||||
/**
|
||||
* Property that contains Editor.js API methods
|
||||
*
|
||||
* @see {docs/api.md}
|
||||
*/
|
||||
private readonly api: API;
|
||||
|
@ -46,7 +49,7 @@ export default class DeleteTune implements BlockTune {
|
|||
*
|
||||
* @param {{api: API}} api
|
||||
*/
|
||||
constructor({api}) {
|
||||
constructor({ api }) {
|
||||
this.api = api;
|
||||
|
||||
this.resetConfirmation = () => {
|
||||
|
@ -56,6 +59,7 @@ export default class DeleteTune implements BlockTune {
|
|||
|
||||
/**
|
||||
* Create "Delete" button and add click event listener
|
||||
*
|
||||
* @returns [Element}
|
||||
*/
|
||||
public render() {
|
||||
|
@ -73,10 +77,10 @@ export default class DeleteTune implements BlockTune {
|
|||
|
||||
/**
|
||||
* Delete block conditions passed
|
||||
*
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
public handleClick(event: MouseEvent): void {
|
||||
|
||||
/**
|
||||
* if block is not waiting the confirmation, subscribe on block-settings-closing event to reset
|
||||
* otherwise delete block
|
||||
|
@ -90,9 +94,7 @@ export default class DeleteTune implements BlockTune {
|
|||
* then reset confirmation state
|
||||
*/
|
||||
this.api.events.on('block-settings-closed', this.resetConfirmation);
|
||||
|
||||
} else {
|
||||
|
||||
/**
|
||||
* Unsubscribe from block-settings closing event
|
||||
*/
|
||||
|
@ -111,10 +113,11 @@ export default class DeleteTune implements BlockTune {
|
|||
|
||||
/**
|
||||
* change tune state
|
||||
*
|
||||
* @param state
|
||||
*/
|
||||
private setConfirmation(state): void {
|
||||
this.needConfirmation = state;
|
||||
this.nodes.button.classList.add(this.CSS.buttonConfirm);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,17 +6,22 @@
|
|||
*/
|
||||
|
||||
import $ from '../dom';
|
||||
import {API, BlockTune} from '../../../types';
|
||||
import { API, BlockTune } from '../../../types';
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export default class MoveDownTune implements BlockTune {
|
||||
/**
|
||||
* Property that contains Editor.js API methods
|
||||
*
|
||||
* @see {api.md}
|
||||
*/
|
||||
private readonly api: API;
|
||||
|
||||
/**
|
||||
* Styles
|
||||
*
|
||||
* @type {{wrapper: string}}
|
||||
*/
|
||||
private CSS = {
|
||||
|
@ -30,7 +35,7 @@ export default class MoveDownTune implements BlockTune {
|
|||
*
|
||||
* @param {{api: API}} api
|
||||
*/
|
||||
public constructor({api}) {
|
||||
constructor({ api }) {
|
||||
this.api = api;
|
||||
}
|
||||
|
||||
|
@ -39,12 +44,13 @@ export default class MoveDownTune implements BlockTune {
|
|||
*/
|
||||
public render() {
|
||||
const moveDownButton = $.make('div', [this.CSS.button, this.CSS.wrapper], {});
|
||||
|
||||
moveDownButton.appendChild($.svg('arrow-down', 14, 14));
|
||||
this.api.listeners.on(
|
||||
moveDownButton,
|
||||
'click',
|
||||
(event) => this.handleClick(event as MouseEvent, moveDownButton),
|
||||
false,
|
||||
false
|
||||
);
|
||||
|
||||
/**
|
||||
|
@ -57,20 +63,21 @@ export default class MoveDownTune implements BlockTune {
|
|||
|
||||
/**
|
||||
* Handle clicks on 'move down' button
|
||||
*
|
||||
* @param {MouseEvent} event
|
||||
* @param {HTMLElement} button
|
||||
*/
|
||||
public handleClick(event: MouseEvent, button: HTMLElement) {
|
||||
|
||||
const currentBlockIndex = this.api.blocks.getCurrentBlockIndex();
|
||||
|
||||
// If Block is last do nothing
|
||||
if (currentBlockIndex === this.api.blocks.getBlocksCount() - 1) {
|
||||
button.classList.add(this.CSS.animation);
|
||||
|
||||
window.setTimeout( () => {
|
||||
window.setTimeout(() => {
|
||||
button.classList.remove(this.CSS.animation);
|
||||
}, 500);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -84,9 +91,7 @@ export default class MoveDownTune implements BlockTune {
|
|||
* Increment scroll by next block's height to save element onscreen-position
|
||||
*/
|
||||
if (nextBlockCoords.top < window.innerHeight) {
|
||||
|
||||
scrollOffset = window.scrollY + nextBlockElement.offsetHeight;
|
||||
|
||||
}
|
||||
|
||||
window.scrollTo(0, scrollOffset);
|
||||
|
|
|
@ -5,18 +5,22 @@
|
|||
* @copyright <CodeX Team> 2018
|
||||
*/
|
||||
import $ from '../dom';
|
||||
import {API, BlockTune} from '../../../types';
|
||||
import { API, BlockTune } from '../../../types';
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export default class MoveUpTune implements BlockTune {
|
||||
|
||||
/**
|
||||
* Property that contains Editor.js API methods
|
||||
*
|
||||
* @see {api.md}
|
||||
*/
|
||||
private readonly api: API;
|
||||
|
||||
/**
|
||||
* Styles
|
||||
*
|
||||
* @type {{wrapper: string}}
|
||||
*/
|
||||
private CSS = {
|
||||
|
@ -30,22 +34,24 @@ export default class MoveUpTune implements BlockTune {
|
|||
*
|
||||
* @param {{api: API}} api
|
||||
*/
|
||||
public constructor({api}) {
|
||||
constructor({ api }) {
|
||||
this.api = api;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create "MoveUp" button and add click event listener
|
||||
*
|
||||
* @returns [HTMLElement}
|
||||
*/
|
||||
public render(): HTMLElement {
|
||||
const moveUpButton = $.make('div', [this.CSS.button, this.CSS.wrapper], {});
|
||||
|
||||
moveUpButton.appendChild($.svg('arrow-up', 14, 14));
|
||||
this.api.listeners.on(
|
||||
moveUpButton,
|
||||
'click',
|
||||
(event) => this.handleClick(event as MouseEvent, moveUpButton),
|
||||
false,
|
||||
false
|
||||
);
|
||||
|
||||
/**
|
||||
|
@ -58,19 +64,20 @@ export default class MoveUpTune implements BlockTune {
|
|||
|
||||
/**
|
||||
* Move current block up
|
||||
*
|
||||
* @param {MouseEvent} event
|
||||
* @param {HTMLElement} button
|
||||
*/
|
||||
public handleClick(event: MouseEvent, button: HTMLElement): void {
|
||||
|
||||
const currentBlockIndex = this.api.blocks.getCurrentBlockIndex();
|
||||
|
||||
if (currentBlockIndex === 0) {
|
||||
button.classList.add(this.CSS.animation);
|
||||
|
||||
window.setTimeout( () => {
|
||||
window.setTimeout(() => {
|
||||
button.classList.remove(this.CSS.animation);
|
||||
}, 500);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -86,7 +93,7 @@ export default class MoveUpTune implements BlockTune {
|
|||
* than we scroll window to the difference between this offsets.
|
||||
*/
|
||||
const currentBlockCoords = currentBlockElement.getBoundingClientRect(),
|
||||
previousBlockCoords = previousBlockElement.getBoundingClientRect();
|
||||
previousBlockCoords = previousBlockElement.getBoundingClientRect();
|
||||
|
||||
let scrollUpOffset;
|
||||
|
||||
|
|
|
@ -6,10 +6,10 @@ import {
|
|||
BlockTune,
|
||||
BlockTuneConstructable,
|
||||
SanitizerConfig,
|
||||
ToolConfig,
|
||||
ToolConfig
|
||||
} from '../../types';
|
||||
|
||||
import {SavedData} from '../types-internal/block-data';
|
||||
import { SavedData } from '../types-internal/block-data';
|
||||
import $ from './dom';
|
||||
import * as _ from './utils';
|
||||
|
||||
|
@ -18,7 +18,7 @@ import * as _ from './utils';
|
|||
* @classdesc This class describes editor`s block, including block`s HTMLElement, data and tool
|
||||
*
|
||||
* @property {BlockTool} tool — current block tool (Paragraph, for example)
|
||||
* @property {Object} CSS — block`s css classes
|
||||
* @property {object} CSS — block`s css classes
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -53,10 +53,10 @@ export enum BlockToolAPI {
|
|||
* @property pluginsContent - HTML content that returns by Tool's render function
|
||||
*/
|
||||
export default class Block {
|
||||
|
||||
/**
|
||||
* CSS classes for the Block
|
||||
* @return {{wrapper: string, content: string}}
|
||||
*
|
||||
* @returns {{wrapper: string, content: string}}
|
||||
*/
|
||||
static get CSS() {
|
||||
return {
|
||||
|
@ -85,8 +85,8 @@ export default class Block {
|
|||
const content = this.holder;
|
||||
const allowedInputTypes = ['text', 'password', 'email', 'number', 'search', 'tel', 'url'];
|
||||
|
||||
const selector = '[contenteditable], textarea, input:not([type]), '
|
||||
+ allowedInputTypes.map((type) => `input[type="${type}"]`).join(', ');
|
||||
const selector = '[contenteditable], textarea, input:not([type]), ' +
|
||||
allowedInputTypes.map((type) => `input[type="${type}"]`).join(', ');
|
||||
|
||||
let inputs = _.array(content.querySelectorAll(selector));
|
||||
|
||||
|
@ -178,7 +178,8 @@ export default class Block {
|
|||
|
||||
/**
|
||||
* Returns Plugins content
|
||||
* @return {HTMLElement}
|
||||
*
|
||||
* @returns {HTMLElement}
|
||||
*/
|
||||
get pluginsContent(): HTMLElement {
|
||||
const blockContentNodes = this.holder.querySelector(`.${Block.CSS.content}`);
|
||||
|
@ -202,7 +203,8 @@ export default class Block {
|
|||
|
||||
/**
|
||||
* Get Block's JSON data
|
||||
* @return {Object}
|
||||
*
|
||||
* @returns {object}
|
||||
*/
|
||||
get data(): BlockToolData {
|
||||
return this.save().then((savedObject) => {
|
||||
|
@ -216,7 +218,8 @@ export default class Block {
|
|||
|
||||
/**
|
||||
* Returns tool's sanitizer config
|
||||
* @return {object}
|
||||
*
|
||||
* @returns {object}
|
||||
*/
|
||||
get sanitize(): SanitizerConfig {
|
||||
return this.tool.sanitize;
|
||||
|
@ -225,7 +228,8 @@ export default class Block {
|
|||
/**
|
||||
* is block mergeable
|
||||
* We plugin have merge function then we call it mergable
|
||||
* @return {boolean}
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
get mergeable(): boolean {
|
||||
return typeof this.tool.merge === 'function';
|
||||
|
@ -233,7 +237,8 @@ export default class Block {
|
|||
|
||||
/**
|
||||
* Check block for emptiness
|
||||
* @return {Boolean}
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
get isEmpty(): boolean {
|
||||
const emptyText = $.isEmpty(this.pluginsContent);
|
||||
|
@ -244,11 +249,13 @@ export default class Block {
|
|||
|
||||
/**
|
||||
* Check if block has a media content such as images, iframes and other
|
||||
* @return {Boolean}
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
get hasMedia(): boolean {
|
||||
/**
|
||||
* This tags represents media-content
|
||||
*
|
||||
* @type {string[]}
|
||||
*/
|
||||
const mediaTags = [
|
||||
|
@ -267,7 +274,8 @@ export default class Block {
|
|||
|
||||
/**
|
||||
* Set focused state
|
||||
* @param {Boolean} state - 'true' to select, 'false' to remove selection
|
||||
*
|
||||
* @param {boolean} state - 'true' to select, 'false' to remove selection
|
||||
*/
|
||||
set focused(state: boolean) {
|
||||
this.holder.classList.toggle(Block.CSS.focused, state);
|
||||
|
@ -276,7 +284,8 @@ export default class Block {
|
|||
/**
|
||||
* Set selected state
|
||||
* We don't need to mark Block as Selected when it is empty
|
||||
* @param {Boolean} state - 'true' to select, 'false' to remove selection
|
||||
*
|
||||
* @param {boolean} state - 'true' to select, 'false' to remove selection
|
||||
*/
|
||||
set selected(state: boolean) {
|
||||
if (state) {
|
||||
|
@ -288,7 +297,8 @@ export default class Block {
|
|||
|
||||
/**
|
||||
* Returns True if it is Selected
|
||||
* @return {boolean}
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
get selected(): boolean {
|
||||
return this.holder.classList.contains(Block.CSS.selected);
|
||||
|
@ -296,7 +306,8 @@ export default class Block {
|
|||
|
||||
/**
|
||||
* Set stretched state
|
||||
* @param {Boolean} state - 'true' to enable, 'false' to disable stretched statte
|
||||
*
|
||||
* @param {boolean} state - 'true' to enable, 'false' to disable stretched statte
|
||||
*/
|
||||
set stretched(state: boolean) {
|
||||
this.holder.classList.toggle(Block.CSS.wrapperStretched, state);
|
||||
|
@ -304,6 +315,7 @@ export default class Block {
|
|||
|
||||
/**
|
||||
* Toggle drop target state
|
||||
*
|
||||
* @param {boolean} state
|
||||
*/
|
||||
public set dropTarget(state) {
|
||||
|
@ -342,6 +354,7 @@ export default class Block {
|
|||
|
||||
/**
|
||||
* Cached inputs
|
||||
*
|
||||
* @type {HTMLElement[]}
|
||||
*/
|
||||
private cachedInputs: HTMLElement[] = [];
|
||||
|
@ -353,18 +366,21 @@ export default class Block {
|
|||
|
||||
/**
|
||||
* Focused input index
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
private inputIndex = 0;
|
||||
|
||||
/**
|
||||
* Mutation observer to handle DOM mutations
|
||||
*
|
||||
* @type {MutationObserver}
|
||||
*/
|
||||
private mutationObserver: MutationObserver;
|
||||
|
||||
/**
|
||||
* Debounce Timer
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
private readonly modificationDebounceTimer = 450;
|
||||
|
@ -387,19 +403,19 @@ export default class Block {
|
|||
}, this.modificationDebounceTimer);
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param {String} toolName - Tool name that passed on initialization
|
||||
* @param {Object} toolInstance — passed Tool`s instance that rendered the Block
|
||||
* @param {Object} toolClass — Tool's class
|
||||
* @param {Object} settings - default settings
|
||||
* @param {Object} apiMethods - Editor API
|
||||
* @class
|
||||
* @param {string} toolName - Tool name that passed on initialization
|
||||
* @param {object} toolInstance — passed Tool`s instance that rendered the Block
|
||||
* @param {object} toolClass — Tool's class
|
||||
* @param {object} settings - default settings
|
||||
* @param {object} apiMethods - Editor API
|
||||
*/
|
||||
constructor(
|
||||
toolName: string,
|
||||
toolInstance: BlockTool,
|
||||
toolClass: BlockToolConstructable,
|
||||
settings: ToolConfig,
|
||||
apiMethods: API,
|
||||
apiMethods: API
|
||||
) {
|
||||
this.name = toolName;
|
||||
this.tool = toolInstance;
|
||||
|
@ -421,8 +437,8 @@ export default class Block {
|
|||
*
|
||||
* Method checks tool property {MethodName}. Fires method with passes params If it is instance of Function
|
||||
*
|
||||
* @param {String} methodName
|
||||
* @param {Object} params
|
||||
* @param {string} methodName
|
||||
* @param {object} params
|
||||
*/
|
||||
public call(methodName: string, params?: object) {
|
||||
/**
|
||||
|
@ -430,6 +446,7 @@ export default class Block {
|
|||
*/
|
||||
if (this.tool[methodName] && this.tool[methodName] instanceof Function) {
|
||||
try {
|
||||
// eslint-disable-next-line no-useless-call
|
||||
this.tool[methodName].call(this.tool, params);
|
||||
} catch (e) {
|
||||
_.log(`Error during '${methodName}' call: ${e.message}`, 'error');
|
||||
|
@ -439,15 +456,18 @@ export default class Block {
|
|||
|
||||
/**
|
||||
* Call plugins merge method
|
||||
* @param {Object} data
|
||||
*
|
||||
* @param {object} data
|
||||
*/
|
||||
public async mergeWith(data: BlockToolData): Promise<void> {
|
||||
await this.tool.merge(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts data from Block
|
||||
* Groups Tool's save processing time
|
||||
* @return {Object}
|
||||
*
|
||||
* @returns {object}
|
||||
*/
|
||||
public async save(): Promise<void|SavedData> {
|
||||
const extractedBlock = await this.tool.save(this.pluginsContent as HTMLElement);
|
||||
|
@ -496,14 +516,15 @@ export default class Block {
|
|||
/**
|
||||
* Make an array with default settings
|
||||
* Each block has default tune instance that have states
|
||||
* @return {BlockTune[]}
|
||||
*
|
||||
* @returns {BlockTune[]}
|
||||
*/
|
||||
public makeTunes(): BlockTune[] {
|
||||
const tunesList = [MoveUpTune, DeleteTune, MoveDownTune];
|
||||
|
||||
// Pluck tunes list and return tune instances with passed Editor API and settings
|
||||
return tunesList.map( (tune: BlockTuneConstructable) => {
|
||||
return new tune({
|
||||
return tunesList.map((Tune: BlockTuneConstructable) => {
|
||||
return new Tune({
|
||||
api: this.api,
|
||||
settings: this.settings,
|
||||
});
|
||||
|
@ -512,12 +533,13 @@ export default class Block {
|
|||
|
||||
/**
|
||||
* Enumerates initialized tunes and returns fragment that can be appended to the toolbars area
|
||||
* @return {DocumentFragment}
|
||||
*
|
||||
* @returns {DocumentFragment}
|
||||
*/
|
||||
public renderTunes(): DocumentFragment {
|
||||
const tunesElement = document.createDocumentFragment();
|
||||
|
||||
this.tunes.forEach( (tune) => {
|
||||
this.tunes.forEach((tune) => {
|
||||
$.append(tunesElement, tune.render());
|
||||
});
|
||||
|
||||
|
@ -545,7 +567,7 @@ export default class Block {
|
|||
subtree: true,
|
||||
characterData: true,
|
||||
attributes: true,
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -558,15 +580,17 @@ export default class Block {
|
|||
|
||||
/**
|
||||
* Make default Block wrappers and put Tool`s content there
|
||||
*
|
||||
* @returns {HTMLDivElement}
|
||||
*/
|
||||
private compose(): HTMLDivElement {
|
||||
const wrapper = $.make('div', Block.CSS.wrapper) as HTMLDivElement,
|
||||
contentNode = $.make('div', Block.CSS.content),
|
||||
pluginsContent = this.tool.render();
|
||||
contentNode = $.make('div', Block.CSS.content),
|
||||
pluginsContent = this.tool.render();
|
||||
|
||||
contentNode.appendChild(pluginsContent);
|
||||
wrapper.appendChild(contentNode);
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import * as _ from './utils';
|
||||
import $ from './dom';
|
||||
import Block, { BlockToolAPI } from './block';
|
||||
import {MoveEvent, MoveEventDetail} from '../../types/tools';
|
||||
import { MoveEvent, MoveEventDetail } from '../../types/tools';
|
||||
|
||||
/**
|
||||
* @class Blocks
|
||||
|
@ -16,7 +16,7 @@ export default class Blocks {
|
|||
/**
|
||||
* Get length of Block instances array
|
||||
*
|
||||
* @returns {Number}
|
||||
* @returns {number}
|
||||
*/
|
||||
public get length(): number {
|
||||
return this.blocks.length;
|
||||
|
@ -47,17 +47,17 @@ export default class Blocks {
|
|||
* blocks[0] = new Block(...)
|
||||
*
|
||||
* @param {Blocks} instance — Blocks instance
|
||||
* @param {Number|String} property — block index or any Blocks class property to set
|
||||
* @param {number|string} property — block index or any Blocks class property to set
|
||||
* @param {Block} value — value to set
|
||||
* @returns {Boolean}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public static set(instance: Blocks, property: number | string, value: Block | any) {
|
||||
|
||||
/**
|
||||
* If property name is not a number (method or other property, access it via reflect
|
||||
*/
|
||||
if (isNaN(Number(property))) {
|
||||
Reflect.set(instance, property, value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -76,11 +76,10 @@ export default class Blocks {
|
|||
* Proxy trap to implement array-like getter
|
||||
*
|
||||
* @param {Blocks} instance — Blocks instance
|
||||
* @param {Number|String} property — Blocks class property
|
||||
* @param {number|string} property — Blocks class property
|
||||
* @returns {Block|*}
|
||||
*/
|
||||
public static get(instance: Blocks, property: any | number) {
|
||||
|
||||
/**
|
||||
* If property is not a number, get it via Reflect object
|
||||
*/
|
||||
|
@ -105,7 +104,7 @@ export default class Blocks {
|
|||
public workingArea: HTMLElement;
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @class
|
||||
*
|
||||
* @param {HTMLElement} workingArea — editor`s working node
|
||||
*/
|
||||
|
@ -126,8 +125,9 @@ export default class Blocks {
|
|||
|
||||
/**
|
||||
* Swaps blocks with indexes first and second
|
||||
* @param {Number} first - first block index
|
||||
* @param {Number} second - second block index
|
||||
*
|
||||
* @param {number} first - first block index
|
||||
* @param {number} second - second block index
|
||||
* @deprecated — use 'move' instead
|
||||
*/
|
||||
public swap(first: number, second: number): void {
|
||||
|
@ -147,13 +147,15 @@ export default class Blocks {
|
|||
|
||||
/**
|
||||
* Move a block from one to another index
|
||||
* @param {Number} toIndex - new index of the block
|
||||
* @param {Number} fromIndex - block to move
|
||||
*
|
||||
* @param {number} toIndex - new index of the block
|
||||
* @param {number} fromIndex - block to move
|
||||
*/
|
||||
public move(toIndex: number, fromIndex: number): void {
|
||||
/**
|
||||
* cut out the block, move the DOM element and insert at the desired index
|
||||
* again (the shifting within the blocks array will happen automatically).
|
||||
*
|
||||
* @see https://stackoverflow.com/a/44932690/1238150
|
||||
*/
|
||||
const block = this.blocks.splice(fromIndex, 1)[0];
|
||||
|
@ -184,13 +186,14 @@ export default class Blocks {
|
|||
/**
|
||||
* Insert new Block at passed index
|
||||
*
|
||||
* @param {Number} index — index to insert Block
|
||||
* @param {number} index — index to insert Block
|
||||
* @param {Block} block — Block to insert
|
||||
* @param {Boolean} replace — it true, replace block on given index
|
||||
* @param {boolean} replace — it true, replace block on given index
|
||||
*/
|
||||
public insert(index: number, block: Block, replace: boolean = false): void {
|
||||
public insert(index: number, block: Block, replace = false): void {
|
||||
if (!this.length) {
|
||||
this.push(block);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -224,7 +227,8 @@ export default class Blocks {
|
|||
|
||||
/**
|
||||
* Remove block
|
||||
* @param {Number|null} index
|
||||
*
|
||||
* @param {number|null} index
|
||||
*/
|
||||
public remove(index: number): void {
|
||||
if (isNaN(index)) {
|
||||
|
@ -266,7 +270,7 @@ export default class Blocks {
|
|||
/**
|
||||
* Get Block by index
|
||||
*
|
||||
* @param {Number} index — Block index
|
||||
* @param {number} index — Block index
|
||||
* @returns {Block}
|
||||
*/
|
||||
public get(index: number): Block {
|
||||
|
@ -277,7 +281,7 @@ export default class Blocks {
|
|||
* Return index of passed Block
|
||||
*
|
||||
* @param {Block} block
|
||||
* @returns {Number}
|
||||
* @returns {number}
|
||||
*/
|
||||
public indexOf(block: Block): number {
|
||||
return this.blocks.indexOf(block);
|
||||
|
@ -303,13 +307,13 @@ export default class Blocks {
|
|||
/**
|
||||
* Composes Block event with passed type and details
|
||||
*
|
||||
* @param {String} type
|
||||
* @param {string} type
|
||||
* @param {MoveEventDetail} detail
|
||||
*/
|
||||
private composeBlockEvent(type: string, detail: MoveEventDetail): MoveEvent {
|
||||
return new CustomEvent(type, {
|
||||
detail,
|
||||
},
|
||||
detail,
|
||||
}
|
||||
) as MoveEvent;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import $ from './dom';
|
||||
import * as _ from './utils';
|
||||
import {EditorConfig, OutputData, SanitizerConfig} from '../../types';
|
||||
import {EditorModules} from '../types-internal/editor-modules';
|
||||
import {LogLevels} from './utils';
|
||||
import { EditorConfig, OutputData, SanitizerConfig } from '../../types';
|
||||
import { EditorModules } from '../types-internal/editor-modules';
|
||||
import { LogLevels } from './utils';
|
||||
|
||||
/**
|
||||
* @typedef {Core} Core - editor core class
|
||||
|
@ -37,7 +37,6 @@ contextRequire.keys().forEach((filename) => {
|
|||
* @type {Core}
|
||||
*/
|
||||
export default class Core {
|
||||
|
||||
/**
|
||||
* Editor configuration passed by user to the constructor
|
||||
*/
|
||||
|
@ -82,7 +81,7 @@ export default class Core {
|
|||
await this.render();
|
||||
|
||||
if ((this.configuration as EditorConfig).autofocus) {
|
||||
const {BlockManager, Caret} = this.moduleInstances;
|
||||
const { BlockManager, Caret } = this.moduleInstances;
|
||||
|
||||
Caret.setToBlock(BlockManager.blocks[0], Caret.positions.START);
|
||||
}
|
||||
|
@ -110,6 +109,7 @@ export default class Core {
|
|||
|
||||
/**
|
||||
* Setting for configuration
|
||||
*
|
||||
* @param {EditorConfig|string|undefined} config
|
||||
*/
|
||||
set configuration(config: EditorConfig|string) {
|
||||
|
@ -134,6 +134,7 @@ export default class Core {
|
|||
|
||||
/**
|
||||
* Place config into the class property
|
||||
*
|
||||
* @type {EditorConfig}
|
||||
*/
|
||||
this.config = config;
|
||||
|
@ -158,18 +159,20 @@ export default class Core {
|
|||
|
||||
/**
|
||||
* Height of Editor's bottom area that allows to set focus on the last Block
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
this.config.minHeight = this.config.minHeight !== undefined ? this.config.minHeight : 300 ;
|
||||
this.config.minHeight = this.config.minHeight !== undefined ? this.config.minHeight : 300;
|
||||
|
||||
/**
|
||||
* Initial block type
|
||||
* Uses in case when there is no blocks passed
|
||||
*
|
||||
* @type {{type: (*), data: {text: null}}}
|
||||
*/
|
||||
const initialBlockData = {
|
||||
type : this.config.initialBlock,
|
||||
data : {},
|
||||
type: this.config.initialBlock,
|
||||
data: {},
|
||||
};
|
||||
|
||||
this.config.placeholder = this.config.placeholder || false;
|
||||
|
@ -200,6 +203,7 @@ export default class Core {
|
|||
|
||||
/**
|
||||
* Returns private property
|
||||
*
|
||||
* @returns {EditorConfig}
|
||||
*/
|
||||
get configuration(): EditorConfig|string {
|
||||
|
@ -208,6 +212,7 @@ export default class Core {
|
|||
|
||||
/**
|
||||
* Checks for required fields in Editor's config
|
||||
*
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
public async validate(): Promise<void> {
|
||||
|
@ -250,7 +255,8 @@ export default class Core {
|
|||
* Start Editor!
|
||||
*
|
||||
* Get list of modules that needs to be prepared and return a sequence (Promise)
|
||||
* @return {Promise}
|
||||
*
|
||||
* @returns {Promise}
|
||||
*/
|
||||
public async start() {
|
||||
const modulesToPrepare = [
|
||||
|
@ -275,7 +281,7 @@ export default class Core {
|
|||
}
|
||||
// _.log(`Preparing ${module} module`, 'timeEnd');
|
||||
}),
|
||||
Promise.resolve(),
|
||||
Promise.resolve()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -290,26 +296,26 @@ export default class Core {
|
|||
* Make modules instances and save it to the @property this.moduleInstances
|
||||
*/
|
||||
private constructModules(): void {
|
||||
modules.forEach( (module) => {
|
||||
modules.forEach((module) => {
|
||||
/**
|
||||
* If module has non-default exports, passed object contains them all and default export as 'default' property
|
||||
*/
|
||||
const Module = typeof module === 'function' ? module : module.default;
|
||||
|
||||
try {
|
||||
|
||||
/**
|
||||
* We use class name provided by displayName property
|
||||
*
|
||||
* On build, Babel will transform all Classes to the Functions so, name will always be 'Function'
|
||||
* To prevent this, we use 'babel-plugin-class-display-name' plugin
|
||||
*
|
||||
* @see https://www.npmjs.com/package/babel-plugin-class-display-name
|
||||
*/
|
||||
this.moduleInstances[Module.displayName] = new Module({
|
||||
config : this.configuration,
|
||||
config: this.configuration,
|
||||
});
|
||||
} catch ( e ) {
|
||||
_.log(`Module ${Module.displayName} skipped because`, 'warn', e);
|
||||
} catch (e) {
|
||||
_.log(`Module ${Module.displayName} skipped because`, 'warn', e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -332,6 +338,7 @@ export default class Core {
|
|||
|
||||
/**
|
||||
* Return modules without passed name
|
||||
*
|
||||
* @param {string} name - module for witch modules difference should be calculated
|
||||
*/
|
||||
private getModulesDiff(name: string): EditorModules {
|
||||
|
|
|
@ -4,8 +4,9 @@
|
|||
export default class Dom {
|
||||
/**
|
||||
* Check if passed tag has no closed tag
|
||||
*
|
||||
* @param {HTMLElement} tag
|
||||
* @return {Boolean}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public static isSingleTag(tag: HTMLElement): boolean {
|
||||
return tag.tagName && [
|
||||
|
@ -32,7 +33,7 @@ export default class Dom {
|
|||
* Check if element is BR or WBR
|
||||
*
|
||||
* @param {HTMLElement} element
|
||||
* @return {boolean}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public static isLineBreakTag(element: HTMLElement) {
|
||||
return element && element.tagName && [
|
||||
|
@ -45,16 +46,16 @@ export default class Dom {
|
|||
* Helper for making Elements with classname and attributes
|
||||
*
|
||||
* @param {string} tagName - new Element tag name
|
||||
* @param {array|string} classNames - list or name of CSS classname(s)
|
||||
* @param {Object} attributes - any attributes
|
||||
* @return {HTMLElement}
|
||||
* @param {Array|string} classNames - list or name of CSS classname(s)
|
||||
* @param {object} attributes - any attributes
|
||||
* @returns {HTMLElement}
|
||||
*/
|
||||
public static make(tagName: string, classNames: string|string[] = null, attributes: object = {}): HTMLElement {
|
||||
const el = document.createElement(tagName);
|
||||
|
||||
if ( Array.isArray(classNames) ) {
|
||||
if (Array.isArray(classNames)) {
|
||||
el.classList.add(...classNames);
|
||||
} else if ( classNames ) {
|
||||
} else if (classNames) {
|
||||
el.classList.add(classNames);
|
||||
}
|
||||
|
||||
|
@ -69,8 +70,9 @@ export default class Dom {
|
|||
|
||||
/**
|
||||
* Creates Text Node with the passed content
|
||||
* @param {String} content - text content
|
||||
* @return {Text}
|
||||
*
|
||||
* @param {string} content - text content
|
||||
* @returns {Text}
|
||||
*/
|
||||
public static text(content: string): Text {
|
||||
return document.createTextNode(content);
|
||||
|
@ -78,12 +80,13 @@ export default class Dom {
|
|||
|
||||
/**
|
||||
* Creates SVG icon linked to the sprite
|
||||
*
|
||||
* @param {string} name - name (id) of icon from sprite
|
||||
* @param {number} width
|
||||
* @param {number} height
|
||||
* @return {SVGElement}
|
||||
* @returns {SVGElement}
|
||||
*/
|
||||
public static svg(name: string, width: number = 14, height: number = 14): SVGElement {
|
||||
public static svg(name: string, width = 14, height = 14): SVGElement {
|
||||
const icon = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
||||
|
||||
icon.classList.add('icon', 'icon--' + name);
|
||||
|
@ -102,10 +105,10 @@ export default class Dom {
|
|||
*/
|
||||
public static append(
|
||||
parent: Element|DocumentFragment,
|
||||
elements: Element|Element[]|DocumentFragment|Text|Text[],
|
||||
elements: Element|Element[]|DocumentFragment|Text|Text[]
|
||||
): void {
|
||||
if ( Array.isArray(elements) ) {
|
||||
elements.forEach( (el) => parent.appendChild(el) );
|
||||
if (Array.isArray(elements)) {
|
||||
elements.forEach((el) => parent.appendChild(el));
|
||||
} else {
|
||||
parent.appendChild(elements);
|
||||
}
|
||||
|
@ -118,9 +121,9 @@ export default class Dom {
|
|||
* @param {Element|Element[]} elements - element or elements list
|
||||
*/
|
||||
public static prepend(parent: Element, elements: Element|Element[]): void {
|
||||
if ( Array.isArray(elements) ) {
|
||||
if (Array.isArray(elements)) {
|
||||
elements = elements.reverse();
|
||||
elements.forEach( (el) => parent.prepend(el) );
|
||||
elements.forEach((el) => parent.prepend(el));
|
||||
} else {
|
||||
parent.prepend(elements);
|
||||
}
|
||||
|
@ -128,6 +131,7 @@ export default class Dom {
|
|||
|
||||
/**
|
||||
* Swap two elements in parent
|
||||
*
|
||||
* @param {HTMLElement} el1 - from
|
||||
* @param {HTMLElement} el2 - to
|
||||
* @deprecated
|
||||
|
@ -135,7 +139,7 @@ export default class Dom {
|
|||
public static swap(el1: HTMLElement, el2: HTMLElement): void {
|
||||
// create marker element and insert it where el1 is
|
||||
const temp = document.createElement('div'),
|
||||
parent = el1.parentNode;
|
||||
parent = el1.parentNode;
|
||||
|
||||
parent.insertBefore(temp, el1);
|
||||
|
||||
|
@ -155,7 +159,7 @@ export default class Dom {
|
|||
* Returns first match
|
||||
*
|
||||
* @param {Element} el - element we searching inside. Default - DOM Document
|
||||
* @param {String} selector - searching string
|
||||
* @param {string} selector - searching string
|
||||
*
|
||||
* @returns {Element}
|
||||
*/
|
||||
|
@ -179,7 +183,7 @@ export default class Dom {
|
|||
* Returns all matches
|
||||
*
|
||||
* @param {Element} el - element we searching inside. Default - DOM Document
|
||||
* @param {String} selector - searching string
|
||||
* @param {string} selector - searching string
|
||||
* @returns {NodeList}
|
||||
*/
|
||||
public static findAll(el: Element|Document = document, selector: string): NodeList {
|
||||
|
@ -194,18 +198,19 @@ export default class Dom {
|
|||
*
|
||||
* @param {Node} node - root Node. From this vertex we start Deep-first search
|
||||
* {@link https://en.wikipedia.org/wiki/Depth-first_search}
|
||||
* @param {Boolean} atLast - find last text node
|
||||
* @return {Node} - it can be text Node or Element Node, so that caret will able to work with it
|
||||
* @param {boolean} atLast - find last text node
|
||||
* @returns {Node} - it can be text Node or Element Node, so that caret will able to work with it
|
||||
*/
|
||||
public static getDeepestNode(node: Node, atLast: boolean = false): Node {
|
||||
public static getDeepestNode(node: Node, atLast = false): Node {
|
||||
/**
|
||||
* Current function have two directions:
|
||||
* - starts from first child and every time gets first or nextSibling in special cases
|
||||
* - starts from last child and gets last or previousSibling
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
const child = atLast ? 'lastChild' : 'firstChild',
|
||||
sibling = atLast ? 'previousSibling' : 'nextSibling';
|
||||
sibling = atLast ? 'previousSibling' : 'nextSibling';
|
||||
|
||||
if (node && node.nodeType === Node.ELEMENT_NODE && node[child]) {
|
||||
let nodeChild = node[child] as Node;
|
||||
|
@ -245,7 +250,7 @@ export default class Dom {
|
|||
/**
|
||||
* Check if object is DOM node
|
||||
*
|
||||
* @param {Object} node
|
||||
* @param {object} node
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public static isElement(node: any): node is Element {
|
||||
|
@ -255,7 +260,7 @@ export default class Dom {
|
|||
/**
|
||||
* Check if object is DocumentFragmemt node
|
||||
*
|
||||
* @param {Object} node
|
||||
* @param {object} node
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public static isFragment(node: any): boolean {
|
||||
|
@ -264,8 +269,9 @@ export default class Dom {
|
|||
|
||||
/**
|
||||
* Check if passed element is contenteditable
|
||||
*
|
||||
* @param {HTMLElement} element
|
||||
* @return {boolean}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public static isContentEditable(element: HTMLElement): boolean {
|
||||
return element.contentEditable === 'true';
|
||||
|
@ -273,8 +279,9 @@ export default class Dom {
|
|||
|
||||
/**
|
||||
* Checks target if it is native input
|
||||
* @param {Element|String|Node} target - HTML element or string
|
||||
* @return {Boolean}
|
||||
*
|
||||
* @param {Element|string|Node} target - HTML element or string
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public static isNativeInput(target: any): boolean {
|
||||
const nativeInputs = [
|
||||
|
@ -287,13 +294,16 @@ export default class Dom {
|
|||
|
||||
/**
|
||||
* Checks if we can set caret
|
||||
*
|
||||
* @param {HTMLElement} target
|
||||
* @return {boolean}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public static canSetCaret(target: HTMLElement): boolean {
|
||||
let result = true;
|
||||
|
||||
if (Dom.isNativeInput(target)) {
|
||||
const inputElement = target as HTMLInputElement;
|
||||
|
||||
switch (inputElement.type) {
|
||||
case 'file':
|
||||
case 'checkbox':
|
||||
|
@ -309,6 +319,7 @@ export default class Dom {
|
|||
} else {
|
||||
result = Dom.isContentEditable(target);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -319,7 +330,7 @@ export default class Dom {
|
|||
* If you have Node with 2 or more children id depth, you better use {@link Dom#isEmpty} method
|
||||
*
|
||||
* @param {Node} node
|
||||
* @return {Boolean} true if it is empty
|
||||
* @returns {boolean} true if it is empty
|
||||
*/
|
||||
public static isNodeEmpty(node: Node): boolean {
|
||||
let nodeText;
|
||||
|
@ -328,7 +339,7 @@ export default class Dom {
|
|||
return false;
|
||||
}
|
||||
|
||||
if ( this.isElement(node) && this.isNativeInput(node) ) {
|
||||
if (this.isElement(node) && this.isNativeInput(node)) {
|
||||
nodeText = (node as HTMLInputElement).value;
|
||||
} else {
|
||||
nodeText = node.textContent.replace('\u200B', '');
|
||||
|
@ -339,8 +350,9 @@ export default class Dom {
|
|||
|
||||
/**
|
||||
* checks node if it is doesn't have any child nodes
|
||||
*
|
||||
* @param {Node} node
|
||||
* @return {boolean}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public static isLeaf(node: Node): boolean {
|
||||
if (!node) {
|
||||
|
@ -357,11 +369,11 @@ export default class Dom {
|
|||
* @description Pushes to stack all DOM leafs and checks for emptiness
|
||||
*
|
||||
* @param {Node} node
|
||||
* @return {boolean}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public static isEmpty(node: Node): boolean {
|
||||
const treeWalker = [],
|
||||
leafs = [];
|
||||
leafs = [];
|
||||
|
||||
if (!node) {
|
||||
return true;
|
||||
|
@ -378,21 +390,25 @@ export default class Dom {
|
|||
|
||||
treeWalker.push(node.firstChild);
|
||||
|
||||
while ( treeWalker.length > 0 ) {
|
||||
while (treeWalker.length > 0) {
|
||||
node = treeWalker.shift();
|
||||
|
||||
if (!node) { continue; }
|
||||
if (!node) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( this.isLeaf(node) ) {
|
||||
if (this.isLeaf(node)) {
|
||||
leafs.push(node);
|
||||
} else {
|
||||
treeWalker.push(node.firstChild);
|
||||
}
|
||||
|
||||
while ( node && node.nextSibling ) {
|
||||
while (node && node.nextSibling) {
|
||||
node = node.nextSibling;
|
||||
|
||||
if (!node) { continue; }
|
||||
if (!node) {
|
||||
continue;
|
||||
}
|
||||
|
||||
treeWalker.push(node);
|
||||
}
|
||||
|
@ -405,14 +421,14 @@ export default class Dom {
|
|||
}
|
||||
}
|
||||
|
||||
return leafs.every( (leaf) => this.isNodeEmpty(leaf) );
|
||||
return leafs.every((leaf) => this.isNodeEmpty(leaf));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if string contains html elements
|
||||
*
|
||||
* @returns {boolean}
|
||||
* @param {String} str
|
||||
* @param {string} str
|
||||
*/
|
||||
public static isHTMLString(str: string): boolean {
|
||||
const wrapper = Dom.make('div');
|
||||
|
@ -491,7 +507,7 @@ export default class Dom {
|
|||
* Check if passed content includes only inline elements
|
||||
*
|
||||
* @param {string|HTMLElement} data - element or html string
|
||||
* @return {boolean}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public static containsOnlyInlineElements(data: string | HTMLElement): boolean {
|
||||
let wrapper: HTMLElement;
|
||||
|
@ -504,8 +520,8 @@ export default class Dom {
|
|||
}
|
||||
|
||||
const check = (element: HTMLElement) => {
|
||||
return !Dom.blockElements.includes(element.tagName.toLowerCase())
|
||||
&& Array.from(element.children).every(check);
|
||||
return !Dom.blockElements.includes(element.tagName.toLowerCase()) &&
|
||||
Array.from(element.children).every(check);
|
||||
};
|
||||
|
||||
return Array.from(wrapper.children).every(check);
|
||||
|
@ -516,11 +532,11 @@ export default class Dom {
|
|||
*
|
||||
* @param {HTMLElement} parent
|
||||
*
|
||||
* @return {HTMLElement[]}
|
||||
* @returns {HTMLElement[]}
|
||||
*/
|
||||
public static getDeepestBlockElements(parent: HTMLElement): HTMLElement[] {
|
||||
if (Dom.containsOnlyInlineElements(parent)) {
|
||||
return [parent];
|
||||
return [ parent ];
|
||||
}
|
||||
|
||||
return Array.from(parent.children).reduce((result, element) => {
|
||||
|
@ -528,17 +544,22 @@ export default class Dom {
|
|||
}, []);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Helper for get holder from {string} or return HTMLElement
|
||||
*
|
||||
* @param element
|
||||
*/
|
||||
public static getHolder(element: string | HTMLElement): HTMLElement {
|
||||
if (typeof element === 'string') { return document.getElementById(element); }
|
||||
if (typeof element === 'string') {
|
||||
return document.getElementById(element);
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method checks passed Node if it is some extension Node
|
||||
*
|
||||
* @param {Node} node - any node
|
||||
*/
|
||||
public static isExtensionNode(node: Node): boolean {
|
||||
|
|
|
@ -7,6 +7,7 @@ import Dom from './dom';
|
|||
export default class DomIterator {
|
||||
/**
|
||||
* This is a static property that defines iteration directions
|
||||
*
|
||||
* @type {{RIGHT: string, LEFT: string}}
|
||||
*/
|
||||
public static directions = {
|
||||
|
@ -22,9 +23,10 @@ export default class DomIterator {
|
|||
/**
|
||||
* Focused button index.
|
||||
* Default is -1 which means nothing is active
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
private cursor: number = -1;
|
||||
private cursor = -1;
|
||||
|
||||
/**
|
||||
* Items to flip
|
||||
|
@ -37,7 +39,7 @@ export default class DomIterator {
|
|||
*/
|
||||
constructor(
|
||||
nodeList: HTMLElement[],
|
||||
focusedCssClass: string,
|
||||
focusedCssClass: string
|
||||
) {
|
||||
this.items = nodeList || [];
|
||||
this.focusedCssClass = focusedCssClass;
|
||||
|
@ -45,7 +47,8 @@ export default class DomIterator {
|
|||
|
||||
/**
|
||||
* Returns Focused button Node
|
||||
* @return {HTMLElement}
|
||||
*
|
||||
* @returns {HTMLElement}
|
||||
*/
|
||||
public get currentItem(): HTMLElement {
|
||||
if (this.cursor === -1) {
|
||||
|
@ -57,6 +60,7 @@ export default class DomIterator {
|
|||
|
||||
/**
|
||||
* Sets items. Can be used when iterable items changed dynamically
|
||||
*
|
||||
* @param {HTMLElement[]} nodeList
|
||||
*/
|
||||
public setItems(nodeList: HTMLElement[]): void {
|
||||
|
@ -93,7 +97,7 @@ export default class DomIterator {
|
|||
* Leafs nodes inside the target list from active element
|
||||
*
|
||||
* @param {string} direction - leaf direction. Can be 'left' or 'right'
|
||||
* @return {Number} index of focused node
|
||||
* @returns {number} index of focused node
|
||||
*/
|
||||
private leafNodesAndReturnIndex(direction: string): number {
|
||||
/**
|
||||
|
@ -138,6 +142,7 @@ export default class DomIterator {
|
|||
if (direction === DomIterator.directions.RIGHT) {
|
||||
/**
|
||||
* If we go right then choose next (+1) Tool
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
focusedButtonIndex = (focusedButtonIndex + 1) % this.items.length;
|
||||
|
@ -145,6 +150,7 @@ export default class DomIterator {
|
|||
/**
|
||||
* If we go left then choose previous (-1) Tool
|
||||
* Before counting module we need to add length before because of "The JavaScript Modulo Bug"
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
focusedButtonIndex = (this.items.length + focusedButtonIndex - 1) % this.items.length;
|
||||
|
|
|
@ -36,21 +36,23 @@ export interface FlipperOptions {
|
|||
* Flipper is a component that iterates passed items array by TAB or Arrows and clicks it by ENTER
|
||||
*/
|
||||
export default class Flipper {
|
||||
|
||||
/**
|
||||
* Instance of flipper iterator
|
||||
*
|
||||
* @type {DomIterator|null}
|
||||
*/
|
||||
private readonly iterator: DomIterator = null;
|
||||
|
||||
/**
|
||||
* Flag that defines activation status
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
private activated: boolean = false;
|
||||
private activated = false;
|
||||
|
||||
/**
|
||||
* Flag that allows arrows usage to flip items
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
private readonly allowArrows: boolean = true;
|
||||
|
@ -61,7 +63,7 @@ export default class Flipper {
|
|||
private readonly activateCallback: () => void;
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @class
|
||||
*
|
||||
* @param {FlipperOptions} options - different constructing settings
|
||||
* @
|
||||
|
@ -129,6 +131,7 @@ export default class Flipper {
|
|||
|
||||
/**
|
||||
* Active tab/arrows handling by flipper
|
||||
*
|
||||
* @param {HTMLElement[]} items - Some modules (like, InlineToolbar, BlockSettings) might refresh buttons dynamically
|
||||
*/
|
||||
public activate(items?: HTMLElement[]): void {
|
||||
|
@ -149,7 +152,8 @@ export default class Flipper {
|
|||
|
||||
/**
|
||||
* Return current focused button
|
||||
* @return {HTMLElement|null}
|
||||
*
|
||||
* @returns {HTMLElement|null}
|
||||
*/
|
||||
public get currentItem(): HTMLElement|null {
|
||||
return this.iterator.currentItem;
|
||||
|
@ -165,6 +169,7 @@ export default class Flipper {
|
|||
|
||||
/**
|
||||
* Drops flipper's iterator cursor
|
||||
*
|
||||
* @see DomIterator#dropCursor
|
||||
*/
|
||||
private dropCursor(): void {
|
||||
|
@ -174,8 +179,9 @@ export default class Flipper {
|
|||
/**
|
||||
* This function is fired before handling flipper keycodes
|
||||
* The result of this function defines if it is need to be handled or not
|
||||
*
|
||||
* @param {KeyboardEvent} event
|
||||
* @return {boolean}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
private isEventReadyForHandling(event: KeyboardEvent): boolean {
|
||||
const handlingKeyCodeList = [
|
||||
|
@ -188,7 +194,7 @@ export default class Flipper {
|
|||
_.keyCodes.LEFT,
|
||||
_.keyCodes.RIGHT,
|
||||
_.keyCodes.UP,
|
||||
_.keyCodes.DOWN,
|
||||
_.keyCodes.DOWN
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -201,12 +207,13 @@ export default class Flipper {
|
|||
|
||||
/**
|
||||
* When flipper is activated tab press will leaf the items
|
||||
*
|
||||
* @param {KeyboardEvent} event
|
||||
*/
|
||||
private handleTabPress(event: KeyboardEvent): void {
|
||||
/** this property defines leaf direction */
|
||||
const shiftKey = event.shiftKey,
|
||||
direction = shiftKey ? DomIterator.directions.LEFT : DomIterator.directions.RIGHT;
|
||||
direction = shiftKey ? DomIterator.directions.LEFT : DomIterator.directions.RIGHT;
|
||||
|
||||
switch (direction) {
|
||||
case DomIterator.directions.RIGHT:
|
||||
|
@ -234,6 +241,7 @@ export default class Flipper {
|
|||
|
||||
/**
|
||||
* Enter press will click current item if flipper is activated
|
||||
*
|
||||
* @param {KeyboardEvent} event
|
||||
*/
|
||||
private handleEnterPress(event: KeyboardEvent): void {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import $ from '../dom';
|
||||
import {API, InlineTool, SanitizerConfig} from '../../../types';
|
||||
import { API, InlineTool, SanitizerConfig } from '../../../types';
|
||||
|
||||
/**
|
||||
* Bold Tool
|
||||
|
@ -9,23 +9,23 @@ import {API, InlineTool, SanitizerConfig} from '../../../types';
|
|||
* Makes selected text bolder
|
||||
*/
|
||||
export default class BoldInlineTool implements InlineTool {
|
||||
|
||||
/**
|
||||
* Specifies Tool as Inline Toolbar Tool
|
||||
*
|
||||
* @return {boolean}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public static isInline = true;
|
||||
|
||||
/**
|
||||
* Title for hover-tooltip
|
||||
*/
|
||||
public static title: string = 'Bold';
|
||||
public static title = 'Bold';
|
||||
|
||||
/**
|
||||
* Sanitizer Rule
|
||||
* Leave <b> tags
|
||||
* @return {object}
|
||||
*
|
||||
* @returns {object}
|
||||
*/
|
||||
static get sanitize(): SanitizerConfig {
|
||||
return {
|
||||
|
@ -62,11 +62,13 @@ export default class BoldInlineTool implements InlineTool {
|
|||
this.nodes.button.type = 'button';
|
||||
this.nodes.button.classList.add(this.CSS.button, this.CSS.buttonModifier);
|
||||
this.nodes.button.appendChild($.svg('bold', 12, 14));
|
||||
|
||||
return this.nodes.button;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap range with <b> tag
|
||||
*
|
||||
* @param {Range} range
|
||||
*/
|
||||
public surround(range: Range): void {
|
||||
|
@ -75,12 +77,14 @@ export default class BoldInlineTool implements InlineTool {
|
|||
|
||||
/**
|
||||
* Check selection and set activated state to button if there are <b> tag
|
||||
*
|
||||
* @param {Selection} selection
|
||||
*/
|
||||
public checkState(selection: Selection): boolean {
|
||||
const isActive = document.queryCommandState(this.commandName);
|
||||
|
||||
this.nodes.button.classList.toggle(this.CSS.buttonActive, isActive);
|
||||
|
||||
return isActive;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import $ from '../dom';
|
||||
import {InlineTool, SanitizerConfig} from '../../../types';
|
||||
import { InlineTool, SanitizerConfig } from '../../../types';
|
||||
|
||||
/**
|
||||
* Italic Tool
|
||||
|
@ -9,23 +9,23 @@ import {InlineTool, SanitizerConfig} from '../../../types';
|
|||
* Style selected text with italic
|
||||
*/
|
||||
export default class ItalicInlineTool implements InlineTool {
|
||||
|
||||
/**
|
||||
* Specifies Tool as Inline Toolbar Tool
|
||||
*
|
||||
* @return {boolean}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public static isInline = true;
|
||||
|
||||
/**
|
||||
* Title for hover-tooltip
|
||||
*/
|
||||
public static title: string = 'Italic';
|
||||
public static title = 'Italic';
|
||||
|
||||
/**
|
||||
* Sanitizer Rule
|
||||
* Leave <i> tags
|
||||
* @return {object}
|
||||
*
|
||||
* @returns {object}
|
||||
*/
|
||||
static get sanitize(): SanitizerConfig {
|
||||
return {
|
||||
|
@ -62,11 +62,13 @@ export default class ItalicInlineTool implements InlineTool {
|
|||
this.nodes.button.type = 'button';
|
||||
this.nodes.button.classList.add(this.CSS.button, this.CSS.buttonModifier);
|
||||
this.nodes.button.appendChild($.svg('italic', 4, 11));
|
||||
|
||||
return this.nodes.button;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap range with <i> tag
|
||||
*
|
||||
* @param {Range} range
|
||||
*/
|
||||
public surround(range: Range): void {
|
||||
|
@ -75,12 +77,14 @@ export default class ItalicInlineTool implements InlineTool {
|
|||
|
||||
/**
|
||||
* Check selection and set activated state to button if there are <i> tag
|
||||
*
|
||||
* @param {Selection} selection
|
||||
*/
|
||||
public checkState(selection: Selection): boolean {
|
||||
const isActive = document.queryCommandState(this.commandName);
|
||||
|
||||
this.nodes.button.classList.toggle(this.CSS.buttonActive, isActive);
|
||||
|
||||
return isActive;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,8 +2,8 @@ import SelectionUtils from '../selection';
|
|||
|
||||
import $ from '../dom';
|
||||
import * as _ from '../utils';
|
||||
import {API, InlineTool, SanitizerConfig} from '../../../types';
|
||||
import {Notifier, Toolbar} from '../../../types/api';
|
||||
import { API, InlineTool, SanitizerConfig } from '../../../types';
|
||||
import { Notifier, Toolbar } from '../../../types/api';
|
||||
|
||||
/**
|
||||
* Link Tool
|
||||
|
@ -13,23 +13,23 @@ import {Notifier, Toolbar} from '../../../types/api';
|
|||
* Wrap selected text with <a> tag
|
||||
*/
|
||||
export default class LinkInlineTool implements InlineTool {
|
||||
|
||||
/**
|
||||
* Specifies Tool as Inline Toolbar Tool
|
||||
*
|
||||
* @return {boolean}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public static isInline = true;
|
||||
|
||||
/**
|
||||
* Title for hover-tooltip
|
||||
*/
|
||||
public static title: string = 'Link';
|
||||
public static title = 'Link';
|
||||
|
||||
/**
|
||||
* Sanitizer Rule
|
||||
* Leave <a> tags
|
||||
* @return {object}
|
||||
*
|
||||
* @returns {object}
|
||||
*/
|
||||
static get sanitize(): SanitizerConfig {
|
||||
return {
|
||||
|
@ -83,7 +83,7 @@ export default class LinkInlineTool implements InlineTool {
|
|||
/**
|
||||
* Input opening state
|
||||
*/
|
||||
private inputOpened: boolean = false;
|
||||
private inputOpened = false;
|
||||
|
||||
/**
|
||||
* Available Toolbar methods (open/close)
|
||||
|
@ -103,7 +103,7 @@ export default class LinkInlineTool implements InlineTool {
|
|||
/**
|
||||
* @param {{api: API}} - Editor.js API
|
||||
*/
|
||||
constructor({api}) {
|
||||
constructor({ api }) {
|
||||
this.toolbar = api.toolbar;
|
||||
this.inlineToolbar = api.inlineToolbar;
|
||||
this.notifier = api.notifier;
|
||||
|
@ -119,6 +119,7 @@ export default class LinkInlineTool implements InlineTool {
|
|||
this.nodes.button.classList.add(this.CSS.button, this.CSS.buttonModifier);
|
||||
this.nodes.button.appendChild($.svg('link', 14, 10));
|
||||
this.nodes.button.appendChild($.svg('unlink', 15, 11));
|
||||
|
||||
return this.nodes.button;
|
||||
}
|
||||
|
||||
|
@ -134,11 +135,13 @@ export default class LinkInlineTool implements InlineTool {
|
|||
this.enterPressed(event);
|
||||
}
|
||||
});
|
||||
|
||||
return this.nodes.input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle clicks on the Inline Toolbar icon
|
||||
*
|
||||
* @param {Range} range
|
||||
*/
|
||||
public surround(range: Range): void {
|
||||
|
@ -168,6 +171,7 @@ export default class LinkInlineTool implements InlineTool {
|
|||
this.closeActions();
|
||||
this.checkState();
|
||||
this.toolbar.close();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -177,6 +181,7 @@ export default class LinkInlineTool implements InlineTool {
|
|||
|
||||
/**
|
||||
* Check selection and set activated state to button if there are <a> tag
|
||||
*
|
||||
* @param {Selection} selection
|
||||
*/
|
||||
public checkState(selection?: Selection): boolean {
|
||||
|
@ -191,6 +196,7 @@ export default class LinkInlineTool implements InlineTool {
|
|||
* Fill input value with link href
|
||||
*/
|
||||
const hrefAttr = anchorTag.getAttribute('href');
|
||||
|
||||
this.nodes.input.value = hrefAttr !== 'null' ? hrefAttr : '';
|
||||
|
||||
this.selection.save();
|
||||
|
@ -216,6 +222,9 @@ export default class LinkInlineTool implements InlineTool {
|
|||
return 'CMD+K';
|
||||
}
|
||||
|
||||
/**
|
||||
* Show/close link input
|
||||
*/
|
||||
private toggleActions(): void {
|
||||
if (!this.inputOpened) {
|
||||
this.openActions(true);
|
||||
|
@ -227,7 +236,7 @@ export default class LinkInlineTool implements InlineTool {
|
|||
/**
|
||||
* @param {boolean} needFocus - on link creation we need to focus input. On editing - nope.
|
||||
*/
|
||||
private openActions(needFocus: boolean = false): void {
|
||||
private openActions(needFocus = false): void {
|
||||
this.nodes.input.classList.add(this.CSS.inputShowed);
|
||||
if (needFocus) {
|
||||
this.nodes.input.focus();
|
||||
|
@ -237,13 +246,15 @@ export default class LinkInlineTool implements InlineTool {
|
|||
|
||||
/**
|
||||
* Close input
|
||||
*
|
||||
* @param {boolean} clearSavedSelection — we don't need to clear saved selection
|
||||
* on toggle-clicks on the icon of opened Toolbar
|
||||
*/
|
||||
private closeActions(clearSavedSelection: boolean = true): void {
|
||||
private closeActions(clearSavedSelection = true): void {
|
||||
if (this.selection.isFakeBackgroundEnabled) {
|
||||
// if actions is broken by other selection We need to save new selection
|
||||
const currentSelection = new SelectionUtils();
|
||||
|
||||
currentSelection.save();
|
||||
|
||||
this.selection.restore();
|
||||
|
@ -263,6 +274,7 @@ export default class LinkInlineTool implements InlineTool {
|
|||
|
||||
/**
|
||||
* Enter pressed on input
|
||||
*
|
||||
* @param {KeyboardEvent} event
|
||||
*/
|
||||
private enterPressed(event: KeyboardEvent): void {
|
||||
|
@ -276,13 +288,13 @@ export default class LinkInlineTool implements InlineTool {
|
|||
}
|
||||
|
||||
if (!this.validateURL(value)) {
|
||||
|
||||
this.notifier.show({
|
||||
message: 'Pasted link is not valid.',
|
||||
style: 'error',
|
||||
});
|
||||
|
||||
_.log('Incorrect Link pasted', 'warn', value);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -305,8 +317,9 @@ export default class LinkInlineTool implements InlineTool {
|
|||
|
||||
/**
|
||||
* Detects if passed string is URL
|
||||
*
|
||||
* @param {string} str
|
||||
* @return {Boolean}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
private validateURL(str: string): boolean {
|
||||
/**
|
||||
|
@ -319,17 +332,20 @@ export default class LinkInlineTool implements InlineTool {
|
|||
* Process link before injection
|
||||
* - sanitize
|
||||
* - add protocol for links like 'google.com'
|
||||
*
|
||||
* @param {string} link - raw user input
|
||||
*/
|
||||
private prepareLink(link: string): string {
|
||||
link = link.trim();
|
||||
link = this.addProtocol(link);
|
||||
|
||||
return link;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add 'http' protocol to the links like 'vc.ru', 'google.com'
|
||||
* @param {String} link
|
||||
*
|
||||
* @param {string} link
|
||||
*/
|
||||
private addProtocol(link: string): string {
|
||||
/**
|
||||
|
@ -345,9 +361,9 @@ export default class LinkInlineTool implements InlineTool {
|
|||
* 2) Anchors looks like "#results"
|
||||
* 3) Protocol-relative URLs like "//google.com"
|
||||
*/
|
||||
const isInternal = /^\/[^\/\s]/.test(link),
|
||||
isAnchor = link.substring(0, 1) === '#',
|
||||
isProtocolRelative = /^\/\/[^\/\s]/.test(link);
|
||||
const isInternal = /^\/[^/\s]/.test(link),
|
||||
isAnchor = link.substring(0, 1) === '#',
|
||||
isProtocolRelative = /^\/\/[^/\s]/.test(link);
|
||||
|
||||
if (!isInternal && !isAnchor && !isProtocolRelative) {
|
||||
link = 'http://' + link;
|
||||
|
@ -358,10 +374,10 @@ export default class LinkInlineTool implements InlineTool {
|
|||
|
||||
/**
|
||||
* Inserts <a> tag with "href"
|
||||
*
|
||||
* @param {string} link - "href" value
|
||||
*/
|
||||
private insertLink(link: string): void {
|
||||
|
||||
/**
|
||||
* Edit all link, not selected part
|
||||
*/
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import Module from '../../__module';
|
||||
|
||||
import {Blocks} from '../../../../types/api';
|
||||
import {BlockToolData, OutputData, ToolConfig} from '../../../../types';
|
||||
import { Blocks } from '../../../../types/api';
|
||||
import { BlockToolData, OutputData, ToolConfig } from '../../../../types';
|
||||
import * as _ from './../../utils';
|
||||
|
||||
/**
|
||||
|
@ -11,7 +11,8 @@ import * as _ from './../../utils';
|
|||
export default class BlocksAPI extends Module {
|
||||
/**
|
||||
* Available methods
|
||||
* @return {Blocks}
|
||||
*
|
||||
* @returns {Blocks}
|
||||
*/
|
||||
get methods(): Blocks {
|
||||
return {
|
||||
|
@ -24,7 +25,7 @@ export default class BlocksAPI extends Module {
|
|||
getBlockByIndex: (index: number) => this.getBlockByIndex(index),
|
||||
getCurrentBlockIndex: () => this.getCurrentBlockIndex(),
|
||||
getBlocksCount: () => this.getBlocksCount(),
|
||||
stretchBlock: (index: number, status: boolean = true) => this.stretchBlock(index, status),
|
||||
stretchBlock: (index: number, status = true) => this.stretchBlock(index, status),
|
||||
insertNewBlock: () => this.insertNewBlock(),
|
||||
insert: this.insert,
|
||||
};
|
||||
|
@ -32,7 +33,8 @@ export default class BlocksAPI extends Module {
|
|||
|
||||
/**
|
||||
* Returns Blocks count
|
||||
* @return {number}
|
||||
*
|
||||
* @returns {number}
|
||||
*/
|
||||
public getBlocksCount(): number {
|
||||
return this.Editor.BlockManager.blocks.length;
|
||||
|
@ -40,7 +42,8 @@ export default class BlocksAPI extends Module {
|
|||
|
||||
/**
|
||||
* Returns current block index
|
||||
* @return {number}
|
||||
*
|
||||
* @returns {number}
|
||||
*/
|
||||
public getCurrentBlockIndex(): number {
|
||||
return this.Editor.BlockManager.currentBlockIndex;
|
||||
|
@ -48,17 +51,20 @@ export default class BlocksAPI extends Module {
|
|||
|
||||
/**
|
||||
* Returns Block holder by Block index
|
||||
* @param {Number} index
|
||||
*
|
||||
* @return {HTMLElement}
|
||||
* @param {number} index
|
||||
*
|
||||
* @returns {HTMLElement}
|
||||
*/
|
||||
public getBlockByIndex(index: number): HTMLElement {
|
||||
const block = this.Editor.BlockManager.getBlockByIndex(index);
|
||||
|
||||
return block.holder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call Block Manager method that swap Blocks
|
||||
*
|
||||
* @param {number} fromIndex - position of first Block
|
||||
* @param {number} toIndex - position of second Block
|
||||
* @deprecated — use 'move' instead
|
||||
|
@ -75,7 +81,8 @@ export default class BlocksAPI extends Module {
|
|||
|
||||
/**
|
||||
* Move block from one index to another
|
||||
* @param {Number} toIndex
|
||||
*
|
||||
* @param {number} toIndex
|
||||
* @param {number} fromIndex
|
||||
*/
|
||||
public move(toIndex: number, fromIndex?: number): void {
|
||||
|
@ -90,6 +97,7 @@ export default class BlocksAPI extends Module {
|
|||
|
||||
/**
|
||||
* Deletes Block
|
||||
*
|
||||
* @param blockIndex
|
||||
*/
|
||||
public delete(blockIndex?: number): void {
|
||||
|
@ -121,29 +129,34 @@ export default class BlocksAPI extends Module {
|
|||
|
||||
/**
|
||||
* Fills Editor with Blocks data
|
||||
*
|
||||
* @param {OutputData} data — Saved Editor data
|
||||
*/
|
||||
public render(data: OutputData): Promise<void> {
|
||||
this.Editor.BlockManager.clear();
|
||||
|
||||
return this.Editor.Renderer.render(data.blocks);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render passed HTML string
|
||||
*
|
||||
* @param {string} data
|
||||
* @return {Promise<void>}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
public renderFromHTML(data: string): Promise<void> {
|
||||
this.Editor.BlockManager.clear();
|
||||
|
||||
return this.Editor.Paste.processText(data, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stretch Block's content
|
||||
*
|
||||
* @param {number} index
|
||||
* @param {boolean} status - true to enable, false to disable
|
||||
*/
|
||||
public stretchBlock(index: number, status: boolean = true): void {
|
||||
public stretchBlock(index: number, status = true): void {
|
||||
const block = this.Editor.BlockManager.getBlockByIndex(index);
|
||||
|
||||
if (!block) {
|
||||
|
@ -167,14 +180,14 @@ export default class BlocksAPI extends Module {
|
|||
data: BlockToolData = {},
|
||||
config: ToolConfig = {},
|
||||
index?: number,
|
||||
needToFocus?: boolean,
|
||||
needToFocus?: boolean
|
||||
): void => {
|
||||
this.Editor.BlockManager.insert(
|
||||
type,
|
||||
data,
|
||||
config,
|
||||
index,
|
||||
needToFocus,
|
||||
needToFocus
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import Module from '../../__module';
|
||||
import {Caret} from '../../../../types/api';
|
||||
import { Caret } from '../../../../types/api';
|
||||
|
||||
/**
|
||||
* @class CaretAPI
|
||||
|
@ -8,7 +8,8 @@ import {Caret} from '../../../../types/api';
|
|||
export default class CaretAPI extends Module {
|
||||
/**
|
||||
* Available methods
|
||||
* @return {Caret}
|
||||
*
|
||||
* @returns {Caret}
|
||||
*/
|
||||
get methods(): Caret {
|
||||
return {
|
||||
|
@ -27,14 +28,15 @@ export default class CaretAPI extends Module {
|
|||
* @param {string} position - position where to set caret
|
||||
* @param {number} offset - caret offset
|
||||
*
|
||||
* @return {boolean}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
private setToFirstBlock = (position: string = this.Editor.Caret.positions.DEFAULT, offset: number = 0): boolean => {
|
||||
private setToFirstBlock = (position: string = this.Editor.Caret.positions.DEFAULT, offset = 0): boolean => {
|
||||
if (!this.Editor.BlockManager.firstBlock) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.Editor.Caret.setToBlock(this.Editor.BlockManager.firstBlock, position, offset);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -44,14 +46,15 @@ export default class CaretAPI extends Module {
|
|||
* @param {string} position - position where to set caret
|
||||
* @param {number} offset - caret offset
|
||||
*
|
||||
* @return {boolean}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
private setToLastBlock = (position: string = this.Editor.Caret.positions.DEFAULT, offset: number = 0): boolean => {
|
||||
private setToLastBlock = (position: string = this.Editor.Caret.positions.DEFAULT, offset = 0): boolean => {
|
||||
if (!this.Editor.BlockManager.lastBlock) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.Editor.Caret.setToBlock(this.Editor.BlockManager.lastBlock, position, offset);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -61,17 +64,18 @@ export default class CaretAPI extends Module {
|
|||
* @param {string} position - position where to set caret
|
||||
* @param {number} offset - caret offset
|
||||
*
|
||||
* @return {boolean}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
private setToPreviousBlock = (
|
||||
position: string = this.Editor.Caret.positions.DEFAULT,
|
||||
offset: number = 0,
|
||||
offset = 0
|
||||
): boolean => {
|
||||
if (!this.Editor.BlockManager.previousBlock) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.Editor.Caret.setToBlock(this.Editor.BlockManager.previousBlock, position, offset);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -81,14 +85,15 @@ export default class CaretAPI extends Module {
|
|||
* @param {string} position - position where to set caret
|
||||
* @param {number} offset - caret offset
|
||||
*
|
||||
* @return {boolean}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
private setToNextBlock = (position: string = this.Editor.Caret.positions.DEFAULT, offset: number = 0): boolean => {
|
||||
private setToNextBlock = (position: string = this.Editor.Caret.positions.DEFAULT, offset = 0): boolean => {
|
||||
if (!this.Editor.BlockManager.nextBlock) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.Editor.Caret.setToBlock(this.Editor.BlockManager.nextBlock, position, offset);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -99,18 +104,19 @@ export default class CaretAPI extends Module {
|
|||
* @param {string} position - position where to set caret
|
||||
* @param {number} offset - caret offset
|
||||
*
|
||||
* @return {boolean}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
private setToBlock = (
|
||||
index: number,
|
||||
position: string = this.Editor.Caret.positions.DEFAULT,
|
||||
offset: number = 0,
|
||||
offset = 0
|
||||
): boolean => {
|
||||
if (!this.Editor.BlockManager.blocks[index]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.Editor.Caret.setToBlock(this.Editor.BlockManager.blocks[index], position, offset);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -119,9 +125,9 @@ export default class CaretAPI extends Module {
|
|||
*
|
||||
* @param {boolean} atEnd - if true, set Caret to the end of the Editor
|
||||
*
|
||||
* @return {boolean}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
private focus = (atEnd: boolean = false) => {
|
||||
private focus = (atEnd = false) => {
|
||||
if (atEnd) {
|
||||
return this.setToLastBlock(this.Editor.Caret.positions.END);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import Module from '../../__module';
|
||||
import {Events} from '../../../../types/api';
|
||||
import { Events } from '../../../../types/api';
|
||||
|
||||
/**
|
||||
* @class EventsAPI
|
||||
|
@ -8,7 +8,8 @@ import {Events} from '../../../../types/api';
|
|||
export default class EventsAPI extends Module {
|
||||
/**
|
||||
* Available methods
|
||||
* @return {Events}
|
||||
*
|
||||
* @returns {Events}
|
||||
*/
|
||||
get methods(): Events {
|
||||
return {
|
||||
|
@ -20,7 +21,8 @@ export default class EventsAPI extends Module {
|
|||
|
||||
/**
|
||||
* Subscribe on Events
|
||||
* @param {String} eventName
|
||||
*
|
||||
* @param {string} eventName
|
||||
* @param {Function} callback
|
||||
*/
|
||||
public on(eventName, callback): void {
|
||||
|
@ -29,8 +31,9 @@ export default class EventsAPI extends Module {
|
|||
|
||||
/**
|
||||
* Emit event with data
|
||||
* @param {String} eventName
|
||||
* @param {Object} data
|
||||
*
|
||||
* @param {string} eventName
|
||||
* @param {object} data
|
||||
*/
|
||||
public emit(eventName, data): void {
|
||||
this.Editor.Events.emit(eventName, data);
|
||||
|
@ -38,11 +41,11 @@ export default class EventsAPI extends Module {
|
|||
|
||||
/**
|
||||
* Unsubscribe from Event
|
||||
* @param {String} eventName
|
||||
*
|
||||
* @param {string} eventName
|
||||
* @param {Function} callback
|
||||
*/
|
||||
public off(eventName, callback): void {
|
||||
this.Editor.Events.off(eventName, callback);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,12 +6,15 @@
|
|||
* if you cant to read more about how API works, please see docs
|
||||
*/
|
||||
import Module from '../../__module';
|
||||
import {API as APIInterfaces} from '../../../../types';
|
||||
import { API as APIInterfaces } from '../../../../types';
|
||||
|
||||
/**
|
||||
* @class API
|
||||
*/
|
||||
export default class API extends Module {
|
||||
/**
|
||||
* Editor.js Core API modules
|
||||
*/
|
||||
public get methods(): APIInterfaces {
|
||||
return {
|
||||
blocks: this.Editor.BlocksAPI.methods,
|
||||
|
|
|
@ -8,7 +8,8 @@ import { InlineToolbar } from '../../../../types/api/inline-toolbar';
|
|||
export default class InlineToolbarAPI extends Module {
|
||||
/**
|
||||
* Available methods
|
||||
* @return {InlineToolbar}
|
||||
*
|
||||
* @returns {InlineToolbar}
|
||||
*/
|
||||
get methods(): InlineToolbar {
|
||||
return {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import Module from '../../__module';
|
||||
import {Listeners} from '../../../../types/api';
|
||||
import { Listeners } from '../../../../types/api';
|
||||
|
||||
/**
|
||||
* @class ListenersAPI
|
||||
|
@ -8,7 +8,8 @@ import {Listeners} from '../../../../types/api';
|
|||
export default class ListenersAPI extends Module {
|
||||
/**
|
||||
* Available methods
|
||||
* @return {Listeners}
|
||||
*
|
||||
* @returns {Listeners}
|
||||
*/
|
||||
get methods(): Listeners {
|
||||
return {
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import Module from '../../__module';
|
||||
import {Notifier} from '../../../../types/api';
|
||||
import {ConfirmNotifierOptions, NotifierOptions, PromptNotifierOptions} from 'codex-notifier';
|
||||
import { Notifier } from '../../../../types/api';
|
||||
import { ConfirmNotifierOptions, NotifierOptions, PromptNotifierOptions } from 'codex-notifier';
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export default class NotifierAPI extends Module {
|
||||
|
||||
/**
|
||||
* Available methods
|
||||
*/
|
||||
|
@ -13,7 +15,11 @@ export default class NotifierAPI extends Module {
|
|||
};
|
||||
}
|
||||
|
||||
public show(options: NotifierOptions | ConfirmNotifierOptions | PromptNotifierOptions) {
|
||||
/**
|
||||
* Show notification
|
||||
* @param options
|
||||
*/
|
||||
public show(options: NotifierOptions | ConfirmNotifierOptions | PromptNotifierOptions): void {
|
||||
return this.Editor.Notifier.show(options);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import Module from '../../__module';
|
||||
import {Sanitizer} from '../../../../types/api';
|
||||
import { Sanitizer } from '../../../../types/api';
|
||||
|
||||
/**
|
||||
* @class SanitizerAPI
|
||||
|
@ -8,7 +8,8 @@ import {Sanitizer} from '../../../../types/api';
|
|||
export default class SanitizerAPI extends Module {
|
||||
/**
|
||||
* Available methods
|
||||
* @return {Sanitizer}
|
||||
*
|
||||
* @returns {Sanitizer}
|
||||
*/
|
||||
get methods(): Sanitizer {
|
||||
return {
|
||||
|
@ -16,8 +17,12 @@ export default class SanitizerAPI extends Module {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform sanitizing of a string
|
||||
* @param taintString - what to sanitize
|
||||
* @param config - sanitizer config
|
||||
*/
|
||||
public clean(taintString, config) {
|
||||
return this.Editor.Sanitizer.clean(taintString, config);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import Module from '../../__module';
|
||||
import {Saver} from '../../../../types/api';
|
||||
import {OutputData} from '../../../../types';
|
||||
import { Saver } from '../../../../types/api';
|
||||
import { OutputData } from '../../../../types';
|
||||
|
||||
/**
|
||||
* @class SaverAPI
|
||||
|
@ -9,7 +9,8 @@ import {OutputData} from '../../../../types';
|
|||
export default class SaverAPI extends Module {
|
||||
/**
|
||||
* Available methods
|
||||
* @return {Saver}
|
||||
*
|
||||
* @returns {Saver}
|
||||
*/
|
||||
get methods(): Saver {
|
||||
return {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import Module from '../../__module';
|
||||
import SelectionUtils from '../../selection';
|
||||
import {Selection as SelectionAPIInterface} from '../../../../types/api';
|
||||
import { Selection as SelectionAPIInterface } from '../../../../types/api';
|
||||
|
||||
/**
|
||||
* @class SelectionAPI
|
||||
|
@ -9,9 +9,10 @@ import {Selection as SelectionAPIInterface} from '../../../../types/api';
|
|||
export default class SelectionAPI extends Module {
|
||||
/**
|
||||
* Available methods
|
||||
* @return {SelectionAPIInterface}
|
||||
*
|
||||
* @returns {SelectionAPIInterface}
|
||||
*/
|
||||
get methods(): SelectionAPIInterface {
|
||||
public get methods(): SelectionAPIInterface {
|
||||
return {
|
||||
findParentTag: (tagName: string, className?: string) => this.findParentTag(tagName, className),
|
||||
expandToTag: (node: HTMLElement) => this.expandToTag(node),
|
||||
|
@ -20,9 +21,10 @@ export default class SelectionAPI extends Module {
|
|||
|
||||
/**
|
||||
* Looks ahead from selection and find passed tag with class name
|
||||
*
|
||||
* @param {string} tagName - tag to find
|
||||
* @param {string} className - tag's class name
|
||||
* @return {HTMLElement|null}
|
||||
* @returns {HTMLElement|null}
|
||||
*/
|
||||
public findParentTag(tagName: string, className?: string): HTMLElement|null {
|
||||
return new SelectionUtils().findParentTag(tagName, className);
|
||||
|
@ -30,10 +32,10 @@ export default class SelectionAPI extends Module {
|
|||
|
||||
/**
|
||||
* Expand selection to passed tag
|
||||
*
|
||||
* @param {HTMLElement} node - tag that should contain selection
|
||||
*/
|
||||
public expandToTag(node: HTMLElement): void {
|
||||
new SelectionUtils().expandToTag(node);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
import Module from '../../__module';
|
||||
import {Styles} from '../../../../types/api';
|
||||
import { Styles } from '../../../../types/api';
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export default class StylesAPI extends Module {
|
||||
get classes(): Styles {
|
||||
/**
|
||||
* Exported classes
|
||||
*/
|
||||
public get classes(): Styles {
|
||||
return {
|
||||
/**
|
||||
* Base Block styles
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import Module from '../../__module';
|
||||
import {Toolbar} from '../../../../types/api';
|
||||
import { Toolbar } from '../../../../types/api';
|
||||
|
||||
/**
|
||||
* @class ToolbarAPI
|
||||
|
@ -8,7 +8,8 @@ import {Toolbar} from '../../../../types/api';
|
|||
export default class ToolbarAPI extends Module {
|
||||
/**
|
||||
* Available methods
|
||||
* @return {Toolbar}
|
||||
*
|
||||
* @returns {Toolbar}
|
||||
*/
|
||||
get methods(): Toolbar {
|
||||
return {
|
||||
|
@ -30,5 +31,4 @@ export default class ToolbarAPI extends Module {
|
|||
public close(): void {
|
||||
this.Editor.Toolbar.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import Module from '../../__module';
|
||||
import { Tooltip } from '../../../../types/api';
|
||||
import {TooltipContent, TooltipOptions} from 'codex-tooltip';
|
||||
import { TooltipContent, TooltipOptions } from 'codex-tooltip';
|
||||
|
||||
/**
|
||||
* @class TooltipAPI
|
||||
|
@ -13,13 +13,13 @@ export default class TooltipAPI extends Module {
|
|||
get methods(): Tooltip {
|
||||
return {
|
||||
show: (element: HTMLElement,
|
||||
content: TooltipContent,
|
||||
options?: TooltipOptions,
|
||||
content: TooltipContent,
|
||||
options?: TooltipOptions
|
||||
) => this.show(element, content, options),
|
||||
hide: () => this.hide(),
|
||||
onHover: (element: HTMLElement,
|
||||
content: TooltipContent,
|
||||
options?: TooltipOptions,
|
||||
content: TooltipContent,
|
||||
options?: TooltipOptions
|
||||
) => this.onHover(element, content, options),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -6,10 +6,13 @@ import * as _ from '../utils';
|
|||
import SelectionUtils from '../selection';
|
||||
import Flipper from '../flipper';
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export default class BlockEvents extends Module {
|
||||
|
||||
/**
|
||||
* All keydowns on Block
|
||||
*
|
||||
* @param {KeyboardEvent} event - keydown
|
||||
*/
|
||||
public keydown(event: KeyboardEvent): void {
|
||||
|
@ -47,14 +50,12 @@ export default class BlockEvents extends Module {
|
|||
case _.keyCodes.ESC:
|
||||
this.escapePressed(event);
|
||||
break;
|
||||
default:
|
||||
this.defaultHandler();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires on keydown before event processing
|
||||
*
|
||||
* @param {KeyboardEvent} event - keydown
|
||||
*/
|
||||
public beforeKeydownProcessing(event: KeyboardEvent): void {
|
||||
|
@ -77,6 +78,7 @@ export default class BlockEvents extends Module {
|
|||
|
||||
/**
|
||||
* Allow to use shortcuts with selected blocks
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
const isShortcut = event.ctrlKey || event.metaKey || event.altKey || event.shiftKey;
|
||||
|
@ -92,9 +94,10 @@ export default class BlockEvents extends Module {
|
|||
* Key up on Block:
|
||||
* - shows Inline Toolbar if something selected
|
||||
* - shows conversion toolbar with 85% of block selection
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
public keyup(event): void {
|
||||
|
||||
/**
|
||||
* If shift key was pressed some special shortcut is used (eg. cross block selection via shift + arrows)
|
||||
*/
|
||||
|
@ -108,12 +111,6 @@ export default class BlockEvents extends Module {
|
|||
this.Editor.UI.checkEmptiness();
|
||||
}
|
||||
|
||||
/**
|
||||
* Mouse up on Block:
|
||||
*/
|
||||
public mouseUp(): void {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up mouse selection handlers
|
||||
*
|
||||
|
@ -131,6 +128,7 @@ export default class BlockEvents extends Module {
|
|||
|
||||
/**
|
||||
* Open Toolbox to leaf Tools
|
||||
*
|
||||
* @param {KeyboardEvent} event
|
||||
*/
|
||||
public tabPressed(event): void {
|
||||
|
@ -226,6 +224,7 @@ export default class BlockEvents extends Module {
|
|||
|
||||
/**
|
||||
* Copy and Delete selected Blocks
|
||||
*
|
||||
* @param {ClipboardEvent} event
|
||||
*/
|
||||
public handleCommandX(event: ClipboardEvent): void {
|
||||
|
@ -247,6 +246,7 @@ export default class BlockEvents extends Module {
|
|||
|
||||
/**
|
||||
* ENTER pressed on block
|
||||
*
|
||||
* @param {KeyboardEvent} event - keydown
|
||||
*/
|
||||
private enter(event: KeyboardEvent): void {
|
||||
|
@ -314,6 +314,7 @@ export default class BlockEvents extends Module {
|
|||
|
||||
/**
|
||||
* Handle backspace keydown on Block
|
||||
*
|
||||
* @param {KeyboardEvent} event - keydown
|
||||
*/
|
||||
private backspace(event: KeyboardEvent): void {
|
||||
|
@ -339,7 +340,7 @@ export default class BlockEvents extends Module {
|
|||
|
||||
Caret.setToBlock(
|
||||
BlockManager.currentBlock,
|
||||
index ? Caret.positions.END : Caret.positions.START,
|
||||
index ? Caret.positions.END : Caret.positions.START
|
||||
);
|
||||
|
||||
/** Close Toolbar */
|
||||
|
@ -347,6 +348,7 @@ export default class BlockEvents extends Module {
|
|||
|
||||
/** Clear selection */
|
||||
BlockSelection.clearSelection(event);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -401,6 +403,7 @@ export default class BlockEvents extends Module {
|
|||
|
||||
Caret.setToBlock(BlockManager.currentBlock);
|
||||
Toolbar.close();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -413,7 +416,7 @@ export default class BlockEvents extends Module {
|
|||
|
||||
Caret.createShadow(targetBlock.pluginsContent);
|
||||
BlockManager.mergeBlocks(targetBlock, blockToMerge)
|
||||
.then( () => {
|
||||
.then(() => {
|
||||
/** Restore caret position after merge */
|
||||
Caret.restoreCaret(targetBlock.pluginsContent as HTMLElement);
|
||||
targetBlock.pluginsContent.normalize();
|
||||
|
@ -423,6 +426,8 @@ export default class BlockEvents extends Module {
|
|||
|
||||
/**
|
||||
* Handle right and down keyboard keys
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
private arrowRightAndDown(event: KeyboardEvent): void {
|
||||
const isFlipperCombination = Flipper.usedKeys.includes(event.keyCode) &&
|
||||
|
@ -446,6 +451,7 @@ export default class BlockEvents extends Module {
|
|||
|
||||
if (event.shiftKey && event.keyCode === _.keyCodes.DOWN && shouldEnableCBS) {
|
||||
this.Editor.CrossBlockSelection.toggleBlockSelectedState();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -474,6 +480,8 @@ export default class BlockEvents extends Module {
|
|||
|
||||
/**
|
||||
* Handle left and up keyboard keys
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
private arrowLeftAndUp(event: KeyboardEvent): void {
|
||||
/**
|
||||
|
@ -498,6 +506,7 @@ export default class BlockEvents extends Module {
|
|||
|
||||
if (event.shiftKey && event.keyCode === _.keyCodes.UP && shouldEnableCBS) {
|
||||
this.Editor.CrossBlockSelection.toggleBlockSelectedState(false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -524,20 +533,17 @@ export default class BlockEvents extends Module {
|
|||
this.Editor.BlockSelection.clearSelection(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default keydown handler
|
||||
*/
|
||||
private defaultHandler(): void {}
|
||||
|
||||
/**
|
||||
* Cases when we need to close Toolbar
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
private needToolbarClosing(event) {
|
||||
const toolboxItemSelected = (event.keyCode === _.keyCodes.ENTER && this.Editor.Toolbox.opened),
|
||||
blockSettingsItemSelected = (event.keyCode === _.keyCodes.ENTER && this.Editor.BlockSettings.opened),
|
||||
inlineToolbarItemSelected = (event.keyCode === _.keyCodes.ENTER && this.Editor.InlineToolbar.opened),
|
||||
conversionToolbarItemSelected = (event.keyCode === _.keyCodes.ENTER && this.Editor.ConversionToolbar.opened),
|
||||
flippingToolbarItems = event.keyCode === _.keyCodes.TAB;
|
||||
blockSettingsItemSelected = (event.keyCode === _.keyCodes.ENTER && this.Editor.BlockSettings.opened),
|
||||
inlineToolbarItemSelected = (event.keyCode === _.keyCodes.ENTER && this.Editor.InlineToolbar.opened),
|
||||
conversionToolbarItemSelected = (event.keyCode === _.keyCodes.ENTER && this.Editor.ConversionToolbar.opened),
|
||||
flippingToolbarItems = event.keyCode === _.keyCodes.TAB;
|
||||
|
||||
/**
|
||||
* Do not close Toolbar in cases:
|
||||
|
@ -545,12 +551,12 @@ export default class BlockEvents extends Module {
|
|||
* 2. When Toolbar is opened and Tab leafs its Tools
|
||||
* 3. When Toolbar's component is opened and some its item selected
|
||||
*/
|
||||
return !(event.shiftKey
|
||||
|| flippingToolbarItems
|
||||
|| toolboxItemSelected
|
||||
|| blockSettingsItemSelected
|
||||
|| inlineToolbarItemSelected
|
||||
|| conversionToolbarItemSelected
|
||||
return !(event.shiftKey ||
|
||||
flippingToolbarItems ||
|
||||
toolboxItemSelected ||
|
||||
blockSettingsItemSelected ||
|
||||
inlineToolbarItemSelected ||
|
||||
conversionToolbarItemSelected
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -559,7 +565,7 @@ export default class BlockEvents extends Module {
|
|||
*/
|
||||
private activateToolbox(): void {
|
||||
if (!this.Editor.Toolbar.opened) {
|
||||
this.Editor.Toolbar.open(false , false);
|
||||
this.Editor.Toolbar.open(false, false);
|
||||
this.Editor.Toolbar.plusButton.show();
|
||||
}
|
||||
|
||||
|
|
|
@ -6,23 +6,23 @@
|
|||
*
|
||||
* @version 2.0.0
|
||||
*/
|
||||
import Block, {BlockToolAPI} from '../block';
|
||||
import Block, { BlockToolAPI } from '../block';
|
||||
import Module from '../__module';
|
||||
import $ from '../dom';
|
||||
import * as _ from '../utils';
|
||||
import Blocks from '../blocks';
|
||||
import {BlockTool, BlockToolConstructable, BlockToolData, PasteEvent, ToolConfig} from '../../../types';
|
||||
import { BlockTool, BlockToolConstructable, BlockToolData, PasteEvent, ToolConfig } from '../../../types';
|
||||
|
||||
/**
|
||||
* @typedef {BlockManager} BlockManager
|
||||
* @property {Number} currentBlockIndex - Index of current working block
|
||||
* @property {number} currentBlockIndex - Index of current working block
|
||||
* @property {Proxy} _blocks - Proxy for Blocks instance {@link Blocks}
|
||||
*/
|
||||
export default class BlockManager extends Module {
|
||||
|
||||
/**
|
||||
* Returns current Block index
|
||||
* @return {number}
|
||||
*
|
||||
* @returns {number}
|
||||
*/
|
||||
public get currentBlockIndex(): number {
|
||||
return this._currentBlockIndex;
|
||||
|
@ -30,6 +30,7 @@ export default class BlockManager extends Module {
|
|||
|
||||
/**
|
||||
* Set current Block index and fire Block lifecycle callbacks
|
||||
*
|
||||
* @param newIndex
|
||||
*/
|
||||
public set currentBlockIndex(newIndex: number) {
|
||||
|
@ -46,7 +47,8 @@ export default class BlockManager extends Module {
|
|||
|
||||
/**
|
||||
* returns first Block
|
||||
* @return {Block}
|
||||
*
|
||||
* @returns {Block}
|
||||
*/
|
||||
public get firstBlock(): Block {
|
||||
return this._blocks[0];
|
||||
|
@ -54,7 +56,8 @@ export default class BlockManager extends Module {
|
|||
|
||||
/**
|
||||
* returns last Block
|
||||
* @return {Block}
|
||||
*
|
||||
* @returns {Block}
|
||||
*/
|
||||
public get lastBlock(): Block {
|
||||
return this._blocks[this._blocks.length - 1];
|
||||
|
@ -63,7 +66,7 @@ export default class BlockManager extends Module {
|
|||
/**
|
||||
* Get current Block instance
|
||||
*
|
||||
* @return {Block}
|
||||
* @returns {Block}
|
||||
*/
|
||||
public get currentBlock(): Block {
|
||||
return this._blocks[this.currentBlockIndex];
|
||||
|
@ -71,7 +74,8 @@ export default class BlockManager extends Module {
|
|||
|
||||
/**
|
||||
* Returns next Block instance
|
||||
* @return {Block|null}
|
||||
*
|
||||
* @returns {Block|null}
|
||||
*/
|
||||
public get nextBlock(): Block {
|
||||
const isLastBlock = this.currentBlockIndex === (this._blocks.length - 1);
|
||||
|
@ -107,7 +111,8 @@ export default class BlockManager extends Module {
|
|||
|
||||
/**
|
||||
* Returns previous Block instance
|
||||
* @return {Block|null}
|
||||
*
|
||||
* @returns {Block|null}
|
||||
*/
|
||||
public get previousBlock(): Block {
|
||||
const isFirstBlock = this.currentBlockIndex === 0;
|
||||
|
@ -142,7 +147,7 @@ export default class BlockManager extends Module {
|
|||
*
|
||||
* @type {number}
|
||||
*/
|
||||
private _currentBlockIndex: number = -1;
|
||||
private _currentBlockIndex = -1;
|
||||
|
||||
/**
|
||||
* Proxy for Blocks instance {@link Blocks}
|
||||
|
@ -185,25 +190,25 @@ export default class BlockManager extends Module {
|
|||
Listeners.on(
|
||||
document,
|
||||
'copy',
|
||||
(e: ClipboardEvent) => BlockEvents.handleCommandC(e),
|
||||
(e: ClipboardEvent) => BlockEvents.handleCommandC(e)
|
||||
);
|
||||
|
||||
/** Copy and cut */
|
||||
Listeners.on(
|
||||
document,
|
||||
'cut',
|
||||
(e: ClipboardEvent) => BlockEvents.handleCommandX(e),
|
||||
(e: ClipboardEvent) => BlockEvents.handleCommandX(e)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates Block instance by tool name
|
||||
*
|
||||
* @param {String} toolName - tools passed in editor config {@link EditorConfig#tools}
|
||||
* @param {Object} data - constructor params
|
||||
* @param {Object} settings - block settings
|
||||
* @param {string} toolName - tools passed in editor config {@link EditorConfig#tools}
|
||||
* @param {object} data - constructor params
|
||||
* @param {object} settings - block settings
|
||||
*
|
||||
* @return {Block}
|
||||
* @returns {Block}
|
||||
*/
|
||||
public composeBlock(toolName: string, data: BlockToolData = {}, settings: ToolConfig = {}): Block {
|
||||
const toolInstance = this.Editor.Tools.construct(toolName, data) as BlockTool;
|
||||
|
@ -218,20 +223,20 @@ export default class BlockManager extends Module {
|
|||
/**
|
||||
* Insert new block into _blocks
|
||||
*
|
||||
* @param {String} toolName — plugin name, by default method inserts initial block type
|
||||
* @param {Object} data — plugin data
|
||||
* @param {Object} settings - default settings
|
||||
* @param {string} toolName — plugin name, by default method inserts initial block type
|
||||
* @param {object} data — plugin data
|
||||
* @param {object} settings - default settings
|
||||
* @param {number} index - index where to insert new Block
|
||||
* @param {boolean} needToFocus - flag shows if needed to update current Block index
|
||||
*
|
||||
* @return {Block}
|
||||
* @returns {Block}
|
||||
*/
|
||||
public insert(
|
||||
toolName: string = this.config.initialBlock,
|
||||
data: BlockToolData = {},
|
||||
settings: ToolConfig = {},
|
||||
index: number = this.currentBlockIndex + 1,
|
||||
needToFocus: boolean = true,
|
||||
needToFocus = true
|
||||
): Block {
|
||||
const block = this.composeBlock(toolName, data, settings);
|
||||
|
||||
|
@ -254,7 +259,7 @@ export default class BlockManager extends Module {
|
|||
public paste(
|
||||
toolName: string,
|
||||
pasteEvent: PasteEvent,
|
||||
replace: boolean = false,
|
||||
replace = false
|
||||
): Block {
|
||||
let block;
|
||||
|
||||
|
@ -269,6 +274,7 @@ export default class BlockManager extends Module {
|
|||
} catch (e) {
|
||||
_.log(`${toolName}: onPaste callback call is failed`, 'error', e);
|
||||
}
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
|
@ -280,9 +286,9 @@ export default class BlockManager extends Module {
|
|||
*
|
||||
* TODO: Remove method and use insert() with index instead (?)
|
||||
*
|
||||
* @return {Block} inserted Block
|
||||
* @returns {Block} inserted Block
|
||||
*/
|
||||
public insertInitialBlockAtIndex(index: number, needToFocus: boolean = false) {
|
||||
public insertInitialBlockAtIndex(index: number, needToFocus = false) {
|
||||
const block = this.composeBlock(this.config.initialBlock, {}, {});
|
||||
|
||||
this._blocks[index] = block;
|
||||
|
@ -298,7 +304,8 @@ export default class BlockManager extends Module {
|
|||
|
||||
/**
|
||||
* Always inserts at the end
|
||||
* @return {Block}
|
||||
*
|
||||
* @returns {Block}
|
||||
*/
|
||||
public insertAtEnd(): Block {
|
||||
/**
|
||||
|
@ -314,10 +321,11 @@ export default class BlockManager extends Module {
|
|||
|
||||
/**
|
||||
* Merge two blocks
|
||||
*
|
||||
* @param {Block} targetBlock - previous block will be append to this block
|
||||
* @param {Block} blockToMerge - block that will be merged with target block
|
||||
*
|
||||
* @return {Promise} - the sequence that can be continued
|
||||
* @returns {Promise} - the sequence that can be continued
|
||||
*/
|
||||
public async mergeBlocks(targetBlock: Block, blockToMerge: Block): Promise<void> {
|
||||
const blockToMergeIndex = this._blocks.indexOf(blockToMerge);
|
||||
|
@ -338,7 +346,8 @@ export default class BlockManager extends Module {
|
|||
|
||||
/**
|
||||
* Remove block with passed index or remove last
|
||||
* @param {Number|null} index
|
||||
*
|
||||
* @param {number|null} index
|
||||
*/
|
||||
public removeBlock(index?: number): void {
|
||||
if (index === undefined) {
|
||||
|
@ -356,7 +365,6 @@ export default class BlockManager extends Module {
|
|||
if (!this.blocks.length) {
|
||||
this.currentBlockIndex = -1;
|
||||
this.insert();
|
||||
return;
|
||||
} else if (index === 0) {
|
||||
this.currentBlockIndex = 0;
|
||||
}
|
||||
|
@ -365,7 +373,8 @@ export default class BlockManager extends Module {
|
|||
/**
|
||||
* Remove only selected Blocks
|
||||
* and returns first Block index where started removing...
|
||||
* @return number|undefined
|
||||
*
|
||||
* @returns number|undefined
|
||||
*/
|
||||
public removeSelectedBlocks(): number|undefined {
|
||||
let firstSelectedBlockIndex;
|
||||
|
@ -405,7 +414,7 @@ export default class BlockManager extends Module {
|
|||
* 1. Extract content from Caret position to the Block`s end
|
||||
* 2. Insert a new Block below current one with extracted content
|
||||
*
|
||||
* @return {Block}
|
||||
* @returns {Block}
|
||||
*/
|
||||
public split(): Block {
|
||||
const extractedFragment = this.Editor.Caret.extractFragmentFromCaretPosition();
|
||||
|
@ -422,6 +431,7 @@ export default class BlockManager extends Module {
|
|||
|
||||
/**
|
||||
* Renew current Block
|
||||
*
|
||||
* @type {Block}
|
||||
*/
|
||||
return this.insert(this.config.initialBlock, data);
|
||||
|
@ -430,16 +440,16 @@ export default class BlockManager extends Module {
|
|||
/**
|
||||
* Replace current working block
|
||||
*
|
||||
* @param {String} toolName — plugin name
|
||||
* @param {string} toolName — plugin name
|
||||
* @param {BlockToolData} data — plugin data
|
||||
* @param {ToolConfig} settings — plugin config
|
||||
*
|
||||
* @return {Block}
|
||||
* @returns {Block}
|
||||
*/
|
||||
public replace(
|
||||
toolName: string = this.config.initialBlock,
|
||||
data: BlockToolData = {},
|
||||
settings: ToolConfig = {},
|
||||
settings: ToolConfig = {}
|
||||
): Block {
|
||||
const block = this.composeBlock(toolName, data, settings);
|
||||
|
||||
|
@ -450,8 +460,9 @@ export default class BlockManager extends Module {
|
|||
|
||||
/**
|
||||
* Returns Block by passed index
|
||||
* @param {Number} index
|
||||
* @return {Block}
|
||||
*
|
||||
* @param {number} index
|
||||
* @returns {Block}
|
||||
*/
|
||||
public getBlockByIndex(index): Block {
|
||||
return this._blocks[index];
|
||||
|
@ -459,6 +470,7 @@ export default class BlockManager extends Module {
|
|||
|
||||
/**
|
||||
* Get Block instance by html element
|
||||
*
|
||||
* @param {Node} element
|
||||
* @returns {Block}
|
||||
*/
|
||||
|
@ -468,8 +480,8 @@ export default class BlockManager extends Module {
|
|||
}
|
||||
|
||||
const nodes = this._blocks.nodes,
|
||||
firstLevelBlock = element.closest(`.${Block.CSS.wrapper}`),
|
||||
index = nodes.indexOf(firstLevelBlock as HTMLElement);
|
||||
firstLevelBlock = element.closest(`.${Block.CSS.wrapper}`),
|
||||
index = nodes.indexOf(firstLevelBlock as HTMLElement);
|
||||
|
||||
if (index >= 0) {
|
||||
return this._blocks[index];
|
||||
|
@ -487,6 +499,7 @@ export default class BlockManager extends Module {
|
|||
|
||||
/**
|
||||
* Mark current Block as selected
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.currentBlock.focused = true;
|
||||
|
@ -496,7 +509,9 @@ export default class BlockManager extends Module {
|
|||
* Remove selection from all Blocks
|
||||
*/
|
||||
public clearFocused(): void {
|
||||
this.blocks.forEach( (block) => block.focused = false);
|
||||
this.blocks.forEach((block) => {
|
||||
block.focused = false;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -520,9 +535,11 @@ export default class BlockManager extends Module {
|
|||
if (parentFirstLevelBlock) {
|
||||
/**
|
||||
* Update current Block's index
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
this.currentBlockIndex = this._blocks.nodes.indexOf(parentFirstLevelBlock as HTMLElement);
|
||||
|
||||
return this.currentBlock;
|
||||
} else {
|
||||
throw new Error('Can not find a Block from this child Node');
|
||||
|
@ -533,7 +550,7 @@ export default class BlockManager extends Module {
|
|||
* Return block which contents passed node
|
||||
*
|
||||
* @param {Node} childNode
|
||||
* @return {Block}
|
||||
* @returns {Block}
|
||||
*/
|
||||
public getBlockByChildNode(childNode: Node): Block {
|
||||
/**
|
||||
|
@ -550,8 +567,9 @@ export default class BlockManager extends Module {
|
|||
|
||||
/**
|
||||
* Swap Blocks Position
|
||||
* @param {Number} fromIndex
|
||||
* @param {Number} toIndex
|
||||
*
|
||||
* @param {number} fromIndex
|
||||
* @param {number} toIndex
|
||||
* @deprecated — use 'move' instead
|
||||
*/
|
||||
public swap(fromIndex, toIndex): void {
|
||||
|
@ -564,18 +582,21 @@ export default class BlockManager extends Module {
|
|||
|
||||
/**
|
||||
* Move a block to a new index
|
||||
* @param {Number} toIndex
|
||||
* @param {Number} fromIndex
|
||||
*
|
||||
* @param {number} toIndex
|
||||
* @param {number} fromIndex
|
||||
*/
|
||||
public move(toIndex, fromIndex = this.currentBlockIndex): void {
|
||||
// make sure indexes are valid and within a valid range
|
||||
if (isNaN(toIndex) || isNaN(fromIndex)) {
|
||||
_.log(`Warning during 'move' call: incorrect indices provided.`, 'warn');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.validateIndex(toIndex) || !this.validateIndex(fromIndex)) {
|
||||
_.log(`Warning during 'move' call: indices cannot be lower than 0 or greater than the amount of blocks.`, 'warn');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -597,11 +618,12 @@ export default class BlockManager extends Module {
|
|||
|
||||
/**
|
||||
* Clears Editor
|
||||
*
|
||||
* @param {boolean} needAddInitialBlock - 1) in internal calls (for example, in api.blocks.render)
|
||||
* we don't need to add empty initial block
|
||||
* 2) in api.blocks.clear we should add empty block
|
||||
*/
|
||||
public clear(needAddInitialBlock: boolean = false): void {
|
||||
public clear(needAddInitialBlock = false): void {
|
||||
this._blocks.removeAll();
|
||||
this.dropPointer();
|
||||
|
||||
|
@ -617,13 +639,13 @@ export default class BlockManager extends Module {
|
|||
|
||||
/**
|
||||
* Bind Events
|
||||
* @param {Object} block
|
||||
*
|
||||
* @param {object} block
|
||||
*/
|
||||
private bindEvents(block: Block): void {
|
||||
const {BlockEvents, Listeners} = this.Editor;
|
||||
const { BlockEvents, Listeners } = this.Editor;
|
||||
|
||||
Listeners.on(block.holder, 'keydown', (event) => BlockEvents.keydown(event as KeyboardEvent), true);
|
||||
Listeners.on(block.holder, 'mouseup', (event) => BlockEvents.mouseUp());
|
||||
Listeners.on(block.holder, 'mousedown', (event: MouseEvent) => BlockEvents.mouseDown(event));
|
||||
Listeners.on(block.holder, 'keyup', (event) => BlockEvents.keyup(event));
|
||||
Listeners.on(block.holder, 'dragover', (event) => BlockEvents.dragOver(event as DragEvent));
|
||||
|
@ -632,6 +654,7 @@ export default class BlockManager extends Module {
|
|||
|
||||
/**
|
||||
* Validates that the given index is not lower than 0 or higher than the amount of blocks
|
||||
*
|
||||
* @param {number} index - index of blocks array to validate
|
||||
*/
|
||||
private validateIndex(index: number): boolean {
|
||||
|
|
|
@ -12,11 +12,14 @@ import $ from '../dom';
|
|||
|
||||
import SelectionUtils from '../selection';
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export default class BlockSelection extends Module {
|
||||
|
||||
/**
|
||||
* Sanitizer Config
|
||||
* @return {SanitizerConfig}
|
||||
*
|
||||
* @returns {SanitizerConfig}
|
||||
*/
|
||||
private get sanitizerConfig() {
|
||||
return {
|
||||
|
@ -47,37 +50,43 @@ export default class BlockSelection extends Module {
|
|||
|
||||
/**
|
||||
* Flag that identifies all Blocks selection
|
||||
* @return {boolean}
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public get allBlocksSelected(): boolean {
|
||||
const {BlockManager} = this.Editor;
|
||||
const { BlockManager } = this.Editor;
|
||||
|
||||
return BlockManager.blocks.every((block) => block.selected === true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set selected all blocks
|
||||
*
|
||||
* @param {boolean} state
|
||||
*/
|
||||
public set allBlocksSelected(state: boolean) {
|
||||
const {BlockManager} = this.Editor;
|
||||
const { BlockManager } = this.Editor;
|
||||
|
||||
BlockManager.blocks.forEach((block) => block.selected = state);
|
||||
BlockManager.blocks.forEach((block) => {
|
||||
block.selected = state;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag that identifies any Block selection
|
||||
* @return {boolean}
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public get anyBlockSelected(): boolean {
|
||||
const {BlockManager} = this.Editor;
|
||||
const { BlockManager } = this.Editor;
|
||||
|
||||
return BlockManager.blocks.some((block) => block.selected === true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return selected Blocks array
|
||||
* @return {Block[]}
|
||||
*
|
||||
* @returns {Block[]}
|
||||
*/
|
||||
public get selectedBlocks(): Block[] {
|
||||
return this.Editor.BlockManager.blocks.filter((block: Block) => block.selected);
|
||||
|
@ -86,26 +95,30 @@ export default class BlockSelection extends Module {
|
|||
/**
|
||||
* Flag used to define block selection
|
||||
* First CMD+A defines it as true and then second CMD+A selects all Blocks
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
private needToSelectAll: boolean = false;
|
||||
private needToSelectAll = false;
|
||||
|
||||
/**
|
||||
* Flag used to define native input selection
|
||||
* In this case we allow double CMD+A to select Block
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
private nativeInputSelected: boolean = false;
|
||||
private nativeInputSelected = false;
|
||||
|
||||
/**
|
||||
* Flag identifies any input selection
|
||||
* That means we can select whole Block
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
private readyToBlockSelection: boolean = false;
|
||||
private readyToBlockSelection = false;
|
||||
|
||||
/**
|
||||
* SelectionUtils instance
|
||||
*
|
||||
* @type {SelectionUtils}
|
||||
*/
|
||||
private selection: SelectionUtils;
|
||||
|
@ -116,13 +129,14 @@ export default class BlockSelection extends Module {
|
|||
* to select all and copy them
|
||||
*/
|
||||
public prepare(): void {
|
||||
const {Shortcuts} = this.Editor;
|
||||
const { Shortcuts } = this.Editor;
|
||||
|
||||
/** Selection shortcut */
|
||||
Shortcuts.add({
|
||||
name: 'CMD+A',
|
||||
handler: (event) => {
|
||||
const {BlockManager} = this.Editor;
|
||||
const { BlockManager } = this.Editor;
|
||||
|
||||
/**
|
||||
* When one page consist of two or more EditorJS instances
|
||||
* Shortcut module tries to handle all events. Thats why Editor's selection works inside the target Editor, but
|
||||
|
@ -143,10 +157,11 @@ export default class BlockSelection extends Module {
|
|||
|
||||
/**
|
||||
* Remove selection of Block
|
||||
*
|
||||
* @param {number?} index - Block index according to the BlockManager's indexes
|
||||
*/
|
||||
public unSelectBlockByIndex(index?) {
|
||||
const {BlockManager} = this.Editor;
|
||||
const { BlockManager } = this.Editor;
|
||||
|
||||
let block;
|
||||
|
||||
|
@ -166,7 +181,7 @@ export default class BlockSelection extends Module {
|
|||
* @param {boolean} restoreSelection - if true, restore saved selection
|
||||
*/
|
||||
public clearSelection(reason?: Event, restoreSelection = false) {
|
||||
const {BlockManager, Caret, RectangleSelection} = this.Editor;
|
||||
const { BlockManager, Caret, RectangleSelection } = this.Editor;
|
||||
|
||||
this.needToSelectAll = false;
|
||||
this.nativeInputSelected = false;
|
||||
|
@ -190,6 +205,7 @@ export default class BlockSelection extends Module {
|
|||
|
||||
if (!this.anyBlockSelected || RectangleSelection.isRectActivated()) {
|
||||
this.Editor.RectangleSelection.clearSelection();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -210,7 +226,7 @@ export default class BlockSelection extends Module {
|
|||
*
|
||||
* @param {ClipboardEvent} e - copy/cut event
|
||||
*
|
||||
* @return Promise<void>
|
||||
* @returns Promise<void>
|
||||
*/
|
||||
public async copySelectedBlocks(e: ClipboardEvent): Promise<void> {
|
||||
/**
|
||||
|
@ -221,19 +237,20 @@ export default class BlockSelection extends Module {
|
|||
const fakeClipboard = $.make('div');
|
||||
|
||||
this.selectedBlocks.forEach((block) => {
|
||||
/**
|
||||
* Make <p> tag that holds clean HTML
|
||||
*/
|
||||
const cleanHTML = this.Editor.Sanitizer.clean(block.holder.innerHTML, this.sanitizerConfig);
|
||||
const fragment = $.make('p');
|
||||
/**
|
||||
* Make <p> tag that holds clean HTML
|
||||
*/
|
||||
const cleanHTML = this.Editor.Sanitizer.clean(block.holder.innerHTML, this.sanitizerConfig);
|
||||
const fragment = $.make('p');
|
||||
|
||||
fragment.innerHTML = cleanHTML;
|
||||
fakeClipboard.appendChild(fragment);
|
||||
fragment.innerHTML = cleanHTML;
|
||||
fakeClipboard.appendChild(fragment);
|
||||
});
|
||||
|
||||
const savedData = await Promise.all(this.selectedBlocks.map((block) => block.save()));
|
||||
|
||||
const textPlain = Array.from(fakeClipboard.childNodes).map((node) => node.textContent).join('\n\n');
|
||||
const textPlain = Array.from(fakeClipboard.childNodes).map((node) => node.textContent)
|
||||
.join('\n\n');
|
||||
const textHTML = fakeClipboard.innerHTML;
|
||||
|
||||
e.clipboardData.setData('text/plain', textPlain);
|
||||
|
@ -243,10 +260,11 @@ export default class BlockSelection extends Module {
|
|||
|
||||
/**
|
||||
* select Block
|
||||
*
|
||||
* @param {number?} index - Block index according to the BlockManager's indexes
|
||||
*/
|
||||
public selectBlockByIndex(index?) {
|
||||
const {BlockManager} = this.Editor;
|
||||
const { BlockManager } = this.Editor;
|
||||
|
||||
/**
|
||||
* Remove previous focused Block's state
|
||||
|
@ -284,6 +302,7 @@ export default class BlockSelection extends Module {
|
|||
/** allow default selection on native inputs */
|
||||
if ($.isNativeInput(event.target) && !this.readyToBlockSelection) {
|
||||
this.readyToBlockSelection = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -296,11 +315,13 @@ export default class BlockSelection extends Module {
|
|||
*/
|
||||
if (inputs.length > 1 && !this.readyToBlockSelection) {
|
||||
this.readyToBlockSelection = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (inputs.length === 1 && !this.needToSelectAll) {
|
||||
this.needToSelectAll = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,14 +19,13 @@ import * as _ from '../utils';
|
|||
* @typedef {Caret} Caret
|
||||
*/
|
||||
export default class Caret extends Module {
|
||||
|
||||
/**
|
||||
* Allowed caret positions in input
|
||||
*
|
||||
* @static
|
||||
* @returns {{START: string, END: string, DEFAULT: string}}
|
||||
*/
|
||||
public get positions(): {START: string, END: string, DEFAULT: string} {
|
||||
public get positions(): {START: string; END: string; DEFAULT: string} {
|
||||
return {
|
||||
START: 'start',
|
||||
END: 'end',
|
||||
|
@ -45,7 +44,8 @@ export default class Caret extends Module {
|
|||
|
||||
/**
|
||||
* Get's deepest first node and checks if offset is zero
|
||||
* @return {boolean}
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public get isAtStart(): boolean {
|
||||
const selection = Selection.get();
|
||||
|
@ -65,6 +65,7 @@ export default class Caret extends Module {
|
|||
/**
|
||||
* Workaround case when caret in the text like " |Hello!"
|
||||
* selection.anchorOffset is 1, but real caret visible position is 0
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
|
||||
|
@ -84,6 +85,7 @@ export default class Caret extends Module {
|
|||
* So we use child with focusOffset index as new anchorNode.
|
||||
*/
|
||||
let focusOffset = selection.focusOffset;
|
||||
|
||||
if (focusNode.nodeType !== Node.TEXT_NODE && focusNode.childNodes.length) {
|
||||
if (focusNode.childNodes[focusOffset]) {
|
||||
focusNode = focusNode.childNodes[focusOffset];
|
||||
|
@ -106,6 +108,7 @@ export default class Caret extends Module {
|
|||
const nothingAtLeft = leftSiblings.every((node) => {
|
||||
/**
|
||||
* Workaround case when block starts with several <br>'s (created by SHIFT+ENTER)
|
||||
*
|
||||
* @see https://github.com/codex-team/editor.js/issues/726
|
||||
* We need to allow to delete such linebreaks, so in this case caret IS NOT AT START
|
||||
*/
|
||||
|
@ -133,7 +136,8 @@ export default class Caret extends Module {
|
|||
|
||||
/**
|
||||
* Get's deepest last node and checks if offset is last node text length
|
||||
* @return {boolean}
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public get isAtEnd(): boolean {
|
||||
const selection = Selection.get();
|
||||
|
@ -161,6 +165,7 @@ export default class Caret extends Module {
|
|||
* So we use child with anchofocusOffset - 1 as new focusNode.
|
||||
*/
|
||||
let focusOffset = selection.focusOffset;
|
||||
|
||||
if (focusNode.nodeType !== Node.TEXT_NODE && focusNode.childNodes.length) {
|
||||
if (focusNode.childNodes[focusOffset - 1]) {
|
||||
focusNode = focusNode.childNodes[focusOffset - 1];
|
||||
|
@ -216,12 +221,12 @@ export default class Caret extends Module {
|
|||
* - last found text node: sets at the end of the node. Also, you can customize the behaviour
|
||||
*
|
||||
* @param {Block} block - Block class
|
||||
* @param {String} position - position where to set caret.
|
||||
* @param {string} position - position where to set caret.
|
||||
* If default - leave default behaviour and apply offset if it's passed
|
||||
* @param {Number} offset - caret offset regarding to the text node
|
||||
* @param {number} offset - caret offset regarding to the text node
|
||||
*/
|
||||
public setToBlock(block: Block, position: string = this.positions.DEFAULT, offset: number = 0): void {
|
||||
const {BlockManager} = this.Editor;
|
||||
public setToBlock(block: Block, position: string = this.positions.DEFAULT, offset = 0): void {
|
||||
const { BlockManager } = this.Editor;
|
||||
let element;
|
||||
|
||||
switch (position) {
|
||||
|
@ -255,7 +260,7 @@ export default class Caret extends Module {
|
|||
/**
|
||||
* @todo try to fix via Promises or use querySelectorAll to not to use timeout
|
||||
*/
|
||||
_.delay( () => {
|
||||
_.delay(() => {
|
||||
this.set(nodeToSet as HTMLElement, offset);
|
||||
}, 20)();
|
||||
|
||||
|
@ -267,12 +272,12 @@ export default class Caret extends Module {
|
|||
* Set caret to the current input of current Block.
|
||||
*
|
||||
* @param {HTMLElement} input - input where caret should be set
|
||||
* @param {String} position - position of the caret.
|
||||
* @param {string} position - position of the caret.
|
||||
* If default - leave default behaviour and apply offset if it's passed
|
||||
* @param {number} offset - caret offset regarding to the text node
|
||||
*/
|
||||
public setToInput(input: HTMLElement, position: string = this.positions.DEFAULT, offset: number = 0): void {
|
||||
const {currentBlock} = this.Editor.BlockManager;
|
||||
public setToInput(input: HTMLElement, position: string = this.positions.DEFAULT, offset = 0): void {
|
||||
const { currentBlock } = this.Editor.BlockManager;
|
||||
const nodeToSet = $.getDeepestNode(input);
|
||||
|
||||
switch (position) {
|
||||
|
@ -297,12 +302,13 @@ export default class Caret extends Module {
|
|||
|
||||
/**
|
||||
* Creates Document Range and sets caret to the element with offset
|
||||
*
|
||||
* @param {HTMLElement} element - target node.
|
||||
* @param {Number} offset - offset
|
||||
* @param {number} offset - offset
|
||||
*/
|
||||
public set(element: HTMLElement, offset: number = 0): void {
|
||||
public set(element: HTMLElement, offset = 0): void {
|
||||
const range = document.createRange(),
|
||||
selection = Selection.get();
|
||||
selection = Selection.get();
|
||||
|
||||
/** if found deepest node is native input */
|
||||
if ($.isNativeInput(element)) {
|
||||
|
@ -312,6 +318,7 @@ export default class Caret extends Module {
|
|||
|
||||
element.focus();
|
||||
(element as HTMLInputElement).selectionStart = (element as HTMLInputElement).selectionEnd = offset;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -322,14 +329,19 @@ export default class Caret extends Module {
|
|||
selection.addRange(range);
|
||||
|
||||
/** If new cursor position is not visible, scroll to it */
|
||||
const {top, bottom} = element.nodeType === Node.ELEMENT_NODE
|
||||
const { top, bottom } = element.nodeType === Node.ELEMENT_NODE
|
||||
? element.getBoundingClientRect()
|
||||
: range.getBoundingClientRect();
|
||||
const {innerHeight} = window;
|
||||
const { innerHeight } = window;
|
||||
|
||||
if (top < 0) { window.scrollBy(0, top); }
|
||||
if (bottom > innerHeight) { window.scrollBy(0, bottom - innerHeight); }
|
||||
if (top < 0) {
|
||||
window.scrollBy(0, top);
|
||||
}
|
||||
if (bottom > innerHeight) {
|
||||
window.scrollBy(0, bottom - innerHeight);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Caret to the last Block
|
||||
* If last block is not empty, append another empty block
|
||||
|
@ -371,6 +383,7 @@ export default class Caret extends Module {
|
|||
|
||||
range.selectNodeContents(currentBlockInput);
|
||||
range.setStart(selectRange.endContainer, selectRange.endOffset);
|
||||
|
||||
return range.extractContents();
|
||||
}
|
||||
}
|
||||
|
@ -381,13 +394,13 @@ export default class Caret extends Module {
|
|||
* Before moving caret, we should check if caret position is at the end of Plugins node
|
||||
* Using {@link Dom#getDeepestNode} to get a last node and match with current selection
|
||||
*
|
||||
* @param {Boolean} force - force navigation even if caret is not at the end
|
||||
* @param {boolean} force - force navigation even if caret is not at the end
|
||||
*
|
||||
* @return {Boolean}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public navigateNext(force: boolean = false): boolean {
|
||||
const {currentBlock, nextContentfulBlock} = this.Editor.BlockManager;
|
||||
const {nextInput} = currentBlock;
|
||||
public navigateNext(force = false): boolean {
|
||||
const { currentBlock, nextContentfulBlock } = this.Editor.BlockManager;
|
||||
const { nextInput } = currentBlock;
|
||||
|
||||
if (!nextContentfulBlock && !nextInput) {
|
||||
return false;
|
||||
|
@ -412,18 +425,18 @@ export default class Caret extends Module {
|
|||
* Before moving caret, we should check if caret position is start of the Plugins node
|
||||
* Using {@link Dom#getDeepestNode} to get a last node and match with current selection
|
||||
*
|
||||
* @param {Boolean} force - force navigation even if caret is not at the start
|
||||
* @param {boolean} force - force navigation even if caret is not at the start
|
||||
*
|
||||
* @return {Boolean}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public navigatePrevious(force: boolean = false): boolean {
|
||||
const {currentBlock, previousContentfulBlock} = this.Editor.BlockManager;
|
||||
public navigatePrevious(force = false): boolean {
|
||||
const { currentBlock, previousContentfulBlock } = this.Editor.BlockManager;
|
||||
|
||||
if (!currentBlock) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const {previousInput} = currentBlock;
|
||||
const { previousInput } = currentBlock;
|
||||
|
||||
if (!previousContentfulBlock && !previousInput) {
|
||||
return false;
|
||||
|
@ -432,10 +445,11 @@ export default class Caret extends Module {
|
|||
if (force || this.isAtStart) {
|
||||
/** If previous Tool`s input exists, focus on it. Otherwise set caret to the previous Block */
|
||||
if (!previousInput) {
|
||||
this.setToBlock( previousContentfulBlock, this.positions.END );
|
||||
this.setToBlock(previousContentfulBlock, this.positions.END);
|
||||
} else {
|
||||
this.setToInput(previousInput, this.positions.END);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -444,6 +458,7 @@ export default class Caret extends Module {
|
|||
|
||||
/**
|
||||
* Inserts shadow element after passed element where caret can be placed
|
||||
*
|
||||
* @param {Node} element
|
||||
*/
|
||||
public createShadow(element): void {
|
||||
|
@ -455,6 +470,7 @@ export default class Caret extends Module {
|
|||
|
||||
/**
|
||||
* Restores caret position
|
||||
*
|
||||
* @param {HTMLElement} element
|
||||
*/
|
||||
public restoreCaret(element: HTMLElement): void {
|
||||
|
@ -519,16 +535,17 @@ export default class Caret extends Module {
|
|||
*
|
||||
* @example
|
||||
* <div contenteditable>
|
||||
* <p></p> |
|
||||
* <p></p> | left first-level siblings
|
||||
* <p></p> |
|
||||
* <blockquote><a><b>adaddad</b><a><blockquote> <-- passed node for example <b>
|
||||
* <p></p> |
|
||||
* <p></p> | right first-level siblings
|
||||
* <p></p> |
|
||||
* <p></p> |
|
||||
* <p></p> | left first-level siblings
|
||||
* <p></p> |
|
||||
* <blockquote><a><b>adaddad</b><a><blockquote> <-- passed node for example <b>
|
||||
* <p></p> |
|
||||
* <p></p> | right first-level siblings
|
||||
* <p></p> |
|
||||
* </div>
|
||||
*
|
||||
* @return {Element[]}
|
||||
* @returns {Element[]}
|
||||
* @param from
|
||||
* @param direction
|
||||
*/
|
||||
private getHigherLevelSiblings(from: HTMLElement, direction?: string): HTMLElement[] {
|
||||
let current = from;
|
||||
|
|
|
@ -3,6 +3,9 @@ import Block from '../block';
|
|||
import SelectionUtils from '../selection';
|
||||
import * as _ from '../utils';
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export default class CrossBlockSelection extends Module {
|
||||
/**
|
||||
* Block where selection is started
|
||||
|
@ -24,7 +27,7 @@ export default class CrossBlockSelection extends Module {
|
|||
return;
|
||||
}
|
||||
|
||||
const {BlockManager, UI, Listeners} = this.Editor;
|
||||
const { BlockManager, UI, Listeners } = this.Editor;
|
||||
|
||||
this.firstSelectedBlock = BlockManager.getBlock(event.target as HTMLElement);
|
||||
this.lastSelectedBlock = this.firstSelectedBlock;
|
||||
|
@ -37,8 +40,8 @@ export default class CrossBlockSelection extends Module {
|
|||
* return boolean is cross block selection started
|
||||
*/
|
||||
public get isCrossBlockSelectionStarted(): boolean {
|
||||
return !!this.firstSelectedBlock
|
||||
&& !!this.lastSelectedBlock;
|
||||
return !!this.firstSelectedBlock &&
|
||||
!!this.lastSelectedBlock;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -47,8 +50,8 @@ export default class CrossBlockSelection extends Module {
|
|||
*
|
||||
* @param {boolean} next - if true, toggle next block. Previous otherwise
|
||||
*/
|
||||
public toggleBlockSelectedState(next: boolean = true): void {
|
||||
const {BlockManager} = this.Editor;
|
||||
public toggleBlockSelectedState(next = true): void {
|
||||
const { BlockManager } = this.Editor;
|
||||
|
||||
if (!this.lastSelectedBlock) {
|
||||
this.lastSelectedBlock = this.firstSelectedBlock = BlockManager.currentBlock;
|
||||
|
@ -84,7 +87,7 @@ export default class CrossBlockSelection extends Module {
|
|||
* @param {Event} reason - event caused clear of selection
|
||||
*/
|
||||
public clear(reason?: Event) {
|
||||
const {BlockManager, BlockSelection, Caret} = this.Editor;
|
||||
const { BlockManager, BlockSelection, Caret } = this.Editor;
|
||||
const fIndex = BlockManager.blocks.indexOf(this.firstSelectedBlock);
|
||||
const lIndex = BlockManager.blocks.indexOf(this.lastSelectedBlock);
|
||||
|
||||
|
@ -121,8 +124,8 @@ export default class CrossBlockSelection extends Module {
|
|||
* Mouse up event handler.
|
||||
* Removes the listeners
|
||||
*/
|
||||
private onMouseUp = (): void => {
|
||||
const {Listeners} = this.Editor;
|
||||
private onMouseUp = (): void => {
|
||||
const { Listeners } = this.Editor;
|
||||
|
||||
Listeners.off(document, 'mouseover', this.onMouseOver);
|
||||
Listeners.off(document, 'mouseup', this.onMouseUp);
|
||||
|
@ -135,7 +138,7 @@ export default class CrossBlockSelection extends Module {
|
|||
* @param {MouseEvent} event
|
||||
*/
|
||||
private onMouseOver = (event: MouseEvent): void => {
|
||||
const {BlockManager} = this.Editor;
|
||||
const { BlockManager } = this.Editor;
|
||||
|
||||
const relatedBlock = BlockManager.getBlockByChildNode(event.relatedTarget as Node) || this.lastSelectedBlock;
|
||||
const targetBlock = BlockManager.getBlockByChildNode(event.target as Node);
|
||||
|
@ -153,12 +156,14 @@ export default class CrossBlockSelection extends Module {
|
|||
|
||||
relatedBlock.selected = true;
|
||||
targetBlock.selected = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (targetBlock === this.firstSelectedBlock) {
|
||||
relatedBlock.selected = false;
|
||||
targetBlock.selected = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -175,7 +180,7 @@ export default class CrossBlockSelection extends Module {
|
|||
* @param {Block} lastBlock
|
||||
*/
|
||||
private toggleBlocksSelectedState(firstBlock: Block, lastBlock: Block): void {
|
||||
const {BlockManager} = this.Editor;
|
||||
const { BlockManager } = this.Editor;
|
||||
const fIndex = BlockManager.blocks.indexOf(firstBlock);
|
||||
const lIndex = BlockManager.blocks.indexOf(lastBlock);
|
||||
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import SelectionUtils from '../selection';
|
||||
|
||||
import Module from '../__module';
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export default class DragNDrop extends Module {
|
||||
|
||||
/**
|
||||
* If drag has been started at editor, we save it
|
||||
*
|
||||
|
@ -22,13 +24,13 @@ export default class DragNDrop extends Module {
|
|||
|
||||
/**
|
||||
* Add drag events listeners to editor zone
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
private bindEvents(): void {
|
||||
this.Editor.Listeners.on(this.Editor.UI.nodes.holder, 'drop', this.processDrop, true);
|
||||
|
||||
this.Editor.Listeners.on(this.Editor.UI.nodes.holder, 'dragstart', (dragEvent: DragEvent) => {
|
||||
|
||||
if (SelectionUtils.isAtEditor && !SelectionUtils.isCollapsed) {
|
||||
this.isStartedAtEditor = true;
|
||||
}
|
||||
|
@ -54,7 +56,9 @@ export default class DragNDrop extends Module {
|
|||
|
||||
dropEvent.preventDefault();
|
||||
|
||||
BlockManager.blocks.forEach((block) => block.dropTarget = false);
|
||||
BlockManager.blocks.forEach((block) => {
|
||||
block.dropTarget = false;
|
||||
});
|
||||
|
||||
if (SelectionUtils.isAtEditor && !SelectionUtils.isCollapsed && this.isStartedAtEditor) {
|
||||
document.execCommand('delete');
|
||||
|
|
|
@ -11,12 +11,12 @@ import Module from '../__module';
|
|||
* @version 1.0.0
|
||||
*
|
||||
* @typedef {Events} Events
|
||||
* @property {Object} subscribers - all subscribers grouped by event name
|
||||
* @property {object} subscribers - all subscribers grouped by event name
|
||||
*/
|
||||
export default class Events extends Module {
|
||||
|
||||
/**
|
||||
* Object with events` names as key and array of callback functions as value
|
||||
*
|
||||
* @type {{}}
|
||||
*/
|
||||
private subscribers: {[name: string]: Array<(data?: any) => any>} = {};
|
||||
|
@ -24,7 +24,7 @@ export default class Events extends Module {
|
|||
/**
|
||||
* Subscribe any event on callback
|
||||
*
|
||||
* @param {String} eventName - event name
|
||||
* @param {string} eventName - event name
|
||||
* @param {Function} callback - subscriber
|
||||
*/
|
||||
public on(eventName: string, callback: (data: any) => any) {
|
||||
|
@ -39,7 +39,7 @@ export default class Events extends Module {
|
|||
/**
|
||||
* Subscribe any event on callback. Callback will be called once and be removed from subscribers array after call.
|
||||
*
|
||||
* @param {String} eventName - event name
|
||||
* @param {string} eventName - event name
|
||||
* @param {Function} callback - subscriber
|
||||
*/
|
||||
public once(eventName: string, callback: (data: any) => any) {
|
||||
|
@ -66,8 +66,8 @@ export default class Events extends Module {
|
|||
/**
|
||||
* Emit callbacks with passed data
|
||||
*
|
||||
* @param {String} eventName - event name
|
||||
* @param {Object} data - subscribers get this data when they were fired
|
||||
* @param {string} eventName - event name
|
||||
* @param {object} data - subscribers get this data when they were fired
|
||||
*/
|
||||
public emit(eventName: string, data?: any): void {
|
||||
if (!this.subscribers[eventName]) {
|
||||
|
@ -77,7 +77,7 @@ export default class Events extends Module {
|
|||
this.subscribers[eventName].reduce((previousData, currentHandler) => {
|
||||
const newData = currentHandler(previousData);
|
||||
|
||||
return newData ? newData : previousData;
|
||||
return newData || previousData;
|
||||
}, data);
|
||||
}
|
||||
|
||||
|
|
|
@ -43,9 +43,9 @@ export interface ListenerData {
|
|||
* @property {Array} allListeners
|
||||
*/
|
||||
export default class Listeners extends Module {
|
||||
|
||||
/**
|
||||
* Stores all listeners data to find/remove/process it
|
||||
*
|
||||
* @type {ListenerData[]}
|
||||
*/
|
||||
private allListeners: ListenerData[] = [];
|
||||
|
@ -54,15 +54,15 @@ export default class Listeners extends Module {
|
|||
* Assigns event listener on element
|
||||
*
|
||||
* @param {EventTarget} element - DOM element that needs to be listened
|
||||
* @param {String} eventType - event type
|
||||
* @param {string} eventType - event type
|
||||
* @param {Function} handler - method that will be fired on event
|
||||
* @param {Boolean|AddEventListenerOptions} options - useCapture or {capture, passive, once}
|
||||
* @param {boolean|AddEventListenerOptions} options - useCapture or {capture, passive, once}
|
||||
*/
|
||||
public on(
|
||||
element: EventTarget,
|
||||
eventType: string,
|
||||
handler: (event: Event) => void,
|
||||
options: boolean | AddEventListenerOptions = false,
|
||||
options: boolean | AddEventListenerOptions = false
|
||||
): void {
|
||||
const assignedEventData = {
|
||||
element,
|
||||
|
@ -73,7 +73,9 @@ export default class Listeners extends Module {
|
|||
|
||||
const alreadyExist = this.findOne(element, eventType, handler);
|
||||
|
||||
if (alreadyExist) { return; }
|
||||
if (alreadyExist) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.allListeners.push(assignedEventData);
|
||||
element.addEventListener(eventType, handler, options);
|
||||
|
@ -83,15 +85,15 @@ export default class Listeners extends Module {
|
|||
* Removes event listener from element
|
||||
*
|
||||
* @param {EventTarget} element - DOM element that we removing listener
|
||||
* @param {String} eventType - event type
|
||||
* @param {string} eventType - event type
|
||||
* @param {Function} handler - remove handler, if element listens several handlers on the same event type
|
||||
* @param {Boolean|AddEventListenerOptions} options - useCapture or {capture, passive, once}
|
||||
* @param {boolean|AddEventListenerOptions} options - useCapture or {capture, passive, once}
|
||||
*/
|
||||
public off(
|
||||
element: EventTarget,
|
||||
eventType: string,
|
||||
handler?: (event: Event) => void,
|
||||
options?: boolean | AddEventListenerOptions,
|
||||
options?: boolean | AddEventListenerOptions
|
||||
): void {
|
||||
const existingListeners = this.findAll(element, eventType, handler);
|
||||
|
||||
|
@ -104,14 +106,13 @@ export default class Listeners extends Module {
|
|||
listener.element.removeEventListener(listener.eventType, listener.handler, listener.options);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {EventTarget} element
|
||||
* @param {String} eventType
|
||||
* @param {string} eventType
|
||||
* @param {Function} handler
|
||||
* @return {ListenerData|null}
|
||||
* @returns {ListenerData|null}
|
||||
*/
|
||||
public findOne(element: EventTarget, eventType?: string, handler?: (event: Event) => void): ListenerData {
|
||||
const foundListeners = this.findAll(element, eventType, handler);
|
||||
|
@ -121,18 +122,18 @@ export default class Listeners extends Module {
|
|||
|
||||
/**
|
||||
* @param {EventTarget} element
|
||||
* @param {String} eventType
|
||||
* @param {string} eventType
|
||||
* @param {Function} handler
|
||||
* @return {ListenerData[]}
|
||||
* @returns {ListenerData[]}
|
||||
*/
|
||||
public findAll(element: EventTarget, eventType?: string, handler?: (event: Event) => void): ListenerData[] {
|
||||
let found;
|
||||
const foundByEventTargets = element ? this.findByEventTarget(element) : [];
|
||||
|
||||
if (element && eventType && handler) {
|
||||
found = foundByEventTargets.filter( (event) => event.eventType === eventType && event.handler === handler );
|
||||
found = foundByEventTargets.filter((event) => event.eventType === eventType && event.handler === handler);
|
||||
} else if (element && eventType) {
|
||||
found = foundByEventTargets.filter( (event) => event.eventType === eventType);
|
||||
found = foundByEventTargets.filter((event) => event.eventType === eventType);
|
||||
} else {
|
||||
found = foundByEventTargets;
|
||||
}
|
||||
|
@ -144,7 +145,7 @@ export default class Listeners extends Module {
|
|||
* Removes all listeners
|
||||
*/
|
||||
public removeAll(): void {
|
||||
this.allListeners.map( (current) => {
|
||||
this.allListeners.map((current) => {
|
||||
current.element.removeEventListener(current.eventType, current.handler, current.options);
|
||||
});
|
||||
|
||||
|
@ -153,6 +154,7 @@ export default class Listeners extends Module {
|
|||
|
||||
/**
|
||||
* Search method: looks for listener by passed element
|
||||
*
|
||||
* @param {EventTarget} element - searching element
|
||||
* @returns {Array} listeners that found on element
|
||||
*/
|
||||
|
@ -166,8 +168,9 @@ export default class Listeners extends Module {
|
|||
|
||||
/**
|
||||
* Search method: looks for listener by passed event type
|
||||
* @param {String} eventType
|
||||
* @return {Array} listeners that found on element
|
||||
*
|
||||
* @param {string} eventType
|
||||
* @returns {Array} listeners that found on element
|
||||
*/
|
||||
private findByType(eventType: string): ListenerData[] {
|
||||
return this.allListeners.filter((listener) => {
|
||||
|
@ -179,8 +182,9 @@ export default class Listeners extends Module {
|
|||
|
||||
/**
|
||||
* Search method: looks for listener by passed handler
|
||||
*
|
||||
* @param {Function} handler
|
||||
* @return {Array} listeners that found on element
|
||||
* @returns {Array} listeners that found on element
|
||||
*/
|
||||
private findByHandler(handler: (event: Event) => void): ListenerData[] {
|
||||
return this.allListeners.filter((listener) => {
|
||||
|
|
|
@ -9,10 +9,13 @@ import Module from '../__module';
|
|||
import * as _ from '../utils';
|
||||
import Block from '../block';
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export default class ModificationsObserver extends Module {
|
||||
|
||||
/**
|
||||
* Debounce Timer
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
public static readonly DebounceTimer = 450;
|
||||
|
@ -29,9 +32,10 @@ export default class ModificationsObserver extends Module {
|
|||
|
||||
/**
|
||||
* Used to prevent several mutation callback execution
|
||||
*
|
||||
* @type {Function}
|
||||
*/
|
||||
private mutationDebouncer = _.debounce( () => {
|
||||
private mutationDebouncer = _.debounce(() => {
|
||||
this.updateNativeInputs();
|
||||
this.config.onChange(this.Editor.API.methods);
|
||||
}, ModificationsObserver.DebounceTimer);
|
||||
|
@ -56,13 +60,14 @@ export default class ModificationsObserver extends Module {
|
|||
|
||||
/**
|
||||
* Preparation method
|
||||
* @return {Promise<void>}
|
||||
*
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
public async prepare(): Promise<void> {
|
||||
/**
|
||||
* wait till Browser render Editor's Blocks
|
||||
*/
|
||||
window.setTimeout( () => {
|
||||
window.setTimeout(() => {
|
||||
this.setObserver();
|
||||
}, 1000);
|
||||
}
|
||||
|
@ -90,7 +95,7 @@ export default class ModificationsObserver extends Module {
|
|||
* so that User can handle outside from API
|
||||
*/
|
||||
private setObserver(): void {
|
||||
const {UI} = this.Editor;
|
||||
const { UI } = this.Editor;
|
||||
const observerOptions = {
|
||||
childList: true,
|
||||
attributes: true,
|
||||
|
@ -107,6 +112,7 @@ export default class ModificationsObserver extends Module {
|
|||
|
||||
/**
|
||||
* MutationObserver events handler
|
||||
*
|
||||
* @param mutationList
|
||||
* @param observer
|
||||
*/
|
||||
|
@ -141,7 +147,6 @@ export default class ModificationsObserver extends Module {
|
|||
*/
|
||||
if (!mutatedTarget.classList.contains(Block.CSS.wrapper)) {
|
||||
contentMutated = true;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -5,13 +5,12 @@ import Module from '../__module';
|
|||
*
|
||||
* @see https://github.com/codex-team/js-notifier
|
||||
*/
|
||||
import notifier, {ConfirmNotifierOptions, NotifierOptions, PromptNotifierOptions} from 'codex-notifier';
|
||||
import notifier, { ConfirmNotifierOptions, NotifierOptions, PromptNotifierOptions } from 'codex-notifier';
|
||||
|
||||
/**
|
||||
* Notifier module
|
||||
*/
|
||||
export default class Notifier extends Module {
|
||||
|
||||
/**
|
||||
* Show web notification
|
||||
*
|
||||
|
|
|
@ -7,7 +7,7 @@ import {
|
|||
BlockToolData,
|
||||
PasteConfig,
|
||||
PasteEvent,
|
||||
PasteEventDetail,
|
||||
PasteEventDetail
|
||||
} from '../../../types';
|
||||
import Block from '../block';
|
||||
|
||||
|
@ -17,6 +17,7 @@ import Block from '../block';
|
|||
interface TagSubstitute {
|
||||
/**
|
||||
* Name of related Tool
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
tool: string;
|
||||
|
@ -28,18 +29,21 @@ interface TagSubstitute {
|
|||
interface PatternSubstitute {
|
||||
/**
|
||||
* Pattern`s key
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
key: string;
|
||||
|
||||
/**
|
||||
* Pattern regexp
|
||||
*
|
||||
* @type {RegExp}
|
||||
*/
|
||||
pattern: RegExp;
|
||||
|
||||
/**
|
||||
* Name of related Tool
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
tool: string;
|
||||
|
@ -51,12 +55,14 @@ interface PatternSubstitute {
|
|||
interface FilesSubstitution {
|
||||
/**
|
||||
* Array of file extensions Tool can handle
|
||||
*
|
||||
* @type {string[]}
|
||||
*/
|
||||
extensions: string[];
|
||||
|
||||
/**
|
||||
* Array of MIME types Tool can handle
|
||||
*
|
||||
* @type {string[]}
|
||||
*/
|
||||
mimeTypes: string[];
|
||||
|
@ -68,12 +74,14 @@ interface FilesSubstitution {
|
|||
interface PasteData {
|
||||
/**
|
||||
* Name of related Tool
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
tool: string;
|
||||
|
||||
/**
|
||||
* Pasted data. Processed and wrapped to HTML element
|
||||
*
|
||||
* @type {HTMLElement}
|
||||
*/
|
||||
content: HTMLElement;
|
||||
|
@ -85,6 +93,7 @@ interface PasteData {
|
|||
|
||||
/**
|
||||
* True if content should be inserted as new Block
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
isBlock: boolean;
|
||||
|
@ -99,7 +108,6 @@ interface PasteData {
|
|||
* @version 2.0.0
|
||||
*/
|
||||
export default class Paste extends Module {
|
||||
|
||||
/** If string`s length is greater than this number we don't check paste patterns */
|
||||
public static readonly PATTERN_PROCESSING_MAX_LENGTH = 450;
|
||||
|
||||
|
@ -121,7 +129,7 @@ export default class Paste extends Module {
|
|||
|
||||
/** Files` substitutions parameters */
|
||||
private toolsFiles: {
|
||||
[tool: string]: FilesSubstitution,
|
||||
[tool: string]: FilesSubstitution;
|
||||
} = {};
|
||||
|
||||
/**
|
||||
|
@ -157,12 +165,13 @@ export default class Paste extends Module {
|
|||
|
||||
if (includesFiles) {
|
||||
await this.processFiles(dataTransfer.files);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const editorJSData = dataTransfer.getData(this.MIME_TYPE);
|
||||
const plainData = dataTransfer.getData('text/plain');
|
||||
let htmlData = dataTransfer.getData('text/html');
|
||||
let htmlData = dataTransfer.getData('text/html');
|
||||
|
||||
/**
|
||||
* If EditorJS json is passed, insert it
|
||||
|
@ -179,7 +188,7 @@ export default class Paste extends Module {
|
|||
* If text was drag'n'dropped, wrap content with P tag to insert it as the new Block
|
||||
*/
|
||||
if (isDragNDrop && plainData.trim() && htmlData.trim()) {
|
||||
htmlData = '<p>' + ( htmlData.trim() ? htmlData : plainData ) + '</p>';
|
||||
htmlData = '<p>' + (htmlData.trim() ? htmlData : plainData) + '</p>';
|
||||
}
|
||||
|
||||
/** Add all tags that can be substituted to sanitizer configuration */
|
||||
|
@ -189,7 +198,7 @@ export default class Paste extends Module {
|
|||
return result;
|
||||
}, {});
|
||||
|
||||
const customConfig = Object.assign({}, toolsTags, Sanitizer.getAllInlineToolsConfig(), {br: {}});
|
||||
const customConfig = Object.assign({}, toolsTags, Sanitizer.getAllInlineToolsConfig(), { br: {} });
|
||||
|
||||
const cleanData = Sanitizer.clean(htmlData, customConfig);
|
||||
|
||||
|
@ -207,8 +216,8 @@ export default class Paste extends Module {
|
|||
* @param {string} data - text to process. Can be HTML or plain.
|
||||
* @param {boolean} isHTML - if passed string is HTML, this parameter should be true
|
||||
*/
|
||||
public async processText(data: string, isHTML: boolean = false) {
|
||||
const {Caret, BlockManager, Tools} = this.Editor;
|
||||
public async processText(data: string, isHTML = false) {
|
||||
const { Caret, BlockManager, Tools } = this.Editor;
|
||||
const dataToInsert = isHTML ? this.processHTML(data) : this.processPlain(data);
|
||||
|
||||
if (!dataToInsert.length) {
|
||||
|
@ -221,6 +230,7 @@ export default class Paste extends Module {
|
|||
} else {
|
||||
this.processSingleBlock(dataToInsert.pop());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -228,7 +238,7 @@ export default class Paste extends Module {
|
|||
const needToReplaceCurrentBlock = isCurrentBlockInitial && BlockManager.currentBlock.isEmpty;
|
||||
|
||||
dataToInsert.map(
|
||||
async (content, i) => this.insertBlock(content, i === 0 && needToReplaceCurrentBlock),
|
||||
async (content, i) => this.insertBlock(content, i === 0 && needToReplaceCurrentBlock)
|
||||
);
|
||||
|
||||
if (BlockManager.currentBlock) {
|
||||
|
@ -240,7 +250,7 @@ export default class Paste extends Module {
|
|||
* Set onPaste callback handler
|
||||
*/
|
||||
private setCallback(): void {
|
||||
const {Listeners} = this.Editor;
|
||||
const { Listeners } = this.Editor;
|
||||
|
||||
Listeners.on(this.Editor.UI.nodes.holder, 'paste', this.handlePasteEvent);
|
||||
}
|
||||
|
@ -270,6 +280,7 @@ export default class Paste extends Module {
|
|||
|
||||
if (tool.pasteConfig === false) {
|
||||
this.exceptionList.push(name);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -286,7 +297,7 @@ export default class Paste extends Module {
|
|||
_.log(
|
||||
`Paste handling for «${name}» Tool hasn't been set up because of the error`,
|
||||
'warn',
|
||||
e,
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -305,8 +316,9 @@ export default class Paste extends Module {
|
|||
_.log(
|
||||
`Paste handler for «${name}» Tool on «${tag}» tag is skipped ` +
|
||||
`because it is already used by «${this.toolsTags[tag].tool}» Tool.`,
|
||||
'warn',
|
||||
'warn'
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -325,9 +337,8 @@ export default class Paste extends Module {
|
|||
* @param {PasteConfig} toolPasteConfig - Tool onPaste configuration
|
||||
*/
|
||||
private getFilesConfig(name: string, toolPasteConfig: PasteConfig): void {
|
||||
|
||||
const {files = {}} = toolPasteConfig;
|
||||
let {extensions, mimeTypes} = files;
|
||||
const { files = {} } = toolPasteConfig;
|
||||
let { extensions, mimeTypes } = files;
|
||||
|
||||
if (!extensions && !mimeTypes) {
|
||||
return;
|
||||
|
@ -347,6 +358,7 @@ export default class Paste extends Module {
|
|||
mimeTypes = mimeTypes.filter((type) => {
|
||||
if (!_.isValidMimeType(type)) {
|
||||
_.log(`MIME type value «${type}» for the «${name}» Tool is not a valid MIME type`, 'warn');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -376,7 +388,7 @@ export default class Paste extends Module {
|
|||
if (!(pattern instanceof RegExp)) {
|
||||
_.log(
|
||||
`Pattern ${pattern} for «${name}» Tool is skipped because it should be a Regexp instance.`,
|
||||
'warn',
|
||||
'warn'
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -404,12 +416,11 @@ export default class Paste extends Module {
|
|||
* @param {ClipboardEvent} event
|
||||
*/
|
||||
private handlePasteEvent = async (event: ClipboardEvent): Promise<void> => {
|
||||
const {BlockManager, Toolbar} = this.Editor;
|
||||
const { BlockManager, Toolbar } = this.Editor;
|
||||
|
||||
/** If target is native input or is not Block, use browser behaviour */
|
||||
if (
|
||||
!BlockManager.currentBlock ||
|
||||
this.isNativeBehaviour(event.target) && !event.clipboardData.types.includes('Files')
|
||||
!BlockManager.currentBlock || this.isNativeBehaviour(event.target) && !event.clipboardData.types.includes('Files')
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
@ -434,14 +445,14 @@ export default class Paste extends Module {
|
|||
* @param {FileList} items - pasted or dropped items
|
||||
*/
|
||||
private async processFiles(items: FileList) {
|
||||
const {BlockManager, Tools} = this.Editor;
|
||||
const { BlockManager, Tools } = this.Editor;
|
||||
|
||||
let dataToInsert: Array<{type: string, event: PasteEvent}>;
|
||||
let dataToInsert: Array<{type: string; event: PasteEvent}>;
|
||||
|
||||
dataToInsert = await Promise.all(
|
||||
Array
|
||||
.from(items)
|
||||
.map((item) => this.processFile(item)),
|
||||
.map((item) => this.processFile(item))
|
||||
);
|
||||
dataToInsert = dataToInsert.filter((data) => !!data);
|
||||
|
||||
|
@ -451,7 +462,7 @@ export default class Paste extends Module {
|
|||
dataToInsert.forEach(
|
||||
(data, i) => {
|
||||
BlockManager.paste(data.type, data.event, i === 0 && needToReplaceCurrentBlock);
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -465,7 +476,7 @@ export default class Paste extends Module {
|
|||
|
||||
const foundConfig = Object
|
||||
.entries(this.toolsFiles)
|
||||
.find(([toolName, {mimeTypes, extensions}]) => {
|
||||
.find(([toolName, { mimeTypes, extensions } ]) => {
|
||||
const [fileType, fileSubtype] = file.type.split('/');
|
||||
|
||||
const foundExt = extensions.find((ext) => ext.toLowerCase() === extension.toLowerCase());
|
||||
|
@ -482,7 +493,7 @@ export default class Paste extends Module {
|
|||
return;
|
||||
}
|
||||
|
||||
const [tool] = foundConfig;
|
||||
const [ tool ] = foundConfig;
|
||||
const pasteEvent = this.composePasteEvent('file', {
|
||||
file,
|
||||
});
|
||||
|
@ -500,7 +511,7 @@ export default class Paste extends Module {
|
|||
* @returns {PasteData[]}
|
||||
*/
|
||||
private processHTML(innerHTML: string): PasteData[] {
|
||||
const {Tools, Sanitizer} = this.Editor;
|
||||
const { Tools, Sanitizer } = this.Editor;
|
||||
const initialTool = this.config.initialBlock;
|
||||
const wrapper = $.make('DIV');
|
||||
|
||||
|
@ -530,7 +541,7 @@ export default class Paste extends Module {
|
|||
break;
|
||||
}
|
||||
|
||||
const {tags} = Tools.blockTools[tool].pasteConfig as PasteConfig;
|
||||
const { tags } = Tools.blockTools[tool].pasteConfig as PasteConfig;
|
||||
|
||||
const toolTags = tags.reduce((result, tag) => {
|
||||
result[tag.toLowerCase()] = {};
|
||||
|
@ -545,7 +556,12 @@ export default class Paste extends Module {
|
|||
data: content,
|
||||
});
|
||||
|
||||
return {content, isBlock, tool, event};
|
||||
return {
|
||||
content,
|
||||
isBlock,
|
||||
tool,
|
||||
event,
|
||||
};
|
||||
})
|
||||
.filter((data) => !$.isNodeEmpty(data.content) || $.isSingleTag(data.content));
|
||||
}
|
||||
|
@ -557,8 +573,8 @@ export default class Paste extends Module {
|
|||
* @returns {PasteData[]}
|
||||
*/
|
||||
private processPlain(plain: string): PasteData[] {
|
||||
const {initialBlock} = this.config as {initialBlock: string},
|
||||
{Tools} = this.Editor;
|
||||
const { initialBlock } = this.config as {initialBlock: string},
|
||||
{ Tools } = this.Editor;
|
||||
|
||||
if (!plain) {
|
||||
return [];
|
||||
|
@ -578,7 +594,12 @@ export default class Paste extends Module {
|
|||
data: content,
|
||||
});
|
||||
|
||||
return {content, tool, isBlock: false, event};
|
||||
return {
|
||||
content,
|
||||
tool,
|
||||
isBlock: false,
|
||||
event,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -588,8 +609,8 @@ export default class Paste extends Module {
|
|||
* @param {PasteData} dataToInsert
|
||||
*/
|
||||
private async processSingleBlock(dataToInsert: PasteData): Promise<void> {
|
||||
const {Caret, BlockManager, Tools} = this.Editor;
|
||||
const {currentBlock} = BlockManager;
|
||||
const { Caret, BlockManager, Tools } = this.Editor;
|
||||
const { currentBlock } = BlockManager;
|
||||
|
||||
/**
|
||||
* If pasted tool isn`t equal current Block or if pasted content contains block elements, insert it as new Block
|
||||
|
@ -600,6 +621,7 @@ export default class Paste extends Module {
|
|||
!$.containsOnlyInlineElements(dataToInsert.content.innerHTML)
|
||||
) {
|
||||
this.insertBlock(dataToInsert, currentBlock && Tools.isInitial(currentBlock.tool) && currentBlock.isEmpty);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -615,8 +637,8 @@ export default class Paste extends Module {
|
|||
* @param {PasteData} dataToInsert
|
||||
*/
|
||||
private async processInlinePaste(dataToInsert: PasteData): Promise<void> {
|
||||
const {BlockManager, Caret, Sanitizer, Tools} = this.Editor;
|
||||
const {content, tool} = dataToInsert;
|
||||
const { BlockManager, Caret, Sanitizer, Tools } = this.Editor;
|
||||
const { content, tool } = dataToInsert;
|
||||
|
||||
const currentBlockIsInitial = BlockManager.currentBlock && Tools.isInitial(BlockManager.currentBlock.tool);
|
||||
|
||||
|
@ -624,15 +646,14 @@ export default class Paste extends Module {
|
|||
const blockData = await this.processPattern(content.textContent);
|
||||
|
||||
if (blockData) {
|
||||
let insertedBlock;
|
||||
const needToReplaceCurrentBlock = BlockManager.currentBlock &&
|
||||
Tools.isInitial(BlockManager.currentBlock.tool) &&
|
||||
BlockManager.currentBlock.isEmpty;
|
||||
|
||||
const needToReplaceCurrentBlock = BlockManager.currentBlock
|
||||
&& Tools.isInitial(BlockManager.currentBlock.tool)
|
||||
&& BlockManager.currentBlock.isEmpty;
|
||||
|
||||
insertedBlock = BlockManager.paste(blockData.tool, blockData.event, needToReplaceCurrentBlock);
|
||||
const insertedBlock = BlockManager.paste(blockData.tool, blockData.event, needToReplaceCurrentBlock);
|
||||
|
||||
Caret.setToBlock(insertedBlock, Caret.positions.END);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -644,7 +665,7 @@ export default class Paste extends Module {
|
|||
document.execCommand(
|
||||
'insertHTML',
|
||||
false,
|
||||
Sanitizer.clean(content.innerHTML, currentToolSanitizeConfig),
|
||||
Sanitizer.clean(content.innerHTML, currentToolSanitizeConfig)
|
||||
);
|
||||
} else {
|
||||
this.insertBlock(dataToInsert);
|
||||
|
@ -657,8 +678,8 @@ export default class Paste extends Module {
|
|||
* @param {string} text
|
||||
* @returns Promise<{data: BlockToolData, tool: string}>
|
||||
*/
|
||||
private async processPattern(text: string): Promise<{event: PasteEvent, tool: string}> {
|
||||
const pattern = this.toolsPatterns.find((substitute) => {
|
||||
private async processPattern(text: string): Promise<{event: PasteEvent; tool: string}> {
|
||||
const pattern = this.toolsPatterns.find((substitute) => {
|
||||
const execResult = substitute.pattern.exec(text);
|
||||
|
||||
if (!execResult) {
|
||||
|
@ -687,17 +708,18 @@ export default class Paste extends Module {
|
|||
* Insert pasted Block content to Editor
|
||||
*
|
||||
* @param {PasteData} data
|
||||
* @param {Boolean} canReplaceCurrentBlock - if true and is current Block is empty, will replace current Block
|
||||
* @param {boolean} canReplaceCurrentBlock - if true and is current Block is empty, will replace current Block
|
||||
* @returns {void}
|
||||
*/
|
||||
private insertBlock(data: PasteData, canReplaceCurrentBlock: boolean = false): void {
|
||||
const {BlockManager, Caret} = this.Editor;
|
||||
const {currentBlock} = BlockManager;
|
||||
private insertBlock(data: PasteData, canReplaceCurrentBlock = false): void {
|
||||
const { BlockManager, Caret } = this.Editor;
|
||||
const { currentBlock } = BlockManager;
|
||||
let block: Block;
|
||||
|
||||
if (canReplaceCurrentBlock && currentBlock && currentBlock.isEmpty) {
|
||||
block = BlockManager.paste(data.tool, data.event, true);
|
||||
Caret.setToBlock(block, Caret.positions.END);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -711,9 +733,9 @@ export default class Paste extends Module {
|
|||
*
|
||||
* @param {object} blocks — Blocks' data to insert
|
||||
*
|
||||
* @return {void}
|
||||
* @returns {void}
|
||||
*/
|
||||
private insertEditorJSData(blocks: Array<{tool: string, data: BlockToolData}>): void {
|
||||
private insertEditorJSData(blocks: Array<{tool: string; data: BlockToolData}>): void {
|
||||
const { BlockManager, Tools } = this.Editor;
|
||||
|
||||
blocks.forEach(({ tool, data }, i) => {
|
||||
|
@ -745,7 +767,7 @@ export default class Paste extends Module {
|
|||
*/
|
||||
private getNodes(wrapper: Node): Node[] {
|
||||
const children = Array.from(wrapper.childNodes),
|
||||
tags = Object.keys(this.toolsTags);
|
||||
tags = Object.keys(this.toolsTags);
|
||||
|
||||
const reducer = (nodes: Node[], node: Node): Node[] => {
|
||||
if ($.isEmpty(node) && !$.isSingleTag(node as HTMLElement)) {
|
||||
|
@ -769,30 +791,31 @@ export default class Paste extends Module {
|
|||
case Node.ELEMENT_NODE:
|
||||
const element = node as HTMLElement;
|
||||
|
||||
const {tool = ''} = this.toolsTags[element.tagName] || {};
|
||||
const { tool = '' } = this.toolsTags[element.tagName] || {};
|
||||
const toolTags = this.tagsByTool[tool] || [];
|
||||
|
||||
const isSubstitutable = tags.includes(element.tagName);
|
||||
const isBlockElement = $.blockElements.includes(element.tagName.toLowerCase());
|
||||
const containsAnotherToolTags = Array
|
||||
.from(element.children)
|
||||
.some(
|
||||
({tagName}) => tags.includes(tagName) && !toolTags.includes(tagName),
|
||||
);
|
||||
.from(element.children)
|
||||
.some(
|
||||
({ tagName }) => tags.includes(tagName) && !toolTags.includes(tagName)
|
||||
);
|
||||
|
||||
const containsBlockElements = Array.from(element.children).some(
|
||||
({tagName}) => $.blockElements.includes(tagName.toLowerCase()),
|
||||
({ tagName }) => $.blockElements.includes(tagName.toLowerCase())
|
||||
);
|
||||
|
||||
/** Append inline elements to previous fragment */
|
||||
if (!isBlockElement && !isSubstitutable && !containsAnotherToolTags) {
|
||||
destNode.appendChild(element);
|
||||
|
||||
return [...nodes, destNode];
|
||||
}
|
||||
|
||||
if (
|
||||
(isSubstitutable && !containsAnotherToolTags) ||
|
||||
(isBlockElement && !containsBlockElements && !containsAnotherToolTags )
|
||||
(isBlockElement && !containsBlockElements && !containsAnotherToolTags)
|
||||
) {
|
||||
return [...nodes, destNode, element];
|
||||
}
|
||||
|
@ -803,6 +826,7 @@ export default class Paste extends Module {
|
|||
*/
|
||||
case Node.TEXT_NODE:
|
||||
destNode.appendChild(node);
|
||||
|
||||
return [...nodes, destNode];
|
||||
|
||||
default:
|
||||
|
|
|
@ -11,10 +11,14 @@ import $ from '../dom';
|
|||
import SelectionUtils from '../selection';
|
||||
import Block from '../block';
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export default class RectangleSelection extends Module {
|
||||
/**
|
||||
* CSS classes for the Block
|
||||
* @return {{wrapper: string, content: string}}
|
||||
*
|
||||
* @returns {{wrapper: string, content: string}}
|
||||
*/
|
||||
static get CSS() {
|
||||
return {
|
||||
|
@ -28,9 +32,10 @@ export default class RectangleSelection extends Module {
|
|||
|
||||
/**
|
||||
* Using the selection rectangle
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
private isRectSelectionActivated: boolean = false;
|
||||
private isRectSelectionActivated = false;
|
||||
|
||||
/**
|
||||
* Speed of Scrolling
|
||||
|
@ -56,12 +61,12 @@ export default class RectangleSelection extends Module {
|
|||
/**
|
||||
* Mouse is clamped
|
||||
*/
|
||||
private mousedown: boolean = false;
|
||||
private mousedown = false;
|
||||
|
||||
/**
|
||||
* Is scrolling now
|
||||
*/
|
||||
private isScrolling: boolean = false;
|
||||
private isScrolling = false;
|
||||
|
||||
/**
|
||||
* Mouse is in scroll zone
|
||||
|
@ -71,10 +76,10 @@ export default class RectangleSelection extends Module {
|
|||
/**
|
||||
* Coords of rect
|
||||
*/
|
||||
private startX: number = 0;
|
||||
private startY: number = 0;
|
||||
private mouseX: number = 0;
|
||||
private mouseY: number = 0;
|
||||
private startX = 0;
|
||||
private startY = 0;
|
||||
private mouseX = 0;
|
||||
private mouseY = 0;
|
||||
|
||||
/**
|
||||
* Selected blocks
|
||||
|
@ -96,8 +101,8 @@ export default class RectangleSelection extends Module {
|
|||
* Creating rect and hang handlers
|
||||
*/
|
||||
public prepare(): void {
|
||||
const {Listeners} = this.Editor;
|
||||
const {container} = this.genHTML();
|
||||
const { Listeners } = this.Editor;
|
||||
const { container } = this.genHTML();
|
||||
|
||||
Listeners.on(container, 'mousedown', (event: MouseEvent) => {
|
||||
if (event.button !== this.MAIN_MOUSE_BUTTON) {
|
||||
|
@ -127,6 +132,7 @@ export default class RectangleSelection extends Module {
|
|||
|
||||
/**
|
||||
* Init rect params
|
||||
*
|
||||
* @param {number} pageX - X coord of mouse
|
||||
* @param {number} pageY - Y coord of mouse
|
||||
*/
|
||||
|
@ -152,7 +158,7 @@ export default class RectangleSelection extends Module {
|
|||
];
|
||||
|
||||
const startsInsideEditor = elemWhereSelectionStart.closest('.' + this.Editor.UI.CSS.editorWrapper);
|
||||
const startsInSelectorToAvoid = selectorsToAvoid.some(((selector) => !!elemWhereSelectionStart.closest(selector)));
|
||||
const startsInSelectorToAvoid = selectorsToAvoid.some((selector) => !!elemWhereSelectionStart.closest(selector));
|
||||
|
||||
/**
|
||||
* If selection starts outside of the editor or inside the blocks or on Editor UI elements, do not handle it
|
||||
|
@ -192,6 +198,7 @@ export default class RectangleSelection extends Module {
|
|||
|
||||
/**
|
||||
* Scroll If mouse in scroll zone
|
||||
*
|
||||
* @param {number} clientY - Y coord of mouse
|
||||
*/
|
||||
private scrollByZones(clientY) {
|
||||
|
@ -205,6 +212,7 @@ export default class RectangleSelection extends Module {
|
|||
|
||||
if (!this.inScrollZone) {
|
||||
this.isScrolling = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -214,8 +222,11 @@ export default class RectangleSelection extends Module {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private genHTML() {
|
||||
const {UI} = this.Editor;
|
||||
const { UI } = this.Editor;
|
||||
|
||||
const container = UI.nodes.holder.querySelector('.' + UI.CSS.editorWrapper);
|
||||
const overlay = $.make('div', RectangleSelection.CSS.overlay, {});
|
||||
|
@ -227,6 +238,7 @@ export default class RectangleSelection extends Module {
|
|||
container.appendChild(overlay);
|
||||
|
||||
this.overlayRectangle = overlayRectangle as HTMLDivElement;
|
||||
|
||||
return {
|
||||
container,
|
||||
overlay,
|
||||
|
@ -235,6 +247,7 @@ export default class RectangleSelection extends Module {
|
|||
|
||||
/**
|
||||
* Activates scrolling if blockSelection is active and mouse is in scroll zone
|
||||
*
|
||||
* @param {number} speed - speed of scrolling
|
||||
*/
|
||||
private scrollVertical(speed) {
|
||||
|
@ -242,6 +255,7 @@ export default class RectangleSelection extends Module {
|
|||
return;
|
||||
}
|
||||
const lastOffset = window.pageYOffset;
|
||||
|
||||
window.scrollBy(0, speed);
|
||||
this.mouseY += window.pageYOffset - lastOffset;
|
||||
setTimeout(() => {
|
||||
|
@ -251,6 +265,7 @@ export default class RectangleSelection extends Module {
|
|||
|
||||
/**
|
||||
* Handles the change in the rectangle and its effect
|
||||
*
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
private changingRectangle(event) {
|
||||
|
@ -263,11 +278,12 @@ export default class RectangleSelection extends Module {
|
|||
this.mouseY = event.pageY;
|
||||
}
|
||||
|
||||
const {rightPos, leftPos, index} = this.genInfoForMouseSelection();
|
||||
const { rightPos, leftPos, index } = this.genInfoForMouseSelection();
|
||||
// There is not new block in selection
|
||||
|
||||
const rectIsOnRighSideOfredactor = this.startX > rightPos && this.mouseX > rightPos;
|
||||
const rectISOnLeftSideOfRedactor = this.startX < leftPos && this.mouseX < leftPos;
|
||||
|
||||
this.rectCrossesBlocks = !(rectIsOnRighSideOfredactor || rectISOnLeftSideOfRedactor);
|
||||
|
||||
if (!this.isRectSelectionActivated) {
|
||||
|
@ -346,7 +362,8 @@ export default class RectangleSelection extends Module {
|
|||
|
||||
/**
|
||||
* Collects information needed to determine the behavior of the rectangle
|
||||
* @return {number} index - index next Block, leftPos - start of left border of Block, rightPos - right border
|
||||
*
|
||||
* @returns {number} index - index next Block, leftPos - start of left border of Block, rightPos - right border
|
||||
*/
|
||||
private genInfoForMouseSelection() {
|
||||
const widthOfRedactor = document.body.offsetWidth;
|
||||
|
@ -355,6 +372,7 @@ export default class RectangleSelection extends Module {
|
|||
const elementUnderMouse = document.elementFromPoint(centerOfRedactor, Y);
|
||||
const blockInCurrentPos = this.Editor.BlockManager.getBlockByChildNode(elementUnderMouse);
|
||||
let index;
|
||||
|
||||
if (blockInCurrentPos !== undefined) {
|
||||
index = this.Editor.BlockManager.blocks.findIndex((block) => block.holder === blockInCurrentPos.holder);
|
||||
}
|
||||
|
@ -372,6 +390,7 @@ export default class RectangleSelection extends Module {
|
|||
|
||||
/**
|
||||
* Select block with index index
|
||||
*
|
||||
* @param index - index of block in redactor
|
||||
*/
|
||||
private addBlockInSelection(index) {
|
||||
|
@ -383,6 +402,7 @@ export default class RectangleSelection extends Module {
|
|||
|
||||
/**
|
||||
* Adds a block to the selection and determines which blocks should be selected
|
||||
*
|
||||
* @param {object} index - index of new block in the reactor
|
||||
*/
|
||||
private trySelectNextBlock(index) {
|
||||
|
@ -409,6 +429,7 @@ export default class RectangleSelection extends Module {
|
|||
for (ind; ind <= index; ind++) {
|
||||
this.addBlockInSelection(ind);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -417,6 +438,7 @@ export default class RectangleSelection extends Module {
|
|||
for (let ind = this.stackOfSelected[sizeStack - 1] - 1; ind >= index; ind--) {
|
||||
this.addBlockInSelection(ind);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -443,6 +465,5 @@ export default class RectangleSelection extends Module {
|
|||
this.stackOfSelected.pop();
|
||||
i--;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import Module from '../__module';
|
||||
/* eslint-disable import/no-duplicates */
|
||||
import * as _ from '../utils';
|
||||
import {ChainData} from '../utils';
|
||||
import {BlockToolData} from '../../../types';
|
||||
import {BlockToolConstructable} from '../../../types/tools';
|
||||
import { ChainData } from '../utils';
|
||||
import { BlockToolData } from '../../../types';
|
||||
import { BlockToolConstructable } from '../../../types/tools';
|
||||
|
||||
/**
|
||||
* Editor.js Renderer Module
|
||||
|
@ -14,9 +15,9 @@ import {BlockToolConstructable} from '../../../types/tools';
|
|||
*/
|
||||
export default class Renderer extends Module {
|
||||
/**
|
||||
* @typedef {Object} RendererBlocks
|
||||
* @property {String} type - tool name
|
||||
* @property {Object} data - tool data
|
||||
* @typedef {object} RendererBlocks
|
||||
* @property {string} type - tool name
|
||||
* @property {object} data - tool data
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -41,10 +42,11 @@ export default class Renderer extends Module {
|
|||
|
||||
/**
|
||||
* Make plugin blocks from array of plugin`s data
|
||||
*
|
||||
* @param {RendererBlocks[]} blocks
|
||||
*/
|
||||
public async render(blocks: BlockToolData[]): Promise<void> {
|
||||
const chainData = blocks.map((block) => ({function: () => this.insertBlock(block)}));
|
||||
const chainData = blocks.map((block) => ({ function: () => this.insertBlock(block) }));
|
||||
|
||||
const sequence = await _.sequence(chainData as ChainData[]);
|
||||
|
||||
|
@ -58,7 +60,7 @@ export default class Renderer extends Module {
|
|||
* Add plugin instance to BlockManager
|
||||
* Insert block to working zone
|
||||
*
|
||||
* @param {Object} item
|
||||
* @param {object} item
|
||||
* @returns {Promise<void>}
|
||||
* @private
|
||||
*/
|
||||
|
@ -76,7 +78,6 @@ export default class Renderer extends Module {
|
|||
throw Error(error);
|
||||
}
|
||||
} else {
|
||||
|
||||
/** If Tool is unavailable, create stub Block for it */
|
||||
const stubData = {
|
||||
savedData: {
|
||||
|
|
|
@ -20,8 +20,8 @@ import Module from '../__module';
|
|||
import * as _ from '../utils';
|
||||
|
||||
/**
|
||||
* @typedef {Object} SanitizerConfig
|
||||
* @property {Object} tags - define tags restrictions
|
||||
* @typedef {object} SanitizerConfig
|
||||
* @property {object} tags - define tags restrictions
|
||||
*
|
||||
* @example
|
||||
*
|
||||
|
@ -36,8 +36,11 @@ import * as _ from '../utils';
|
|||
*/
|
||||
|
||||
import HTMLJanitor from 'html-janitor';
|
||||
import {BlockToolData, InlineToolConstructable, SanitizerConfig} from '../../../types';
|
||||
import { BlockToolData, InlineToolConstructable, SanitizerConfig } from '../../../types';
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export default class Sanitizer extends Module {
|
||||
/**
|
||||
* Memoize tools config
|
||||
|
@ -54,12 +57,12 @@ export default class Sanitizer extends Module {
|
|||
*
|
||||
* Enumerate blocks and clean data
|
||||
*
|
||||
* @param blocksData
|
||||
* @param {{tool, data: BlockToolData}[]} blocksData[]
|
||||
*/
|
||||
public sanitizeBlocks(
|
||||
blocksData: Array<{tool: string, data: BlockToolData}>,
|
||||
): Array<{tool: string, data: BlockToolData}> {
|
||||
|
||||
blocksData: Array<{tool: string; data: BlockToolData}>
|
||||
): Array<{tool: string; data: BlockToolData}> {
|
||||
return blocksData.map((block) => {
|
||||
const toolConfig = this.composeToolConfig(block.tool);
|
||||
|
||||
|
@ -105,6 +108,7 @@ export default class Sanitizer extends Module {
|
|||
if (typeof dataToSanitize === 'string') {
|
||||
return this.cleanOneItem(dataToSanitize, rules);
|
||||
}
|
||||
|
||||
return dataToSanitize;
|
||||
}
|
||||
}
|
||||
|
@ -116,10 +120,9 @@ export default class Sanitizer extends Module {
|
|||
* @param {string} taintString - taint string
|
||||
* @param {SanitizerConfig} customConfig - allowed tags
|
||||
*
|
||||
* @return {string} clean HTML
|
||||
* @returns {string} clean HTML
|
||||
*/
|
||||
public clean(taintString: string, customConfig: SanitizerConfig = {} as SanitizerConfig): string {
|
||||
|
||||
const sanitizerConfig = {
|
||||
tags: customConfig,
|
||||
};
|
||||
|
@ -128,6 +131,7 @@ export default class Sanitizer extends Module {
|
|||
* API client can use custom config to manage sanitize process
|
||||
*/
|
||||
const sanitizerInstance = this.createHTMLJanitorInstance(sanitizerConfig);
|
||||
|
||||
return sanitizerInstance.clean(taintString);
|
||||
}
|
||||
|
||||
|
@ -136,7 +140,7 @@ export default class Sanitizer extends Module {
|
|||
*
|
||||
* @param {string} toolName
|
||||
* @param {SanitizerConfig} toolRules
|
||||
* @return {SanitizerConfig}
|
||||
* @returns {SanitizerConfig}
|
||||
*/
|
||||
public composeToolConfig(toolName: string): SanitizerConfig {
|
||||
/**
|
||||
|
@ -160,9 +164,11 @@ export default class Sanitizer extends Module {
|
|||
const toolRules = toolClass.sanitize;
|
||||
|
||||
const toolConfig = {} as SanitizerConfig;
|
||||
|
||||
for (const fieldName in toolRules) {
|
||||
if (toolRules.hasOwnProperty(fieldName)) {
|
||||
const rule = toolRules[fieldName];
|
||||
|
||||
if (typeof rule === 'object') {
|
||||
toolConfig[fieldName] = Object.assign({}, baseConfig, rule);
|
||||
} else {
|
||||
|
@ -179,9 +185,11 @@ export default class Sanitizer extends Module {
|
|||
* Returns Sanitizer config
|
||||
* When Tool's "inlineToolbar" value is True, get all sanitizer rules from all tools,
|
||||
* otherwise get only enabled
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public getInlineToolsConfig(name: string): SanitizerConfig {
|
||||
const {Tools} = this.Editor;
|
||||
const { Tools } = this.Editor;
|
||||
const toolsConfig = Tools.getToolSettings(name);
|
||||
const enableInlineTools = toolsConfig.inlineToolbar || [];
|
||||
|
||||
|
@ -196,10 +204,10 @@ export default class Sanitizer extends Module {
|
|||
/**
|
||||
* getting only enabled
|
||||
*/
|
||||
(enableInlineTools as string[]).map( (inlineToolName) => {
|
||||
(enableInlineTools as string[]).map((inlineToolName) => {
|
||||
config = Object.assign(
|
||||
config,
|
||||
Tools.inline[inlineToolName][Tools.INTERNAL_SETTINGS.SANITIZE_CONFIG],
|
||||
Tools.inline[inlineToolName][Tools.INTERNAL_SETTINGS.SANITIZE_CONFIG]
|
||||
) as SanitizerConfig;
|
||||
});
|
||||
}
|
||||
|
@ -217,7 +225,7 @@ export default class Sanitizer extends Module {
|
|||
* Return general config for all inline tools
|
||||
*/
|
||||
public getAllInlineToolsConfig(): SanitizerConfig {
|
||||
const {Tools} = this.Editor;
|
||||
const { Tools } = this.Editor;
|
||||
|
||||
if (this.inlineToolsConfigCache) {
|
||||
return this.inlineToolsConfigCache;
|
||||
|
@ -226,7 +234,7 @@ export default class Sanitizer extends Module {
|
|||
const config: SanitizerConfig = {} as SanitizerConfig;
|
||||
|
||||
Object.entries(Tools.inline)
|
||||
.forEach( ([name, inlineTool]: [string, InlineToolConstructable]) => {
|
||||
.forEach(([name, inlineTool]: [string, InlineToolConstructable]) => {
|
||||
Object.assign(config, inlineTool[Tools.INTERNAL_SETTINGS.SANITIZE_CONFIG]);
|
||||
});
|
||||
|
||||
|
@ -237,18 +245,20 @@ export default class Sanitizer extends Module {
|
|||
|
||||
/**
|
||||
* Clean array
|
||||
* @param {array} array - [1, 2, {}, []]
|
||||
*
|
||||
* @param {Array} array - [1, 2, {}, []]
|
||||
* @param {object} ruleForItem
|
||||
*/
|
||||
private cleanArray(array: any[], ruleForItem: SanitizerConfig): any[] {
|
||||
return array.map( (arrayItem) => this.deepSanitize(arrayItem, ruleForItem));
|
||||
return array.map((arrayItem) => this.deepSanitize(arrayItem, ruleForItem));
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean object
|
||||
*
|
||||
* @param {object} object - {level: 0, text: 'adada', items: [1,2,3]}}
|
||||
* @param {object} rules - { b: true } or true|false
|
||||
* @return {object}
|
||||
* @returns {object}
|
||||
*/
|
||||
private cleanObject(object: any, rules: SanitizerConfig|{[field: string]: SanitizerConfig}): any {
|
||||
const cleanData = {};
|
||||
|
@ -269,13 +279,14 @@ export default class Sanitizer extends Module {
|
|||
|
||||
cleanData[fieldName] = this.deepSanitize(currentIterationItem, ruleForItem as SanitizerConfig);
|
||||
}
|
||||
|
||||
return cleanData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} taintString
|
||||
* @param {SanitizerConfig|boolean} rule
|
||||
* @return {string}
|
||||
* @returns {string}
|
||||
*/
|
||||
private cleanOneItem(taintString: string, rule: SanitizerConfig|boolean): string {
|
||||
if (typeof rule === 'object') {
|
||||
|
@ -291,6 +302,7 @@ export default class Sanitizer extends Module {
|
|||
* Check if passed item is a HTML Janitor rule:
|
||||
* { a : true }, {}, false, true, function(){} — correct rules
|
||||
* undefined, null, 0, 1, 2 — not a rules
|
||||
*
|
||||
* @param config
|
||||
*/
|
||||
private isRule(config: SanitizerConfig): boolean {
|
||||
|
@ -311,6 +323,7 @@ export default class Sanitizer extends Module {
|
|||
if (config) {
|
||||
return new HTMLJanitor(config);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
* @version 2.0.0
|
||||
*/
|
||||
import Module from '../__module';
|
||||
import {OutputData} from '../../../types';
|
||||
import {ValidatedData} from '../../types-internal/block-data';
|
||||
import { OutputData } from '../../../types';
|
||||
import { ValidatedData } from '../../types-internal/block-data';
|
||||
import Block from '../block';
|
||||
import * as _ from '../utils';
|
||||
|
||||
|
@ -18,17 +18,18 @@ declare const VERSION: string;
|
|||
*
|
||||
* @typedef {Saver} Saver
|
||||
* @property {Element} html - Editor HTML content
|
||||
* @property {String} json - Editor JSON output
|
||||
* @property {string} json - Editor JSON output
|
||||
*/
|
||||
export default class Saver extends Module {
|
||||
/**
|
||||
* Composes new chain of Promises to fire them alternatelly
|
||||
* @return {OutputData}
|
||||
*
|
||||
* @returns {OutputData}
|
||||
*/
|
||||
public async save(): Promise<OutputData> {
|
||||
const {BlockManager, Sanitizer, ModificationsObserver} = this.Editor;
|
||||
const { BlockManager, Sanitizer, ModificationsObserver } = this.Editor;
|
||||
const blocks = BlockManager.blocks,
|
||||
chainData = [];
|
||||
chainData = [];
|
||||
|
||||
/**
|
||||
* Disable modifications observe while saving
|
||||
|
@ -36,7 +37,7 @@ export default class Saver extends Module {
|
|||
ModificationsObserver.disable();
|
||||
|
||||
blocks.forEach((block: Block) => {
|
||||
chainData.push(this.getSavedData(block));
|
||||
chainData.push(this.getSavedData(block));
|
||||
});
|
||||
|
||||
const extractedData = await Promise.all(chainData);
|
||||
|
@ -49,20 +50,25 @@ export default class Saver extends Module {
|
|||
|
||||
/**
|
||||
* Saves and validates
|
||||
*
|
||||
* @param {Block} block - Editor's Tool
|
||||
* @return {ValidatedData} - Tool's validated data
|
||||
* @returns {ValidatedData} - Tool's validated data
|
||||
*/
|
||||
private async getSavedData(block: Block): Promise<ValidatedData> {
|
||||
const blockData = await block.save();
|
||||
const isValid = blockData && await block.validate(blockData.data);
|
||||
const blockData = await block.save();
|
||||
const isValid = blockData && await block.validate(blockData.data);
|
||||
|
||||
return {...blockData, isValid};
|
||||
return {
|
||||
...blockData,
|
||||
isValid,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates output object with saved data, time and version of editor
|
||||
*
|
||||
* @param {ValidatedData} allExtractedData
|
||||
* @return {OutputData}
|
||||
* @returns {OutputData}
|
||||
*/
|
||||
private makeOutput(allExtractedData): OutputData {
|
||||
let totalTime = 0;
|
||||
|
@ -70,7 +76,7 @@ export default class Saver extends Module {
|
|||
|
||||
_.log('[Editor.js saving]:', 'groupCollapsed');
|
||||
|
||||
allExtractedData.forEach(({tool, data, time, isValid}) => {
|
||||
allExtractedData.forEach(({ tool, data, time, isValid }) => {
|
||||
totalTime += time;
|
||||
|
||||
/**
|
||||
|
@ -85,12 +91,14 @@ export default class Saver extends Module {
|
|||
} else {
|
||||
_.log(`Block «${tool}» skipped because saved data is invalid`);
|
||||
_.log(undefined, 'groupEnd');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/** If it was stub Block, get original data */
|
||||
if (tool === this.Editor.Tools.stubTool) {
|
||||
blocks.push(data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
import Shortcut from '@codexteam/shortcuts';
|
||||
|
||||
/**
|
||||
* Contains keyboard and mouse events binded on each Block by Block Manager
|
||||
*/
|
||||
import Module from '../__module';
|
||||
|
||||
/**
|
||||
* ShortcutData interface
|
||||
* Each shortcut must have name and handler
|
||||
|
@ -20,11 +25,6 @@ export interface ShortcutData {
|
|||
handler(event): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains keyboard and mouse events binded on each Block by Block Manager
|
||||
*/
|
||||
import Module from '../__module';
|
||||
|
||||
/**
|
||||
* @class Shortcut
|
||||
* @classdesc Allows to register new shortcut
|
||||
|
@ -34,12 +34,14 @@ import Module from '../__module';
|
|||
export default class Shortcuts extends Module {
|
||||
/**
|
||||
* All registered shortcuts
|
||||
*
|
||||
* @type {Shortcut[]}
|
||||
*/
|
||||
private registeredShortcuts: Shortcut[] = [];
|
||||
|
||||
/**
|
||||
* Register shortcut
|
||||
*
|
||||
* @param {ShortcutData} shortcut
|
||||
*/
|
||||
public add(shortcut: ShortcutData): void {
|
||||
|
@ -54,6 +56,7 @@ export default class Shortcuts extends Module {
|
|||
|
||||
/**
|
||||
* Remove shortcut
|
||||
*
|
||||
* @param {ShortcutData} shortcut
|
||||
*/
|
||||
public remove(shortcut: string): void {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import Module from '../../__module';
|
||||
import $ from '../../dom';
|
||||
import Flipper, {FlipperOptions} from '../../flipper';
|
||||
import Flipper, { FlipperOptions } from '../../flipper';
|
||||
import * as _ from '../../utils';
|
||||
|
||||
/**
|
||||
|
@ -15,12 +15,12 @@ import * as _ from '../../utils';
|
|||
* |________________________|
|
||||
*/
|
||||
export default class BlockSettings extends Module {
|
||||
|
||||
/**
|
||||
* Module Events
|
||||
* @return {{opened: string, closed: string}}
|
||||
*
|
||||
* @returns {{opened: string, closed: string}}
|
||||
*/
|
||||
public get events(): {opened: string, closed: string} {
|
||||
public get events(): {opened: string; closed: string} {
|
||||
return {
|
||||
opened: 'block-settings-opened',
|
||||
closed: 'block-settings-closed',
|
||||
|
@ -29,7 +29,8 @@ export default class BlockSettings extends Module {
|
|||
|
||||
/**
|
||||
* Block Settings CSS
|
||||
* @return {{wrapper, wrapperOpened, toolSettings, defaultSettings, button}}
|
||||
*
|
||||
* @returns {{wrapper, wrapperOpened, toolSettings, defaultSettings, button}}
|
||||
*/
|
||||
public get CSS() {
|
||||
return {
|
||||
|
@ -41,13 +42,14 @@ export default class BlockSettings extends Module {
|
|||
|
||||
button: 'ce-settings__button',
|
||||
|
||||
focusedButton : 'ce-settings__button--focused',
|
||||
focusedButton: 'ce-settings__button--focused',
|
||||
focusedButtonAnimated: 'ce-settings__button--focused-animated',
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Is Block Settings opened or not
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public get opened(): boolean {
|
||||
|
@ -70,6 +72,7 @@ export default class BlockSettings extends Module {
|
|||
|
||||
/**
|
||||
* Instance of class that responses for leafing buttons by arrows/tab
|
||||
*
|
||||
* @type {Flipper|null}
|
||||
*/
|
||||
private flipper: Flipper = null;
|
||||
|
@ -79,7 +82,7 @@ export default class BlockSettings extends Module {
|
|||
* - Tool's Settings
|
||||
* - Default Settings [Move, Remove, etc]
|
||||
*
|
||||
* @return {Element}
|
||||
* @returns {Element}
|
||||
*/
|
||||
public make(): void {
|
||||
this.nodes.wrapper = $.make('div', this.CSS.wrapper);
|
||||
|
@ -145,7 +148,8 @@ export default class BlockSettings extends Module {
|
|||
|
||||
/**
|
||||
* Returns Tools Settings and Default Settings
|
||||
* @return {HTMLElement[]}
|
||||
*
|
||||
* @returns {HTMLElement[]}
|
||||
*/
|
||||
public get blockTunesButtons(): HTMLElement[] {
|
||||
/**
|
||||
|
@ -198,7 +202,7 @@ export default class BlockSettings extends Module {
|
|||
* Restoring focus on current Block after settings clicked.
|
||||
* For example, when H3 changed to H2 — DOM Elements replaced, so we need to focus a new one
|
||||
*/
|
||||
_.delay( () => {
|
||||
_.delay(() => {
|
||||
this.Editor.Caret.setToBlock(this.Editor.BlockManager.currentBlock);
|
||||
}, 10)();
|
||||
},
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import Module from '../../__module';
|
||||
import $ from '../../dom';
|
||||
import {BlockToolConstructable} from '../../../../types';
|
||||
import { BlockToolConstructable } from '../../../../types';
|
||||
import * as _ from '../../utils';
|
||||
import {SavedData} from '../../../types-internal/block-data';
|
||||
import { SavedData } from '../../../types-internal/block-data';
|
||||
import Block from '../../block';
|
||||
import Flipper from '../../flipper';
|
||||
|
||||
|
@ -23,8 +23,8 @@ export default class ConversionToolbar extends Module {
|
|||
conversionToolHidden: 'ce-conversion-tool--hidden',
|
||||
conversionToolIcon: 'ce-conversion-tool__icon',
|
||||
|
||||
conversionToolFocused : 'ce-conversion-tool--focused',
|
||||
conversionToolActive : 'ce-conversion-tool--active',
|
||||
conversionToolFocused: 'ce-conversion-tool--focused',
|
||||
conversionToolActive: 'ce-conversion-tool--active',
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -38,9 +38,10 @@ export default class ConversionToolbar extends Module {
|
|||
|
||||
/**
|
||||
* Conversion Toolbar open/close state
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
public opened: boolean = false;
|
||||
public opened = false;
|
||||
|
||||
/**
|
||||
* Available tools
|
||||
|
@ -49,6 +50,7 @@ export default class ConversionToolbar extends Module {
|
|||
|
||||
/**
|
||||
* Instance of class that responses for leafing buttons by arrows/tab
|
||||
*
|
||||
* @type {Flipper|null}
|
||||
*/
|
||||
private flipper: Flipper = null;
|
||||
|
@ -87,7 +89,8 @@ export default class ConversionToolbar extends Module {
|
|||
|
||||
/**
|
||||
* Toggle conversion dropdown visibility
|
||||
* @param {function} [togglingCallback] — callback that will accept opening state
|
||||
*
|
||||
* @param {Function} [togglingCallback] — callback that will accept opening state
|
||||
*/
|
||||
public toggle(togglingCallback?: (openedState: boolean) => void): void {
|
||||
if (!this.opened) {
|
||||
|
@ -157,6 +160,7 @@ export default class ConversionToolbar extends Module {
|
|||
public async replaceWithBlock(replacingToolName: string): Promise <void> {
|
||||
/**
|
||||
* At first, we get current Block data
|
||||
*
|
||||
* @type {BlockToolConstructable}
|
||||
*/
|
||||
const currentBlockClass = this.Editor.BlockManager.currentBlock.class;
|
||||
|
@ -175,6 +179,7 @@ export default class ConversionToolbar extends Module {
|
|||
|
||||
/**
|
||||
* Getting a class of replacing Tool
|
||||
*
|
||||
* @type {BlockToolConstructable}
|
||||
*/
|
||||
const replacingTool = this.Editor.Tools.toolsClasses[replacingToolName] as BlockToolConstructable;
|
||||
|
@ -186,7 +191,7 @@ export default class ConversionToolbar extends Module {
|
|||
*
|
||||
* In both cases returning value must be a string
|
||||
*/
|
||||
let exportData: string = '';
|
||||
let exportData = '';
|
||||
const exportProp = currentBlockClass[INTERNAL_SETTINGS.CONVERSION_CONFIG].export;
|
||||
|
||||
if (typeof exportProp === 'function') {
|
||||
|
@ -196,6 +201,7 @@ export default class ConversionToolbar extends Module {
|
|||
} else {
|
||||
_.log('Conversion «export» property must be a string or function. ' +
|
||||
'String means key of saved data object to export. Function should export processed string to export.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -204,7 +210,7 @@ export default class ConversionToolbar extends Module {
|
|||
*/
|
||||
const cleaned: string = this.Editor.Sanitizer.clean(
|
||||
exportData,
|
||||
replacingTool.sanitize,
|
||||
replacingTool.sanitize
|
||||
);
|
||||
|
||||
/**
|
||||
|
@ -222,6 +228,7 @@ export default class ConversionToolbar extends Module {
|
|||
} else {
|
||||
_.log('Conversion «import» property must be a string or function. ' +
|
||||
'String means key of tool data to import. Function accepts a imported string and return composed tool data.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -273,6 +280,10 @@ export default class ConversionToolbar extends Module {
|
|||
|
||||
/**
|
||||
* Add tool to the Conversion Toolbar
|
||||
*
|
||||
* @param toolName
|
||||
* @param toolIcon
|
||||
* @param title
|
||||
*/
|
||||
private addTool(toolName: string, toolIcon: string, title: string): void {
|
||||
const tool = $.make('div', [ ConversionToolbar.CSS.conversionTool ]);
|
||||
|
|
|
@ -42,7 +42,7 @@ import * as _ from '../../utils';
|
|||
* @classdesc Toolbar module
|
||||
*
|
||||
* @typedef {Toolbar} Toolbar
|
||||
* @property {Object} nodes
|
||||
* @property {object} nodes
|
||||
* @property {Element} nodes.wrapper - Toolbar main element
|
||||
* @property {Element} nodes.content - Zone with Plus button and toolbox.
|
||||
* @property {Element} nodes.actions - Zone with Block Settings and Remove Button
|
||||
|
@ -59,21 +59,22 @@ export default class Toolbar extends Module {
|
|||
* HTML Elements used for Toolbar UI
|
||||
*/
|
||||
public nodes: {[key: string]: HTMLElement} = {
|
||||
wrapper : null,
|
||||
content : null,
|
||||
actions : null,
|
||||
wrapper: null,
|
||||
content: null,
|
||||
actions: null,
|
||||
|
||||
// Content Zone
|
||||
plusButton : null,
|
||||
plusButton: null,
|
||||
|
||||
// Actions Zone
|
||||
blockActionsButtons: null,
|
||||
settingsToggler : null,
|
||||
settingsToggler: null,
|
||||
};
|
||||
|
||||
/**
|
||||
* CSS styles
|
||||
* @return {Object}
|
||||
*
|
||||
* @returns {object}
|
||||
*/
|
||||
public get CSS() {
|
||||
return {
|
||||
|
@ -104,7 +105,7 @@ export default class Toolbar extends Module {
|
|||
/**
|
||||
* Make Content Zone and Actions Zone
|
||||
*/
|
||||
['content', 'actions'].forEach( (el) => {
|
||||
['content', 'actions'].forEach((el) => {
|
||||
this.nodes[el] = $.make('div', this.CSS[el]);
|
||||
});
|
||||
|
||||
|
@ -149,7 +150,7 @@ export default class Toolbar extends Module {
|
|||
* - Settings Panel
|
||||
*/
|
||||
this.nodes.blockActionsButtons = $.make('div', this.CSS.blockActionsButtons);
|
||||
this.nodes.settingsToggler = $.make('span', this.CSS.settingsToggler);
|
||||
this.nodes.settingsToggler = $.make('span', this.CSS.settingsToggler);
|
||||
const settingsIcon = $.svg('dots', 8, 8);
|
||||
|
||||
$.append(this.nodes.settingsToggler, settingsIcon);
|
||||
|
@ -179,9 +180,10 @@ export default class Toolbar extends Module {
|
|||
|
||||
/**
|
||||
* Move Toolbar to the Current Block
|
||||
* @param {Boolean} forceClose - force close Toolbar Settings and Toolbar
|
||||
*
|
||||
* @param {boolean} forceClose - force close Toolbar Settings and Toolbar
|
||||
*/
|
||||
public move(forceClose: boolean = true): void {
|
||||
public move(forceClose = true): void {
|
||||
if (forceClose) {
|
||||
/** Close Toolbox when we move toolbar */
|
||||
this.Editor.Toolbox.close();
|
||||
|
@ -222,6 +224,7 @@ export default class Toolbar extends Module {
|
|||
|
||||
/**
|
||||
* Open Toolbar with Plus Button and Actions
|
||||
*
|
||||
* @param {boolean} withBlockActions - by default, Toolbar opens with Block Actions.
|
||||
* This flag allows to open Toolbar without Actions.
|
||||
* @param {boolean} needToCloseToolbox - by default, Toolbar will be moved with opening
|
||||
|
@ -229,7 +232,7 @@ export default class Toolbar extends Module {
|
|||
* with closing Toolbox and Block Settings
|
||||
* This flag allows to open Toolbar with Toolbox
|
||||
*/
|
||||
public open(withBlockActions: boolean = true, needToCloseToolbox: boolean = true): void {
|
||||
public open(withBlockActions = true, needToCloseToolbox = true): void {
|
||||
_.delay(() => {
|
||||
this.move(needToCloseToolbox);
|
||||
this.nodes.wrapper.classList.add(this.CSS.toolbarOpened);
|
||||
|
@ -244,7 +247,8 @@ export default class Toolbar extends Module {
|
|||
|
||||
/**
|
||||
* returns toolbar opened state
|
||||
* @return {Boolean}
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public get opened(): boolean {
|
||||
return this.nodes.wrapper.classList.contains(this.CSS.toolbarOpened);
|
||||
|
@ -264,9 +268,10 @@ export default class Toolbar extends Module {
|
|||
|
||||
/**
|
||||
* Plus Button public methods
|
||||
* @return {{hide: function(): void, show: function(): void}}
|
||||
*
|
||||
* @returns {{hide: function(): void, show: function(): void}}
|
||||
*/
|
||||
public get plusButton(): {hide: () => void, show: () => void} {
|
||||
public get plusButton(): {hide: () => void; show: () => void} {
|
||||
return {
|
||||
hide: () => this.nodes.plusButton.classList.add(this.CSS.plusButtonHidden),
|
||||
show: () => {
|
||||
|
@ -280,14 +285,15 @@ export default class Toolbar extends Module {
|
|||
|
||||
/**
|
||||
* Block actions appearance manipulations
|
||||
* @return {{hide: function(): void, show: function(): void}}
|
||||
*
|
||||
* @returns {{hide: function(): void, show: function(): void}}
|
||||
*/
|
||||
private get blockActions(): {hide: () => void, show: () => void} {
|
||||
private get blockActions(): {hide: () => void; show: () => void} {
|
||||
return {
|
||||
hide: () => {
|
||||
this.nodes.actions.classList.remove(this.CSS.actionsOpened);
|
||||
},
|
||||
show : () => {
|
||||
show: () => {
|
||||
this.nodes.actions.classList.add(this.CSS.actionsOpened);
|
||||
},
|
||||
};
|
||||
|
@ -295,6 +301,7 @@ export default class Toolbar extends Module {
|
|||
|
||||
/**
|
||||
* Handler for Plus Button
|
||||
*
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
private plusButtonClicked(): void {
|
||||
|
|
|
@ -3,7 +3,7 @@ import $ from '../../dom';
|
|||
|
||||
import SelectionUtils from '../../selection';
|
||||
import * as _ from '../../utils';
|
||||
import {InlineTool, InlineToolConstructable, ToolConstructable, ToolSettings} from '../../../../types';
|
||||
import { InlineTool, InlineToolConstructable, ToolConstructable, ToolSettings } from '../../../../types';
|
||||
import Flipper from '../../flipper';
|
||||
|
||||
/**
|
||||
|
@ -14,7 +14,6 @@ import Flipper from '../../flipper';
|
|||
* |________________________|
|
||||
*/
|
||||
export default class InlineToolbar extends Module {
|
||||
|
||||
/**
|
||||
* CSS styles
|
||||
*/
|
||||
|
@ -37,19 +36,20 @@ export default class InlineToolbar extends Module {
|
|||
|
||||
/**
|
||||
* State of inline toolbar
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
public opened: boolean = false;
|
||||
public opened = false;
|
||||
|
||||
/**
|
||||
* Inline Toolbar elements
|
||||
*/
|
||||
private nodes: {
|
||||
wrapper: HTMLElement,
|
||||
buttons: HTMLElement,
|
||||
conversionToggler: HTMLElement,
|
||||
conversionTogglerContent: HTMLElement,
|
||||
actions: HTMLElement,
|
||||
wrapper: HTMLElement;
|
||||
buttons: HTMLElement;
|
||||
conversionToggler: HTMLElement;
|
||||
conversionTogglerContent: HTMLElement;
|
||||
actions: HTMLElement;
|
||||
} = {
|
||||
wrapper: null,
|
||||
buttons: null,
|
||||
|
@ -74,15 +74,17 @@ export default class InlineToolbar extends Module {
|
|||
|
||||
/**
|
||||
* Buttons List
|
||||
*
|
||||
* @type {NodeList}
|
||||
*/
|
||||
private buttonsList: NodeList = null;
|
||||
|
||||
/**
|
||||
* Cache for Inline Toolbar width
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
private width: number = 0;
|
||||
private width = 0;
|
||||
|
||||
/**
|
||||
* Instance of class that responses for leafing buttons by arrows/tab
|
||||
|
@ -169,14 +171,16 @@ export default class InlineToolbar extends Module {
|
|||
|
||||
/**
|
||||
* Shows Inline Toolbar if something is selected
|
||||
*
|
||||
* @param {boolean} [needToClose] - pass true to close toolbar if it is not allowed.
|
||||
* Avoid to use it just for closing IT, better call .close() clearly.
|
||||
*/
|
||||
public tryToShow(needToClose: boolean = false): void {
|
||||
public tryToShow(needToClose = false): void {
|
||||
if (!this.allowedToShow()) {
|
||||
if (needToClose) {
|
||||
this.close();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -196,11 +200,11 @@ export default class InlineToolbar extends Module {
|
|||
const wrapperOffset = this.Editor.UI.nodes.wrapper.getBoundingClientRect();
|
||||
const newCoords = {
|
||||
x: selectionRect.x - wrapperOffset.left,
|
||||
y: selectionRect.y
|
||||
+ selectionRect.height
|
||||
y: selectionRect.y +
|
||||
selectionRect.height -
|
||||
// + window.scrollY
|
||||
- wrapperOffset.top
|
||||
+ this.toolbarVerticalMargin,
|
||||
wrapperOffset.top +
|
||||
this.toolbarVerticalMargin,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -222,12 +226,12 @@ export default class InlineToolbar extends Module {
|
|||
*/
|
||||
this.nodes.wrapper.classList.toggle(
|
||||
this.CSS.inlineToolbarLeftOriented,
|
||||
realLeftCoord < this.Editor.UI.contentRect.left,
|
||||
realLeftCoord < this.Editor.UI.contentRect.left
|
||||
);
|
||||
|
||||
this.nodes.wrapper.classList.toggle(
|
||||
this.CSS.inlineToolbarRightOriented,
|
||||
realRightCoord > this.Editor.UI.contentRect.right,
|
||||
realRightCoord > this.Editor.UI.contentRect.right
|
||||
);
|
||||
|
||||
this.nodes.wrapper.style.left = Math.floor(newCoords.x) + 'px';
|
||||
|
@ -331,7 +335,7 @@ export default class InlineToolbar extends Module {
|
|||
return false;
|
||||
}
|
||||
|
||||
const target = !$.isElement(currentSelection.anchorNode )
|
||||
const target = !$.isElement(currentSelection.anchorNode)
|
||||
? currentSelection.anchorNode.parentElement
|
||||
: currentSelection.anchorNode;
|
||||
|
||||
|
@ -363,13 +367,14 @@ export default class InlineToolbar extends Module {
|
|||
*/
|
||||
private filterTools(): void {
|
||||
const currentSelection = SelectionUtils.get(),
|
||||
currentBlock = this.Editor.BlockManager.getBlock(currentSelection.anchorNode as HTMLElement);
|
||||
currentBlock = this.Editor.BlockManager.getBlock(currentSelection.anchorNode as HTMLElement);
|
||||
|
||||
const toolSettings = this.Editor.Tools.getToolSettings(currentBlock.name),
|
||||
inlineToolbarSettings = toolSettings && toolSettings[this.Editor.Tools.USER_SETTINGS.ENABLED_INLINE_TOOLS];
|
||||
inlineToolbarSettings = toolSettings && toolSettings[this.Editor.Tools.USER_SETTINGS.ENABLED_INLINE_TOOLS];
|
||||
|
||||
/**
|
||||
* All Inline Toolbar buttons
|
||||
*
|
||||
* @type {HTMLElement[]}
|
||||
*/
|
||||
const buttons = Array.from(this.nodes.buttons.querySelectorAll(`.${this.CSS.inlineToolButton}`)) as HTMLElement[];
|
||||
|
@ -458,7 +463,7 @@ export default class InlineToolbar extends Module {
|
|||
* Changes Conversion Dropdown content for current block's Tool
|
||||
*/
|
||||
private setConversionTogglerContent(): void {
|
||||
const {BlockManager, Tools} = this.Editor;
|
||||
const { BlockManager, Tools } = this.Editor;
|
||||
const toolName = BlockManager.currentBlock.name;
|
||||
|
||||
/**
|
||||
|
@ -478,11 +483,11 @@ export default class InlineToolbar extends Module {
|
|||
const userToolboxSettings = toolSettings.toolbox || {};
|
||||
|
||||
this.nodes.conversionTogglerContent.innerHTML =
|
||||
userToolboxSettings.icon
|
||||
|| toolboxSettings.icon
|
||||
|| userToolboxSettings.title
|
||||
|| toolboxSettings.title
|
||||
|| _.capitalize(toolName);
|
||||
userToolboxSettings.icon ||
|
||||
toolboxSettings.icon ||
|
||||
userToolboxSettings.title ||
|
||||
toolboxSettings.title ||
|
||||
_.capitalize(toolName);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -510,6 +515,9 @@ export default class InlineToolbar extends Module {
|
|||
|
||||
/**
|
||||
* Add tool button and activate clicks
|
||||
*
|
||||
* @param toolName
|
||||
* @param tool
|
||||
*/
|
||||
private addTool(toolName: string, tool: InlineTool): void {
|
||||
const {
|
||||
|
@ -522,6 +530,7 @@ export default class InlineToolbar extends Module {
|
|||
|
||||
if (!button) {
|
||||
_.log('Render method must return an instance of Node', 'warn', toolName);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -530,6 +539,7 @@ export default class InlineToolbar extends Module {
|
|||
|
||||
if (typeof tool.renderActions === 'function') {
|
||||
const actions = tool.renderActions();
|
||||
|
||||
this.nodes.actions.appendChild(actions);
|
||||
}
|
||||
|
||||
|
@ -558,7 +568,7 @@ export default class InlineToolbar extends Module {
|
|||
|
||||
return (toolClass as ToolSettings).class[Tools.INTERNAL_SETTINGS.IS_INLINE];
|
||||
})
|
||||
.map(([name]: [string, InlineToolConstructable | ToolSettings]) => name);
|
||||
.map(([ name ]: [string, InlineToolConstructable | ToolSettings]) => name);
|
||||
|
||||
/**
|
||||
* 1) For internal tools, check public getter 'shortcut'
|
||||
|
@ -592,11 +602,11 @@ export default class InlineToolbar extends Module {
|
|||
placement: 'top',
|
||||
hidingDelay: 100,
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable Tool shortcut with Editor Shortcuts Module
|
||||
*
|
||||
* @param {InlineTool} tool - Tool instance
|
||||
* @param {string} shortcut - shortcut according to the ShortcutData Module format
|
||||
*/
|
||||
|
@ -604,7 +614,7 @@ export default class InlineToolbar extends Module {
|
|||
this.Editor.Shortcuts.add({
|
||||
name: shortcut,
|
||||
handler: (event) => {
|
||||
const {currentBlock} = this.Editor.BlockManager;
|
||||
const { currentBlock } = this.Editor.BlockManager;
|
||||
|
||||
/**
|
||||
* Editor is not focused
|
||||
|
@ -618,7 +628,7 @@ export default class InlineToolbar extends Module {
|
|||
* it can be used by tools like «Mention» that works without selection:
|
||||
* Example: by SHIFT+@ show dropdown and insert selected username
|
||||
*/
|
||||
// if (SelectionUtils.isCollapsed) return;
|
||||
// if (SelectionUtils.isCollapsed) return;
|
||||
|
||||
const toolSettings = this.Editor.Tools.getToolSettings(currentBlock.name);
|
||||
|
||||
|
@ -634,6 +644,7 @@ export default class InlineToolbar extends Module {
|
|||
|
||||
/**
|
||||
* Inline Tool button clicks
|
||||
*
|
||||
* @param {InlineTool} tool - Tool's instance
|
||||
*/
|
||||
private toolClicked(tool: InlineTool): void {
|
||||
|
|
|
@ -1,32 +1,32 @@
|
|||
import Module from '../../__module';
|
||||
import $ from '../../dom';
|
||||
import * as _ from '../../utils';
|
||||
import {BlockToolConstructable} from '../../../../types';
|
||||
import { BlockToolConstructable } from '../../../../types';
|
||||
import Flipper from '../../flipper';
|
||||
import {BlockToolAPI} from '../../block';
|
||||
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
|
||||
* @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,
|
||||
*
|
||||
* @returns {{toolbox: string, toolboxButton string, toolboxButtonActive: string,
|
||||
* toolboxOpened: string, tooltip: string, tooltipShown: string, tooltipShortcut: string}}
|
||||
*/
|
||||
get CSS() {
|
||||
return {
|
||||
return {
|
||||
toolbox: 'ce-toolbox',
|
||||
toolboxButton: 'ce-toolbox__button',
|
||||
toolboxButtonActive : 'ce-toolbox__button--active',
|
||||
toolboxButtonActive: 'ce-toolbox__button--active',
|
||||
toolboxOpened: 'ce-toolbox--opened',
|
||||
openedToolbarHolderModifier: 'codex-editor--toolbox-opened',
|
||||
|
||||
|
@ -37,7 +37,8 @@ export default class Toolbox extends Module {
|
|||
|
||||
/**
|
||||
* Returns True if Toolbox is Empty and nothing to show
|
||||
* @return {boolean}
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public get isEmpty(): boolean {
|
||||
return this.displayedToolsCount === 0;
|
||||
|
@ -45,16 +46,17 @@ export default class Toolbox extends Module {
|
|||
|
||||
/**
|
||||
* Opening state
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
public opened: boolean = false;
|
||||
public opened = false;
|
||||
|
||||
/**
|
||||
* HTMLElements used for Toolbox UI
|
||||
*/
|
||||
public nodes: {
|
||||
toolbox: HTMLElement,
|
||||
buttons: HTMLElement[],
|
||||
toolbox: HTMLElement;
|
||||
buttons: HTMLElement[];
|
||||
} = {
|
||||
toolbox: null,
|
||||
buttons: [],
|
||||
|
@ -62,12 +64,14 @@ export default class Toolbox extends Module {
|
|||
|
||||
/**
|
||||
* How many tools displayed in Toolbox
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
private displayedToolsCount: number = 0;
|
||||
private displayedToolsCount = 0;
|
||||
|
||||
/**
|
||||
* Instance of class that responses for leafing buttons by arrows/tab
|
||||
*
|
||||
* @type {Flipper|null}
|
||||
*/
|
||||
private flipper: Flipper = null;
|
||||
|
@ -140,7 +144,7 @@ export default class Toolbox extends Module {
|
|||
|
||||
for (const toolName in tools) {
|
||||
if (tools.hasOwnProperty(toolName)) {
|
||||
this.addTool(toolName, tools[toolName] as BlockToolConstructable);
|
||||
this.addTool(toolName, tools[toolName] as BlockToolConstructable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -166,6 +170,7 @@ export default class Toolbox extends Module {
|
|||
|
||||
if (toolToolboxSettings && !toolToolboxSettings.icon) {
|
||||
_.log('Toolbar icon is missed. Tool %o skipped', 'warn', toolName);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -222,8 +227,8 @@ export default class Toolbox extends Module {
|
|||
/**
|
||||
* Draw tooltip for toolbox tools
|
||||
*
|
||||
* @param {String} toolName - toolbox tool name
|
||||
* @return { HTMLElement }
|
||||
* @param {string} toolName - toolbox tool name
|
||||
* @returns { HTMLElement }
|
||||
*/
|
||||
private drawTooltip(toolName: string): HTMLElement {
|
||||
const toolSettings = this.Editor.Tools.getToolSettings(toolName);
|
||||
|
@ -251,9 +256,10 @@ export default class Toolbox extends Module {
|
|||
|
||||
/**
|
||||
* 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
|
||||
* @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({
|
||||
|
@ -270,6 +276,7 @@ export default class Toolbox extends Module {
|
|||
*/
|
||||
private enableFlipper(): void {
|
||||
const tools = Array.from(this.nodes.toolbox.childNodes) as HTMLElement[];
|
||||
|
||||
this.flipper = new Flipper({
|
||||
items: tools,
|
||||
focusedItemClass: this.CSS.toolboxButtonActive,
|
||||
|
@ -281,14 +288,14 @@ export default class Toolbox extends Module {
|
|||
* Can be called when button clicked on Toolbox or by ShortcutData
|
||||
*
|
||||
* @param {BlockToolConstructable} tool - Tool Class
|
||||
* @param {String} toolName - Tool name
|
||||
* @param {string} toolName - Tool name
|
||||
*/
|
||||
private insertNewBlock(tool: BlockToolConstructable, toolName: string) {
|
||||
const {BlockManager, Caret} = this.Editor;
|
||||
const { BlockManager, Caret } = this.Editor;
|
||||
/**
|
||||
* @type {Block}
|
||||
*/
|
||||
const {currentBlock} = BlockManager;
|
||||
const { currentBlock } = BlockManager;
|
||||
|
||||
let newBlock;
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import {
|
|||
InlineToolConstructable, Tool,
|
||||
ToolConfig,
|
||||
ToolConstructable,
|
||||
ToolSettings,
|
||||
ToolSettings
|
||||
} from '../../../types';
|
||||
import BoldInlineTool from '../inline-tools/inline-tool-bold';
|
||||
import ItalicInlineTool from '../inline-tools/inline-tool-italic';
|
||||
|
@ -31,17 +31,18 @@ import Stub from '../tools/stub';
|
|||
* @property {EditorConfig} config - Editor config
|
||||
*/
|
||||
export default class Tools extends Module {
|
||||
|
||||
/**
|
||||
* Name of Stub Tool
|
||||
* Stub Tool is used to substitute unavailable block Tools and store their data
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
public stubTool = 'stub';
|
||||
|
||||
/**
|
||||
* Returns available Tools
|
||||
* @return {Tool[]}
|
||||
*
|
||||
* @returns {Tool[]}
|
||||
*/
|
||||
public get available(): {[name: string]: ToolConstructable} {
|
||||
return this.toolsAvailable;
|
||||
|
@ -49,7 +50,8 @@ export default class Tools extends Module {
|
|||
|
||||
/**
|
||||
* Returns unavailable Tools
|
||||
* @return {Tool[]}
|
||||
*
|
||||
* @returns {Tool[]}
|
||||
*/
|
||||
public get unavailable(): {[name: string]: ToolConstructable} {
|
||||
return this.toolsUnavailable;
|
||||
|
@ -57,14 +59,15 @@ export default class Tools extends Module {
|
|||
|
||||
/**
|
||||
* Return Tools for the Inline Toolbar
|
||||
* @return {Object} - object of Inline Tool's classes
|
||||
*
|
||||
* @returns {object} - object of Inline Tool's classes
|
||||
*/
|
||||
public get inline(): {[name: string]: ToolConstructable} {
|
||||
if (this._inlineTools) {
|
||||
return this._inlineTools;
|
||||
}
|
||||
|
||||
const tools = Object.entries(this.available).filter( ([name, tool]) => {
|
||||
const tools = Object.entries(this.available).filter(([name, tool]) => {
|
||||
if (!tool[this.INTERNAL_SETTINGS.IS_INLINE]) {
|
||||
return false;
|
||||
}
|
||||
|
@ -73,14 +76,15 @@ export default class Tools extends Module {
|
|||
* Some Tools validation
|
||||
*/
|
||||
const inlineToolRequiredMethods = ['render', 'surround', 'checkState'];
|
||||
const notImplementedMethods = inlineToolRequiredMethods.filter( (method) => !this.constructInline(tool)[method]);
|
||||
const notImplementedMethods = inlineToolRequiredMethods.filter((method) => !this.constructInline(tool)[method]);
|
||||
|
||||
if (notImplementedMethods.length) {
|
||||
_.log(
|
||||
`Incorrect Inline Tool: ${tool.name}. Some of required methods is not implemented %o`,
|
||||
'warn',
|
||||
notImplementedMethods,
|
||||
notImplementedMethods
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -92,7 +96,9 @@ export default class Tools extends Module {
|
|||
*/
|
||||
const result = {};
|
||||
|
||||
tools.forEach(([name, tool]) => result[name] = tool);
|
||||
tools.forEach(([name, tool]) => {
|
||||
result[name] = tool;
|
||||
});
|
||||
|
||||
/**
|
||||
* Cache prepared Tools
|
||||
|
@ -107,7 +113,7 @@ export default class Tools extends Module {
|
|||
*/
|
||||
public get blockTools(): {[name: string]: BlockToolConstructable} {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const tools = Object.entries(this.available).filter( ([name, tool]) => {
|
||||
const tools = Object.entries(this.available).filter(([name, tool]) => {
|
||||
return !tool[this.INTERNAL_SETTINGS.IS_INLINE];
|
||||
});
|
||||
|
||||
|
@ -116,7 +122,9 @@ export default class Tools extends Module {
|
|||
*/
|
||||
const result = {};
|
||||
|
||||
tools.forEach(([name, tool]) => result[name] = tool);
|
||||
tools.forEach(([name, tool]) => {
|
||||
result[name] = tool;
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -124,7 +132,7 @@ export default class Tools extends Module {
|
|||
/**
|
||||
* Constant for available Tools internal settings provided by Tool developer
|
||||
*
|
||||
* @return {object}
|
||||
* @returns {object}
|
||||
*/
|
||||
public get INTERNAL_SETTINGS() {
|
||||
return {
|
||||
|
@ -155,7 +163,8 @@ export default class Tools extends Module {
|
|||
/**
|
||||
* Map {name: Class, ...} where:
|
||||
* name — block type name in JSON. Got from EditorConfig.tools keys
|
||||
* @type {Object}
|
||||
*
|
||||
* @type {object}
|
||||
*/
|
||||
public readonly toolsClasses: {[name: string]: ToolConstructable} = {};
|
||||
|
||||
|
@ -171,24 +180,26 @@ export default class Tools extends Module {
|
|||
|
||||
/**
|
||||
* Tools settings in a map {name: settings, ...}
|
||||
* @type {Object}
|
||||
*
|
||||
* @type {object}
|
||||
*/
|
||||
private readonly toolsSettings: {[name: string]: ToolSettings} = {};
|
||||
|
||||
/**
|
||||
* Cache for the prepared inline tools
|
||||
*
|
||||
* @type {null|object}
|
||||
* @private
|
||||
*/
|
||||
private _inlineTools: {[name: string]: ToolConstructable} = {};
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @class
|
||||
*
|
||||
* @param {EditorConfig} config
|
||||
*/
|
||||
constructor({config}) {
|
||||
super({config});
|
||||
constructor({ config }) {
|
||||
super({ config });
|
||||
|
||||
this.toolsClasses = {};
|
||||
|
||||
|
@ -197,14 +208,16 @@ export default class Tools extends Module {
|
|||
/**
|
||||
* Available tools list
|
||||
* {name: Class, ...}
|
||||
* @type {Object}
|
||||
*
|
||||
* @type {object}
|
||||
*/
|
||||
this.toolsAvailable = {};
|
||||
|
||||
/**
|
||||
* Tools that rejected a prepare method
|
||||
* {name: Class, ... }
|
||||
* @type {Object}
|
||||
*
|
||||
* @type {object}
|
||||
*/
|
||||
this.toolsUnavailable = {};
|
||||
|
||||
|
@ -213,7 +226,8 @@ export default class Tools extends Module {
|
|||
|
||||
/**
|
||||
* Creates instances via passed or default configuration
|
||||
* @return {Promise}
|
||||
*
|
||||
* @returns {Promise}
|
||||
*/
|
||||
public prepare() {
|
||||
this.validateTools();
|
||||
|
@ -238,12 +252,14 @@ export default class Tools extends Module {
|
|||
if (typeof this.config.tools[toolName] === 'object') {
|
||||
/**
|
||||
* Save Tool's class from 'class' field
|
||||
*
|
||||
* @type {Tool}
|
||||
*/
|
||||
this.toolsClasses[toolName] = (this.config.tools[toolName] as ToolSettings).class;
|
||||
|
||||
/**
|
||||
* Save Tool's settings
|
||||
*
|
||||
* @type {ToolSettings}
|
||||
*/
|
||||
this.toolsSettings[toolName] = this.config.tools[toolName] as ToolSettings;
|
||||
|
@ -255,15 +271,17 @@ export default class Tools extends Module {
|
|||
} else {
|
||||
/**
|
||||
* Save Tool's class
|
||||
*
|
||||
* @type {Tool}
|
||||
*/
|
||||
this.toolsClasses[toolName] = this.config.tools[toolName] as ToolConstructable;
|
||||
|
||||
/**
|
||||
* Set empty settings for Block by default
|
||||
*
|
||||
* @type {{}}
|
||||
*/
|
||||
this.toolsSettings[toolName] = {class: this.config.tools[toolName] as ToolConstructable};
|
||||
this.toolsSettings[toolName] = { class: this.config.tools[toolName] as ToolConstructable };
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -306,12 +324,12 @@ export default class Tools extends Module {
|
|||
/**
|
||||
* Return Tool`s instance
|
||||
*
|
||||
* @param {String} tool — tool name
|
||||
* @param {string} tool — tool name
|
||||
* @param {BlockToolData} data — initial data
|
||||
* @return {BlockTool}
|
||||
* @returns {BlockTool}
|
||||
*/
|
||||
public construct(tool, data) {
|
||||
const plugin = this.toolsClasses[tool];
|
||||
const Plugin = this.toolsClasses[tool];
|
||||
|
||||
/**
|
||||
* Configuration to be passed to the Tool's constructor
|
||||
|
@ -332,7 +350,7 @@ export default class Tools extends Module {
|
|||
data,
|
||||
};
|
||||
|
||||
return new plugin(constructorOptions);
|
||||
return new Plugin(constructorOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -340,7 +358,7 @@ export default class Tools extends Module {
|
|||
*
|
||||
* @param {InlineTool} tool
|
||||
* @param {ToolSettings} toolSettings
|
||||
* @return {InlineTool} — instance
|
||||
* @returns {InlineTool} — instance
|
||||
*/
|
||||
public constructInline(tool: InlineToolConstructable, toolSettings: ToolSettings = {} as ToolSettings): InlineTool {
|
||||
/**
|
||||
|
@ -351,13 +369,15 @@ export default class Tools extends Module {
|
|||
config: (toolSettings[this.USER_SETTINGS.CONFIG] || {}) as ToolSettings,
|
||||
};
|
||||
|
||||
// eslint-disable-next-line new-cap
|
||||
return new tool(constructorOptions) as InlineTool;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if passed Tool is an instance of Initial Block Tool
|
||||
*
|
||||
* @param {Tool} tool - Tool to check
|
||||
* @return {Boolean}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public isInitial(tool) {
|
||||
return tool instanceof this.available[this.config.initialBlock];
|
||||
|
@ -365,8 +385,9 @@ export default class Tools extends Module {
|
|||
|
||||
/**
|
||||
* Return Tool's config by name
|
||||
*
|
||||
* @param {string} toolName
|
||||
* @return {ToolSettings}
|
||||
* @returns {ToolSettings}
|
||||
*/
|
||||
public getToolSettings(toolName): ToolSettings {
|
||||
return this.toolsSettings[toolName];
|
||||
|
@ -374,15 +395,16 @@ export default class Tools extends Module {
|
|||
|
||||
/**
|
||||
* Binds prepare function of plugins with user or default config
|
||||
* @return {Array} list of functions that needs to be fired sequentially
|
||||
*
|
||||
* @returns {Array} list of functions that needs to be fired sequentially
|
||||
*/
|
||||
private getListOfPrepareFunctions(): Array<{
|
||||
function: (data: {toolName: string, config: ToolConfig}) => void,
|
||||
data: {toolName: string, config: ToolConfig},
|
||||
function: (data: {toolName: string; config: ToolConfig}) => void;
|
||||
data: {toolName: string; config: ToolConfig};
|
||||
}> {
|
||||
const toolPreparationList: Array<{
|
||||
function: (data: {toolName: string, config: ToolConfig}) => void,
|
||||
data: {toolName: string, config: ToolConfig}}
|
||||
function: (data: {toolName: string; config: ToolConfig}) => void;
|
||||
data: {toolName: string; config: ToolConfig};}
|
||||
> = [];
|
||||
|
||||
for (const toolName in this.toolsClasses) {
|
||||
|
@ -426,7 +448,7 @@ export default class Tools extends Module {
|
|||
|
||||
if (!_.isFunction(tool) && !_.isFunction((tool as ToolSettings).class)) {
|
||||
throw Error(
|
||||
`Tool «${toolName}» must be a constructor function or an object with function in the «class» property`,
|
||||
`Tool «${toolName}» must be a constructor function or an object with function in the «class» property`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -439,14 +461,14 @@ export default class Tools extends Module {
|
|||
*/
|
||||
get internalTools() {
|
||||
return {
|
||||
bold: {class: BoldInlineTool},
|
||||
italic: {class: ItalicInlineTool},
|
||||
link: {class: LinkInlineTool},
|
||||
bold: { class: BoldInlineTool },
|
||||
italic: { class: ItalicInlineTool },
|
||||
link: { class: LinkInlineTool },
|
||||
paragraph: {
|
||||
class: Paragraph,
|
||||
inlineToolbar: true,
|
||||
},
|
||||
stub: {class: Stub},
|
||||
stub: { class: Stub },
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import Module from '../__module';
|
|||
* Use external module CodeX Tooltip
|
||||
*/
|
||||
import CodeXTooltips, { TooltipContent, TooltipOptions } from 'codex-tooltip';
|
||||
import {ModuleConfig} from '../../types-internal/module-config';
|
||||
import { ModuleConfig } from '../../types-internal/module-config';
|
||||
|
||||
/**
|
||||
* Tooltip
|
||||
|
@ -12,19 +12,19 @@ import {ModuleConfig} from '../../types-internal/module-config';
|
|||
* Decorates any tooltip module like adapter
|
||||
*/
|
||||
export default class Tooltip extends Module {
|
||||
|
||||
/**
|
||||
* Tooltips lib: CodeX Tooltips
|
||||
*
|
||||
* @see https://github.com/codex-team/codex.tooltips
|
||||
*/
|
||||
private lib: CodeXTooltips = new CodeXTooltips();
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @class
|
||||
* @param {EditorConfig}
|
||||
*/
|
||||
constructor({config}: ModuleConfig) {
|
||||
super({config});
|
||||
constructor({ config }: ModuleConfig) {
|
||||
super({ config });
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -35,22 +35,21 @@ import Flipper from '../flipper';
|
|||
* @property {Element} nodes.redactor - <ce-redactor>
|
||||
*/
|
||||
export default class UI extends Module {
|
||||
|
||||
/**
|
||||
* Editor.js UI CSS class names
|
||||
* @return {{editorWrapper: string, editorZone: string}}
|
||||
*/
|
||||
public get CSS(): {
|
||||
editorWrapper: string, editorWrapperNarrow: string, editorZone: string, editorZoneHidden: string,
|
||||
editorLoader: string, editorEmpty: string,
|
||||
} {
|
||||
editorWrapper: string; editorWrapperNarrow: string; editorZone: string; editorZoneHidden: string;
|
||||
editorLoader: string; editorEmpty: string;
|
||||
} {
|
||||
return {
|
||||
editorWrapper : 'codex-editor',
|
||||
editorWrapperNarrow : 'codex-editor--narrow',
|
||||
editorZone : 'codex-editor__redactor',
|
||||
editorZoneHidden : 'codex-editor__redactor--hidden',
|
||||
editorLoader : 'codex-editor__loader',
|
||||
editorEmpty : 'codex-editor--empty',
|
||||
editorWrapper: 'codex-editor',
|
||||
editorWrapperNarrow: 'codex-editor--narrow',
|
||||
editorZone: 'codex-editor__redactor',
|
||||
editorZoneHidden: 'codex-editor__redactor--hidden',
|
||||
editorLoader: 'codex-editor__loader',
|
||||
editorEmpty: 'codex-editor--empty',
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -85,7 +84,7 @@ export default class UI extends Module {
|
|||
* Flag that became true on mobile viewport
|
||||
* @type {boolean}
|
||||
*/
|
||||
public isMobile: boolean = false;
|
||||
public isMobile = false;
|
||||
|
||||
/**
|
||||
* HTML Elements used for UI
|
||||
|
@ -177,7 +176,7 @@ export default class UI extends Module {
|
|||
* Check if Editor is empty and set CSS class to wrapper
|
||||
*/
|
||||
public checkEmptiness(): void {
|
||||
const {BlockManager} = this.Editor;
|
||||
const { BlockManager } = this.Editor;
|
||||
|
||||
this.nodes.wrapper.classList.toggle(this.CSS.editorEmpty, BlockManager.isEditorEmpty);
|
||||
}
|
||||
|
@ -199,9 +198,10 @@ export default class UI extends Module {
|
|||
public get someFlipperButtonFocused(): boolean {
|
||||
return Object.entries(this.Editor).filter(([moduleName, moduleClass]) => {
|
||||
return moduleClass.flipper instanceof Flipper;
|
||||
}).some(([moduleName, moduleClass]) => {
|
||||
return moduleClass.flipper.currentItem;
|
||||
});
|
||||
})
|
||||
.some(([moduleName, moduleClass]) => {
|
||||
return moduleClass.flipper.currentItem;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -244,7 +244,7 @@ export default class UI extends Module {
|
|||
/**
|
||||
* Create and save main UI elements
|
||||
*/
|
||||
this.nodes.wrapper = $.make('div', this.CSS.editorWrapper);
|
||||
this.nodes.wrapper = $.make('div', this.CSS.editorWrapper);
|
||||
this.nodes.redactor = $.make('div', this.CSS.editorZone);
|
||||
|
||||
/**
|
||||
|
@ -261,7 +261,6 @@ export default class UI extends Module {
|
|||
|
||||
this.nodes.wrapper.appendChild(this.nodes.redactor);
|
||||
this.nodes.holder.appendChild(this.nodes.wrapper);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -294,17 +293,17 @@ export default class UI extends Module {
|
|||
this.nodes.redactor,
|
||||
'click',
|
||||
(event) => this.redactorClicked(event as MouseEvent),
|
||||
false,
|
||||
false
|
||||
);
|
||||
this.Editor.Listeners.on(this.nodes.redactor,
|
||||
'mousedown',
|
||||
(event) => this.documentTouched(event as MouseEvent),
|
||||
true,
|
||||
true
|
||||
);
|
||||
this.Editor.Listeners.on(this.nodes.redactor,
|
||||
'touchstart',
|
||||
(event) => this.documentTouched(event as MouseEvent),
|
||||
true,
|
||||
true
|
||||
);
|
||||
|
||||
this.Editor.Listeners.on(document, 'keydown', (event) => this.documentKeydown(event as KeyboardEvent), true);
|
||||
|
@ -363,7 +362,7 @@ export default class UI extends Module {
|
|||
*/
|
||||
private defaultBehaviour(event: KeyboardEvent): void {
|
||||
const keyDownOnEditor = (event.target as HTMLElement).closest(`.${this.CSS.editorWrapper}`);
|
||||
const {currentBlock} = this.Editor.BlockManager;
|
||||
const { currentBlock } = this.Editor.BlockManager;
|
||||
const isMetaKey = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
|
||||
|
||||
/**
|
||||
|
@ -388,10 +387,11 @@ export default class UI extends Module {
|
|||
* @param {KeyboardEvent} event
|
||||
*/
|
||||
private backspacePressed(event: KeyboardEvent): void {
|
||||
const {BlockManager, BlockSelection, Caret} = this.Editor;
|
||||
const { BlockManager, BlockSelection, Caret } = this.Editor;
|
||||
|
||||
if (BlockSelection.anyBlockSelected) {
|
||||
const selectionPositionIndex = BlockManager.removeSelectedBlocks();
|
||||
|
||||
Caret.setToBlock(BlockManager.insertInitialBlockAtIndex(selectionPositionIndex, true), Caret.positions.START);
|
||||
|
||||
/** Clear selection */
|
||||
|
@ -418,6 +418,7 @@ export default class UI extends Module {
|
|||
|
||||
if (BlockSelection.anyBlockSelected) {
|
||||
const selectionPositionIndex = BlockManager.removeSelectedBlocks();
|
||||
|
||||
Caret.setToBlock(BlockManager.insertInitialBlockAtIndex(selectionPositionIndex, true), Caret.positions.START);
|
||||
|
||||
/** Clear selection */
|
||||
|
@ -431,6 +432,7 @@ export default class UI extends Module {
|
|||
event.preventDefault();
|
||||
event.stopImmediatePropagation();
|
||||
event.stopPropagation();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -596,6 +598,7 @@ export default class UI extends Module {
|
|||
const validUrl = _.getValidUrl(href);
|
||||
|
||||
_.openTab(validUrl);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -635,7 +638,6 @@ export default class UI extends Module {
|
|||
* We need to skip such firings
|
||||
*/
|
||||
if (!focusedElement || !focusedElement.closest(`.${Block.CSS.content}`)) {
|
||||
|
||||
/**
|
||||
* If new selection is not on Inline Toolbar, we need to close it
|
||||
*/
|
||||
|
|
|
@ -26,7 +26,7 @@ if (!Element.prototype.matches) {
|
|||
Element.prototype.msMatchesSelector ||
|
||||
Element.prototype.oMatchesSelector ||
|
||||
Element.prototype.webkitMatchesSelector ||
|
||||
function(s) {
|
||||
function (s) {
|
||||
const matches = (this.document || this.ownerDocument).querySelectorAll(s);
|
||||
let i = matches.length;
|
||||
|
||||
|
@ -46,7 +46,8 @@ if (!Element.prototype.matches) {
|
|||
* {@link https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill}
|
||||
*/
|
||||
if (!Element.prototype.closest) {
|
||||
Element.prototype.closest = function(s) {
|
||||
Element.prototype.closest = function (s) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||
let el = this;
|
||||
|
||||
if (!document.documentElement.contains(el)) {
|
||||
|
|
|
@ -30,15 +30,16 @@ interface Document {
|
|||
|
||||
/**
|
||||
* Working with selection
|
||||
*
|
||||
* @typedef {SelectionUtils} SelectionUtils
|
||||
*/
|
||||
export default class SelectionUtils {
|
||||
|
||||
/**
|
||||
* Editor styles
|
||||
* @return {{editorWrapper: string, editorZone: string}}
|
||||
*
|
||||
* @returns {{editorWrapper: string, editorZone: string}}
|
||||
*/
|
||||
static get CSS(): { editorWrapper: string, editorZone: string } {
|
||||
static get CSS(): { editorWrapper: string; editorZone: string } {
|
||||
return {
|
||||
editorWrapper: 'codex-editor',
|
||||
editorZone: 'codex-editor__redactor',
|
||||
|
@ -48,7 +49,8 @@ export default class SelectionUtils {
|
|||
/**
|
||||
* Returns selected anchor
|
||||
* {@link https://developer.mozilla.org/ru/docs/Web/API/Selection/anchorNode}
|
||||
* @return {Node|null}
|
||||
*
|
||||
* @returns {Node|null}
|
||||
*/
|
||||
static get anchorNode(): Node | null {
|
||||
const selection = window.getSelection();
|
||||
|
@ -58,7 +60,8 @@ export default class SelectionUtils {
|
|||
|
||||
/**
|
||||
* Returns selected anchor element
|
||||
* @return {Element|null}
|
||||
*
|
||||
* @returns {Element|null}
|
||||
*/
|
||||
static get anchorElement(): Element | null {
|
||||
const selection = window.getSelection();
|
||||
|
@ -83,7 +86,8 @@ export default class SelectionUtils {
|
|||
/**
|
||||
* Returns selection offset according to the anchor node
|
||||
* {@link https://developer.mozilla.org/ru/docs/Web/API/Selection/anchorOffset}
|
||||
* @return {Number|null}
|
||||
*
|
||||
* @returns {number|null}
|
||||
*/
|
||||
static get anchorOffset(): number | null {
|
||||
const selection = window.getSelection();
|
||||
|
@ -93,7 +97,8 @@ export default class SelectionUtils {
|
|||
|
||||
/**
|
||||
* Is current selection range collapsed
|
||||
* @return {boolean|null}
|
||||
*
|
||||
* @returns {boolean|null}
|
||||
*/
|
||||
static get isCollapsed(): boolean | null {
|
||||
const selection = window.getSelection();
|
||||
|
@ -103,7 +108,8 @@ export default class SelectionUtils {
|
|||
|
||||
/**
|
||||
* Check current selection if it is at Editor's zone
|
||||
* @return {boolean}
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
static get isAtEditor(): boolean {
|
||||
const selection = SelectionUtils.get();
|
||||
|
@ -118,6 +124,7 @@ export default class SelectionUtils {
|
|||
}
|
||||
|
||||
let editorZone = null;
|
||||
|
||||
if (selectedNode) {
|
||||
editorZone = selectedNode.closest(`.${SelectionUtils.CSS.editorZone}`);
|
||||
}
|
||||
|
@ -130,7 +137,8 @@ export default class SelectionUtils {
|
|||
|
||||
/**
|
||||
* Return first range
|
||||
* @return {Range|null}
|
||||
*
|
||||
* @returns {Range|null}
|
||||
*/
|
||||
static get range(): Range {
|
||||
const selection = window.getSelection();
|
||||
|
@ -140,11 +148,12 @@ export default class SelectionUtils {
|
|||
|
||||
/**
|
||||
* Calculates position and size of selected text
|
||||
* @return {{x, y, width, height, top?, left?, bottom?, right?}}
|
||||
*
|
||||
* @returns {{x, y, width, height, top?, left?, bottom?, right?}}
|
||||
*/
|
||||
static get rect(): DOMRect | ClientRect {
|
||||
let sel: Selection | MSSelection = (document as Document).selection,
|
||||
range: TextRange | Range;
|
||||
range: TextRange | Range;
|
||||
|
||||
let rect = {
|
||||
x: 0,
|
||||
|
@ -166,6 +175,7 @@ export default class SelectionUtils {
|
|||
|
||||
if (!window.getSelection) {
|
||||
_.log('Method window.getSelection is not supported', 'warn');
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
|
@ -173,6 +183,7 @@ export default class SelectionUtils {
|
|||
|
||||
if (sel.rangeCount === null || isNaN(sel.rangeCount)) {
|
||||
_.log('Method SelectionUtils.rangeCount is not supported', 'warn');
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
|
@ -210,6 +221,7 @@ export default class SelectionUtils {
|
|||
|
||||
/**
|
||||
* Returns selected text as String
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
static get text(): string {
|
||||
|
@ -219,7 +231,8 @@ export default class SelectionUtils {
|
|||
/**
|
||||
* Returns window SelectionUtils
|
||||
* {@link https://developer.mozilla.org/ru/docs/Web/API/Window/getSelection}
|
||||
* @return {Selection}
|
||||
*
|
||||
* @returns {Selection}
|
||||
*/
|
||||
public static get(): Selection {
|
||||
return window.getSelection();
|
||||
|
@ -230,6 +243,7 @@ export default class SelectionUtils {
|
|||
|
||||
/**
|
||||
* This property can store SelectionUtils's range for restoring later
|
||||
*
|
||||
* @type {Range|null}
|
||||
*/
|
||||
public savedSelectionRange: Range = null;
|
||||
|
@ -237,7 +251,7 @@ export default class SelectionUtils {
|
|||
/**
|
||||
* Fake background is active
|
||||
*
|
||||
* @return {boolean}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public isFakeBackgroundEnabled = false;
|
||||
|
||||
|
@ -312,10 +326,10 @@ export default class SelectionUtils {
|
|||
/**
|
||||
* Looks ahead to find passed tag from current selection
|
||||
*
|
||||
* @param {String} tagName - tag to found
|
||||
* @param {String} [className] - tag's class name
|
||||
* @param {Number} [searchDepth] - count of tags that can be included. For better performance.
|
||||
* @return {HTMLElement|null}
|
||||
* @param {string} tagName - tag to found
|
||||
* @param {string} [className] - tag's class name
|
||||
* @param {number} [searchDepth] - count of tags that can be included. For better performance.
|
||||
* @returns {HTMLElement|null}
|
||||
*/
|
||||
public findParentTag(tagName: string, className?: string, searchDepth = 10): HTMLElement | null {
|
||||
const selection = window.getSelection();
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
import $ from '../../dom';
|
||||
import {BlockTool, BlockToolData} from '../../../../types';
|
||||
import { BlockTool, BlockToolData } from '../../../../types';
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export default class Stub implements BlockTool {
|
||||
/**
|
||||
* Stub styles
|
||||
*
|
||||
* @type {{wrapper: string; info: string; title: string; subtitle: string}}
|
||||
*/
|
||||
private CSS = {
|
||||
|
@ -33,7 +37,12 @@ export default class Stub implements BlockTool {
|
|||
*/
|
||||
private readonly savedData: BlockToolData;
|
||||
|
||||
constructor({data, config, api}) {
|
||||
/**
|
||||
* @param data
|
||||
* @param config
|
||||
* @param api
|
||||
*/
|
||||
constructor({ data, config, api }) {
|
||||
this.title = data.title || 'Error';
|
||||
this.subtitle = 'The block can not be displayed correctly.';
|
||||
this.savedData = data.savedData;
|
||||
|
@ -43,7 +52,8 @@ export default class Stub implements BlockTool {
|
|||
|
||||
/**
|
||||
* Returns stub holder
|
||||
* @return {HTMLElement}
|
||||
*
|
||||
* @returns {HTMLElement}
|
||||
*/
|
||||
public render(): HTMLElement {
|
||||
return this.wrapper;
|
||||
|
@ -51,7 +61,8 @@ export default class Stub implements BlockTool {
|
|||
|
||||
/**
|
||||
* Return original Tool data
|
||||
* @return {BlockToolData}
|
||||
*
|
||||
* @returns {BlockToolData}
|
||||
*/
|
||||
public save(): BlockToolData {
|
||||
return this.savedData;
|
||||
|
@ -59,7 +70,8 @@ export default class Stub implements BlockTool {
|
|||
|
||||
/**
|
||||
* Create Tool html markup
|
||||
* @return {HTMLElement}
|
||||
*
|
||||
* @returns {HTMLElement}
|
||||
*/
|
||||
private make(): HTMLElement {
|
||||
const wrapper = $.make('div', this.CSS.wrapper);
|
||||
|
|
|
@ -20,8 +20,8 @@ export enum LogLevels {
|
|||
declare const VERSION: string;
|
||||
|
||||
/**
|
||||
* @typedef {Object} ChainData
|
||||
* @property {Object} data - data that will be passed to the success or fallback
|
||||
* @typedef {object} ChainData
|
||||
* @property {object} data - data that will be passed to the success or fallback
|
||||
* @property {Function} function - function's that must be called asynchronically
|
||||
*/
|
||||
export interface ChainData {
|
||||
|
@ -35,7 +35,8 @@ export interface ChainData {
|
|||
|
||||
/**
|
||||
* Returns basic keycodes as constants
|
||||
* @return {{}}
|
||||
*
|
||||
* @returns {{}}
|
||||
*/
|
||||
export const keyCodes = {
|
||||
BACKSPACE: 8,
|
||||
|
@ -73,17 +74,15 @@ export const mouseButtons = {
|
|||
* @param {string} type - logging type 'log'|'warn'|'error'|'info'
|
||||
* @param {*} [args] - argument to log with a message
|
||||
* @param {string} style - additional styling to message
|
||||
* @param labeled
|
||||
*/
|
||||
function _log(
|
||||
labeled: boolean,
|
||||
msg: string,
|
||||
type: string = 'log',
|
||||
type = 'log',
|
||||
args?: any,
|
||||
style: string = 'color: inherit',
|
||||
style = 'color: inherit'
|
||||
): void {
|
||||
|
||||
if ( !('console' in window) || !window.console[ type ] ) {
|
||||
if (!('console' in window) || !window.console[type]) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -156,7 +155,7 @@ _log.logLevel = LogLevels.VERBOSE;
|
|||
*
|
||||
* @param {LogLevels} logLevel - log level to set
|
||||
*/
|
||||
export function setLogLevel(logLevel: LogLevels) {
|
||||
export function setLogLevel(logLevel: LogLevels): void {
|
||||
_log.logLevel = logLevel;
|
||||
}
|
||||
|
||||
|
@ -172,31 +171,34 @@ export const logLabeled = _log.bind(window, true);
|
|||
|
||||
/**
|
||||
* Returns true if passed key code is printable (a-Z, 0-9, etc) character.
|
||||
*
|
||||
* @param {number} keyCode
|
||||
* @return {boolean}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isPrintableKey( keyCode: number ): boolean {
|
||||
return (keyCode > 47 && keyCode < 58) || // number keys
|
||||
keyCode === 32 || keyCode === 13 || // Spacebar & return key(s)
|
||||
(keyCode > 64 && keyCode < 91) || // letter keys
|
||||
(keyCode > 95 && keyCode < 112) || // Numpad keys
|
||||
export function isPrintableKey(keyCode: number): boolean {
|
||||
return (keyCode > 47 && keyCode < 58) || // number keys
|
||||
keyCode === 32 || keyCode === 13 || // Spacebar & return key(s)
|
||||
(keyCode > 64 && keyCode < 91) || // letter keys
|
||||
(keyCode > 95 && keyCode < 112) || // Numpad keys
|
||||
(keyCode > 185 && keyCode < 193) || // ;=,-./` (in order)
|
||||
(keyCode > 218 && keyCode < 223); // [\]' (in order)
|
||||
(keyCode > 218 && keyCode < 223); // [\]' (in order)
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires a promise sequence asyncronically
|
||||
* Fires a promise sequence asynchronously
|
||||
*
|
||||
* @param {ChainData[]} chains - list or ChainData's
|
||||
* @param {Function} success - success callback
|
||||
* @param {Function} fallback - callback that fires in case of errors
|
||||
*
|
||||
* @return {Promise}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export async function sequence(
|
||||
chains: ChainData[],
|
||||
success: (data: any) => void = () => {},
|
||||
fallback: (data: any) => void = () => {},
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
success: (data: any) => void = (): void => {},
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
fallback: (data: any) => void = (): void => {},
|
||||
): Promise<void> {
|
||||
/**
|
||||
* Decorator
|
||||
|
@ -206,12 +208,12 @@ export async function sequence(
|
|||
* @param {Function} successCallback
|
||||
* @param {Function} fallbackCallback
|
||||
*
|
||||
* @return {Promise}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
async function waitNextBlock(
|
||||
chainData: ChainData,
|
||||
successCallback: (data: any) => void,
|
||||
fallbackCallback: (data: any) => void,
|
||||
fallbackCallback: (data: any) => void
|
||||
): Promise<void> {
|
||||
try {
|
||||
await chainData.function(chainData.data);
|
||||
|
@ -228,8 +230,9 @@ export async function sequence(
|
|||
* reduce current element will not be able to continue while can't get
|
||||
* a resolved Promise
|
||||
*/
|
||||
return await chains.reduce(async (previousValue, currentValue) => {
|
||||
return chains.reduce(async (previousValue, currentValue) => {
|
||||
await previousValue;
|
||||
|
||||
return waitNextBlock(currentValue, success, fallback);
|
||||
}, Promise.resolve());
|
||||
}
|
||||
|
@ -239,7 +242,7 @@ export async function sequence(
|
|||
*
|
||||
* @param {ArrayLike} collection
|
||||
*
|
||||
* @return {Array}
|
||||
* @returns {Array}
|
||||
*/
|
||||
export function array(collection: ArrayLike<any>): any[] {
|
||||
return Array.prototype.slice.call(collection);
|
||||
|
@ -247,8 +250,9 @@ export function array(collection: ArrayLike<any>): any[] {
|
|||
|
||||
/**
|
||||
* Check if passed variable is a function
|
||||
*
|
||||
* @param {*} fn
|
||||
* @return {boolean}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isFunction(fn: any): boolean {
|
||||
return typeof fn === 'function';
|
||||
|
@ -256,8 +260,9 @@ export function isFunction(fn: any): boolean {
|
|||
|
||||
/**
|
||||
* Check if passed function is a class
|
||||
* @param {function} fn
|
||||
* @return {boolean}
|
||||
*
|
||||
* @param {Function} fn
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isClass(fn: any): boolean {
|
||||
return typeof fn === 'function' && /^\s*class\s+/.test(fn.toString());
|
||||
|
@ -266,8 +271,8 @@ export function isClass(fn: any): boolean {
|
|||
/**
|
||||
* Checks if object is empty
|
||||
*
|
||||
* @param {Object} object
|
||||
* @return {boolean}
|
||||
* @param {object} object
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isEmpty(object: object): boolean {
|
||||
if (!object) {
|
||||
|
@ -279,8 +284,9 @@ export function isEmpty(object: object): boolean {
|
|||
|
||||
/**
|
||||
* Check if passed object is a Promise
|
||||
*
|
||||
* @param {*} object - object to check
|
||||
* @return {Boolean}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isPromise(object: any): boolean {
|
||||
return Promise.resolve(object) === object;
|
||||
|
@ -290,12 +296,14 @@ export function isPromise(object: any): boolean {
|
|||
* Delays method execution
|
||||
*
|
||||
* @param {Function} method
|
||||
* @param {Number} timeout
|
||||
* @param {number} timeout
|
||||
*/
|
||||
export function delay(method: (...args: any[]) => any, timeout: number) {
|
||||
return function() {
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||
const context = this,
|
||||
args = arguments;
|
||||
// eslint-disable-next-line prefer-rest-params
|
||||
args = arguments;
|
||||
|
||||
window.setTimeout(() => method.apply(context, args), timeout);
|
||||
};
|
||||
|
@ -305,7 +313,7 @@ export function delay(method: (...args: any[]) => any, timeout: number) {
|
|||
* Get file extension
|
||||
*
|
||||
* @param {File} file
|
||||
* @return string
|
||||
* @returns string
|
||||
*/
|
||||
export function getFileExtension(file: File): string {
|
||||
return file.name.split('.').pop();
|
||||
|
@ -315,7 +323,7 @@ export function getFileExtension(file: File): string {
|
|||
* Check if string is MIME type
|
||||
*
|
||||
* @param {string} type
|
||||
* @return boolean
|
||||
* @returns boolean
|
||||
*/
|
||||
export function isValidMimeType(type: string): boolean {
|
||||
return /^[-\w]+\/([-+\w]+|\*)$/.test(type);
|
||||
|
@ -328,17 +336,20 @@ export function isValidMimeType(type: string): boolean {
|
|||
* Note that this method returns Function and declared variable need to be called
|
||||
*
|
||||
* @param {Function} func - function that we're throttling
|
||||
* @param {Number} wait - time in milliseconds
|
||||
* @param {Boolean} immediate - call now
|
||||
* @return {Function}
|
||||
* @param {number} wait - time in milliseconds
|
||||
* @param {boolean} immediate - call now
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function debounce(func: () => void, wait?: number , immediate?: boolean): () => void {
|
||||
export function debounce(func: () => void, wait?: number, immediate?: boolean): () => void {
|
||||
let timeout;
|
||||
|
||||
return () => {
|
||||
return (): void => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||
const context = this,
|
||||
args = arguments;
|
||||
// eslint-disable-next-line prefer-rest-params
|
||||
args = arguments;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
||||
const later = () => {
|
||||
timeout = null;
|
||||
if (!immediate) {
|
||||
|
@ -358,9 +369,10 @@ export function debounce(func: () => void, wait?: number , immediate?: boolean):
|
|||
|
||||
/**
|
||||
* Copies passed text to the clipboard
|
||||
* @param text
|
||||
*
|
||||
* @param text - text to copy
|
||||
*/
|
||||
export function copyTextToClipboard(text) {
|
||||
export function copyTextToClipboard(text): void {
|
||||
const el = Dom.make('div', 'codex-editor-clipboard', {
|
||||
innerHTML: text,
|
||||
});
|
||||
|
@ -369,6 +381,7 @@ export function copyTextToClipboard(text) {
|
|||
|
||||
const selection = window.getSelection();
|
||||
const range = document.createRange();
|
||||
|
||||
range.selectNode(el);
|
||||
|
||||
window.getSelection().removeAllRanges();
|
||||
|
@ -380,8 +393,6 @@ export function copyTextToClipboard(text) {
|
|||
|
||||
/**
|
||||
* Returns object with os name as key and boolean as value. Shows current user OS
|
||||
*
|
||||
* @return {[key: string]: boolean}
|
||||
*/
|
||||
export function getUserOS(): {[key: string]: boolean} {
|
||||
const OS = {
|
||||
|
@ -395,6 +406,7 @@ export function getUserOS(): {[key: string]: boolean} {
|
|||
|
||||
if (userOS) {
|
||||
OS[userOS] = true;
|
||||
|
||||
return OS;
|
||||
}
|
||||
|
||||
|
@ -403,8 +415,9 @@ export function getUserOS(): {[key: string]: boolean} {
|
|||
|
||||
/**
|
||||
* Capitalizes first letter of the string
|
||||
*
|
||||
* @param {string} text
|
||||
* @return {string}
|
||||
* @returns {string}
|
||||
*/
|
||||
export function capitalize(text: string): string {
|
||||
return text[0].toUpperCase() + text.slice(1);
|
||||
|
@ -412,14 +425,17 @@ export function capitalize(text: string): string {
|
|||
|
||||
/**
|
||||
* Merge to objects recursively
|
||||
*
|
||||
* @param {object} target
|
||||
* @param {object[]} sources
|
||||
* @return {object}
|
||||
* @returns {object}
|
||||
*/
|
||||
export function deepMerge(target, ...sources) {
|
||||
export function deepMerge(target, ...sources): {[key: string]: any} {
|
||||
const isObject = (item) => item && typeOf(item) === 'object';
|
||||
|
||||
if (!sources.length) { return target; }
|
||||
if (!sources.length) {
|
||||
return target;
|
||||
}
|
||||
const source = sources.shift();
|
||||
|
||||
if (isObject(target) && isObject(source)) {
|
||||
|
@ -444,9 +460,10 @@ export function deepMerge(target, ...sources) {
|
|||
*
|
||||
* Note! This is a simple solution, it can give false-positive results.
|
||||
* To detect touch devices more carefully, use 'touchstart' event listener
|
||||
*
|
||||
* @see http://www.stucox.com/blog/you-cant-detect-a-touchscreen/
|
||||
*
|
||||
* @return {boolean}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const isTouchSupported: boolean = 'ontouchstart' in document.documentElement;
|
||||
|
||||
|
@ -461,6 +478,7 @@ export function typeOf(object: any): string {
|
|||
|
||||
/**
|
||||
* Make shortcut command more human-readable
|
||||
*
|
||||
* @param {string} shortcut — string like 'CMD+B'
|
||||
*/
|
||||
export function beautifyShortcut(shortcut: string): string {
|
||||
|
@ -493,7 +511,7 @@ export function beautifyShortcut(shortcut: string): string {
|
|||
* If url has `one slash`, then it concatenates with window location origin
|
||||
* or when url has `two lack` it appends only protocol
|
||||
*
|
||||
* @param {String} url
|
||||
* @param {string} url
|
||||
*/
|
||||
export function getValidUrl(url: string): string {
|
||||
try {
|
||||
|
@ -514,7 +532,7 @@ export function getValidUrl(url: string): string {
|
|||
/**
|
||||
* Opens new Tab with passed URL
|
||||
*
|
||||
* @param {String} url - URL address to redirect
|
||||
* @param {string} url - URL address to redirect
|
||||
*/
|
||||
export function openTab(url: string): void {
|
||||
window.open(url, '_blank');
|
||||
|
|
|
@ -9,58 +9,60 @@
|
|||
module.exports = (env, argv) => {
|
||||
const path = require('path');
|
||||
const TerserPlugin = require('terser-webpack-plugin');
|
||||
const {LicenseWebpackPlugin} = require('license-webpack-plugin');
|
||||
const { LicenseWebpackPlugin } = require('license-webpack-plugin');
|
||||
const pkg = require('./package.json');
|
||||
|
||||
/**
|
||||
* Environment
|
||||
*
|
||||
* @type {any}
|
||||
*/
|
||||
const NODE_ENV = argv.mode || 'development';
|
||||
const VERSION = process.env.VERSION || pkg.version;
|
||||
const VERSION = process.env.VERSION || pkg.version;
|
||||
|
||||
/**
|
||||
* Plugins for bundle
|
||||
*
|
||||
* @type {webpack}
|
||||
*/
|
||||
const webpack = require('webpack');
|
||||
|
||||
return {
|
||||
entry: {
|
||||
'editor': ['@babel/polyfill/noConflict', './src/codex.ts']
|
||||
editor: ['@babel/polyfill/noConflict', './src/codex.ts'],
|
||||
},
|
||||
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: '[name].js',
|
||||
library: [ 'EditorJS' ],
|
||||
libraryTarget: 'umd'
|
||||
libraryTarget: 'umd',
|
||||
},
|
||||
|
||||
watchOptions: {
|
||||
aggregateTimeout: 50
|
||||
aggregateTimeout: 50,
|
||||
},
|
||||
|
||||
/**
|
||||
* Tell webpack what directories should be searched when resolving modules.
|
||||
*/
|
||||
resolve: {
|
||||
modules: [path.join(__dirname, 'src'), 'node_modules'],
|
||||
extensions: ['.js', '.ts']
|
||||
modules: [path.join(__dirname, 'src'), 'node_modules'],
|
||||
extensions: ['.js', '.ts'],
|
||||
},
|
||||
|
||||
plugins: [
|
||||
/** Pass variables into modules */
|
||||
new webpack.DefinePlugin({
|
||||
NODE_ENV: JSON.stringify(NODE_ENV),
|
||||
VERSION: JSON.stringify(VERSION)
|
||||
VERSION: JSON.stringify(VERSION),
|
||||
}),
|
||||
|
||||
new webpack.BannerPlugin({
|
||||
banner: `Editor.js\n\n@version ${VERSION}\n\n@licence Apache-2.0\n@author CodeX <https://codex.so>\n\n@uses html-janitor\n@licence Apache-2.0 (https://github.com/guardian/html-janitor/blob/master/LICENSE)`
|
||||
banner: `Editor.js\n\n@version ${VERSION}\n\n@licence Apache-2.0\n@author CodeX <https://codex.so>\n\n@uses html-janitor\n@licence Apache-2.0 (https://github.com/guardian/html-janitor/blob/master/LICENSE)`,
|
||||
}),
|
||||
|
||||
new LicenseWebpackPlugin()
|
||||
new LicenseWebpackPlugin(),
|
||||
],
|
||||
|
||||
module: {
|
||||
|
@ -72,35 +74,29 @@ module.exports = (env, argv) => {
|
|||
loader: 'babel-loader',
|
||||
options: {
|
||||
cacheDirectory: true,
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
loader: 'ts-loader'
|
||||
loader: 'ts-loader',
|
||||
},
|
||||
{
|
||||
loader: 'tslint-loader',
|
||||
options: {
|
||||
fix: true
|
||||
}
|
||||
}
|
||||
]
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
exclude: /node_modules/,
|
||||
use: [
|
||||
'postcss-loader'
|
||||
]
|
||||
'postcss-loader',
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.(svg)$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'raw-loader',
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
devtool: NODE_ENV === 'development' ? 'source-map' : false,
|
||||
|
@ -109,9 +105,9 @@ module.exports = (env, argv) => {
|
|||
minimizer: [
|
||||
new TerserPlugin({
|
||||
cache: true,
|
||||
parallel: true
|
||||
})
|
||||
]
|
||||
}
|
||||
parallel: true,
|
||||
}),
|
||||
],
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
476
yarn.lock
476
yarn.lock
|
@ -2,7 +2,13 @@
|
|||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.5.5":
|
||||
"@babel/code-frame@^7.0.0":
|
||||
version "7.8.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e"
|
||||
dependencies:
|
||||
"@babel/highlight" "^7.8.3"
|
||||
|
||||
"@babel/code-frame@^7.5.5":
|
||||
version "7.5.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.5.5.tgz#bc0782f6d69f7b7d49531219699b988f669a8f9d"
|
||||
dependencies:
|
||||
|
@ -200,6 +206,10 @@
|
|||
dependencies:
|
||||
"@babel/types" "^7.7.4"
|
||||
|
||||
"@babel/helper-validator-identifier@^7.9.0":
|
||||
version "7.9.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz#90977a8e6fbf6b431a7dc31752eee233bf052d80"
|
||||
|
||||
"@babel/helper-wrap-function@^7.7.4":
|
||||
version "7.7.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.7.4.tgz#37ab7fed5150e22d9d7266e830072c0cdd8baace"
|
||||
|
@ -217,12 +227,12 @@
|
|||
"@babel/traverse" "^7.7.4"
|
||||
"@babel/types" "^7.7.4"
|
||||
|
||||
"@babel/highlight@^7.0.0":
|
||||
version "7.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.5.0.tgz#56d11312bd9248fa619591d02472be6e8cb32540"
|
||||
"@babel/highlight@^7.0.0", "@babel/highlight@^7.8.3":
|
||||
version "7.9.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.9.0.tgz#4e9b45ccb82b79607271b2979ad82c7b68163079"
|
||||
dependencies:
|
||||
"@babel/helper-validator-identifier" "^7.9.0"
|
||||
chalk "^2.0.0"
|
||||
esutils "^2.0.2"
|
||||
js-tokens "^4.0.0"
|
||||
|
||||
"@babel/parser@^7.7.4":
|
||||
|
@ -670,6 +680,10 @@
|
|||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
|
||||
|
||||
"@types/eslint-visitor-keys@^1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d"
|
||||
|
||||
"@types/events@*":
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7"
|
||||
|
@ -682,6 +696,10 @@
|
|||
"@types/minimatch" "*"
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/json-schema@^7.0.3":
|
||||
version "7.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.4.tgz#38fd73ddfd9b55abb1e1b2ed578cb55bd7b7d339"
|
||||
|
||||
"@types/minimatch@*":
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
|
||||
|
@ -753,6 +771,45 @@
|
|||
"@types/webpack-sources" "*"
|
||||
source-map "^0.6.0"
|
||||
|
||||
"@typescript-eslint/eslint-plugin@^2.12.0":
|
||||
version "2.27.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.27.0.tgz#e479cdc4c9cf46f96b4c287755733311b0d0ba4b"
|
||||
dependencies:
|
||||
"@typescript-eslint/experimental-utils" "2.27.0"
|
||||
functional-red-black-tree "^1.0.1"
|
||||
regexpp "^3.0.0"
|
||||
tsutils "^3.17.1"
|
||||
|
||||
"@typescript-eslint/experimental-utils@2.27.0":
|
||||
version "2.27.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.27.0.tgz#801a952c10b58e486c9a0b36cf21e2aab1e9e01a"
|
||||
dependencies:
|
||||
"@types/json-schema" "^7.0.3"
|
||||
"@typescript-eslint/typescript-estree" "2.27.0"
|
||||
eslint-scope "^5.0.0"
|
||||
eslint-utils "^2.0.0"
|
||||
|
||||
"@typescript-eslint/parser@^2.12.0":
|
||||
version "2.27.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-2.27.0.tgz#d91664335b2c46584294e42eb4ff35838c427287"
|
||||
dependencies:
|
||||
"@types/eslint-visitor-keys" "^1.0.0"
|
||||
"@typescript-eslint/experimental-utils" "2.27.0"
|
||||
"@typescript-eslint/typescript-estree" "2.27.0"
|
||||
eslint-visitor-keys "^1.1.0"
|
||||
|
||||
"@typescript-eslint/typescript-estree@2.27.0":
|
||||
version "2.27.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.27.0.tgz#a288e54605412da8b81f1660b56c8b2e42966ce8"
|
||||
dependencies:
|
||||
debug "^4.1.1"
|
||||
eslint-visitor-keys "^1.1.0"
|
||||
glob "^7.1.6"
|
||||
is-glob "^4.0.1"
|
||||
lodash "^4.17.15"
|
||||
semver "^6.3.0"
|
||||
tsutils "^3.17.1"
|
||||
|
||||
"@webassemblyjs/ast@1.8.5":
|
||||
version "1.8.5"
|
||||
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.8.5.tgz#51b1c5fe6576a34953bf4b253df9f0d490d9e359"
|
||||
|
@ -893,17 +950,17 @@ abbrev@1:
|
|||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
|
||||
|
||||
acorn-jsx@^5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.1.0.tgz#294adb71b57398b0680015f0a38c563ee1db5384"
|
||||
acorn-jsx@^5.2.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.2.0.tgz#4c66069173d6fdd68ed85239fc256226182b2ebe"
|
||||
|
||||
acorn@^6.2.1:
|
||||
version "6.4.1"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474"
|
||||
|
||||
acorn@^7.1.0:
|
||||
version "7.1.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.0.tgz#949d36f2c292535da602283586c2477c57eb2d6c"
|
||||
acorn@^7.1.1:
|
||||
version "7.1.1"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.1.tgz#e35668de0b402f359de515c5482a1ab9f89a69bf"
|
||||
|
||||
aggregate-error@^3.0.0:
|
||||
version "3.0.1"
|
||||
|
@ -929,7 +986,7 @@ ajv@^5.0.0:
|
|||
fast-json-stable-stringify "^2.0.0"
|
||||
json-schema-traverse "^0.3.0"
|
||||
|
||||
ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2:
|
||||
ajv@^6.1.0:
|
||||
version "6.10.2"
|
||||
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52"
|
||||
dependencies:
|
||||
|
@ -938,15 +995,24 @@ ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2:
|
|||
json-schema-traverse "^0.4.1"
|
||||
uri-js "^4.2.2"
|
||||
|
||||
ajv@^6.10.0, ajv@^6.10.2:
|
||||
version "6.12.0"
|
||||
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.0.tgz#06d60b96d87b8454a5adaba86e7854da629db4b7"
|
||||
dependencies:
|
||||
fast-deep-equal "^3.1.1"
|
||||
fast-json-stable-stringify "^2.0.0"
|
||||
json-schema-traverse "^0.4.1"
|
||||
uri-js "^4.2.2"
|
||||
|
||||
alphanum-sort@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3"
|
||||
|
||||
ansi-escapes@^4.2.1:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.0.tgz#a4ce2b33d6b214b7950d8595c212f12ac9cc569d"
|
||||
version "4.3.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.1.tgz#a5c47cc43181f1f38ffd7076837700d395522a61"
|
||||
dependencies:
|
||||
type-fest "^0.8.1"
|
||||
type-fest "^0.11.0"
|
||||
|
||||
ansi-regex@^2.0.0:
|
||||
version "2.1.1"
|
||||
|
@ -1017,6 +1083,14 @@ array-find-index@^1.0.1:
|
|||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
|
||||
|
||||
array-includes@^3.0.3:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.1.tgz#cdd67e6852bdf9c1215460786732255ed2459348"
|
||||
dependencies:
|
||||
define-properties "^1.1.3"
|
||||
es-abstract "^1.17.0"
|
||||
is-string "^1.0.5"
|
||||
|
||||
array-union@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39"
|
||||
|
@ -1031,6 +1105,13 @@ array-unique@^0.3.2:
|
|||
version "0.3.2"
|
||||
resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
|
||||
|
||||
array.prototype.flat@^1.2.1:
|
||||
version "1.2.3"
|
||||
resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz#0de82b426b0318dbfdb940089e38b043d37f6c7b"
|
||||
dependencies:
|
||||
define-properties "^1.1.3"
|
||||
es-abstract "^1.17.0-next.1"
|
||||
|
||||
arrify@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
|
||||
|
@ -1578,6 +1659,10 @@ commander@^2.12.1, commander@^2.20.0, commander@^2.8.1:
|
|||
version "2.20.3"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
|
||||
|
||||
comment-parser@^0.7.2:
|
||||
version "0.7.2"
|
||||
resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-0.7.2.tgz#baf6d99b42038678b81096f15b630d18142f4b8a"
|
||||
|
||||
commondir@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
|
||||
|
@ -1611,6 +1696,10 @@ constants-browserify@^1.0.0:
|
|||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
|
||||
|
||||
contains-path@^0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a"
|
||||
|
||||
convert-source-map@^1.7.0:
|
||||
version "1.7.0"
|
||||
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442"
|
||||
|
@ -1902,7 +1991,7 @@ cyclist@^1.0.1:
|
|||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9"
|
||||
|
||||
debug@^2.2.0, debug@^2.3.3:
|
||||
debug@^2.2.0, debug@^2.3.3, debug@^2.6.9:
|
||||
version "2.6.9"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
||||
dependencies:
|
||||
|
@ -2005,6 +2094,13 @@ dir-glob@^2.2.2:
|
|||
dependencies:
|
||||
path-type "^3.0.0"
|
||||
|
||||
doctrine@1.5.0:
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa"
|
||||
dependencies:
|
||||
esutils "^2.0.2"
|
||||
isarray "^1.0.0"
|
||||
|
||||
doctrine@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961"
|
||||
|
@ -2152,7 +2248,7 @@ errno@^0.1.3, errno@~0.1.7:
|
|||
dependencies:
|
||||
prr "~1.0.1"
|
||||
|
||||
error-ex@^1.3.1:
|
||||
error-ex@^1.2.0, error-ex@^1.3.1:
|
||||
version "1.3.2"
|
||||
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
|
||||
dependencies:
|
||||
|
@ -2173,6 +2269,22 @@ es-abstract@^1.12.0, es-abstract@^1.5.1:
|
|||
string.prototype.trimleft "^2.1.0"
|
||||
string.prototype.trimright "^2.1.0"
|
||||
|
||||
es-abstract@^1.17.0, es-abstract@^1.17.0-next.1, es-abstract@^1.17.5:
|
||||
version "1.17.5"
|
||||
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.5.tgz#d8c9d1d66c8981fb9200e2251d799eee92774ae9"
|
||||
dependencies:
|
||||
es-to-primitive "^1.2.1"
|
||||
function-bind "^1.1.1"
|
||||
has "^1.0.3"
|
||||
has-symbols "^1.0.1"
|
||||
is-callable "^1.1.5"
|
||||
is-regex "^1.0.5"
|
||||
object-inspect "^1.7.0"
|
||||
object-keys "^1.1.1"
|
||||
object.assign "^4.1.0"
|
||||
string.prototype.trimleft "^2.1.1"
|
||||
string.prototype.trimright "^2.1.1"
|
||||
|
||||
es-to-primitive@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a"
|
||||
|
@ -2189,6 +2301,30 @@ escape-string-regexp@^1.0.5:
|
|||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
||||
|
||||
eslint-config-codex@^1.3.2:
|
||||
version "1.3.2"
|
||||
resolved "https://registry.yarnpkg.com/eslint-config-codex/-/eslint-config-codex-1.3.2.tgz#063007f215832fd8a967e7e53084f480ba24596c"
|
||||
dependencies:
|
||||
"@typescript-eslint/eslint-plugin" "^2.12.0"
|
||||
"@typescript-eslint/parser" "^2.12.0"
|
||||
eslint-config-standard "14.1.0"
|
||||
eslint-plugin-import "2.19.1"
|
||||
eslint-plugin-jsdoc "^22.1.0"
|
||||
eslint-plugin-node "10.0.0"
|
||||
eslint-plugin-promise "4.2.1"
|
||||
eslint-plugin-standard "4.0.1"
|
||||
|
||||
eslint-config-standard@14.1.0:
|
||||
version "14.1.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-14.1.0.tgz#b23da2b76fe5a2eba668374f246454e7058f15d4"
|
||||
|
||||
eslint-import-resolver-node@^0.3.2:
|
||||
version "0.3.3"
|
||||
resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.3.tgz#dbaa52b6b2816b50bc6711af75422de808e98404"
|
||||
dependencies:
|
||||
debug "^2.6.9"
|
||||
resolve "^1.13.1"
|
||||
|
||||
eslint-loader@^3.0.3:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/eslint-loader/-/eslint-loader-3.0.3.tgz#e018e3d2722381d982b1201adb56819c73b480ca"
|
||||
|
@ -2199,6 +2335,68 @@ eslint-loader@^3.0.3:
|
|||
object-hash "^2.0.1"
|
||||
schema-utils "^2.6.1"
|
||||
|
||||
eslint-module-utils@^2.4.1:
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz#579ebd094f56af7797d19c9866c9c9486629bfa6"
|
||||
dependencies:
|
||||
debug "^2.6.9"
|
||||
pkg-dir "^2.0.0"
|
||||
|
||||
eslint-plugin-es@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-2.0.0.tgz#0f5f5da5f18aa21989feebe8a73eadefb3432976"
|
||||
dependencies:
|
||||
eslint-utils "^1.4.2"
|
||||
regexpp "^3.0.0"
|
||||
|
||||
eslint-plugin-import@2.19.1:
|
||||
version "2.19.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.19.1.tgz#5654e10b7839d064dd0d46cd1b88ec2133a11448"
|
||||
dependencies:
|
||||
array-includes "^3.0.3"
|
||||
array.prototype.flat "^1.2.1"
|
||||
contains-path "^0.1.0"
|
||||
debug "^2.6.9"
|
||||
doctrine "1.5.0"
|
||||
eslint-import-resolver-node "^0.3.2"
|
||||
eslint-module-utils "^2.4.1"
|
||||
has "^1.0.3"
|
||||
minimatch "^3.0.4"
|
||||
object.values "^1.1.0"
|
||||
read-pkg-up "^2.0.0"
|
||||
resolve "^1.12.0"
|
||||
|
||||
eslint-plugin-jsdoc@^22.1.0:
|
||||
version "22.1.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-22.1.0.tgz#dadfa62653fc0d87f900d810307f5ed07ef6ecd5"
|
||||
dependencies:
|
||||
comment-parser "^0.7.2"
|
||||
debug "^4.1.1"
|
||||
jsdoctypeparser "^6.1.0"
|
||||
lodash "^4.17.15"
|
||||
regextras "^0.7.0"
|
||||
semver "^6.3.0"
|
||||
spdx-expression-parse "^3.0.0"
|
||||
|
||||
eslint-plugin-node@10.0.0:
|
||||
version "10.0.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-10.0.0.tgz#fd1adbc7a300cf7eb6ac55cf4b0b6fc6e577f5a6"
|
||||
dependencies:
|
||||
eslint-plugin-es "^2.0.0"
|
||||
eslint-utils "^1.4.2"
|
||||
ignore "^5.1.1"
|
||||
minimatch "^3.0.4"
|
||||
resolve "^1.10.1"
|
||||
semver "^6.1.0"
|
||||
|
||||
eslint-plugin-promise@4.2.1:
|
||||
version "4.2.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz#845fd8b2260ad8f82564c1222fce44ad71d9418a"
|
||||
|
||||
eslint-plugin-standard@4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-4.0.1.tgz#ff0519f7ffaff114f76d1bd7c3996eef0f6e20b4"
|
||||
|
||||
eslint-scope@^4.0.3:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848"
|
||||
|
@ -2213,19 +2411,25 @@ eslint-scope@^5.0.0:
|
|||
esrecurse "^4.1.0"
|
||||
estraverse "^4.1.1"
|
||||
|
||||
eslint-utils@^1.4.3:
|
||||
eslint-utils@^1.4.2, eslint-utils@^1.4.3:
|
||||
version "1.4.3"
|
||||
resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f"
|
||||
dependencies:
|
||||
eslint-visitor-keys "^1.1.0"
|
||||
|
||||
eslint-utils@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.0.0.tgz#7be1cc70f27a72a76cd14aa698bcabed6890e1cd"
|
||||
dependencies:
|
||||
eslint-visitor-keys "^1.1.0"
|
||||
|
||||
eslint-visitor-keys@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2"
|
||||
|
||||
eslint@^6.7.2:
|
||||
version "6.7.2"
|
||||
resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.7.2.tgz#c17707ca4ad7b2d8af986a33feba71e18a9fecd1"
|
||||
eslint@^6.8.0:
|
||||
version "6.8.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.8.0.tgz#62262d6729739f9275723824302fb227c8c93ffb"
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.0.0"
|
||||
ajv "^6.10.0"
|
||||
|
@ -2266,11 +2470,11 @@ eslint@^6.7.2:
|
|||
v8-compile-cache "^2.0.3"
|
||||
|
||||
espree@^6.1.2:
|
||||
version "6.1.2"
|
||||
resolved "https://registry.yarnpkg.com/espree/-/espree-6.1.2.tgz#6c272650932b4f91c3714e5e7b5f5e2ecf47262d"
|
||||
version "6.2.1"
|
||||
resolved "https://registry.yarnpkg.com/espree/-/espree-6.2.1.tgz#77fc72e1fd744a2052c20f38a5b575832e82734a"
|
||||
dependencies:
|
||||
acorn "^7.1.0"
|
||||
acorn-jsx "^5.1.0"
|
||||
acorn "^7.1.1"
|
||||
acorn-jsx "^5.2.0"
|
||||
eslint-visitor-keys "^1.1.0"
|
||||
|
||||
esprima@^4.0.0:
|
||||
|
@ -2278,10 +2482,10 @@ esprima@^4.0.0:
|
|||
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
|
||||
|
||||
esquery@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708"
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.2.0.tgz#a010a519c0288f2530b3404124bfb5f02e9797fe"
|
||||
dependencies:
|
||||
estraverse "^4.0.0"
|
||||
estraverse "^5.0.0"
|
||||
|
||||
esrecurse@^4.1.0:
|
||||
version "4.2.1"
|
||||
|
@ -2289,10 +2493,14 @@ esrecurse@^4.1.0:
|
|||
dependencies:
|
||||
estraverse "^4.1.0"
|
||||
|
||||
estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1:
|
||||
estraverse@^4.1.0, estraverse@^4.1.1:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
|
||||
|
||||
estraverse@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.0.0.tgz#ac81750b482c11cca26e4b07e83ed8f75fbcdc22"
|
||||
|
||||
esutils@^2.0.2:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
|
||||
|
@ -2399,6 +2607,10 @@ fast-deep-equal@^2.0.1:
|
|||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
|
||||
|
||||
fast-deep-equal@^3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4"
|
||||
|
||||
fast-glob@^2.2.6:
|
||||
version "2.2.7"
|
||||
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d"
|
||||
|
@ -2411,8 +2623,8 @@ fast-glob@^2.2.6:
|
|||
micromatch "^3.1.10"
|
||||
|
||||
fast-json-stable-stringify@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
|
||||
|
||||
fast-levenshtein@~2.0.6:
|
||||
version "2.0.6"
|
||||
|
@ -2423,8 +2635,8 @@ figgy-pudding@^3.5.1:
|
|||
resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790"
|
||||
|
||||
figures@^3.0.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/figures/-/figures-3.1.0.tgz#4b198dd07d8d71530642864af2d45dd9e459c4ec"
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af"
|
||||
dependencies:
|
||||
escape-string-regexp "^1.0.5"
|
||||
|
||||
|
@ -2480,7 +2692,7 @@ find-up@^1.0.0:
|
|||
path-exists "^2.0.0"
|
||||
pinkie-promise "^2.0.0"
|
||||
|
||||
find-up@^2.0.0:
|
||||
find-up@^2.0.0, find-up@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
|
||||
dependencies:
|
||||
|
@ -2517,8 +2729,8 @@ flat-cache@^2.0.1:
|
|||
write "1.0.3"
|
||||
|
||||
flatted@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.1.tgz#69e57caa8f0eacbc281d2e2cb458d46fdb449e08"
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138"
|
||||
|
||||
flatten@^1.0.2:
|
||||
version "1.0.3"
|
||||
|
@ -2635,8 +2847,8 @@ glob-parent@^3.1.0:
|
|||
path-dirname "^1.0.0"
|
||||
|
||||
glob-parent@^5.0.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.0.tgz#5f4c1d1e748d30cd73ad2944b3577a81b081e8c2"
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229"
|
||||
dependencies:
|
||||
is-glob "^4.0.1"
|
||||
|
||||
|
@ -2644,7 +2856,7 @@ glob-to-regexp@^0.3.0:
|
|||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab"
|
||||
|
||||
glob@^7.1.1, glob@^7.1.3, glob@^7.1.4:
|
||||
glob@^7.1.1, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6:
|
||||
version "7.1.6"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
|
||||
dependencies:
|
||||
|
@ -2692,8 +2904,8 @@ globals@^11.1.0:
|
|||
resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
|
||||
|
||||
globals@^12.1.0:
|
||||
version "12.3.0"
|
||||
resolved "https://registry.yarnpkg.com/globals/-/globals-12.3.0.tgz#1e564ee5c4dded2ab098b0f88f24702a3c56be13"
|
||||
version "12.4.0"
|
||||
resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8"
|
||||
dependencies:
|
||||
type-fest "^0.8.1"
|
||||
|
||||
|
@ -2884,7 +3096,7 @@ ignore@^4.0.3, ignore@^4.0.6:
|
|||
version "4.0.6"
|
||||
resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc"
|
||||
|
||||
ignore@^5.1.4:
|
||||
ignore@^5.1.1, ignore@^5.1.4:
|
||||
version "5.1.4"
|
||||
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.4.tgz#84b7b3dbe64552b6ef0eca99f6743dbec6d97adf"
|
||||
|
||||
|
@ -2969,21 +3181,21 @@ ini@^1.3.4, ini@^1.3.5, ini@~1.3.0:
|
|||
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
|
||||
|
||||
inquirer@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.0.0.tgz#9e2b032dde77da1db5db804758b8fea3a970519a"
|
||||
version "7.1.0"
|
||||
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.1.0.tgz#1298a01859883e17c7264b82870ae1034f92dd29"
|
||||
dependencies:
|
||||
ansi-escapes "^4.2.1"
|
||||
chalk "^2.4.2"
|
||||
chalk "^3.0.0"
|
||||
cli-cursor "^3.1.0"
|
||||
cli-width "^2.0.0"
|
||||
external-editor "^3.0.3"
|
||||
figures "^3.0.0"
|
||||
lodash "^4.17.15"
|
||||
mute-stream "0.0.8"
|
||||
run-async "^2.2.0"
|
||||
rxjs "^6.4.0"
|
||||
run-async "^2.4.0"
|
||||
rxjs "^6.5.3"
|
||||
string-width "^4.1.0"
|
||||
strip-ansi "^5.1.0"
|
||||
strip-ansi "^6.0.0"
|
||||
through "^2.3.6"
|
||||
|
||||
interpret@1.2.0:
|
||||
|
@ -3057,6 +3269,10 @@ is-callable@^1.1.4:
|
|||
version "1.1.4"
|
||||
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75"
|
||||
|
||||
is-callable@^1.1.5:
|
||||
version "1.1.5"
|
||||
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.5.tgz#f7e46b596890456db74e7f6e976cb3273d06faab"
|
||||
|
||||
is-color-stop@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-color-stop/-/is-color-stop-1.1.0.tgz#cfff471aee4dd5c9e158598fbe12967b5cdad345"
|
||||
|
@ -3186,6 +3402,12 @@ is-regex@^1.0.4:
|
|||
dependencies:
|
||||
has "^1.0.1"
|
||||
|
||||
is-regex@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.5.tgz#39d589a358bf18967f726967120b8fc1aed74eae"
|
||||
dependencies:
|
||||
has "^1.0.3"
|
||||
|
||||
is-regexp@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-2.1.0.tgz#cd734a56864e23b956bf4e7c66c396a4c0b22c2d"
|
||||
|
@ -3198,6 +3420,10 @@ is-stream@^1.1.0:
|
|||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
|
||||
|
||||
is-string@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6"
|
||||
|
||||
is-svg@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-3.0.0.tgz#9321dbd29c212e5ca99c4fa9794c714bcafa2f75"
|
||||
|
@ -3274,6 +3500,10 @@ js-yaml@^3.13.1:
|
|||
argparse "^1.0.7"
|
||||
esprima "^4.0.0"
|
||||
|
||||
jsdoctypeparser@^6.1.0:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/jsdoctypeparser/-/jsdoctypeparser-6.1.0.tgz#acfb936c26300d98f1405cb03e20b06748e512a8"
|
||||
|
||||
jsesc@^2.5.1:
|
||||
version "2.5.2"
|
||||
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
|
||||
|
@ -3368,6 +3598,15 @@ lines-and-columns@^1.1.6:
|
|||
version "1.1.6"
|
||||
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00"
|
||||
|
||||
load-json-file@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8"
|
||||
dependencies:
|
||||
graceful-fs "^4.1.2"
|
||||
parse-json "^2.2.0"
|
||||
pify "^2.0.0"
|
||||
strip-bom "^3.0.0"
|
||||
|
||||
load-json-file@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b"
|
||||
|
@ -3668,6 +3907,10 @@ minimist@^1.2.0:
|
|||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
|
||||
|
||||
minimist@^1.2.5:
|
||||
version "1.2.5"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
|
||||
|
||||
minipass-collect@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617"
|
||||
|
@ -3727,12 +3970,18 @@ mixin-deep@^1.2.0:
|
|||
for-in "^1.0.2"
|
||||
is-extendable "^1.0.1"
|
||||
|
||||
mkdirp@0.5.1, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1:
|
||||
mkdirp@0.5.1, mkdirp@^0.5.0, mkdirp@~0.5.1:
|
||||
version "0.5.1"
|
||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
|
||||
dependencies:
|
||||
minimist "0.0.8"
|
||||
|
||||
mkdirp@^0.5.1:
|
||||
version "0.5.5"
|
||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
|
||||
dependencies:
|
||||
minimist "^1.2.5"
|
||||
|
||||
move-concurrently@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"
|
||||
|
@ -4134,6 +4383,12 @@ parse-entities@^1.0.2, parse-entities@^1.1.0:
|
|||
is-decimal "^1.0.0"
|
||||
is-hexadecimal "^1.0.0"
|
||||
|
||||
parse-json@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
|
||||
dependencies:
|
||||
error-ex "^1.2.0"
|
||||
|
||||
parse-json@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0"
|
||||
|
@ -4192,6 +4447,12 @@ path-parse@^1.0.6:
|
|||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
|
||||
|
||||
path-type@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73"
|
||||
dependencies:
|
||||
pify "^2.0.0"
|
||||
|
||||
path-type@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f"
|
||||
|
@ -4216,7 +4477,7 @@ picomatch@^2.0.5:
|
|||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.1.1.tgz#ecdfbea7704adb5fe6fb47f9866c4c0e15e905c5"
|
||||
|
||||
pify@^2.3.0:
|
||||
pify@^2.0.0, pify@^2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
|
||||
|
||||
|
@ -4250,6 +4511,12 @@ pkg-dir@^1.0.0:
|
|||
dependencies:
|
||||
find-up "^1.0.0"
|
||||
|
||||
pkg-dir@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b"
|
||||
dependencies:
|
||||
find-up "^2.1.0"
|
||||
|
||||
pkg-dir@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3"
|
||||
|
@ -5053,6 +5320,13 @@ read-cache@^1.0.0:
|
|||
dependencies:
|
||||
pify "^2.3.0"
|
||||
|
||||
read-pkg-up@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be"
|
||||
dependencies:
|
||||
find-up "^2.0.0"
|
||||
read-pkg "^2.0.0"
|
||||
|
||||
read-pkg-up@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07"
|
||||
|
@ -5060,6 +5334,14 @@ read-pkg-up@^3.0.0:
|
|||
find-up "^2.0.0"
|
||||
read-pkg "^3.0.0"
|
||||
|
||||
read-pkg@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8"
|
||||
dependencies:
|
||||
load-json-file "^2.0.0"
|
||||
normalize-package-data "^2.3.2"
|
||||
path-type "^2.0.0"
|
||||
|
||||
read-pkg@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389"
|
||||
|
@ -5143,6 +5425,10 @@ regexpp@^2.0.1:
|
|||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f"
|
||||
|
||||
regexpp@^3.0.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2"
|
||||
|
||||
regexpu-core@^4.6.0:
|
||||
version "4.6.0"
|
||||
resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.6.0.tgz#2037c18b327cfce8a6fea2a4ec441f2432afb8b6"
|
||||
|
@ -5154,6 +5440,10 @@ regexpu-core@^4.6.0:
|
|||
unicode-match-property-ecmascript "^1.0.4"
|
||||
unicode-match-property-value-ecmascript "^1.1.0"
|
||||
|
||||
regextras@^0.7.0:
|
||||
version "0.7.0"
|
||||
resolved "https://registry.yarnpkg.com/regextras/-/regextras-0.7.0.tgz#2298bef8cfb92b1b7e3b9b12aa8f69547b7d71e4"
|
||||
|
||||
regjsgen@^0.5.0:
|
||||
version "0.5.1"
|
||||
resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.1.tgz#48f0bf1a5ea205196929c0d9798b42d1ed98443c"
|
||||
|
@ -5270,6 +5560,12 @@ resolve@^1.1.7, resolve@^1.10.0, resolve@^1.3.2, resolve@^1.8.1:
|
|||
dependencies:
|
||||
path-parse "^1.0.6"
|
||||
|
||||
resolve@^1.10.1, resolve@^1.12.0, resolve@^1.13.1:
|
||||
version "1.15.1"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.1.tgz#27bdcdeffeaf2d6244b95bb0f9f4b4653451f3e8"
|
||||
dependencies:
|
||||
path-parse "^1.0.6"
|
||||
|
||||
restore-cursor@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e"
|
||||
|
@ -5295,7 +5591,7 @@ rimraf@2.6.3:
|
|||
dependencies:
|
||||
glob "^7.1.3"
|
||||
|
||||
rimraf@^2.4.4, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.3, rimraf@^2.7.1:
|
||||
rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.3, rimraf@^2.7.1:
|
||||
version "2.7.1"
|
||||
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
|
||||
dependencies:
|
||||
|
@ -5314,9 +5610,9 @@ ripemd160@^2.0.0, ripemd160@^2.0.1:
|
|||
hash-base "^3.0.0"
|
||||
inherits "^2.0.1"
|
||||
|
||||
run-async@^2.2.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0"
|
||||
run-async@^2.4.0:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.0.tgz#e59054a5b86876cfae07f431d18cbaddc594f1e8"
|
||||
dependencies:
|
||||
is-promise "^2.1.0"
|
||||
|
||||
|
@ -5326,9 +5622,9 @@ run-queue@^1.0.0, run-queue@^1.0.3:
|
|||
dependencies:
|
||||
aproba "^1.1.1"
|
||||
|
||||
rxjs@^6.4.0:
|
||||
version "6.5.3"
|
||||
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.3.tgz#510e26317f4db91a7eb1de77d9dd9ba0a4899a3a"
|
||||
rxjs@^6.5.3:
|
||||
version "6.5.5"
|
||||
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.5.tgz#c5c884e3094c8cfee31bf27eb87e54ccfc87f9ec"
|
||||
dependencies:
|
||||
tslib "^1.9.0"
|
||||
|
||||
|
@ -5379,7 +5675,7 @@ schema-utils@^2.5.0, schema-utils@^2.6.0, schema-utils@^2.6.1:
|
|||
version "5.7.1"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
|
||||
|
||||
semver@^6.0.0, semver@^6.1.2, semver@^6.3.0:
|
||||
semver@^6.0.0, semver@^6.1.0, semver@^6.1.2, semver@^6.3.0:
|
||||
version "6.3.0"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
|
||||
|
||||
|
@ -5425,10 +5721,14 @@ shebang-regex@^1.0.0:
|
|||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
|
||||
|
||||
signal-exit@^3.0.0, signal-exit@^3.0.2:
|
||||
signal-exit@^3.0.0:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
|
||||
|
||||
signal-exit@^3.0.2:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
|
||||
|
||||
simple-swizzle@^0.2.2:
|
||||
version "0.2.2"
|
||||
resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a"
|
||||
|
@ -5634,6 +5934,13 @@ string-width@^4.1.0, string-width@^4.2.0:
|
|||
is-fullwidth-code-point "^3.0.0"
|
||||
strip-ansi "^6.0.0"
|
||||
|
||||
string.prototype.trimend@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913"
|
||||
dependencies:
|
||||
define-properties "^1.1.3"
|
||||
es-abstract "^1.17.5"
|
||||
|
||||
string.prototype.trimleft@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz#6cc47f0d7eb8d62b0f3701611715a3954591d634"
|
||||
|
@ -5641,6 +5948,14 @@ string.prototype.trimleft@^2.1.0:
|
|||
define-properties "^1.1.3"
|
||||
function-bind "^1.1.1"
|
||||
|
||||
string.prototype.trimleft@^2.1.1:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz#4408aa2e5d6ddd0c9a80739b087fbc067c03b3cc"
|
||||
dependencies:
|
||||
define-properties "^1.1.3"
|
||||
es-abstract "^1.17.5"
|
||||
string.prototype.trimstart "^1.0.0"
|
||||
|
||||
string.prototype.trimright@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz#669d164be9df9b6f7559fa8e89945b168a5a6c58"
|
||||
|
@ -5648,6 +5963,21 @@ string.prototype.trimright@^2.1.0:
|
|||
define-properties "^1.1.3"
|
||||
function-bind "^1.1.1"
|
||||
|
||||
string.prototype.trimright@^2.1.1:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz#c76f1cef30f21bbad8afeb8db1511496cfb0f2a3"
|
||||
dependencies:
|
||||
define-properties "^1.1.3"
|
||||
es-abstract "^1.17.5"
|
||||
string.prototype.trimend "^1.0.0"
|
||||
|
||||
string.prototype.trimstart@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54"
|
||||
dependencies:
|
||||
define-properties "^1.1.3"
|
||||
es-abstract "^1.17.5"
|
||||
|
||||
string_decoder@^1.0.0, string_decoder@^1.1.1:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
|
||||
|
@ -5710,8 +6040,8 @@ strip-indent@^2.0.0:
|
|||
resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68"
|
||||
|
||||
strip-json-comments@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.0.1.tgz#85713975a91fb87bf1b305cca77395e40d2a64a7"
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.0.tgz#7638d31422129ecf4457440009fba03f9f9ac180"
|
||||
|
||||
strip-json-comments@~2.0.1:
|
||||
version "2.0.1"
|
||||
|
@ -5998,19 +6328,13 @@ ts-loader@^6.2.1:
|
|||
micromatch "^4.0.0"
|
||||
semver "^6.0.0"
|
||||
|
||||
tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0:
|
||||
tslib@^1.8.0, tslib@^1.8.1:
|
||||
version "1.10.0"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"
|
||||
|
||||
tslint-loader@^3.5.4:
|
||||
version "3.5.4"
|
||||
resolved "https://registry.yarnpkg.com/tslint-loader/-/tslint-loader-3.5.4.tgz#052af7f0772434451ea1b247bb55407f878a4c40"
|
||||
dependencies:
|
||||
loader-utils "^1.0.2"
|
||||
mkdirp "^0.5.1"
|
||||
object-assign "^4.1.1"
|
||||
rimraf "^2.4.4"
|
||||
semver "^5.3.0"
|
||||
tslib@^1.9.0:
|
||||
version "1.11.1"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35"
|
||||
|
||||
tslint@^5.14.0:
|
||||
version "5.20.1"
|
||||
|
@ -6036,6 +6360,12 @@ tsutils@^2.29.0:
|
|||
dependencies:
|
||||
tslib "^1.8.1"
|
||||
|
||||
tsutils@^3.17.1:
|
||||
version "3.17.1"
|
||||
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759"
|
||||
dependencies:
|
||||
tslib "^1.8.1"
|
||||
|
||||
tty-browserify@0.0.0:
|
||||
version "0.0.0"
|
||||
resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"
|
||||
|
@ -6046,6 +6376,10 @@ type-check@~0.3.2:
|
|||
dependencies:
|
||||
prelude-ls "~1.1.2"
|
||||
|
||||
type-fest@^0.11.0:
|
||||
version "0.11.0"
|
||||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1"
|
||||
|
||||
type-fest@^0.8.1:
|
||||
version "0.8.1"
|
||||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
|
||||
|
|
Loading…
Reference in a new issue