mirror of
https://github.com/codex-team/editor.js
synced 2024-06-04 23:12:34 +02:00
Mutation callback (#444)
* modification observer initials * add debouncer to callback execution * change feature name * update * code improvements * tslint fixes * use debouncer from utils * add types * upgrade * fix * update
This commit is contained in:
parent
2c0d747035
commit
7acf321454
|
@ -1,6 +1,6 @@
|
|||
<p align="center"><img src="https://capella.pics/3c0b525b-50d9-4720-8aad-9148114cfa6e.jpg"></p>
|
||||
|
||||
![](https://flat.badgen.net/badge/CodeX%20Editor/v2.0.9/blue?icon=npm)
|
||||
![](https://flat.badgen.net/badge/CodeX%20Editor/v2.0.10/blue?icon=npm)
|
||||
|
||||
## Version 2.0-beta is here!
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -177,6 +177,26 @@ editor.saver.save()
|
|||
});
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
Also CodeX Editor provides useful methods to work with Editor's state.
|
||||
|
||||
```javascript
|
||||
var editor = new CodexEditor({
|
||||
// Other configuration properties
|
||||
|
||||
/**
|
||||
* onReady callback
|
||||
*/
|
||||
onReady: () => {console.log('CodeX Editor is ready to work!')},
|
||||
|
||||
/**
|
||||
* onChange callback
|
||||
*/
|
||||
onChange: () => {console.log('Now I know that Editor\'s content changed!')}
|
||||
});
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
Take a look at the [example.html](../example/example.html) to view more detailed examples.
|
||||
|
|
|
@ -226,6 +226,9 @@
|
|||
},
|
||||
onReady: function(){
|
||||
saveButton.click();
|
||||
},
|
||||
onChange: function() {
|
||||
console.log('something changed');
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "codex.editor",
|
||||
"version": "2.0.9",
|
||||
"version": "2.0.10",
|
||||
"description": "Codex Editor. Native JS, based on API and Open Source",
|
||||
"main": "build/codex-editor.js",
|
||||
"scripts": {
|
||||
|
|
|
@ -66,6 +66,7 @@ export default class CodexEditor {
|
|||
const destroy = () => {
|
||||
editor.moduleInstances.Listeners.removeAll();
|
||||
editor.moduleInstances.UI.destroy();
|
||||
editor.moduleInstances.ModificationsObserver.destroy();
|
||||
editor = null;
|
||||
|
||||
for (const field in this) {
|
||||
|
|
|
@ -90,7 +90,7 @@ export default class Core {
|
|||
|
||||
/**
|
||||
* Setting for configuration
|
||||
* @param {EditorConfig|string|null} config
|
||||
* @param {IEditorConfig|string|null} config
|
||||
*/
|
||||
set configuration(config) {
|
||||
/**
|
||||
|
@ -129,6 +129,7 @@ export default class Core {
|
|||
this.config.tools = config.tools || {};
|
||||
this.config.data = config.data || {};
|
||||
this.config.onReady = config.onReady || function () {};
|
||||
this.config.onChange = config.onChange || function () {};
|
||||
|
||||
/**
|
||||
* Initialize Blocks to pass data to the Renderer
|
||||
|
@ -261,7 +262,7 @@ export default class Core {
|
|||
* @return {Promise}
|
||||
*/
|
||||
async start() {
|
||||
const modulesToPrepare = ['Tools', 'UI', 'BlockManager', 'Paste'];
|
||||
const modulesToPrepare = ['Tools', 'UI', 'BlockManager', 'Paste', 'ModificationsObserver'];
|
||||
|
||||
await modulesToPrepare.reduce(
|
||||
(promise, module) => promise.then(async () => {
|
||||
|
|
|
@ -49,4 +49,9 @@ export default interface IEditorConfig {
|
|||
* Editor initialization callback
|
||||
*/
|
||||
onReady?(): void;
|
||||
|
||||
/**
|
||||
* Trigger callback if Content has beed changed
|
||||
*/
|
||||
onChange?(): void;
|
||||
}
|
||||
|
|
73
src/components/modules/modificationsObserver.ts
Normal file
73
src/components/modules/modificationsObserver.ts
Normal file
|
@ -0,0 +1,73 @@
|
|||
/**
|
||||
* @module ModificationsObserver
|
||||
*
|
||||
* Handles any mutations
|
||||
* and gives opportunity to handle outside
|
||||
*/
|
||||
|
||||
import IEditorConfig from '../interfaces/editor-config';
|
||||
|
||||
declare const Module: any;
|
||||
declare const _: any;
|
||||
|
||||
export default class ModificationsObserver extends Module {
|
||||
|
||||
/**
|
||||
* Debounce Timer
|
||||
* @type {number}
|
||||
*/
|
||||
public static readonly DebounceTimer = 450;
|
||||
|
||||
/**
|
||||
* Used to prevent several mutation callback execution
|
||||
* @type {Function}
|
||||
*/
|
||||
private mutationDebouncer = _.debounce( () => {
|
||||
this.config.onChange.call();
|
||||
}, ModificationsObserver.DebounceTimer);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param {IEditorConfig} config
|
||||
*/
|
||||
constructor({config}) {
|
||||
super({config});
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear timeout and set null to mutationDebouncer property
|
||||
*/
|
||||
public destroy() {
|
||||
this.mutationDebouncer = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Preparation method
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
public async prepare(): Promise<void> {
|
||||
/**
|
||||
* wait till Browser render Editor's Blocks
|
||||
*/
|
||||
window.setTimeout( () => {
|
||||
this.setObserver();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* setObserver
|
||||
*
|
||||
* sets 'DOMSubtreeModified' listener on Editor's UI.nodes.redactor
|
||||
* so that User can handle outside from API
|
||||
*/
|
||||
private setObserver(): void {
|
||||
const {Listeners, UI} = this.Editor;
|
||||
|
||||
/**
|
||||
* Set Listener to the Editor <div> element that holds only Blocks
|
||||
*/
|
||||
Listeners.on(UI.nodes.redactor, 'DOMSubtreeModified', () => {
|
||||
this.mutationDebouncer();
|
||||
}, false);
|
||||
}
|
||||
}
|
|
@ -196,4 +196,39 @@ export default class Util {
|
|||
window.setTimeout(() => method.apply(context, args), timeout);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Debouncing method
|
||||
* Call method after passed time
|
||||
*
|
||||
* 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}
|
||||
*/
|
||||
public static debounce(func: () => void, wait: number , immediate: boolean): () => void {
|
||||
let timeout;
|
||||
|
||||
return () => {
|
||||
const context = this,
|
||||
args = arguments;
|
||||
|
||||
const later = () => {
|
||||
timeout = null;
|
||||
if (!immediate) {
|
||||
func.apply(context, args);
|
||||
}
|
||||
};
|
||||
|
||||
const callNow = immediate && !timeout;
|
||||
|
||||
window.clearTimeout(timeout);
|
||||
timeout = window.setTimeout(later, wait);
|
||||
if (callNow) {
|
||||
func.apply(context, args);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue