In this example, a Single HTML source is used for various injections.
@@ -62,86 +63,94 @@ -diff --git a/CHANGES.md b/CHANGES.md index ed514500f..836ae18ea 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,6 +5,7 @@ Features ~~~~~~~~ +- Add ``utils.getCSSValue`` for retrieving CSS property values for DOM nodes. - Add configurable scrolling behavior to pat-inject. - Add ``webpack-visualizer-plugin`` for analyzation of generated bundles. - Add ``pat-fullscreen`` pattern to allow any element to be displayed in fullscreen-mode. @@ -13,6 +14,7 @@ Features - Integrated pat-display-time from https://github.com/ploneintranet/pat-display-time - Fixed an issue with pat-scroll when placed on an item without a href - Fixed an issue with pat-autofocus that would set focus on hidden items +- Fixed an issue with pat-inject scroll that would scroll too much (#694) Fixes ~~~~~ diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 35de78b31..44efc0919 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -8202,9 +8202,9 @@ } }, "moment": { - "version": "2.23.0", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.23.0.tgz", - "integrity": "sha512-3IE39bHVqFbWWaPOMHZF98Q9c3LDKGTmypMiTM2QygGXXElkFWIH7GxfmlwmY2vwa+wmNsoYZmG2iusf1ZjJoA==" + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", + "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" }, "moment-timezone": { "version": "0.5.13", diff --git a/package.json b/package.json index e94781db3..fe0c0eae3 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "logging": "https://github.com/Patternslib/logging.git", "masonry-layout": "4.2.0", "modernizr": "^3.7.1", - "moment": "2.23.0", + "moment": "2.24.0", "moment-timezone": "0.5.13", "parsleyjs": "2.7.2", "photoswipe": "4.1.3", diff --git a/src/core/utils.js b/src/core/utils.js index c5b2cb05c..bc65031a1 100644 --- a/src/core/utils.js +++ b/src/core/utils.js @@ -459,6 +459,17 @@ define([ return $relatives; } + function getCSSValue(el, property, asFloat) { + /* Return a CSS property value for a given DOM node. + * Optionally parse as float. + */ + var value = window.getComputedStyle(el).getPropertyValue(property); + if (asFloat) { + value = parseFloat(value) || 0.0; + } + return value; + } + var utils = { // pattern pimping - own module? jqueryPlugin: jqueryPlugin, @@ -477,8 +488,8 @@ define([ isElementInViewport: isElementInViewport, hasValue: hasValue, parseTime: parseTime, - findRelatives: findRelatives - + findRelatives: findRelatives, + getCSSValue: getCSSValue }; return utils; }); diff --git a/src/pat/inject/index.html b/src/pat/inject/index.html index 253162271..814a4470b 100644 --- a/src/pat/inject/index.html +++ b/src/pat/inject/index.html @@ -11,7 +11,8 @@
-In this example, a Single HTML source is used for various injections.
@@ -62,86 +63,94 @@ -- ? -
-- ? -
-- ? -
-+ ? +
++ ? +
++ ? +
+
- <a href="inject-text.html" class="pat-inject" data-pat-inject="scroll:#scroll-target">
+ <a href="index.html" class="pat-inject" data-pat-inject="scroll:#demo-history">
- <a href="inject-sources.html" class="pat-inject" data-pat-inject="target:#pos-4; scroll: #dieu-nu-p-1">
+ <a href="index.html" class="pat-inject" data-pat-inject="scroll:top">
- <a href="index.html" class="pat-inject" data-pat-inject="scroll:#demo-history">
+ <a href="inject-text.html" class="pat-inject" data-pat-inject="scroll:#scroll-target">
- <a href="index.html" class="pat-inject" data-pat-inject="scroll:top">
+ <a href="inject-text.html#pos-4" class="pat-inject" data-pat-inject="scroll:target">
- <a href="inject-text.html#pos-4" class="pat-inject" data-pat-inject="scroll:target">
+ <a href="inject-text.html" class="pat-inject" data-pat-inject="scroll:none">
- <a href="inject-text.html" class="pat-inject" data-pat-inject="scroll:none">
+ <a href="inject-sources.html#pos-3" class="pat-inject" data-pat-inject="target:#pos-4; scroll: #dieu-nu-p-1">
+
+
+ <a href="inject-sources.html" class="pat-inject" data-pat-inject="target:#pos-4; scroll: #pos-2">
- ? -
-- ? -
-+ ? +
++ ? +
+Inject some text and record the history
here goes the injection
-diff --git a/src/pat/inject/inject.js b/src/pat/inject/inject.js index d93d1ddb2..174819e67 100644 --- a/src/pat/inject/inject.js +++ b/src/pat/inject/inject.js @@ -489,14 +489,60 @@ define([ if (cfg.scroll && cfg.scroll !== 'none') { - if (cfg.scroll === 'top') { - var scroll_container = $(cfg.target).parents().addBack().filter(':scrollable'); - scroll_container = scroll_container.length ? scroll_container : $(window); - scroll_container[0].scrollTo(0, 0); - } else if (cfg.scroll === 'target') { - $(cfg.target)[0].scrollIntoView(); + var scroll_container = cfg.$target.parents().addBack().filter(':scrollable'); + scroll_container = scroll_container.length ? scroll_container[0] : window; + + // default for scroll===top + var top = 0; + var left = 0; + + if (cfg.scroll !== 'top') { + var scroll_target; + if (cfg.scroll === 'target') { + scroll_target = cfg.$target[0]; + } else { + scroll_target = $injected.filter(cfg.scroll)[0]; + } + + // Get the reference element to which against we calculate + // the relative position of the target. + // In case of a scroll container of window, we do not have + // getBoundingClientRect method, so get the body instead. + var scroll_container_ref = scroll_container; + if (scroll_container_ref === window) { + scroll_container_ref = document.body; + } + + // Calculate absolute [¹] position difference between + // scroll_container and scroll_target. + // Substract the container's border from the scrolling + // value, as this one isn't respected by + // getBoundingClientRect [²] and would lead to covered + // items [³]. + // ¹) so that it doesn't make a difference, if the element + // is below or above the scrolling container. We just need + // to know the absolute difference. + // ²) Calculations are based from the viewport. + // ³) See: + // https://docs.microsoft.com/en-us/previous-versions//hh781509(v=vs.85) + // https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect + left = Math.abs( + scroll_target.getBoundingClientRect().left + - scroll_container_ref.getBoundingClientRect().left + - utils.getCSSValue(scroll_container, 'border-left', true) + ); + top = Math.abs( + scroll_target.getBoundingClientRect().top + - scroll_container_ref.getBoundingClientRect().top + - utils.getCSSValue(scroll_container, 'border-top', true) + ); + + } + if (scroll_container === window) { + scroll_container.scrollTo(left, top); } else { - $(cfg.scroll)[0].scrollIntoView(); + scroll_container.scrollLeft = left; + scroll_container.scrollTop = top; } } diff --git a/tests/specs/core/utils.js b/tests/specs/core/utils.js index 0ee831b43..7d46a2c77 100644 --- a/tests/specs/core/utils.js +++ b/tests/specs/core/utils.js @@ -265,7 +265,7 @@ define(["underscore", "pat-utils"], function(_, utils) { setTimeout(function () { expect($slave[0].style.display).toBe("none"); expect(Array.prototype.slice.call($slave[0].classList)).toEqual(["hidden"]); - + }, 500); }); @@ -280,7 +280,7 @@ define(["underscore", "pat-utils"], function(_, utils) { "pat-update", {pattern: "depends", transition: "start"}); expect($.fn.trigger).toHaveBeenCalledWith( "pat-update", {pattern: "depends", transition: "complete"}); - + }, 500); }); @@ -363,4 +363,34 @@ define(["underscore", "pat-utils"], function(_, utils) { expect(utils.parseTime("1000w")).toBe(1000); }); }); + + describe("getCSSValue", function() { + it("returns values for properties of a html node", function() { + + var el1 = document.createElement('div'); + var el2 = document.createElement('div'); + + // Need to attach element to body to make CSS calculation work. + document.body.appendChild(el1); + + el1.style['font-size'] = '12px'; + el1.style['margin-top'] = '26px'; + el1.style.position = 'relative'; + + el2.style['margin-bottom'] = '10px'; + + el1.appendChild(el2); + + expect(utils.getCSSValue(el1, 'font-size')).toBe('12px'); + expect(utils.getCSSValue(el1, 'font-size', true)).toBe(12.0); + expect(utils.getCSSValue(el2, 'font-size')).toBe('12px'); + + expect(utils.getCSSValue(el1, 'position')).toBe('relative'); + + expect(utils.getCSSValue(el1, 'margin-top', true)).toBe(26.0); + expect(utils.getCSSValue(el2, 'margin-top', true)).toBe(0.0); + expect(utils.getCSSValue(el2, 'margin-bottom', true)).toBe(10.0); + + }); + }); });