From 41262f42650cfbf8fdd494120817da30af9fb80f Mon Sep 17 00:00:00 2001 From: Pawel Kozlowski Date: Mon, 6 Apr 2015 21:45:54 +0200 Subject: [PATCH] feat(Ruler): introduce Ruler service Closes #1089 Closes #1253 --- modules/angular2/src/dom/browser_adapter.dart | 1 + modules/angular2/src/dom/browser_adapter.es6 | 7 ++- modules/angular2/src/dom/dom_adapter.js | 3 + modules/angular2/src/dom/parse5_adapter.cjs | 3 + modules/angular2/src/services/ruler.js | 34 +++++++++++ .../test/services/rectangle_mock.dart | 6 ++ .../angular2/test/services/rectangle_mock.es6 | 3 + modules/angular2/test/services/ruler_spec.js | 57 +++++++++++++++++++ 8 files changed, 112 insertions(+), 2 deletions(-) create mode 100644 modules/angular2/src/services/ruler.js create mode 100644 modules/angular2/test/services/rectangle_mock.dart create mode 100644 modules/angular2/test/services/rectangle_mock.es6 create mode 100644 modules/angular2/test/services/ruler_spec.js diff --git a/modules/angular2/src/dom/browser_adapter.dart b/modules/angular2/src/dom/browser_adapter.dart index 36e02d214e..ae948627de 100644 --- a/modules/angular2/src/dom/browser_adapter.dart +++ b/modules/angular2/src/dom/browser_adapter.dart @@ -176,6 +176,7 @@ class BrowserDomAdapter extends GenericBrowserDomAdapter { document.implementation.createHtmlDocument('fakeTitle'); HtmlDocument defaultDoc() => document; + Rectangle getBoundingClientRect(el) => el.getBoundingClientRect(); String getTitle() => document.title; void setTitle(String newTitle) { document.title = newTitle; diff --git a/modules/angular2/src/dom/browser_adapter.es6 b/modules/angular2/src/dom/browser_adapter.es6 index 69780016c5..5620d250fb 100644 --- a/modules/angular2/src/dom/browser_adapter.es6 +++ b/modules/angular2/src/dom/browser_adapter.es6 @@ -58,9 +58,9 @@ export class BrowserDomAdapter extends GenericBrowserDomAdapter { } content(node:HTMLElement):Node { if (this.hasProperty(node, "content")) { - return node.content; + return node.content; } else { - return node; + return node; } } firstChild(el):Node { @@ -228,6 +228,9 @@ export class BrowserDomAdapter extends GenericBrowserDomAdapter { defaultDoc() { return document; } + getBoundingClientRect(el) { + return el.getBoundingClientRect(); + } getTitle() { return document.title; } diff --git a/modules/angular2/src/dom/dom_adapter.js b/modules/angular2/src/dom/dom_adapter.js index f799b9a532..17906bed44 100644 --- a/modules/angular2/src/dom/dom_adapter.js +++ b/modules/angular2/src/dom/dom_adapter.js @@ -210,6 +210,9 @@ export class DomAdapter { defaultDoc() { throw _abstract(); } + getBoundingClientRect(el) { + throw _abstract(); + } getTitle() { throw _abstract(); } diff --git a/modules/angular2/src/dom/parse5_adapter.cjs b/modules/angular2/src/dom/parse5_adapter.cjs index c209ae7146..83a8e78b57 100644 --- a/modules/angular2/src/dom/parse5_adapter.cjs +++ b/modules/angular2/src/dom/parse5_adapter.cjs @@ -377,6 +377,9 @@ export class Parse5DomAdapter extends DomAdapter { } return defDoc; } + getBoundingClientRect(el) { + return {left: 0, top: 0, width: 0, height: 0}; + } getTitle() { return this.defaultDoc().title || ""; } diff --git a/modules/angular2/src/services/ruler.js b/modules/angular2/src/services/ruler.js new file mode 100644 index 0000000000..8d14b4f175 --- /dev/null +++ b/modules/angular2/src/services/ruler.js @@ -0,0 +1,34 @@ +import {Promise, PromiseWrapper} from 'angular2/src/facade/async'; +import {DomAdapter} from 'angular2/src/dom/dom_adapter'; +import {NgElement} from 'angular2/src/core/dom/element'; + +export class Rectangle { + left; + right; + top; + bottom; + height; + width; + constructor(left, top, width, height) { + this.left = left; + this.right = left + width; + this.top = top; + this.bottom = top + height; + this.height = height; + this.width = width; + } +} + +export class Ruler { + domAdapter: DomAdapter; + constructor(domAdapter: DomAdapter) { + this.domAdapter = domAdapter; + } + + measure(el:NgElement): Promise { + var clntRect = this.domAdapter.getBoundingClientRect(el.domElement); + + //even if getBoundingClientRect is synchronous we use async API in preparation for further changes + return PromiseWrapper.resolve(new Rectangle(clntRect.left, clntRect.top, clntRect.width, clntRect.height)); + } +} diff --git a/modules/angular2/test/services/rectangle_mock.dart b/modules/angular2/test/services/rectangle_mock.dart new file mode 100644 index 0000000000..fca577c569 --- /dev/null +++ b/modules/angular2/test/services/rectangle_mock.dart @@ -0,0 +1,6 @@ +import 'dart:html'; + +Rectangle createRectangle(left, top, width, height) { + return new Rectangle(left, top, width, height); +} + diff --git a/modules/angular2/test/services/rectangle_mock.es6 b/modules/angular2/test/services/rectangle_mock.es6 new file mode 100644 index 0000000000..c8a8a3140a --- /dev/null +++ b/modules/angular2/test/services/rectangle_mock.es6 @@ -0,0 +1,3 @@ +export function createRectangle(left, top, width, height) { + return {left, top, width, height}; +} diff --git a/modules/angular2/test/services/ruler_spec.js b/modules/angular2/test/services/ruler_spec.js new file mode 100644 index 0000000000..ffb62efb67 --- /dev/null +++ b/modules/angular2/test/services/ruler_spec.js @@ -0,0 +1,57 @@ +import {AsyncTestCompleter, inject, ddescribe, describe, it, iit, xit, expect, SpyObject} from 'angular2/test_lib'; + +import {DOM, DomAdapter} from 'angular2/src/dom/dom_adapter'; +import {NgElement} from 'angular2/src/core/dom/element'; + +import {Ruler, Rectangle} from 'angular2/src/services/ruler'; +import {createRectangle} from './rectangle_mock'; + +class DomAdapterMock extends DomAdapter { + rect; + constructor(rect) { + super(); + this.rect = rect; + } + + getBoundingClientRect(elm) { + return this.rect; + } +} + +function assertDimensions(rect: Rectangle, left, right, top, bottom, width, height) { + expect(rect.left).toEqual(left); + expect(rect.right).toEqual(right); + expect(rect.top).toEqual(top); + expect(rect.bottom).toEqual(bottom); + expect(rect.width).toEqual(width); + expect(rect.height).toEqual(height); +} + +export function main() { + + describe('ruler service', () => { + + it('should allow measuring NgElements', + inject([AsyncTestCompleter], (async) => { + var ruler = new Ruler(new DomAdapterMock(createRectangle(10, 20, 200, 100))); + + ruler.measure(new NgElement(null)).then((rect) => { + assertDimensions(rect, 10, 210, 20, 120, 200, 100); + async.done(); + }); + })); + + + it('should return 0 for all rectangle values while measuring elements in a document fragment', + inject([AsyncTestCompleter], (async) => { + var ruler = new Ruler(DOM); + + ruler.measure(new NgElement(DOM.createElement('div'))).then((rect) => { + //here we are using an element created in a doc fragment so all the measures will come back as 0 + assertDimensions(rect, 0, 0, 0, 0, 0, 0); + async.done(); + }); + })); + + }); +}