From 08d12b855690ca402fa4ec3af6b0fee54515ab5c Mon Sep 17 00:00:00 2001 From: cibernox Date: Sun, 9 Apr 2017 20:11:35 +0100 Subject: [PATCH] Make addon work without jQuery I'm trying to make easier to run ember apps without jquery. I'm preparing my addons to work without it to set an example, and my addons use this addon. --- addon/href-to.js | 25 +++++++++------ .../browser/ember-href-to.js | 32 +++++++++++++------ tests/acceptance/href-to-test.js | 26 +++++++++++---- tests/dummy/config/environment.js | 2 +- tests/integration/href-to-test.js | 4 +-- tests/unit/href-to-test.js | 8 ++--- 6 files changed, 64 insertions(+), 33 deletions(-) diff --git a/addon/href-to.js b/addon/href-to.js index 39adfc0..8d2b47f 100644 --- a/addon/href-to.js +++ b/addon/href-to.js @@ -2,11 +2,12 @@ import Em from 'ember'; export default class { - constructor(applicationInstance, event) { + constructor(applicationInstance, event, target = event.target) { this.applicationInstance = applicationInstance; this.event = event; - this.target = Em.$(event.currentTarget); - this.url = this.target.attr('href'); + this.target = target; + let hrefAttr = this.target.attributes.href; + this.url = hrefAttr && hrefAttr.value; } maybeHandle() { @@ -41,25 +42,29 @@ export default class { } hasNoTargetBlank() { - return this.target.attr('target') !== '_blank'; + let attr = this.target.attributes.target; + return !attr || attr.value !== '_blank'; } isNotIgnored() { - return Em.isNone(this.target.attr('data-href-to-ignore')); + return !this.target.attributes['data-href-to-ignore']; } hasNoActionHelper() { - return Em.isNone(this.target.attr('data-ember-action')); + return !this.target.attributes['data-ember-action']; } hasNoDownload() { - return this.target.attr('download') === undefined; + return !this.target.attributes.download; } isNotLinkComponent() { - let id = this.target[0].id; - let componentInstance = this._getContainer(this.applicationInstance).lookup('-view-registry:main')[id]; - let isLinkComponent = componentInstance ? componentInstance instanceof Em.LinkComponent : false; + let isLinkComponent = false; + let id = this.target.id; + if (id) { + let componentInstance = this._getContainer(this.applicationInstance).lookup('-view-registry:main')[id]; + isLinkComponent = componentInstance && componentInstance instanceof Em.LinkComponent; + } return !isLinkComponent; } diff --git a/app/instance-initializers/browser/ember-href-to.js b/app/instance-initializers/browser/ember-href-to.js index 63e7987..05674ed 100644 --- a/app/instance-initializers/browser/ember-href-to.js +++ b/app/instance-initializers/browser/ember-href-to.js @@ -1,17 +1,29 @@ import Em from 'ember'; import HrefTo from 'ember-href-to/href-to'; +let hrefToClickHandler; +function closestLink(el) { + if (el.closest) { + return el.closest('a'); + } else { + el = el.parentElement; + while (el.tagName !== 'A') { + el = el.parentElement; + } + return el; + } +} export default { name: 'ember-href-to', - initialize: function(applicationInstance) { - let $body = Em.$(document.body); - $body.off('click.href-to', 'a'); - - $body.on('click.href-to', 'a', (e) => { - let hrefTo = new HrefTo(applicationInstance, e); - hrefTo.maybeHandle(); - - return true; - }); + initialize(applicationInstance) { + document.body.removeEventListener('click', hrefToClickHandler); + hrefToClickHandler = function(e) { + let link = e.target.tagName === 'A' ? e.target : closestLink(e.target); + if (link) { + let hrefTo = new HrefTo(applicationInstance, e, link); + hrefTo.maybeHandle(); + } + } + document.body.addEventListener('click', hrefToClickHandler); } }; diff --git a/tests/acceptance/href-to-test.js b/tests/acceptance/href-to-test.js index 6941c55..aaca23d 100644 --- a/tests/acceptance/href-to-test.js +++ b/tests/acceptance/href-to-test.js @@ -1,4 +1,3 @@ -import Ember from 'ember'; import { test } from 'qunit'; import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; @@ -46,6 +45,14 @@ test('clicking a href-to with an inner element', function(assert) { }); }); +test('it doesn\'t affect clicking on elements outside links', function(assert) { + visit('/'); + leftClick('#href-to-links'); + andThen(function() { + assert.equal(currentURL(), '/'); + }); +}); + test('clicking an anchor which has no href', function(assert) { visit('/'); leftClick('#href-to-links a:contains(An anchor with no href)'); @@ -85,11 +92,18 @@ test('clicking an action works', function(assert) { test('clicking a href-to to should propagate events and prevent default ', function(assert) { visit('/'); andThen(function() { - let event = Ember.$.Event('click', { which: 1 }); - let element = findWithAssert('#href-to-links a:contains(About)'); - element.trigger(event); - assert.equal(event.isDefaultPrevented(), true, 'should prevent default'); - assert.equal(event.isPropagationStopped(), false, 'should not stop propagation'); + let event = new window.MouseEvent('click', { + 'view': window, + 'bubbles': true, + 'cancelable': true + }); + let element = findWithAssert('#href-to-links a:contains(About)')[0]; + let ancestor = document.querySelector('#href-to-links'); + ancestor.addEventListener('click', function(e) { + assert.equal(event, e, 'should not stop propagation'); + }); + element.dispatchEvent(event); + assert.equal(event.defaultPrevented, true, 'should prevent default'); }); }); diff --git a/tests/dummy/config/environment.js b/tests/dummy/config/environment.js index 2529939..42675b7 100644 --- a/tests/dummy/config/environment.js +++ b/tests/dummy/config/environment.js @@ -22,7 +22,7 @@ module.exports = function(environment) { if (environment === 'development') { // ENV.APP.LOG_RESOLVER = true; // ENV.APP.LOG_ACTIVE_GENERATION = true; - // ENV.APP.LOG_TRANSITIONS = true; + ENV.APP.LOG_TRANSITIONS = true; // ENV.APP.LOG_TRANSITIONS_INTERNAL = true; // ENV.APP.LOG_VIEW_LOOKUPS = true; } diff --git a/tests/integration/href-to-test.js b/tests/integration/href-to-test.js index af09c8c..877fb0c 100644 --- a/tests/integration/href-to-test.js +++ b/tests/integration/href-to-test.js @@ -14,7 +14,7 @@ test(`#isNotLinkComponent should be true if the event target is not an instance this.render(hbs`{{not-a-link class='not-a-link'}}`); let event = leftClickEvent(); - event.currentTarget = this.$('.not-a-link')[0]; + event.target = this.$('.not-a-link')[0]; let hrefTo = new HrefTo(this.container, event); assert.ok(hrefTo.isNotLinkComponent()); @@ -24,7 +24,7 @@ test(`#isNotLinkComponent should be false if the event target is an instance of this.render(hbs`{{a-link 'about' 'about' class='a-link'}}`); let event = leftClickEvent(); - event.currentTarget = this.$('.a-link')[0]; + event.target = this.$('.a-link')[0]; let hrefTo = new HrefTo(this.container, event); assert.notOk(hrefTo.isNotLinkComponent()); diff --git a/tests/unit/href-to-test.js b/tests/unit/href-to-test.js index fcae7ab..2d386fd 100644 --- a/tests/unit/href-to-test.js +++ b/tests/unit/href-to-test.js @@ -20,22 +20,22 @@ function leftClickEvent() { } function getClickEventOnEl(string) { - let el = $(string); + let el = $(string)[0]; let event = leftClickEvent(); - event.currentTarget = el; + event.target = el; return event; } test('#isUnmodifiedLeftClick should be true for left clicks', function(assert) { - let event = { which: 1, ctrlKey: false, metaKey: false }; + let event = { which: 1, ctrlKey: false, metaKey: false, target: { attributes: {} } }; let hrefTo = createHrefToForEvent(event); assert.ok(hrefTo.isUnmodifiedLeftClick()); }); test('#isUnmodifiedLeftClick should be false for right clicks', function(assert) { - let event = { which: 2, ctrlKey: false, metaKey: false }; + let event = { which: 2, ctrlKey: false, metaKey: false, target: { attributes: {} } }; let hrefTo = createHrefToForEvent(event); assert.notOk(hrefTo.isUnmodifiedLeftClick());