Skip to content

Commit

Permalink
feat(textInput): able to unregister single or all text input handlers (
Browse files Browse the repository at this point in the history
  • Loading branch information
eguitarz authored and bantic committed Sep 6, 2016
1 parent 2fe7f0f commit 68a60ae
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 0 deletions.
5 changes: 5 additions & 0 deletions README.md
Expand Up @@ -241,6 +241,11 @@ editor.onTextInput({
The editor has several default text input handlers that are defined in
`src/js/editor/text-input-handlers.js`.

To remove default text input handlers, simply call the unregister function.
```javascript
editor.unregisterAllTextInputHandlers();
```

### DOM Parsing hooks

A developer can override the default parsing behavior for leaf DOM nodes in
Expand Down
20 changes: 20 additions & 0 deletions src/js/editor/editor.js
Expand Up @@ -710,6 +710,7 @@ class Editor {
* Register a handler that will be invoked by the editor after the user enters
* matching text.
* @param {Object} inputHandler
* @param {String} inputHandler.name Required. Used by identifying handlers.
* @param {String} [inputHandler.text] Required if `match` is not provided
* @param {RegExp} [inputHandler.match] Required if `text` is not provided
* @param {Function} inputHandler.run This callback is invoked with the {@link Editor}
Expand All @@ -724,6 +725,25 @@ class Editor {
this._eventManager.registerInputHandler(inputHandler);
}

/**
* Unregister all text input handlers
*
* @public
*/
unregisterAllTextInputHandlers() {
this._eventManager.unregisterAllTextInputHandlers();
}

/**
* Unregister text input handler by name
* @param {String} name The name of handler to be removed
*
* @public
*/
unregisterTextInputHandler(name) {
this._eventManager.unregisterInputHandler(name);
}

/**
* @param {Function} callback Called when the editor's state (active markups or
* active sections) has changed, either via user input or programmatically
Expand Down
9 changes: 9 additions & 0 deletions src/js/editor/event-manager.js
Expand Up @@ -45,6 +45,15 @@ export default class EventManager {
this._textInputHandler.register(inputHandler);
}

unregisterInputHandler(name) {
this._textInputHandler.unregister(name);
}

unregisterAllTextInputHandlers() {
this._textInputHandler.destroy();
this._textInputHandler = new TextInputHandler(this.editor);
}

_addListener(context, type) {
assert(`Missing listener for ${type}`, !!this[type]);

Expand Down
11 changes: 11 additions & 0 deletions src/js/editor/text-input-handler.js
@@ -1,5 +1,6 @@
import { endsWith } from 'mobiledoc-kit/utils/string-utils';
import assert from 'mobiledoc-kit/utils/assert';
import deprecate from 'mobiledoc-kit/utils/deprecate';

class TextInputHandler {
constructor(editor) {
Expand All @@ -12,6 +13,15 @@ class TextInputHandler {
this._handlers.push(handler);
}

unregister(name) {
let handlers = this._handlers;
for (let i=0; i<handlers.length; i++) {
if (handlers[i].name === name) {
handlers.splice(i, 1);
}
}
}

handle(string) {
let { editor } = this;
editor.insertText(string);
Expand Down Expand Up @@ -40,6 +50,7 @@ class TextInputHandler {
}

_validateHandler(handler) {
deprecate('Registered input handlers require a "name" property so that they can be unregistered', !!handler.name);
return !!handler.run && // has `run`
(!!handler.text || !!handler.match) && // and `text` or `match`
!(!!handler.text && !!handler.match); // not both `text` and `match`
Expand Down
3 changes: 3 additions & 0 deletions src/js/editor/text-input-handlers.js
Expand Up @@ -53,20 +53,23 @@ export function replaceWithHeaderSection(editor, headingTagName) {

export const DEFAULT_TEXT_INPUT_HANDLERS = [
{
name: 'ul',
// "* " -> ul
match: /^\* $/,
run(editor) {
replaceWithListSection(editor, 'ul');
}
},
{
name: 'ol',
// "1" -> ol, "1." -> ol
match: /^1\.? $/,
run(editor) {
replaceWithListSection(editor, 'ol');
}
},
{
name: 'heading',
// "# " -> h1, "## " -> h2, "### " -> h3
match: /^(#{1,3}) $/,
run(editor, matches) {
Expand Down
47 changes: 47 additions & 0 deletions tests/acceptance/editor-input-handlers-test.js
Expand Up @@ -177,6 +177,7 @@ test('an input handler will trigger anywhere in the text', (assert) => {
let expandCount = 0;
let lastMatches;
editor.onTextInput({
name: 'at',
text: '@',
run: (editor, matches) => {
expandCount++;
Expand Down Expand Up @@ -210,6 +211,7 @@ test('an input handler can provide a `match` instead of `text`', (assert) => {
let lastMatches;
let regex = /.(.)X$/;
editor.onTextInput({
name: 'test',
match: regex,
run: (editor, matches) => {
expandCount++;
Expand Down Expand Up @@ -243,6 +245,7 @@ test('an input handler can provide a `match` that matches at start and end', (as
let lastMatches;
let regex = /^\d\d\d$/;
editor.onTextInput({
name: 'test',
match: regex,
run: (editor, matches) => {
expandCount++;
Expand Down Expand Up @@ -273,6 +276,7 @@ test('input handler can be triggered by TAB', (assert) => {

let didMatch;
editor.onTextInput({
name: 'test',
match: /abc\t/,
run() {
didMatch = true;
Expand All @@ -283,3 +287,46 @@ test('input handler can be triggered by TAB', (assert) => {

assert.ok(didMatch);
});

test('can unregister all handlers', (assert) => {
editor = Helpers.editor.buildFromText('');
// there are 3 default helpers
assert.equal(editor._eventManager._textInputHandler._handlers.length, 3);
editor.onTextInput({
name: 'first',
match: /abc\t/,
run() {}
});
editor.onTextInput({
name: 'second',
match: /abc\t/,
run() {}
});
assert.equal(editor._eventManager._textInputHandler._handlers.length, 5);
editor.unregisterAllTextInputHandlers();
assert.equal(editor._eventManager._textInputHandler._handlers.length, 0);
});

test('can unregister handler by name', (assert) => {
editor = Helpers.editor.buildFromText('');
const handlerName = 'ul';
let handlers = editor._eventManager._textInputHandler._handlers;
assert.ok(handlers.filter(handler => handler.name === handlerName).length);
editor.unregisterTextInputHandler(handlerName);
assert.notOk(handlers.filter(handler => handler.name === handlerName).length);
});

test('can unregister handlers by duplicate name', (assert) => {
editor = Helpers.editor.buildFromText('');
const handlerName = 'ul';
editor.onTextInput({
name: handlerName,
match: /abc/,
run() {}
});
let handlers = editor._eventManager._textInputHandler._handlers;
assert.equal(handlers.length, 4); // 3 default + 1 custom handlers
editor.unregisterTextInputHandler(handlerName);
assert.equal(handlers.length, 2);
assert.notOk(handlers.filter(handler => handler.name === handlerName).length);
});

0 comments on commit 68a60ae

Please sign in to comment.