ui: Adds `document` and `viewport` methods to the dom service (#5052)

`window` and `document` are easily injected anyhow, but this
primarily this keeps everything dom related in the same place.

Included here are changes to make all ember related objects use the dom
service `document` and `viewport` instead of just `document` and
`window`.

Quote from a previous PR (#4924) which explains the thinking around this:

> Now I have all these things in the dom service, it would make sense
to get window from there also. I was thinking of making a viewport
method, which would be a nice word whether window was a browser window,
an iframe (not really a window) like when ember testing, or anything
else. To me the viewport is what we are actually talking about here.
This commit is contained in:
John Cowen 2018-12-05 09:07:16 +00:00 committed by John Cowen
parent 9a27b2c74d
commit c4effc9734
5 changed files with 35 additions and 13 deletions

View File

@ -3,8 +3,6 @@ import { get, set } from '@ember/object';
import { inject as service } from '@ember/service';
export default Component.extend({
dom: service('dom'),
// TODO: could this be dom.viewport() ?
win: window,
isDropdownVisible: false,
didInsertElement: function() {
get(this, 'dom')
@ -19,11 +17,12 @@ export default Component.extend({
},
change: function(e) {
const dom = get(this, 'dom');
const win = dom.viewport();
const $root = dom.root();
const $body = dom.element('body');
if (e.target.checked) {
$root.classList.add('template-with-vertical-menu');
$body.style.height = $root.style.height = get(this, 'win').innerHeight + 'px';
$body.style.height = $root.style.height = win.innerHeight + 'px';
} else {
$root.classList.remove('template-with-vertical-menu');
$body.style.height = $root.style.height = null;

View File

@ -1,16 +1,19 @@
import Mixin from '@ember/object/mixin';
import { inject as service } from '@ember/service';
import { next } from '@ember/runloop';
import { get } from '@ember/object';
const isOutside = function(element, e) {
// TODO: Potentially move this to dom service
const isOutside = function(element, e, doc = document) {
if (element) {
const isRemoved = !e.target || !document.contains(e.target);
const isRemoved = !e.target || !doc.contains(e.target);
const isInside = element === e.target || element.contains(e.target);
return !isRemoved && !isInside;
} else {
return false;
}
};
const handler = function(e) {
const el = get(this, 'element');
if (isOutside(el, e)) {
@ -18,6 +21,7 @@ const handler = function(e) {
}
};
export default Mixin.create({
dom: service('dom'),
init: function() {
this._super(...arguments);
this.handler = handler.bind(this);
@ -26,12 +30,14 @@ export default Mixin.create({
onblur: function() {},
didInsertElement: function() {
this._super(...arguments);
const doc = get(this, 'dom').document();
next(this, () => {
document.addEventListener('click', this.handler);
doc.addEventListener('click', this.handler);
});
},
willDestroyElement: function() {
this._super(...arguments);
document.removeEventListener('click', this.handler);
const doc = get(this, 'dom').document();
doc.removeEventListener('click', this.handler);
},
});

View File

@ -1,11 +1,12 @@
import Mixin from '@ember/object/mixin';
import { inject as service } from '@ember/service';
import { get } from '@ember/object';
import { assert } from '@ember/debug';
export default Mixin.create({
dom: service('dom'),
resize: function(e) {
assert('with-resizing.resize needs to be overridden', false);
},
win: window,
init: function() {
this._super(...arguments);
this.handler = e => {
@ -17,14 +18,18 @@ export default Mixin.create({
},
didInsertElement: function() {
this._super(...arguments);
get(this, 'win').addEventListener('resize', this.handler, false);
get(this, 'dom')
.viewport()
.addEventListener('resize', this.handler, false);
this.didAppear();
},
didAppear: function() {
this.handler({ target: get(this, 'win') });
this.handler({ target: get(this, 'dom').viewport() });
},
willDestroyElement: function() {
get(this, 'win').removeEventListener('resize', this.handler, false);
get(this, 'dom')
.viewport()
.removeEventListener('resize', this.handler, false);
this._super(...arguments);
},
});

View File

@ -23,10 +23,17 @@ let $_;
const clickFirstAnchor = clickFirstAnchorFactory(closest);
export default Service.extend({
doc: document,
win: window,
init: function() {
this._super(...arguments);
$_ = getComponentFactory(getOwner(this));
},
document: function() {
return get(this, 'doc');
},
viewport: function() {
return get(this, 'win');
},
// TODO: should this be here? Needs a better name at least
clickFirstAnchor: clickFirstAnchor,
closest: closest,

View File

@ -12,8 +12,13 @@ module('Integration | Mixin | with-resizing', function(hooks) {
addEventListener: this.stub(),
removeEventListener: this.stub(),
};
const dom = {
viewport: function() {
return win;
},
};
const subject = EmberObject.extend(Mixin, {
win: win,
dom: dom,
}).create();
const resize = this.stub(subject, 'resize');
subject.didInsertElement();