Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove jQuery #114

Merged
merged 1 commit into from
May 10, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 70 additions & 78 deletions addon/event_dispatcher.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,31 @@
import { assert } from '@ember/debug';
import { getOwner } from '@ember/application';
import { merge, assign as _assign } from '@ember/polyfills';
import { isNone } from '@ember/utils';
import { get, set } from '@ember/object';
import { get } from '@ember/object';
import Ember from 'ember';
import defaultHammerEvents from './hammer-events';
import dasherizedToCamel from './utils/string/dasherized-to-camel';
import jQuery from 'jquery';
import mobileDetection from './utils/is-mobile';

const {
EventDispatcher,
} = Ember;


let ROOT_ELEMENT_CLASS = 'ember-application';
let ROOT_ELEMENT_SELECTOR = '.' + ROOT_ELEMENT_CLASS;

const eventEndings = {
pan: ['Start','Move', 'End', 'Cancel', 'Left', 'Right', 'Up', 'Down'],
pinch: ['Start','Move', 'End', 'Cancel', 'In', 'Out'],
pan: ['Start', 'Move', 'End', 'Cancel', 'Left', 'Right', 'Up', 'Down'],
pinch: ['Start', 'Move', 'End', 'Cancel', 'In', 'Out'],
press: ['Up'],
rotate: ['Start','Move', 'End', 'Cancel'],
rotate: ['Start', 'Move', 'End', 'Cancel'],
swipe: ['Left', 'Right', 'Up', 'Down'],
tap: []
};

const assign = _assign || merge;

const notFocusableTypes = ['submit', 'file', 'button', 'hidden', 'reset', 'range', 'radio', 'image', 'checkbox'];

const fastFocusEvents = ['click', 'touchend'];

export default EventDispatcher.extend({

/**
Expand Down Expand Up @@ -59,50 +57,69 @@ export default EventDispatcher.extend({
},

_fastFocus() {
let $root = jQuery(this.get('rootElement'));
$root.on('click.ember-gestures touchend.ember-gestures', function (e) {

/*
Implements fastfocus mechanisms on mobile web/Cordova
*/
if (mobileDetection.is()) {
var $element = jQuery(e.currentTarget);
var $target = jQuery(e.target);

/*
If the click was on an input element that needs to be able to focus, recast
the click as a "focus" event.
This fixes tap events on mobile where keyboardShrinksView or similar is true.
Such devices depend on the ghost click to trigger focus, but the ghost click
will never reach the element.
*/
var notFocusableTypes = ['submit', 'file', 'button', 'hidden', 'reset', 'range', 'radio', 'image', 'checkbox'];

//fastfocus
if ($element.is('textarea') || ($element.is('input') && notFocusableTypes.indexOf($element.attr('type')) === -1)) {
$element.focus();

} else if ($target.is('textarea') || ($target.is('input') && notFocusableTypes.indexOf($target.attr('type')) === -1)) {
$target.focus();
}
}
let rootElementSelector = get(this, 'rootElement');
let rootElement;
if (rootElementSelector.nodeType) {
rootElement = rootElementSelector;
} else {
rootElement = document.querySelector(rootElementSelector);
}

fastFocusEvents.forEach((event) => {
let listener = this._gestureEvents[event] = (e) => {
if (mobileDetection.is()) {
let element = e.currentTarget;
let target = e.target;

/*
If the click was on an input element that needs to be able to focus, recast
the click as a "focus" event.
This fixes tap events on mobile where keyboardShrinksView or similar is true.
Such devices depend on the ghost click to trigger focus, but the ghost click
will never reach the element.
*/

//fastfocus
if (element.tagName === 'TEXTAREA' || (element.tagName === 'INPUT' && notFocusableTypes.indexOf(element.getAttribute('type')) === -1)) {
element.focus();

} else if (target.tagName === 'TEXTAREA' || (target.tagName === 'INPUT' && notFocusableTypes.indexOf(target.getAttribute('type')) === -1)) {
target.focus();
}
}
};
rootElement.addEventListener(event, listener);
});

},

willDestroy() {
jQuery(this.get('rootElement')).off('.ember-gestures');
let rootElementSelector = get(this, 'rootElement');
let rootElement;
if (rootElementSelector.nodeType) {
rootElement = rootElementSelector;
} else {
rootElement = document.querySelector(rootElementSelector);
}

if (rootElement) {
for (let event in this._gestureEvents) {
rootElement.removeEventListener(event, this._gestureEvents[event]);
delete this._gestureEvents[event];
}
}
this._super(...arguments);
},

_finalEvents: null,

init() {
this._gestureEvents = Object.create(null);
this._super(...arguments);
},

setup(addedEvents, rootElement) {
this._initializeGestures();
const events = this._finalEvents = assign({}, get(this, 'events'));

let event;
let events = assign({}, get(this, 'events'));

// remove undesirable events from Ember's Eventing
if (this.get('removeTracking')) {
Expand All @@ -128,51 +145,27 @@ export default EventDispatcher.extend({
events.dblclick = null;
}

// assign custom events into Ember's Eventing
assign(events, addedEvents || {});

// delete unwanted events
for (event in events) {
if (events.hasOwnProperty(event)) {
if (!events[event]) {
delete events[event];
}
for (let event in events) {
if (events.hasOwnProperty(event) && !events[event]) {
delete events[event];
}
}

// assign our events into Ember's Eventing
assign(events, this.get('_gestures'));

if (!isNone(rootElement)) {
set(this, 'rootElement', rootElement);
}
this._fastFocus();


rootElement = jQuery(get(this, 'rootElement'));

assert(`You cannot use the same root element (${rootElement.selector || rootElement[0].tagName}) multiple times in an Ember.Application`, !rootElement.is(ROOT_ELEMENT_SELECTOR));
assert('You cannot make a new Ember.Application using a root element that is a descendent of an existing Ember.Application', !rootElement.closest(ROOT_ELEMENT_SELECTOR).length);
assert('You cannot make a new Ember.Application using a root element that is an ancestor of an existing Ember.Application', !rootElement.find(ROOT_ELEMENT_SELECTOR).length);
// override default events
this.set('events', events);

rootElement.addClass(ROOT_ELEMENT_CLASS);
// add our events to addition events
let additionalEvents = assign({}, addedEvents);
additionalEvents = assign(additionalEvents, this.get('_gestures'));

assert(`Unable to add '${ROOT_ELEMENT_CLASS}' class to rootElement. Make sure you set rootElement to the body or an element in the body.`, rootElement.is(ROOT_ELEMENT_SELECTOR));

// needed for Ember 2.12+ support (setupHandler takes 4 args)
let viewRegistry = this._getViewRegistry && this._getViewRegistry();
this._fastFocus();

for (event in events) {
if (events.hasOwnProperty(event)) {
this.setupHandler(rootElement, event, events[event], viewRegistry);
}
}
return this._super(additionalEvents, rootElement);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: I removed quite a bit of code duplicated from the original EventDispatcher, by calling its super method here, instead of overriding and duplicating everything.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is great work -- just so i fully understand -

previously we called assign(events, this.get('_gestures')); then this._fastFocus();, and then registered each event, including those added via this.get('_gestures') --- now we're calling this.set('events', events); then this._fastFocus(); and then calling return this._super(additionalEvents, rootElement); to allow the ember event dispatcher to do the for (event in events) {... this.setupHandler ... for us, correct?

If I'm missing something, please let me know.

One more q, where'd this guy go?

$root.on('click.ember-gestures touchend.ember-gestures', function (e) {

other than that, at least with just an eyeball review on github here, it looks like you nailed it... is there any way u could bring a piece of code from ur app into a test? (there isn't really much testing now.. so u can provide another way to prove its correctness) -- basically anything that will verify the new behavior matches the previous behavior, without careful reading through the diff here, would be nice, in some form, even logging the events registered through ember vs those on the rootElement itself, via this._fastFocus(), aka, those not using the previous verbose this.setupHandler loop -- would ease any concerns I have over my own ability to read and understand this code, old and new :)

also @runspired should approve this as he wrote it originally... i think i made any concerns obvious, the rest checks out except the ordering where mentioned, and the missing .on('click... from jquery (maybe i just missed it).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eriktrom the changes here lived in fork I created a while ago, so I have to refresh my memories a bit... 😬

to allow the ember event dispatcher to do the for (event in events) {... this.setupHandler ... for us, correct?

Yes, exactly. setup() supports a list of additional events, so I just use that to pass the gestures specific events to the parent to let it attach the event listeners for them.

One more q, where'd this guy go?

This adds click and touchend listeners via jQuery, and the same happens here:
https://github.com/html-next/ember-gestures/pull/114/files#diff-89ef10d070270d2503408f9f16d8b558R91
for the fastFocusEvents here: https://github.com/html-next/ember-gestures/pull/114/files#diff-89ef10d070270d2503408f9f16d8b558R27

is there any way u could bring a piece of code from ur app into a test

Hm, not really. These are app specific (lots of acceptance and component integration tests), which would certainly have failed indirectly if the EventDispatcher was not working correctly. I also verified that some gestures we used like swipes were still working.

For adding some real tests here, I am afraid to not have enough time for this atm, to do it properly. :(

}

});



function addEvent(hash, gesture, name) {
const eventName = dasherizedToCamel(name);
const eventBase = eventName.toLowerCase();
Expand All @@ -186,15 +179,14 @@ function addEvent(hash, gesture, name) {
});
}


// this function can be replaced in ember 1.13 with a private api
// and in ember 2.0 with a potentially public api matching 1.13's
// private api. This is a stop gap for pre-ember 1.13
function getModuleList() {
/* global requirejs */
const list = [];

for(var moduleName in requirejs.entries) {
for (let moduleName in requirejs.entries) {
if (Object.prototype.hasOwnProperty.call(requirejs.entries, moduleName)) {
const parts = moduleName.match(/ember-gestures\/recognizers\/(.*)/);

Expand Down
69 changes: 0 additions & 69 deletions addon/eventer.js

This file was deleted.