Fixes for 2.19 (#1356)

* Fixes

* Update docs/CHANGELOG.md

Co-authored-by: Peter Savchenko <specc.dev@gmail.com>

* Fix RTL

* Optimize tune down

* Add explanation on focus events listeners

Co-authored-by: Peter Savchenko <specc.dev@gmail.com>
This commit is contained in:
George Berezhnoy 2020-10-13 00:03:27 +03:00 committed by GitHub
parent 0037a91051
commit 9581fc2dc9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 86 additions and 83 deletions

2
dist/editor.js vendored

File diff suppressed because one or more lines are too long

View file

@ -21,6 +21,7 @@
- `Fix` - Fixed the `Tab` key behavior when the caret is not set inside contenteditable element, but the block is selected [#1302](https://github.com/codex-team/editor.js/issues/1302).
- `Fix` - Fixed the `onChange` callback issue. This method didn't be called for native inputs before some contentedtable element changed [#843](https://github.com/codex-team/editor.js/issues/843)
- `Fix` - Fixed the `onChange` callback issue. This method didn't be called after the callback throws an exception [#1339](https://github.com/codex-team/editor.js/issues/1339)
- `Deprecated` — The Inline Tool `clear()` method is deprecated because the new instance of Inline Tools will be created on every showing of the Inline Toolbar
### 2.18

View file

@ -1,5 +1,5 @@
<!--
Use this page for debugging purposes.
Use this page for RTL mode debugging.
Editor Tools are loaded as git-submodules.
You can pull modules by running `yarn pull_tools` and start experimenting.
-->
@ -7,7 +7,7 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Editor.js 🤩🧦🤨 example</title>
<title>Editor.js RTL example</title>
<link href="https://fonts.googleapis.com/css?family=PT+Mono" rel="stylesheet">
<link href="assets/demo.css" rel="stylesheet">
<script src="assets/json-preview.js"></script>

View file

@ -26,6 +26,16 @@
<div class="ce-example__button" id="saveButton">
editor.save()
</div>
<div class="ce-example__statusbar">
Readonly:
<b id="readonly-state">
Off
</b>
<div class="ce-example__statusbar-button" id="toggleReadOnlyButton">
toggle
</div>
</div>
</div>
<div class="ce-example__output">
<pre class="ce-example__output-content" id="output"></pre>
@ -65,21 +75,29 @@
<!-- Initialization -->
<script>
/**
* Saving button
*/
const saveButton = document.getElementById('saveButton');
/**
* To initialize the Editor, create a new instance with configuration object
* @see docs/installation.md for mode details
*/
var editor = new EditorJS({
/**
* Enable/Disable the read only mode
*/
readOnly: false,
/**
* Wrapper of Editor
*/
holder: 'editorjs',
/**
* Common Inline Toolbar settings
* - if true (or not specified), the order from 'tool' property will be used
* - if an array of tool names, this order will be used
*/
// inlineToolbar: ['link', 'marker', 'bold', 'italic'],
// inlineToolbar: true,
/**
* Tools list
*/
@ -89,7 +107,7 @@
*/
header: {
class: Header,
inlineToolbar: ['link'],
inlineToolbar: ['marker', 'link'],
config: {
placeholder: 'Header'
},
@ -268,13 +286,37 @@
}
});
/**
* Saving button
*/
const saveButton = document.getElementById('saveButton');
/**
* Toggle read-only button
*/
const toggleReadOnlyButton = document.getElementById('toggleReadOnlyButton');
const readOnlyIndicator = document.getElementById('readonly-state');
/**
* Saving example
*/
saveButton.addEventListener('click', function () {
editor.save().then((savedData) => {
cPreview.show(savedData, document.getElementById("output"));
});
editor.save()
.then((savedData) => {
cPreview.show(savedData, document.getElementById("output"));
})
.catch((error) => {
console.error('Saving error', error);
});
});
/**
* Toggle read-only example
*/
toggleReadOnlyButton.addEventListener('click', async () => {
const readOnlyState = await editor.readOnly.toggle();
readOnlyIndicator.textContent = readOnlyState ? 'On' : 'Off';
});
</script>
</body>

View file

@ -53,7 +53,7 @@ export default class EditorJS {
/**
* If `onReady` was passed in `configuration` then redefine onReady function
*/
if (typeof configuration === 'object' && typeof configuration.onReady === 'function') {
if (typeof configuration === 'object' && _.isFunction(configuration.onReady)) {
onReady = configuration.onReady;
}

View file

@ -71,9 +71,10 @@ export default class MoveDownTune implements BlockTune {
*/
public handleClick(event: MouseEvent, button: HTMLElement): void {
const currentBlockIndex = this.api.blocks.getCurrentBlockIndex();
const nextBlock = this.api.blocks.getBlockByIndex(currentBlockIndex + 1);
// If Block is last do nothing
if (currentBlockIndex === this.api.blocks.getBlocksCount() - 1) {
if (!nextBlock) {
button.classList.add(this.CSS.animation);
window.setTimeout(() => {
@ -83,12 +84,6 @@ export default class MoveDownTune implements BlockTune {
return;
}
const nextBlock = this.api.blocks.getBlockByIndex(currentBlockIndex + 1);
if (!nextBlock) {
return;
}
const nextBlockElement = nextBlock.holder;
const nextBlockCoords = nextBlockElement.getBoundingClientRect();

View file

@ -228,7 +228,7 @@ export default class Block {
config: this.config,
api: this.api.getMethodsForTool(name, ToolType.Block),
block: this.blockAPI,
readOnly: readOnly,
readOnly,
});
this.holder = this.compose();
@ -359,7 +359,7 @@ export default class Block {
* @returns {boolean}
*/
public mergeable(): boolean {
return typeof this.tool.merge === 'function';
return _.isFunction(this.tool.merge);
}
/**
@ -659,7 +659,7 @@ export default class Block {
/**
* Mutation observer doesn't track changes in "<input>" and "<textarea>"
* so we need to track focus events
* so we need to track focus events to update current input and clear cache.
*/
this.addInputEvents();
}

View file

@ -185,6 +185,7 @@ export default class Core {
a: true,
} as SanitizerConfig;
this.config.hideToolbar = this.config.hideToolbar ? this.config.hideToolbar : false;
this.config.tools = this.config.tools || {};
this.config.i18n = this.config.i18n || {};
@ -208,7 +209,6 @@ export default class Core {
}
this.config.readOnly = this.config.readOnly as boolean || false;
this.config.i18n = {};
/**
* Adjust i18n
@ -220,11 +220,7 @@ export default class Core {
/**
* Text direction. If not set, uses ltr
*/
if (config.i18n?.direction) {
this.config.i18n = {
direction: config.i18n?.direction || 'ltr',
};
}
this.config.i18n.direction = config.i18n?.direction || 'ltr';
}
/**
@ -292,8 +288,6 @@ export default class Core {
'InlineToolbar',
'BlockManager',
'Paste',
'DragNDrop',
'ModificationsObserver',
'BlockSelection',
'RectangleSelection',
'CrossBlockSelection',
@ -337,7 +331,7 @@ export default class Core {
/**
* 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;
const Module = _.isFunction(module) ? module : module.default;
try {
/**

View file

@ -259,7 +259,7 @@ export default class Flipper {
this.iterator.currentItem.click();
}
if (typeof this.activateCallback === 'function') {
if (_.isFunction(this.activateCallback)) {
this.activateCallback(this.iterator.currentItem);
}

View file

@ -13,15 +13,6 @@ export default class DragNDrop extends Module {
*/
private isStartedAtEditor = false;
/**
* Bind module. Enable all bindings if it is not read-only mode
*/
public prepare(): void {
if (!this.Editor.ReadOnly.isEnabled) {
this.enableModuleBindings();
}
}
/**
* Toggle read-only state
*

View file

@ -38,7 +38,7 @@ export default class ModificationsObserver extends Module {
private mutationDebouncer = _.debounce(() => {
this.updateNativeInputs();
if (typeof this.config.onChange === 'function') {
if (_.isFunction(this.config.onChange)) {
this.config.onChange(this.Editor.API.methods);
}
}, ModificationsObserver.DebounceTimer);
@ -62,17 +62,6 @@ export default class ModificationsObserver extends Module {
this.mutationDebouncer = null;
}
/**
* Preparation method
*
* @returns {Promise<void>}
*/
public async prepare(): Promise<void> {
if (!this.Editor.ReadOnly.isEnabled) {
this.enableModule();
}
}
/**
* Set read-only state
*

View file

@ -144,9 +144,6 @@ export default class Paste extends Module {
*/
public async prepare(): Promise<void> {
this.processTools();
if (!this.Editor.ReadOnly.isEnabled) {
this.setCallback();
}
}
/**

View file

@ -309,7 +309,7 @@ export default class Sanitizer extends Module {
* @param {SanitizerConfig} config - config to check
*/
private isRule(config: SanitizerConfig): boolean {
return typeof config === 'object' || typeof config === 'boolean' || typeof config === 'function';
return typeof config === 'object' || typeof config === 'boolean' || _.isFunction(config);
}
/**

View file

@ -216,7 +216,7 @@ export default class BlockSettings extends Module<BlockSettingsNodes> {
* Add Tool's settings
*/
private addToolSettings(): void {
if (typeof this.Editor.BlockManager.currentBlock.tool.renderSettings === 'function') {
if (_.isFunction(this.Editor.BlockManager.currentBlock.tool.renderSettings)) {
$.append(this.nodes.toolSettings, this.Editor.BlockManager.currentBlock.tool.renderSettings());
}
}

View file

@ -112,7 +112,7 @@ export default class ConversionToolbar extends Module<ConversionToolbarNodes> {
this.close();
}
if (typeof togglingCallback === 'function') {
if (_.isFunction(togglingCallback)) {
this.togglingCallback = togglingCallback;
}
}
@ -136,7 +136,7 @@ export default class ConversionToolbar extends Module<ConversionToolbarNodes> {
}));
this.flipper.focusFirst();
if (typeof this.togglingCallback === 'function') {
if (_.isFunction(this.togglingCallback)) {
this.togglingCallback(true);
}
}, 50);
@ -150,7 +150,7 @@ export default class ConversionToolbar extends Module<ConversionToolbarNodes> {
this.flipper.deactivate();
this.nodes.wrapper.classList.remove(ConversionToolbar.CSS.conversionToolbarShowed);
if (typeof this.togglingCallback === 'function') {
if (_.isFunction(this.togglingCallback)) {
this.togglingCallback(false);
}
}
@ -207,7 +207,7 @@ export default class ConversionToolbar extends Module<ConversionToolbarNodes> {
let exportData = '';
const exportProp = currentBlockClass[INTERNAL_SETTINGS.CONVERSION_CONFIG].export;
if (typeof exportProp === 'function') {
if (_.isFunction(exportProp)) {
exportData = exportProp(blockData);
} else if (typeof exportProp === 'string') {
exportData = blockData[exportProp];
@ -234,7 +234,7 @@ export default class ConversionToolbar extends Module<ConversionToolbarNodes> {
let newBlockData = {};
const importProp = replacingTool[INTERNAL_SETTINGS.CONVERSION_CONFIG].import;
if (typeof importProp === 'function') {
if (_.isFunction(importProp)) {
newBlockData = importProp(cleaned);
} else if (typeof importProp === 'string') {
newBlockData[importProp] = cleaned;

View file

@ -141,9 +141,6 @@ export default class Toolbar extends Module<ToolbarNodes> {
/**
* Module preparation method
* Steps:
* - Make Toolbar dependent components like BlockSettings, Toolbox and so on
* - Make itself and append dependent nodes to itself
*/
public async prepare(): Promise<void> {
/**
@ -369,6 +366,11 @@ export default class Toolbar extends Module<ToolbarNodes> {
*
* Toolbar contains BlockSettings and Toolbox.
* Thats why at first we draw its components and then Toolbar itself
*
* Steps:
* - Make Toolbar dependent components like BlockSettings, Toolbox and so on
* - Make itself and append dependent nodes to itself
*
*/
private drawUI(): void {
/**

View file

@ -197,7 +197,7 @@ export default class InlineToolbar extends Module<InlineToolbarNodes> {
/**
* @todo replace 'clear' with 'destroy'
*/
if (typeof toolInstance.clear === 'function') {
if (_.isFunction(toolInstance.clear)) {
toolInstance.clear();
}
});
@ -614,7 +614,7 @@ export default class InlineToolbar extends Module<InlineToolbarNodes> {
this.nodes.buttons.appendChild(button);
this.toolsInstances.set(toolName, tool);
if (typeof tool.renderActions === 'function') {
if (_.isFunction(tool.renderActions)) {
const actions = tool.renderActions();
this.nodes.actions.appendChild(actions);

View file

@ -444,7 +444,7 @@ export default class Tools extends Module {
*/
toolPreparationList.push({
// eslint-disable-next-line @typescript-eslint/no-empty-function
function: typeof toolClass.prepare === 'function' ? toolClass.prepare : (): void => { },
function: _.isFunction(toolClass.prepare) ? toolClass.prepare : (): void => { },
data: {
toolName,
config: toolConfig,

View file

@ -163,13 +163,6 @@ export default class UI extends Module<UINodes> {
* Load and append CSS
*/
this.loadStyles();
/**
* Prepare with read-only state from config
*/
if (!this.Editor.ReadOnly.isEnabled) {
this.enableModuleBindings();
}
}
/**

View file

@ -276,7 +276,7 @@ export function isFunction(fn: any): fn is Function {
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function isClass(fn: any): boolean {
return typeof fn === 'function' && /^\s*class\s+/.test(fn.toString());
return isFunction(fn) && /^\s*class\s+/.test(fn.toString());
}
/**

View file

@ -15,11 +15,10 @@ export interface Blocks {
* Render passed data
*
* @param {OutputData} data - saved Block data
* @param {boolean} readOnly - the flag that should be used to render a block in the read-only mode
*
* @returns {Promise<void>}
*/
render(data: OutputData, readOnly: boolean): Promise<void>;
render(data: OutputData): Promise<void>;
/**
* Render passed HTML string

View file

@ -17,9 +17,9 @@ export interface BlockTool extends BaseTool {
sanitize?: SanitizerConfig;
/**
* @param {boolean} readOnly - render HTML on readonly mode
* Creates and returns Tools HTML markup
*/
render(readOnly?: boolean): HTMLElement;
render(): HTMLElement;
/**
* Process Tool's element in DOM and return raw data
@ -59,7 +59,7 @@ export interface BlockTool extends BaseTool {
* Called when the editor is destroyed
*/
destroy?(): void;
/**
* Lifecycle hooks
*/