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:
Murod Khaydarov 2018-09-05 00:34:11 +03:00 committed by GitHub
parent 2c0d747035
commit 7acf321454
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 176 additions and 38 deletions

View file

@ -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

View file

@ -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.

View file

@ -226,6 +226,9 @@
},
onReady: function(){
saveButton.click();
},
onChange: function() {
console.log('something changed');
}
});

View file

@ -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": {

View file

@ -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) {

View file

@ -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 () => {

View file

@ -49,4 +49,9 @@ export default interface IEditorConfig {
* Editor initialization callback
*/
onReady?(): void;
/**
* Trigger callback if Content has beed changed
*/
onChange?(): void;
}

View 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);
}
}

View file

@ -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);
}
};
}
}