@cocreate/scroll
Advanced tools
@@ -25,9 +25,9 @@ name: Automated Workflow | ||
| - name: Checkout | ||
| uses: actions/checkout@v3 | ||
| uses: actions/checkout@v4 | ||
| - name: Setup Node.js | ||
| uses: actions/setup-node@v3 | ||
| uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: 14 | ||
| node-version: 22 # Required for the latest semantic-release plugins | ||
| - name: Semantic Release | ||
| uses: cycjimmy/semantic-release-action@v3 | ||
| uses: cycjimmy/semantic-release-action@v4 # Update to v4 for better Node 20+ support | ||
| id: semantic | ||
@@ -40,3 +40,3 @@ with: | ||
| env: | ||
| GITHUB_TOKEN: "${{ secrets.GITHUB }}" | ||
| GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" # Use the built-in token if possible | ||
| NPM_TOKEN: "${{ secrets.NPM_TOKEN }}" | ||
@@ -46,2 +46,1 @@ outputs: | ||
| new_release_version: "${{ steps.semantic.outputs.new_release_version }}" | ||
+12
-0
@@ -0,1 +1,13 @@ | ||
| # [1.14.0](https://github.com/CoCreate-app/CoCreate-scroll/compare/v1.13.4...v1.14.0) (2026-01-15) | ||
| ### Bug Fixes | ||
| * update worklow ([ac9e74a](https://github.com/CoCreate-app/CoCreate-scroll/commit/ac9e74a15fd8c7d27dc5809130ea0ee99c46777f)) | ||
| ### Features | ||
| * comprehensive initalization of ([cecbfce](https://github.com/CoCreate-app/CoCreate-scroll/commit/cecbfcec1d9d7f34b9d4a339d5e5ed3e8f38c363)) | ||
| ## [1.13.4](https://github.com/CoCreate-app/CoCreate-scroll/compare/v1.13.3...v1.13.4) (2025-09-07) | ||
@@ -2,0 +14,0 @@ |
+1
-1
| { | ||
| "name": "@cocreate/scroll", | ||
| "version": "1.13.4", | ||
| "version": "1.14.0", | ||
| "description": "A simple scroll component in vanilla javascript. Easily configured using HTML5 attributes and/or JavaScript API.", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
+313
-287
| import Observer from "@cocreate/observer"; | ||
| import Actions from "@cocreate/actions"; | ||
| const selector = | ||
| "[scroll], [scroll-to], [scrollable-x], [scrollable-y], [scroll-up], [scroll-down], [scroll-top], [scroll-bottom], [scroll-limbo], [scroll-intersect], [scrolling]"; | ||
| const CoCreateScroll = { | ||
| delta: 3, | ||
| observer: null, | ||
| timer: null, | ||
| firedEvents: new Map(), | ||
| delta: 3, | ||
| observer: null, | ||
| // timer: null, // Removed: Timer needs to be instance-specific, not global | ||
| firedEvents: new Map(), | ||
| init: function () { | ||
| let elements = document.querySelectorAll( | ||
| `[scroll], [scroll-to], [scrollable-x], [scrollable-y]` | ||
| ); | ||
| this.__initIntersectionObserver(); | ||
| this.initElements(elements); | ||
| }, | ||
| init: function () { | ||
| let elements = document.querySelectorAll(selector); | ||
| this.__initIntersectionObserver(); | ||
| this.initElements(elements); | ||
| }, | ||
| initElements: function (elements) { | ||
| for (let el of elements) this.initElement(el); | ||
| }, | ||
| initElements: function (elements) { | ||
| for (let el of elements) this.initElement(el); | ||
| }, | ||
| initElement: function (element) { | ||
| const self = this; | ||
| const upSize = this.__getSize(element.getAttribute("scroll-up")); | ||
| const downSize = this.__getSize(element.getAttribute("scroll-down")); | ||
| const attrName = element.getAttribute("scroll-attribute") || "class"; | ||
| const targetSelector = element.getAttribute("scroll-query"); | ||
| const scrollSelector = element.getAttribute("scroll-element"); | ||
| const intersectValue = element.getAttribute("scroll-intersect"); | ||
| const scrollTo = element.getAttribute("scroll-to"); | ||
| initElement: function (element) { | ||
| const self = this; | ||
| const upSize = this.__getSize(element.getAttribute("scroll-up")); | ||
| const downSize = this.__getSize(element.getAttribute("scroll-down")); | ||
| const attrName = element.getAttribute("scroll-attribute") || "class"; | ||
| const targetSelector = element.getAttribute("scroll-query"); | ||
| const scrollSelector = element.getAttribute("scroll-element"); | ||
| const intersectValue = element.getAttribute("scroll-intersect"); | ||
| const scrollTo = element.getAttribute("scroll-to"); | ||
| updateScrollableAttributes(element); | ||
| updateScrollableAttributes(element); | ||
| let values = | ||
| element.getAttribute("scroll") || | ||
| element.getAttribute("scroll-value"); | ||
| if (values || values === "") | ||
| values = values.split(",").map((x) => x.trim()); | ||
| let values = | ||
| element.getAttribute("scroll") || | ||
| element.getAttribute("scroll-value"); | ||
| if (values || values === "") | ||
| values = values.split(",").map((x) => x.trim()); | ||
| let scrollInfo = { | ||
| attrName: attrName, | ||
| values: values, | ||
| upSize: upSize, | ||
| downSize: downSize, | ||
| scrollTop: element.getAttribute("scroll-top"), | ||
| scrollLimbo: element.getAttribute("scroll-limbo"), | ||
| scrollBottom: element.getAttribute("scroll-bottom"), | ||
| scrolling: element.getAttribute("scrolling"), | ||
| scrollTo | ||
| }; | ||
| let scrollInfo = { | ||
| attrName: attrName, | ||
| values: values, | ||
| upSize: upSize, | ||
| downSize: downSize, | ||
| scrollTop: element.getAttribute("scroll-top"), | ||
| scrollLimbo: element.getAttribute("scroll-limbo"), | ||
| scrollBottom: element.getAttribute("scroll-bottom"), | ||
| scrolling: element.getAttribute("scrolling"), | ||
| scrollTo, | ||
| timer: null // Added: Store timer here to persist across events | ||
| }; | ||
| let elements = [element]; | ||
| if (targetSelector) { | ||
| elements = document.querySelectorAll(targetSelector); | ||
| } | ||
| let elements = [element]; | ||
| if (targetSelector) { | ||
| elements = document.querySelectorAll(targetSelector); | ||
| } | ||
| elements.forEach((el) => { | ||
| el.scrollStatus = { currentPos: 0 }; | ||
| }); | ||
| elements.forEach((el) => { | ||
| el.scrollStatus = { currentPos: 0 }; | ||
| }); | ||
| // this.__runScrollEvent(element, scrollInfo); | ||
| // this.__runScrollEvent(element, scrollInfo); | ||
| let scrollableElements; | ||
| if (scrollSelector) | ||
| scrollableElements = document.querySelectorAll(scrollSelector); | ||
| else if (element.hasAttribute("scroll-element")) | ||
| scrollableElements = [element]; | ||
| let scrollableElements; | ||
| if (scrollSelector) | ||
| scrollableElements = document.querySelectorAll(scrollSelector); | ||
| else if (element.hasAttribute("scroll-element")) | ||
| scrollableElements = [element]; | ||
| if (scrollableElements) { | ||
| for (let scrollableEl of scrollableElements) { | ||
| scrollableEl.addEventListener("scroll", function (event) { | ||
| self._scrollEvent( | ||
| elements, | ||
| element, | ||
| scrollInfo, | ||
| scrollableEl | ||
| ); | ||
| }); | ||
| } | ||
| } else { | ||
| // this.WindowInit = true; | ||
| window.addEventListener("scroll", function (event) { | ||
| self._scrollEvent(elements, element, scrollInfo); | ||
| }); | ||
| } | ||
| if (scrollableElements) { | ||
| for (let scrollableEl of scrollableElements) { | ||
| scrollableEl.addEventListener("scroll", function (event) { | ||
| self._scrollEvent( | ||
| elements, | ||
| element, | ||
| scrollInfo, | ||
| scrollableEl | ||
| ); | ||
| }); | ||
| } | ||
| } else { | ||
| // this.WindowInit = true; | ||
| window.addEventListener("scroll", function (event) { | ||
| self._scrollEvent(elements, element, scrollInfo); | ||
| }); | ||
| } | ||
| if (intersectValue && window.IntersectionObserver && this.observer) { | ||
| this.observer.observe(element); | ||
| } | ||
| if (intersectValue && window.IntersectionObserver && this.observer) { | ||
| this.observer.observe(element); | ||
| } | ||
| if (scrollTo) { | ||
| this.setScrollPosition(element, scrollTo); | ||
| } | ||
| }, | ||
| if (scrollTo) { | ||
| this.setScrollPosition(element, scrollTo); | ||
| } | ||
| }, | ||
| _scrollEvent: function (elements, element, scrollInfo, scrollableEl) { | ||
| const self = this; | ||
| if (!element.scrollStatus) return; | ||
| let scrollEl = scrollableEl || window; | ||
| if ( | ||
| Math.abs( | ||
| scrollEl.scrollTop || | ||
| scrollEl.scrollY - element.scrollStatus.currentPos | ||
| ) <= self.delta | ||
| ) { | ||
| return; | ||
| } | ||
| _scrollEvent: function (elements, element, scrollInfo, scrollableEl) { | ||
| const self = this; | ||
| if (!element.scrollStatus) return; | ||
| let scrollEl = scrollableEl || window; | ||
| if ( | ||
| Math.abs( | ||
| scrollEl.scrollTop || | ||
| scrollEl.scrollY - element.scrollStatus.currentPos | ||
| ) <= self.delta | ||
| ) { | ||
| return; | ||
| } | ||
| let timer = null; | ||
| if (timer != null) { | ||
| clearTimeout(timer); | ||
| } | ||
| // Fix: Use the timer stored in scrollInfo so it persists | ||
| if (scrollInfo.timer != null) { | ||
| clearTimeout(scrollInfo.timer); | ||
| } | ||
| elements.forEach((el) => { | ||
| self.__setScrolling(el, scrollInfo, false); | ||
| self.__runScrollEvent(el, scrollInfo, scrollableEl); | ||
| }); | ||
| elements.forEach((el) => { | ||
| self.__setScrolling(el, scrollInfo, false); | ||
| self.__runScrollEvent(el, scrollInfo, scrollableEl); | ||
| }); | ||
| timer = setTimeout(function () { | ||
| elements.forEach((el) => { | ||
| self.__setScrolling(el, scrollInfo, true); | ||
| }); | ||
| }, 500); | ||
| }, | ||
| scrollInfo.timer = setTimeout(function () { | ||
| elements.forEach((el) => { | ||
| self.__setScrolling(el, scrollInfo, true); | ||
| }); | ||
| }, 500); | ||
| }, | ||
| setScrollPosition: function (element, scrollTo) { | ||
| if (!scrollTo) return; | ||
| if (scrollTo.includes("top")) { | ||
| element.scrollTop = 0; | ||
| } else if (scrollTo.includes("bottom")) { | ||
| element.scrollTop = element.scrollHeight; | ||
| } | ||
| setScrollPosition: function (element, scrollTo) { | ||
| if (!scrollTo) return; | ||
| if (scrollTo.includes("top")) { | ||
| element.scrollTop = 0; | ||
| } else if (scrollTo.includes("bottom")) { | ||
| element.scrollTop = element.scrollHeight; | ||
| } | ||
| if (scrollTo.includes("left")) { | ||
| element.scrollLeft = 0; | ||
| } else if (scrollTo.includes("right")) { | ||
| element.scrollLeft = element.scrollWidth; | ||
| } | ||
| }, | ||
| if (scrollTo.includes("left")) { | ||
| element.scrollLeft = 0; | ||
| } else if (scrollTo.includes("right")) { | ||
| element.scrollLeft = element.scrollWidth; | ||
| } | ||
| }, | ||
| __initIntersectionObserver: function () { | ||
| const self = this; | ||
| this.observer = new IntersectionObserver((entries) => { | ||
| entries.forEach((entry) => { | ||
| let element = entry.target; | ||
| const attrName = | ||
| element.getAttribute("scroll-attribute") || "class"; | ||
| const targetSelector = element.getAttribute("scroll-query"); | ||
| const intersectValue = element.getAttribute("scroll-intersect"); | ||
| __initIntersectionObserver: function () { | ||
| const self = this; | ||
| this.observer = new IntersectionObserver((entries) => { | ||
| // Deduplicate: Keep only the latest entry for each target element | ||
| const uniqueEntries = new Map(); | ||
| entries.forEach((entry) => { | ||
| uniqueEntries.set(entry.target, entry); | ||
| }); | ||
| let targetElements = [element]; | ||
| if (targetSelector) { | ||
| targetElements = document.querySelectorAll(targetSelector); | ||
| } | ||
| if (entry.isIntersecting > 0) { | ||
| targetElements.forEach((el) => | ||
| self.__addAttributeValue(el, attrName, intersectValue) | ||
| ); | ||
| } else { | ||
| targetElements.forEach((el) => | ||
| self.__removeAttrbuteValue(el, attrName, intersectValue) | ||
| ); | ||
| } | ||
| }); | ||
| }); | ||
| }, | ||
| // Process only the unique, latest entries | ||
| uniqueEntries.forEach((entry) => { | ||
| let element = entry.target; | ||
| const attrName = | ||
| element.getAttribute("scroll-attribute") || "class"; | ||
| const targetSelector = element.getAttribute("scroll-query"); | ||
| const intersectValue = element.getAttribute("scroll-intersect"); | ||
| __setScrolling: function (element, info, stopped = false) { | ||
| const { scrolling, attrName } = info; | ||
| if (stopped) { | ||
| this.__removeAttrbuteValue(element, attrName, scrolling); | ||
| } else { | ||
| this.__addAttributeValue(element, attrName, scrolling); | ||
| } | ||
| }, | ||
| let targetElements = [element]; | ||
| if (targetSelector) { | ||
| targetElements = document.querySelectorAll(targetSelector); | ||
| } | ||
| if (entry.isIntersecting) { | ||
| targetElements.forEach((el) => | ||
| self.__addAttributeValue(el, attrName, intersectValue) | ||
| ); | ||
| } else { | ||
| targetElements.forEach((el) => | ||
| self.__removeAttributeValue(el, attrName, intersectValue) | ||
| ); | ||
| } | ||
| }); | ||
| }); | ||
| }, | ||
| __runScrollEvent: function (element, info, scrollableEl) { | ||
| if (!element.scrollStatus) return; | ||
| const currentPos = element.scrollStatus.currentPos; | ||
| let scrollY, scrollHeight, innerHeight; | ||
| if (scrollableEl) { | ||
| scrollY = scrollableEl.scrollTop; | ||
| scrollHeight = scrollableEl.scrollHeight; | ||
| innerHeight = scrollableEl.clientHeight; | ||
| } else { | ||
| scrollY = window.scrollY; | ||
| scrollHeight = document.body.scrollHeight; | ||
| innerHeight = window.innerHeight; | ||
| } | ||
| const { | ||
| upSize, | ||
| downSize, | ||
| attrName, | ||
| values, | ||
| scrollTop, | ||
| scrollBottom, | ||
| scrollLimbo | ||
| } = info; | ||
| __setScrolling: function (element, info, stopped = false) { | ||
| const { scrolling, attrName } = info; | ||
| if (stopped) { | ||
| this.__removeAttributeValue(element, attrName, scrolling); | ||
| } else { | ||
| this.__addAttributeValue(element, attrName, scrolling); | ||
| } | ||
| }, | ||
| let newTime = new Date().getTime(); | ||
| if ((values && !info.datetime) || newTime - info.datetime > 200) { | ||
| info["datetime"] = newTime; | ||
| __runScrollEvent: function (element, info, scrollableEl) { | ||
| if (!element.scrollStatus) return; | ||
| const currentPos = element.scrollStatus.currentPos; | ||
| let scrollY, scrollHeight, innerHeight; | ||
| if (scrollableEl) { | ||
| scrollY = scrollableEl.scrollTop; | ||
| scrollHeight = scrollableEl.scrollHeight; | ||
| innerHeight = scrollableEl.clientHeight; | ||
| } else { | ||
| scrollY = window.scrollY; | ||
| scrollHeight = document.body.scrollHeight; | ||
| innerHeight = window.innerHeight; | ||
| } | ||
| const { | ||
| upSize, | ||
| downSize, | ||
| attrName, | ||
| values, | ||
| scrollTop, | ||
| scrollBottom, | ||
| scrollLimbo | ||
| } = info; | ||
| if (upSize <= currentPos - scrollY) { | ||
| this.__addAttributeValue(element, attrName, values[0]); | ||
| this.__removeAttrbuteValue(element, attrName, values[1]); | ||
| } else if (downSize <= scrollY - currentPos) { | ||
| this.__removeAttrbuteValue(element, attrName, values[0]); | ||
| this.__addAttributeValue(element, attrName, values[1]); | ||
| } | ||
| } | ||
| let newTime = new Date().getTime(); | ||
| if ((values && !info.datetime) || newTime - info.datetime > 200) { | ||
| info["datetime"] = newTime; | ||
| //. scroll top case | ||
| if (scrollY <= this.delta) { | ||
| if (values) { | ||
| this.__removeAttrbuteValue(element, attrName, values[0]); | ||
| this.__removeAttrbuteValue(element, attrName, values[1]); | ||
| } | ||
| this.__addAttributeValue(element, attrName, scrollTop); | ||
| } else { | ||
| this.__removeAttrbuteValue(element, attrName, scrollTop); | ||
| } | ||
| if (upSize <= currentPos - scrollY) { | ||
| this.__addAttributeValue(element, attrName, values[0]); | ||
| this.__removeAttributeValue(element, attrName, values[1]); | ||
| } else if (downSize <= scrollY - currentPos) { | ||
| this.__removeAttributeValue(element, attrName, values[0]); | ||
| this.__addAttributeValue(element, attrName, values[1]); | ||
| } | ||
| } | ||
| //. scroll bottom case | ||
| // if ((window.innerHeight + scrollY) >= document.body.scrollHeight) { | ||
| if (innerHeight + scrollY >= scrollHeight) { | ||
| // this.__removeAttrbuteValue(element, attrName, values[0]); | ||
| // this.__removeAttrbuteValue(element, attrName, values[1]); | ||
| //. scroll top case | ||
| if (scrollY <= this.delta) { | ||
| if (values) { | ||
| this.__removeAttributeValue(element, attrName, values[0]); | ||
| this.__removeAttributeValue(element, attrName, values[1]); | ||
| } | ||
| this.__addAttributeValue(element, attrName, scrollTop); | ||
| } else { | ||
| this.__removeAttributeValue(element, attrName, scrollTop); | ||
| } | ||
| this.__addAttributeValue(element, attrName, scrollBottom); | ||
| } else { | ||
| this.__removeAttrbuteValue(element, attrName, scrollBottom); | ||
| } | ||
| //. scroll bottom case | ||
| // if ((window.innerHeight + scrollY) >= document.body.scrollHeight) { | ||
| if (innerHeight + scrollY >= scrollHeight) { | ||
| // this.__removeAttributeValue(element, attrName, values[0]); | ||
| // this.__removeAttributeValue(element, attrName, values[1]); | ||
| // if (scrollY != 0 && (scrollY + window.innerHeight) != document.body.scrollHeight){ | ||
| if (scrollY != 0 && scrollY + innerHeight != scrollHeight) { | ||
| this.__addAttributeValue(element, attrName, scrollLimbo); | ||
| } else { | ||
| this.__removeAttrbuteValue(element, attrName, scrollLimbo); | ||
| } | ||
| this.__addAttributeValue(element, attrName, scrollBottom); | ||
| } else { | ||
| this.__removeAttributeValue(element, attrName, scrollBottom); | ||
| } | ||
| element.scrollStatus.currentPos = scrollY; | ||
| }, | ||
| // if (scrollY != 0 && (scrollY + window.innerHeight) != document.body.scrollHeight){ | ||
| if (scrollY != 0 && scrollY + innerHeight != scrollHeight) { | ||
| this.__addAttributeValue(element, attrName, scrollLimbo); | ||
| } else { | ||
| this.__removeAttributeValue(element, attrName, scrollLimbo); | ||
| } | ||
| __addAttributeValue: function (element, attrName, value) { | ||
| if (!value) return; | ||
| let check = new RegExp("(\\s|^)" + value + "(\\s|$)"); | ||
| let attrValue = element.getAttribute(attrName) || ""; | ||
| element.scrollStatus.currentPos = scrollY; | ||
| }, | ||
| if (!check.test(attrValue)) { | ||
| if (attrName === "class") attrValue += " " + value; | ||
| else attrValue = value; | ||
| element.setAttribute(attrName, attrValue); | ||
| } | ||
| }, | ||
| __addAttributeValue: function (element, attrName, value) { | ||
| if (!value) return; | ||
| // Optimization: Use classList if the attribute is 'class' | ||
| if (attrName === "class") { | ||
| element.classList.add(value); | ||
| return; | ||
| } | ||
| __removeAttrbuteValue: function (element, attrName, value) { | ||
| if (!value) return; | ||
| let check = new RegExp("(\\s|^)" + value + "(\\s|$)"); | ||
| let attrValue = element.getAttribute(attrName) || ""; | ||
| let check = new RegExp("(\\s|^)" + value + "(\\s|$)"); | ||
| let attrValue = element.getAttribute(attrName) || ""; | ||
| if (check.test(attrValue)) { | ||
| attrValue = attrValue.replace(check, " ").trim(); | ||
| element.setAttribute(attrName, attrValue); | ||
| } | ||
| }, | ||
| if (!check.test(attrValue)) { | ||
| // Logic note: For non-class attributes, we append with a space | ||
| // This mimics class-like behavior for custom attributes | ||
| if (attrValue.length > 0) attrValue += " " + value; | ||
| else attrValue = value; | ||
| element.setAttribute(attrName, attrValue); | ||
| } | ||
| }, | ||
| __getSize: function (attrValue, isWidth) { | ||
| let size = 0; | ||
| if (!attrValue) { | ||
| return 0; | ||
| } | ||
| __removeAttributeValue: function (element, attrName, value) { | ||
| if (!value) return; | ||
| // Optimization: Use classList if the attribute is 'class' | ||
| if (attrName === "class") { | ||
| element.classList.remove(value); | ||
| return; | ||
| } | ||
| if (attrValue.includes("%")) { | ||
| size = attrValue.replace("%", "").trim(); | ||
| size = Number(size) || 0; | ||
| let check = new RegExp("(\\s|^)" + value + "(\\s|$)"); | ||
| let attrValue = element.getAttribute(attrName) || ""; | ||
| size = isWidth | ||
| ? window.innerWidth / size | ||
| : window.innerHeight / size; | ||
| } else { | ||
| size = attrValue.replace("px", "").trim(); | ||
| size = Number(size) || 0; | ||
| } | ||
| if (check.test(attrValue)) { | ||
| attrValue = attrValue.replace(check, " ").trim(); | ||
| element.setAttribute(attrName, attrValue); | ||
| } | ||
| }, | ||
| return size; | ||
| } | ||
| __getSize: function (attrValue, isWidth) { | ||
| let size = 0; | ||
| if (!attrValue) { | ||
| return 0; | ||
| } | ||
| if (attrValue.includes("%")) { | ||
| size = attrValue.replace("%", "").trim(); | ||
| size = Number(size) || 0; | ||
| // Fix: Logic was inverted (dividing screen by size). | ||
| // Changed to standard percentage calculation: size% of screen. | ||
| size = isWidth | ||
| ? window.innerWidth * (size / 100) | ||
| : window.innerHeight * (size / 100); | ||
| } else { | ||
| size = attrValue.replace("px", "").trim(); | ||
| size = Number(size) || 0; | ||
| } | ||
| return size; | ||
| } | ||
| }; | ||
| function updateScrollableAttributes(element) { | ||
| if (element.hasAttribute("scrollable-y")) { | ||
| if (element.scrollWidth > element.clientWidth) | ||
| element.setAttribute("scrollable-y", "true"); | ||
| else element.setAttribute("scrollable-y", "false"); | ||
| } | ||
| if (element.hasAttribute("scrollable-y")) { | ||
| if (element.scrollWidth > element.clientWidth) | ||
| element.setAttribute("scrollable-y", "true"); | ||
| else element.setAttribute("scrollable-y", "false"); | ||
| } | ||
| if (element.hasAttribute("scrollable-x")) { | ||
| if (element.scrollHeight > element.clientHeight) | ||
| element.setAttribute("scrollable-x", "true"); | ||
| else element.setAttribute("scrollable-x", "false"); | ||
| } | ||
| if (element.hasAttribute("scrollable-x")) { | ||
| if (element.scrollHeight > element.clientHeight) | ||
| element.setAttribute("scrollable-x", "true"); | ||
| else element.setAttribute("scrollable-x", "false"); | ||
| } | ||
| } | ||
| Observer.init({ | ||
| name: "CoCreateScrollCreate", | ||
| types: ["addedNodes"], | ||
| selector: "[scroll], [scroll-to], [scrollable-x], [scrollable-y]", | ||
| callback: function (mutation) { | ||
| CoCreateScroll.initElement(mutation.target); | ||
| } | ||
| name: "CoCreateScrollCreate", | ||
| types: ["addedNodes"], | ||
| selector: selector, | ||
| callback: function (mutation) { | ||
| CoCreateScroll.initElement(mutation.target); | ||
| } | ||
| }); | ||
| Observer.init({ | ||
| name: "CoCreateScrollAttributes", | ||
| types: ["attributes"], | ||
| attributeFilter: ["scroll-to"], | ||
| // target: selector, // blocks mutations when applied | ||
| callback: function (mutation) { | ||
| CoCreateScroll.setScrollPosition( | ||
| mutation.target, | ||
| mutation.target.getAttribute("scroll-to") | ||
| ); | ||
| } | ||
| name: "CoCreateScrollAttributes", | ||
| types: ["attributes"], | ||
| attributeFilter: ["scroll-to"], | ||
| // target: selector, // blocks mutations when applied | ||
| callback: function (mutation) { | ||
| CoCreateScroll.setScrollPosition( | ||
| mutation.target, | ||
| mutation.target.getAttribute("scroll-to") | ||
| ); | ||
| } | ||
| }); | ||
| Observer.init({ | ||
| name: "CoCreateScrollAttributes", | ||
| types: ["attributes"], | ||
| attributeFilter: ["scrollable-x", "scrollable-y"], | ||
| // target: selector, // blocks mutations when applied | ||
| callback: function (mutation) { | ||
| if ( | ||
| mutation.oldValue !== | ||
| mutation.target.getAttribute(mutation.attributeName) | ||
| ) | ||
| updateScrollableAttributes(mutation.target); | ||
| } | ||
| name: "CoCreateScrollAttributes", | ||
| types: ["attributes"], | ||
| attributeFilter: ["scrollable-x", "scrollable-y"], | ||
| // target: selector, // blocks mutations when applied | ||
| callback: function (mutation) { | ||
| if ( | ||
| mutation.oldValue !== | ||
| mutation.target.getAttribute(mutation.attributeName) | ||
| ) | ||
| updateScrollableAttributes(mutation.target); | ||
| } | ||
| }); | ||
| Actions.init({ | ||
| name: "scroll-to", | ||
| callback: (action) => { | ||
| // CoCreateScroll.setScrollPosition(mutation.target) | ||
| } | ||
| name: "scroll-to", | ||
| callback: (action) => { | ||
| // CoCreateScroll.setScrollPosition(mutation.target) | ||
| } | ||
| }); | ||
@@ -348,2 +374,2 @@ | ||
| export default CoCreateScroll; | ||
| export default CoCreateScroll; |
119204
3.42%444
4.72%