Skip to content

Commit

Permalink
Merge pull request #556 from daviferreira/detach-custom-events
Browse files Browse the repository at this point in the history
Expose method of detaching custom event listeners + detach on destroy
  • Loading branch information
Noah Chase committed Apr 13, 2015
2 parents 34f038c + 6a74b5a commit e6393f3
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 10 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ Check out the Wiki page for a list of available themes: [https://github.com/davi
* __.execAction(action, opts)__: executes an built-in action via `document.execCommand`
* __.createLink(opts)__: creates a link via the native `document.execCommand('createLink')` command
* __.subscribe(event, listener)__: attaches a listener to a custom medium-editor event
* __.unsubscribe(event, listener)__: detaches a listener from a custom medium-editor event
* __.saveSelection()__: internally store the set of selected text
* __.restoreSelection()__: restore the selection to what was selected when `saveSelection()` was called
* __.selectAllContents()__: expands the selection to contain all text within the focused contenteditable
Expand Down
34 changes: 30 additions & 4 deletions dist/js/medium-editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -1356,21 +1356,42 @@ var Events;
},

// custom events
attachCustomEvent: function (event, handler) {
attachCustomEvent: function (event, listener) {
this.setupListener(event);
// If we don't suppot this custom event, don't do anything
if (this.listeners[event]) {
if (!this.customEvents[event]) {
this.customEvents[event] = [];
}
this.customEvents[event].push(handler);
this.customEvents[event].push(listener);
}
},

detachCustomEvent: function (event, listener) {
var index = this.indexOfCustomListener(event, listener);
if (index !== -1) {
this.customEvents[event].splice(index, 1);
// TODO: If array is empty, should detach internal listeners via destoryListener()
}
},

indexOfCustomListener: function (event, listener) {
if (!this.customEvents[event] || !this.customEvents[event].length) {
return -1;
}

return this.customEvents[event].indexOf(listener);
},

detachAllCustomEvents: function () {
this.customEvents = {};
// TODO: Should detach internal listeners here via destroyListener()
},

triggerCustomEvent: function (name, data, editable) {
if (this.customEvents[name]) {
this.customEvents[name].forEach(function (handler) {
handler(data, editable);
this.customEvents[name].forEach(function (listener) {
listener(data, editable);
});
}
},
Expand Down Expand Up @@ -3637,6 +3658,7 @@ function MediumEditor(elements, options) {
}, this);

this.events.detachAllDOMEvents();
this.events.detachAllCustomEvents();
},

on: function (target, event, listener, useCapture) {
Expand All @@ -3651,6 +3673,10 @@ function MediumEditor(elements, options) {
this.events.attachCustomEvent(event, listener);
},

unsubscribe: function (event, listener) {
this.events.detachCustomEvent(event, listener);
},

delay: function (fn) {
var self = this;
return setTimeout(function () {
Expand Down
4 changes: 2 additions & 2 deletions dist/js/medium-editor.min.js

Large diffs are not rendered by default.

67 changes: 67 additions & 0 deletions spec/events.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,71 @@ describe('Events TestCase', function () {
expect(spy).not.toHaveBeenCalled();
});
});

describe('Custom Focus/Blur Listener', function () {
it('should be called and passed the editable element when the editable gets focus', function () {
var editor = new MediumEditor('.editor'),
focusedEditable,
blurredEditable,
focusListener = function (event, editable) { focusedEditable = editable; },
blurListener = function (event, editable) { blurredEditable = editable; };
editor.subscribe('focus', focusListener);
editor.subscribe('blur', blurListener);

editor.selectElement(this.el.firstChild);
expect(focusedEditable).toBe(this.el);
expect(blurredEditable).toBeUndefined();

fireEvent(document.body, 'click');
expect(blurredEditable).toBe(this.el);
});

it('should not trigger after detaching', function () {
var focusSpy = jasmine.createSpy('handler'),
blurSpy = jasmine.createSpy('handler'),
editor = new MediumEditor('.editor');
editor.subscribe('focus', focusSpy);
editor.subscribe('blur', blurSpy);

editor.selectElement(this.el.firstChild);
expect(focusSpy.calls.count()).toBe(1);
expect(blurSpy).not.toHaveBeenCalled();

fireEvent(document.body, 'click');
expect(blurSpy).toHaveBeenCalled();

editor.unsubscribe('focus', focusSpy);
editor.selectElement(this.el.firstChild);
expect(focusSpy.calls.count()).toBe(1);

editor.unsubscribe('blur', blurSpy);
fireEvent(document.body, 'click');
expect(blurSpy.calls.count()).toBe(1);
});

it('should not be called after destroying editor', function () {
var editor = new MediumEditor('.editor'),
focusSpy = jasmine.createSpy('handler'),
blurSpy = jasmine.createSpy('handler');
editor.subscribe('focus', focusSpy);
editor.subscribe('blur', blurSpy);

this.el.focus();
fireEvent(this.el, 'focus');
expect(focusSpy.calls.count()).toBe(1);
expect(blurSpy).not.toHaveBeenCalled();

fireEvent(document.body, 'click');
expect(blurSpy).toHaveBeenCalled();

editor.destroy();

this.el.focus();
fireEvent(this.el, 'focus');
expect(focusSpy.calls.count()).toBe(1);

fireEvent(document.body, 'click');
expect(blurSpy.calls.count()).toBe(1);
});
});
});
5 changes: 5 additions & 0 deletions src/js/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,7 @@ function MediumEditor(elements, options) {
}, this);

this.events.detachAllDOMEvents();
this.events.detachAllCustomEvents();
},

on: function (target, event, listener, useCapture) {
Expand All @@ -555,6 +556,10 @@ function MediumEditor(elements, options) {
this.events.attachCustomEvent(event, listener);
},

unsubscribe: function (event, listener) {
this.events.detachCustomEvent(event, listener);
},

delay: function (fn) {
var self = this;
return setTimeout(function () {
Expand Down
29 changes: 25 additions & 4 deletions src/js/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,21 +51,42 @@ var Events;
},

// custom events
attachCustomEvent: function (event, handler) {
attachCustomEvent: function (event, listener) {
this.setupListener(event);
// If we don't suppot this custom event, don't do anything
if (this.listeners[event]) {
if (!this.customEvents[event]) {
this.customEvents[event] = [];
}
this.customEvents[event].push(handler);
this.customEvents[event].push(listener);
}
},

detachCustomEvent: function (event, listener) {
var index = this.indexOfCustomListener(event, listener);
if (index !== -1) {
this.customEvents[event].splice(index, 1);
// TODO: If array is empty, should detach internal listeners via destoryListener()
}
},

indexOfCustomListener: function (event, listener) {
if (!this.customEvents[event] || !this.customEvents[event].length) {
return -1;
}

return this.customEvents[event].indexOf(listener);
},

detachAllCustomEvents: function () {
this.customEvents = {};
// TODO: Should detach internal listeners here via destroyListener()
},

triggerCustomEvent: function (name, data, editable) {
if (this.customEvents[name]) {
this.customEvents[name].forEach(function (handler) {
handler(data, editable);
this.customEvents[name].forEach(function (listener) {
listener(data, editable);
});
}
},
Expand Down

0 comments on commit e6393f3

Please sign in to comment.