Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Added enyo.dom.calcViewportPositionForNode helper function #185

Merged
merged 3 commits into from

2 participants

@onecrayon

Here's my calcViewportPositionForNode addition to enyo.dom, as per the discussion here:

https://groups.google.com/d/topic/enyo-development/S-eY8HNLktU/discussion

Although my use-case for this is pretty specific to my particular app, the function seemed generically useful enough to be worth submitting to Enyo core for consideration.

@onecrayon onecrayon Added enyo.dom.calcViewportPositionForNode as a helper function for l…
…ocating nodes within the viewport (to absolutely position a floating Popup near a particular DOM element, for instance)

Enyo-DCO-1.1-Signed-off-by: Ian Beck <ian@onecrayon.com>
72e6599
@unwiredben

Any chance you want to write a test case for this to put into \enyo\tools\test\core\tests? Without it being used elsewhere in core, I'd be afraid it could break without us knowing it.

onecrayon added some commits
@onecrayon onecrayon Modified viewport measuring logic to ensure that it works regardless …
…of whether body element is 100% height/width or has margins

Added enyo.dom.getWindowHeight to compliment getWindowWidth
Enyo-DCO-1.1-Signed-off-by: Ian Beck <ian@onecrayon.com>
5fc8cdc
@onecrayon onecrayon Added test suite for relative viewport position measuring method in e…
…nyo.dom

Enyo-DCO-1.1-Signed-off-by: Ian Beck <ian@onecrayon.com>
b741947
@onecrayon

I totally spaced on the request for a test case for some reason, but now here it is! Good thing you had me write that, too, since it caused me to discover an oversight in the measurement logic for pages where the body is not 100% width/height without a scrollbar. :-)

@unwiredben

Yeah, I find writing tests helps me find corner cases a lot easier than just fixing a problem.

@unwiredben unwiredben merged commit 37b1a0c into from
@unwiredben unwiredben commented on the diff
source/dom/dom.js
@@ -124,5 +138,38 @@ enyo.dom = {
//* Gets the calculated margin of a node.
calcMarginExtents: function(inNode) {
return this.calcBoxExtents(inNode, "margin");
+ },
+ //* Returns an object like `{top: 0, left: 0, bottom: 100, right: 100, height: 10, width: 10}` that represents the object's position within the viewport. Negative values mean part of the object is not visible.
+ calcViewportPositionForNode: function(inNode) {
+ // Parse upward and grab our positioning relative to the viewport
+ var left = top = 0,

just fixed a bug here in master, but wanted to point it out to you -- this doesn't declare a local variable named top, but instead uses a global named top.

Thanks for the FYI! I'm frankly unsure why I used that pattern at all; normally I separate everything into its own comma-delimited assignment. Good to know that the habit has a purpose behind it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Nov 29, 2012
  1. @onecrayon

    Added enyo.dom.calcViewportPositionForNode as a helper function for l…

    onecrayon authored
    …ocating nodes within the viewport (to absolutely position a floating Popup near a particular DOM element, for instance)
    
    Enyo-DCO-1.1-Signed-off-by: Ian Beck <ian@onecrayon.com>
Commits on Dec 12, 2012
  1. @onecrayon

    Modified viewport measuring logic to ensure that it works regardless …

    onecrayon authored
    …of whether body element is 100% height/width or has margins
    
    Added enyo.dom.getWindowHeight to compliment getWindowWidth
    Enyo-DCO-1.1-Signed-off-by: Ian Beck <ian@onecrayon.com>
  2. @onecrayon

    Added test suite for relative viewport position measuring method in e…

    onecrayon authored
    …nyo.dom
    
    Enyo-DCO-1.1-Signed-off-by: Ian Beck <ian@onecrayon.com>
This page is out of date. Refresh to see the latest.
View
47 source/dom/dom.js
@@ -69,6 +69,20 @@ enyo.dom = {
}
return 320;
},
+ getWindowHeight: function() {
+ if (window.innerHeight) {
+ return window.innerHeight;
+ }
+ if (document.body && document.body.offsetHeight) {
+ return document.body.offsetHeight;
+ }
+ if (document.compatMode=='CSS1Compat' &&
+ document.documentElement &&
+ document.documentElement.offsetHeight ) {
+ return document.documentElement.offsetHeight;
+ }
+ return 480;
+ },
// moved from FittableLayout.js into common protected code
_ieCssToPixelValue: function(inNode, inValue) {
var v = inValue;
@@ -124,5 +138,38 @@ enyo.dom = {
//* Gets the calculated margin of a node.
calcMarginExtents: function(inNode) {
return this.calcBoxExtents(inNode, "margin");
+ },
+ //* Returns an object like `{top: 0, left: 0, bottom: 100, right: 100, height: 10, width: 10}` that represents the object's position within the viewport. Negative values mean part of the object is not visible.
+ calcViewportPositionForNode: function(inNode) {
+ // Parse upward and grab our positioning relative to the viewport
+ var left = top = 0,

just fixed a bug here in master, but wanted to point it out to you -- this doesn't declare a local variable named top, but instead uses a global named top.

Thanks for the FYI! I'm frankly unsure why I used that pattern at all; normally I separate everything into its own comma-delimited assignment. Good to know that the habit has a purpose behind it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ node = inNode,
+ width = node.offsetWidth,
+ height = node.offsetHeight,
+ docHeight = (document.body.parentNode.offsetHeight > this.getWindowHeight() ? this.getWindowHeight() - document.body.parentNode.scrollTop : document.body.parentNode.offsetHeight),
+ docWidth = (document.body.parentNode.offsetWidth > this.getWindowWidth() ? this.getWindowWidth() - document.body.parentNode.scrollLeft : document.body.parentNode.offsetWidth),
+ transformProp = enyo.dom.getStyleTransformProp(),
+ xregex = /translateX\((-?\d+)px\)/i,
+ yregex = /translateY\((-?\d+)px\)/i;
+ if (node.offsetParent) {
+ do {
+ left += node.offsetLeft - (node.offsetParent ? node.offsetParent.scrollLeft : 0);
+ if (transformProp && xregex.test(node.style[transformProp])) {
+ left += parseInt(node.style[transformProp].replace(xregex, '$1'));
+ }
+ top += node.offsetTop - (node.offsetParent ? node.offsetParent.scrollTop : 0);
+ if (transformProp && yregex.test(node.style[transformProp])) {
+ top += parseInt(node.style[transformProp].replace(yregex, '$1'));
+ }
+ } while (node = node.offsetParent);
+ }
+ return {
+ 'top': top,
+ 'left': left,
+ 'bottom': docHeight - top - height,
+ 'right': docWidth - left - width,
+ 'height': height,
+ 'width': width
+ };
}
};
View
53 tools/test/core/tests/ViewportPositioningTest.js
@@ -0,0 +1,53 @@
+enyo.kind({
+ name: "ViewportPositioningTest",
+ kind: enyo.TestSuite,
+
+ testMeasuringViewportCoordinates: function() {
+ var K = enyo.kind({
+ kind: enyo.Control,
+ style: "position: absolute; top: 10px; left: 10px; width: 10px; height: 10px;"
+ });
+
+ // Similar to ControlTest, create a testing div to test DOM information with (delete at end)
+ var div = document.createElement("div");
+ document.body.appendChild(div);
+ // Apply fixed positioning so that we know where things should be relative to the viewport
+ div.style.position = 'fixed';
+ div.style.top = '0px';
+ div.style.left = '0px';
+ div.style.width = '100%';
+ div.style.height = '100%';
+
+ var k = new K();
+ k.renderInto(div);
+
+ var p = enyo.dom.calcViewportPositionForNode(k.hasNode()),
+ // Bottom and right require calculating viewport size
+ fromBottom = (document.body.parentNode.offsetHeight > enyo.dom.getWindowHeight() ? enyo.dom.getWindowHeight() - document.body.parentNode.scrollTop : document.body.parentNode.offsetHeight) - 20,
+ fromRight = (document.body.parentNode.offsetWidth > enyo.dom.getWindowWidth() ? enyo.dom.getWindowWidth() - document.body.parentNode.scrollLeft : document.body.parentNode.offsetWidth) - 20;
+ if (p.top !== 10) {
+ this.log('top failed with value: ' + p.top + ' (should be 10)');
+ }
+ if (p.left !== 10) {
+ this.log('left failed with value: ' + p.left + ' (should be 10)');
+ }
+ if (p.bottom !== fromBottom) {
+ this.log('bottom measurement failed with value: ' + p.bottom + ' (should be ' + fromBottom + ')');
+ }
+ if (p.right !== fromRight) {
+ this.log('right measurement failed with value: ' + p.right + ' (should be ' + fromRight + ')');
+ }
+ if (p.width !== 10) {
+ this.log('width failed with value: ' + p.width + ' (should be 10)');
+ }
+ if (p.height !== 10) {
+ this.log('height failed with value: ' + p.height + ' (should be 10)');
+ }
+
+ // Clean up
+ k.destroy();
+ document.body.removeChild(div);
+
+ this.finish(this.logMessages && this.logMessages.length ? 'Following measurements failed:' : '');
+ }
+});
View
3  tools/test/core/tests/package.js
@@ -10,5 +10,6 @@ enyo.depends(
"ControlTest.js",
"ControlPropsTest.js",
"DecodePackagePathTest.js",
- "PathResolverTest.js"
+ "PathResolverTest.js",
+ "ViewportPositioningTest.js"
);
Something went wrong with that request. Please try again.