Skip to content

Commit

Permalink
Merge pull request #113 from bustlelabs/cleanup-listeners
Browse files Browse the repository at this point in the history
Cleanup listeners
  • Loading branch information
bantic committed Sep 3, 2015
2 parents 4ea9e76 + 3d56c76 commit 27cf9e2
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 121 deletions.
227 changes: 108 additions & 119 deletions src/js/editor/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,25 +29,17 @@ import RenderTree from 'content-kit-editor/models/render-tree';
import MobiledocRenderer from '../renderers/mobiledoc';

import { mergeWithOptions } from 'content-kit-utils';
import {
clearChildNodes,
addClassName,
parseHTML
} from '../utils/dom-utils';
import {
forEach,
filter
} from '../utils/array-utils';
import { clearChildNodes, addClassName, parseHTML } from '../utils/dom-utils';
import { forEach, filter } from '../utils/array-utils';
import { getData, setData } from '../utils/element-utils';
import mixin from '../utils/mixin';
import EventListenerMixin from '../utils/event-listener';
import Cursor from '../utils/cursor';
import PostNodeBuilder from '../models/post-node-builder';
import {
DEFAULT_TEXT_EXPANSIONS,
findExpansion,
validateExpansion
DEFAULT_TEXT_EXPANSIONS, findExpansion, validateExpansion
} from './text-expansions';
import { capitalize } from '../utils/string-utils';

export const EDITOR_ELEMENT_CLASS_NAME = 'ck-editor';

Expand Down Expand Up @@ -75,94 +67,6 @@ function runCallbacks(callbacks, args) {
}
}

function bindContentEditableTypingListeners(editor) {
// On 'PASTE' sanitize and insert
editor.addEventListener(editor.element, 'paste', function(e) {
var data = e.clipboardData;
var pastedHTML = data && data.getData && data.getData('text/html');
var sanitizedHTML = pastedHTML && editor._renderer.rerender(pastedHTML);
if (sanitizedHTML) {
document.execCommand('insertHTML', false, sanitizedHTML);
editor.rerender();
}
e.preventDefault();
return false;
});
}

function bindSelectionEvent(editor) {
/**
* The following events/sequences can create a selection and are handled:
* * mouseup -- can happen anywhere in document, must wait until next tick to read selection
* * keyup when key is a movement key and shift is pressed -- in editor element
* * keyup when key combo was cmd-A (alt-A) aka "select all"
* * keyup when key combo was cmd-Z (browser restores selection if there was one)
*
* These cases can create a selection and are not handled:
* * ctrl-click -> context menu -> click "select all"
*/

const toggleSelection = () => {
return editor.cursor.hasSelection() ? editor.reportSelection() :
editor.reportNoSelection();
};

// mouseup will not properly report a selection until the next tick, so add a timeout:
const mouseupHandler = () => setTimeout(toggleSelection);
editor.addEventListener(document, 'mouseup', mouseupHandler);

const keyupHandler = toggleSelection;
editor.addEventListener(editor.element, 'keyup', keyupHandler);
}

function bindKeyListeners(editor) {
if (!editor.isEditable) {
return;
}
editor.addEventListener(document, 'keyup', (event) => {
const key = Key.fromEvent(event);
if (key.isEscape()) {
editor.trigger('escapeKey');
}
});

editor.addEventListener(editor.element, 'keydown', (event) => {
editor.handleExpansion(event);
});

editor.addEventListener(document, 'keydown', (event) => {
if (!editor.isEditable) {
return;
}
const key = Key.fromEvent(event);

if (key.isDelete()) {
editor.handleDeletion(event);
event.preventDefault();
} else if (key.isEnter()) {
editor.handleNewline(event);
} else if (key.isPrintable()) {
if (editor.cursor.hasSelection()) {
let offsets = editor.cursor.offsets;
editor.run((postEditor) => {
postEditor.deleteRange(editor.cursor.offsets);
});
editor.cursor.moveToSection(offsets.headSection, offsets.headSectionOffset);
}
}
});
}

function bindDragAndDrop(editor) {
// TODO. For now, just prevent redirect when dropping something on the page
editor.addEventListener(window, 'dragover', function(e) {
e.preventDefault(); // prevents showing cursor where to drop
});
editor.addEventListener(window, 'drop', function(e) {
e.preventDefault(); // prevent page from redirecting
});
}

function makeButtons(editor) {
const headingCommand = new HeadingCommand(editor);
const headingButton = new ReversibleToolbarButton(headingCommand, editor);
Expand Down Expand Up @@ -289,27 +193,11 @@ class Editor {

clearChildNodes(element);

bindContentEditableTypingListeners(this);
bindDragAndDrop(this);
bindSelectionEvent(this);
bindKeyListeners(this);
this.addEventListener(element, 'input', () => this.handleInput());

this._setupListeners();
this._initEmbedCommands();

this.toolbar = new TextFormatToolbar({
editor: this,
rootElement: element,
commands: [],
buttons: makeButtons(this),
sticky: this.stickyToolbar
});
this.addView(this.toolbar);

this.addView(new Tooltip({
rootElement: element,
showForTag: 'a'
}));
this._addToolbar();
this._addTooltip();

// A call to `run` will trigger the didUpdatePostCallbacks hooks with a
// postEditor.
Expand All @@ -321,6 +209,20 @@ class Editor {
}
}

_addToolbar() {
this.addView(new TextFormatToolbar({
editor: this,
rootElement: this.element,
commands: [],
buttons: makeButtons(this),
sticky: this.stickyToolbar
}));
}

_addTooltip() {
this.addView(new Tooltip({rootElement: this.element, showForTag: 'a'}));
}

get expansions() {
if (!this._expansions) { this._expansions = []; }
return this._expansions;
Expand Down Expand Up @@ -640,6 +542,93 @@ class Editor {
rootElement: this.element
}));
}

_setupListeners() {
const elementEvents = ['keydown', 'keyup', 'input', 'dragover', 'drop', 'paste'];
const documentEvents = ['mouseup'];

elementEvents.forEach(eventName => {
this.addEventListener(this.element, eventName,
(...args) => this.handleEvent(eventName, ...args)
);
});

documentEvents.forEach(eventName => {
this.addEventListener(document, eventName,
(...args) => this.handleEvent(eventName, ...args)
);
});
}

handleEvent(eventName, ...args) {
const methodName = `handle${capitalize(eventName)}`;
if (!this[methodName]) { throw new Error(`No handler for ${eventName}`); }
this[methodName](...args);
}

handleMouseup() {
// mouseup does not correctly report a selection until the next tick
setTimeout(() => this._reportSelectionState());
}

handleKeyup(event) {
const key = Key.fromEvent(event);

if (key.isEscape()) { this.trigger('escapeKey'); }
this._reportSelectionState();
}

/*
The following events/sequences can create a selection and are handled:
* mouseup -- can happen anywhere in document, must wait until next tick to read selection
* keyup when key is a movement key and shift is pressed -- in editor element
* keyup when key combo was cmd-A (alt-A) aka "select all"
* keyup when key combo was cmd-Z (browser may restore selection)
These cases can create a selection and are not handled:
* ctrl-click -> context menu -> click "select all"
*/
_reportSelectionState() {
if (this.cursor.hasSelection()) {
this.reportSelection();
} else {
this.reportNoSelection();
}
}

handleDragover(e) {
e.preventDefault(); // FIXME for now, just prevent default
}

handleDrop(e) {
e.preventDefault(); // FIXME for now, just prevent default
}

handleKeydown(event) {
if (!this.isEditable) { return; }

const key = Key.fromEvent(event);

if (key.isDelete()) {
this.handleDeletion(event);
event.preventDefault();
} else if (key.isEnter()) {
this.handleNewline(event);
} else if (key.isPrintable()) {
if (this.cursor.hasSelection()) {
let offsets = this.cursor.offsets;
this.run((postEditor) => {
postEditor.deleteRange(this.cursor.offsets);
});
this.cursor.moveToSection(offsets.headSection, offsets.headSectionOffset);
}
}

this.handleExpansion(event);
}

handlePaste(event) {
event.preventDefault(); // FIXME for now, just prevent pasting
}
}

mixin(Editor, EventEmitter);
Expand Down
4 changes: 4 additions & 0 deletions src/js/utils/string-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ export function dasherize(string) {
});
}

export function capitalize(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}

export function startsWith(string, character) {
return string.charAt(0) === character;
}
Expand Down
4 changes: 2 additions & 2 deletions tests/helpers/dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ function triggerDelete(editor) {
let event = { preventDefault() {} };
editor.handleDeletion(event);
} else {
triggerKeyEvent(document, 'keydown', KEY_CODES.BACKSPACE);
triggerKeyEvent(editor.element, 'keydown', KEY_CODES.BACKSPACE);
}
}

Expand All @@ -157,7 +157,7 @@ function triggerEnter(editor) {
let event = { preventDefault() {} };
editor.handleNewline(event);
} else {
triggerKeyEvent(document, 'keydown', KEY_CODES.ENTER);
triggerKeyEvent(editor.element, 'keydown', KEY_CODES.ENTER);
}
}

Expand Down

0 comments on commit 27cf9e2

Please sign in to comment.