diff --git a/.npmignore b/.npmignore deleted file mode 100644 index 2ec3d9e..0000000 --- a/.npmignore +++ /dev/null @@ -1,6 +0,0 @@ -.idea -bower_components -bower.json -.babelrc -.eslint* -rollup.config.js \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 765b2b2..4fea956 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,20 +2,20 @@ ## Reporting an issue -If you have found a bug please feel free to report an issue after ensuring that there is no such bug yet (check [existing issues](https://github.com/Amphiluke/floating-scroll/issues) first). Be sure to write a clear description of the problem. It will be great if you also provide a minimum example revealing the bug. You may use such services as [JSFiddle](https://jsfiddle.net/) and [RawGit](https://rawgit.com/) to assemble a live demo for the issue you found. +If you have found a bug, please feel free to report an issue after ensuring that there is no such bug yet (check [existing issues](https://github.com/Amphiluke/floating-scroll/issues) first). Be sure to write a clear description of the problem. It will be great if you also provide a minimum example revealing the bug. You may use such services as [CodePen](https://codepen.io/) or [JSFiddle](https://jsfiddle.net/) and [unpkg](https://unpkg.com/) to assemble a live demo for the issue you’ve found. ## Making changes in code and opening a pull request -If you know the way to fix some bug or just to make the plugin better then you are welcome to open a pull request. Please provide a clear and detailed description of what do your changes fix or improve, or refer an existing issue containing such an explanation. +If you know the way to fix some bug or just to make the plugin better, you are welcome to open a pull request. Please provide a clear and detailed description of what do your changes fix or improve, or refer an existing issue containing such an explanation. Before submitting a new pull request be sure to do the following things. * Ensure that your changes do not break existing features. -* Test your changes in different browsers: Chrome, Firefox, Safari, Opera, Internet Explorer, and Edge. +* Test your changes in different browsers: Chrome, Firefox, Safari, Opera, and Edge. * Note that the plugin is currently compatible with ancient versions of jQuery (1.4.3+). If your changes break this compatibility please think if you can rewrite your code to keep compatibility unaffected. However if your changes are so important and cool that they outweigh all benefits of supporting ancient versions of jQuery then it is possible to soften this requirement within reasonable limits. * Before committing your changes please make sure that the plugin sources pass ESLint checks. Just use the command `npm run lint` in the project directory (of course, you need to install the project first by executing `npm install`). Fix any problems reported by ESLint before submitting a pull request. * Do not forget to update the minified version of the plugin sources. Use the command `npm run build` for that. -Thanks for contribution! :tea: +Thanks for your contribution! :tea: Amphiluke diff --git a/README.md b/README.md index 2648d23..d5fb250 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,12 @@ The general purpose of the plugin is to provide some lengthy containers on the p ## Details & API -There is the only public method used to instantiate and control a floating scrollbar — `.floatingScroll()`. The plugin method `.floatingScroll()` should be called in context of a scrollable container. It takes an optional argument `method`. The currently supported methods are +There is the only public method used to instantiate and control a floating scrollbar — `.floatingScroll()`. Unless otherwise indicated, the plugin method `.floatingScroll()` should be called in context of a scrollable container. It takes an optional argument `method`. The currently supported methods are * [`init`](#initialisation) (default value) — used to initialize a floating scrollbar widget; * [`update`](#updating-scrollbar) — used t force update of the floating scrollbar parameters (size and position); -* [`destroy`](#destroying-floating-scrollbar) — removes a scrollbar and all related event handlers. +* [`destroy`](#destroying-floating-scrollbar) — removes a scrollbar and all related event handlers; +* [`destroyDetached`](#destroying-detached-widgets) — destroys floating scrollbar instances whose containers were removed from the document (requires a different context, see below). You may also [trigger](https://api.jquery.com/trigger/) events `update.fscroll` and `destroy.fscroll` on containers with attached floating scrollbar: this does the same as invoking the corresponding methods. @@ -33,7 +34,7 @@ The plugin requires the CSS file [jquery.floatingscroll.css](dist/jquery.floatin The only thing required to apply floatingScroll to a static container (whose sizes will never change during the session) is a single call of the `.floatingScroll()` method on the DOM ready event: ```javascript -$(document).ready(function () { +$(() => { $(".spacious-container").floatingScroll(); }); ``` @@ -41,7 +42,7 @@ $(document).ready(function () { Starting with v3.1.0, the method `init` supports passing options. Currently, the only supported parameter is `orientation`. Default scrollbar orientation is `"horizontal"` but you can also make a vertical floating scrollbar using options: ```javascript -$(document).ready(function () { +$(() => { $(".spacious-container").floatingScroll("init", { orientation: "vertical" }); @@ -68,7 +69,7 @@ If you attach a floating scrollbar to a container whose size and/or content may ```javascript $(".spacious-container").floatingScroll("init"); -$("#refresh-button").click(function () { +$("#refresh-button").click(() => { // ... some actions which change the total scroll width of the container ... $(".spacious-container").floatingScroll("update"); }); @@ -82,6 +83,18 @@ To detach a scrollbar and remove all related event handlers, use the method `des $(".spacious-container").floatingScroll("destroy"); ``` +### Destroying detached widgets + +If your app completely re-renders a large portion of DOM where floating scrollbar widgets were mounted, actual container references are lost, and therefore you cannot destroy the widgets and perform related cleanup using the `destroy` method. In this case, you may just call the `destroyDetached` method, and the pluign will find all “zombie” instances and will destroy them for you. Unlike the other methods, this one needs to be called in context of `$(window)`: + +```javascript +$(".main-view .spacious-container").floatingScroll("init"); +// ... the app re-renders the main view ... +$(".main-view").html("..."); +// destroy floating scrollbar widgets whose containers are not in the document anymore +$(window).floatingScroll("destroyDetached"); +``` + ### Special cases If you want to attach a floating scrollbar to a container living in a positioned box (e.g. a modal popup with `position: fixed`) then you need to apply two special indicating class names in the markup. The plugin detects these indicating class names (they are prefixed with `fl-scrolls-`) and switches to a special functioning mode. diff --git a/dist/jquery.floatingscroll.es6.min.js b/dist/jquery.floatingscroll.es6.min.js index 9571fde..5fbaf18 100644 --- a/dist/jquery.floatingscroll.es6.min.js +++ b/dist/jquery.floatingscroll.es6.min.js @@ -1,6 +1,6 @@ /*! -floating-scroll v3.1.1 +floating-scroll v3.2.0 https://amphiluke.github.io/floating-scroll/ (c) 2021 Amphiluke */ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(require("jquery")):"function"==typeof define&&define.amd?define(["jquery"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).jQuery)}(this,(function(e){"use strict";const t="horizontal",i="vertical";let n={init(e,i){let n=this;n.orientationProps=(e=>{let i=e===t;return{ORIENTATION:e,SIZE:i?"width":"height",X_SIZE:i?"height":"width",OFFSET_SIZE:i?"offsetWidth":"offsetHeight",OFFSET_X_SIZE:i?"offsetHeight":"offsetWidth",CLIENT_SIZE:i?"clientWidth":"clientHeight",CLIENT_X_SIZE:i?"clientHeight":"clientWidth",INNER_X_SIZE:i?"innerHeight":"innerWidth",SCROLL_SIZE:i?"scrollWidth":"scrollHeight",SCROLL_POS:i?"scrollLeft":"scrollTop",START:i?"left":"top",X_START:i?"top":"left",X_END:i?"bottom":"right"}})(i);let o=e.closest(".fl-scrolls-body");o.length&&(n.scrollBody=o),n.container=e[0],n.visible=!0,n.initWidget(),n.updateAPI(),n.addEventHandlers(),n.skipSyncContainer=n.skipSyncWidget=!1},initWidget(){let t=this;const{ORIENTATION:i,SIZE:n,SCROLL_SIZE:o}=t.orientationProps;let l=t.widget=e(`
`);e("").appendTo(l)[n](t.container[o]),l.appendTo(t.container)},addEventHandlers(){let t=this;(t.eventHandlers=[{$el:t.scrollBody||e(window),handlers:{scroll(){t.updateAPI()},resize(){t.updateAPI()}}},{$el:t.widget,handlers:{scroll(){t.visible&&!t.skipSyncContainer&&t.syncContainer(),t.skipSyncContainer=!1}}},{$el:e(t.container),handlers:{scroll(){t.skipSyncWidget||t.syncWidget(),t.skipSyncWidget=!1},focusin(){setTimeout((()=>{t.widget&&t.syncWidget()}),0)},"update.fscroll"({namespace:e}){"fscroll"===e&&t.updateAPI()},"destroy.fscroll"({namespace:e}){"fscroll"===e&&t.destroyAPI()}}}]).forEach((({$el:e,handlers:t})=>e.bind(t)))},checkVisibility(){let e=this,{widget:t,container:i,scrollBody:n}=e;const{SCROLL_SIZE:o,OFFSET_SIZE:l,X_START:s,X_END:r,INNER_X_SIZE:c,CLIENT_X_SIZE:d}=e.orientationProps;let a=t[0][o]<=t[0][l];if(!a){let e=i.getBoundingClientRect(),t=n?n[0].getBoundingClientRect()[r]:window[c]||document.documentElement[d];a=e[r]<=t||e[s]>t}e.visible===a&&(e.visible=!a,t.toggleClass("fl-scrolls-hidden"))},syncContainer(){let e=this;const{SCROLL_POS:t}=e.orientationProps;let i=e.widget[0][t];e.container[t]!==i&&(e.skipSyncWidget=!0,e.container[t]=i)},syncWidget(){let e=this;const{SCROLL_POS:t}=e.orientationProps;let i=e.container[t];e.widget[0][t]!==i&&(e.skipSyncContainer=!0,e.widget[0][t]=i)},updateAPI(){let t=this;const{SIZE:i,X_SIZE:n,OFFSET_X_SIZE:o,CLIENT_SIZE:l,CLIENT_X_SIZE:s,SCROLL_SIZE:r,START:c}=t.orientationProps;let{widget:d,container:a,scrollBody:h}=t,S=a[l],f=a[r];d[i](S),h||d.css(c,`${a.getBoundingClientRect()[c]}px`),e("div",d)[i](f),f>S&&d[n](d[0][o]-d[0][s]+1),t.syncWidget(),t.checkVisibility()},destroyAPI(){let e=this;e.eventHandlers.forEach((({$el:e,handlers:t})=>e.unbind(t))),e.widget.remove(),e.eventHandlers=e.widget=e.container=e.scrollBody=null}};e.fn.floatingScroll=function(o="init",l={}){if("init"===o){let{orientation:o=t}=l;if(o!==t&&o!==i)throw new Error(`Scrollbar orientation should be either “${t}” or “vertical”`);this.each(((t,i)=>Object.create(n).init(e(i),o)))}else Object.prototype.hasOwnProperty.call(n,`${o}API`)&&this.trigger(`${o}.fscroll`);return this},e((()=>{e("body [data-fl-scrolls]").each(((t,i)=>{let n=e(i);n.floatingScroll("init",n.data("flScrolls")||{})}))}))})); +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(require("jquery")):"function"==typeof define&&define.amd?define(["jquery"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).jQuery)}(this,(function(e){"use strict";const t="horizontal",i="vertical";let n={init(e,i){let n=this;n.orientationProps=(e=>{let i=e===t;return{ORIENTATION:e,SIZE:i?"width":"height",X_SIZE:i?"height":"width",OFFSET_SIZE:i?"offsetWidth":"offsetHeight",OFFSET_X_SIZE:i?"offsetHeight":"offsetWidth",CLIENT_SIZE:i?"clientWidth":"clientHeight",CLIENT_X_SIZE:i?"clientHeight":"clientWidth",INNER_X_SIZE:i?"innerHeight":"innerWidth",SCROLL_SIZE:i?"scrollWidth":"scrollHeight",SCROLL_POS:i?"scrollLeft":"scrollTop",START:i?"left":"top",X_START:i?"top":"left",X_END:i?"bottom":"right"}})(i);let o=e.closest(".fl-scrolls-body");o.length&&(n.scrollBody=o),n.container=e[0],n.visible=!0,n.initWidget(),n.updateAPI(),n.addEventHandlers(),n.skipSyncContainer=n.skipSyncWidget=!1},initWidget(){let t=this;const{ORIENTATION:i,SIZE:n,SCROLL_SIZE:o}=t.orientationProps;let l=t.widget=e(``);e("").appendTo(l)[n](t.container[o]),l.appendTo(t.container)},addEventHandlers(){let t=this;(t.eventHandlers=[{$el:e(window),handlers:{"destroyDetached.fscroll"({namespace:e}){"fscroll"===e&&t.destroyDetachedAPI()}}},{$el:t.scrollBody||e(window),handlers:{scroll(){t.updateAPI()},resize(){t.updateAPI()}}},{$el:t.widget,handlers:{scroll(){t.visible&&!t.skipSyncContainer&&t.syncContainer(),t.skipSyncContainer=!1}}},{$el:e(t.container),handlers:{scroll(){t.skipSyncWidget||t.syncWidget(),t.skipSyncWidget=!1},focusin(){setTimeout((()=>{t.widget&&t.syncWidget()}),0)},"update.fscroll"({namespace:e}){"fscroll"===e&&t.updateAPI()},"destroy.fscroll"({namespace:e}){"fscroll"===e&&t.destroyAPI()}}}]).forEach((({$el:e,handlers:t})=>e.bind(t)))},checkVisibility(){let e=this,{widget:t,container:i,scrollBody:n}=e;const{SCROLL_SIZE:o,OFFSET_SIZE:l,X_START:s,X_END:r,INNER_X_SIZE:d,CLIENT_X_SIZE:c}=e.orientationProps;let a=t[0][o]<=t[0][l];if(!a){let e=i.getBoundingClientRect(),t=n?n[0].getBoundingClientRect()[r]:window[d]||document.documentElement[c];a=e[r]<=t||e[s]>t}e.visible===a&&(e.visible=!a,t.toggleClass("fl-scrolls-hidden"))},syncContainer(){let e=this;const{SCROLL_POS:t}=e.orientationProps;let i=e.widget[0][t];e.container[t]!==i&&(e.skipSyncWidget=!0,e.container[t]=i)},syncWidget(){let e=this;const{SCROLL_POS:t}=e.orientationProps;let i=e.container[t];e.widget[0][t]!==i&&(e.skipSyncContainer=!0,e.widget[0][t]=i)},updateAPI(){let t=this;const{SIZE:i,X_SIZE:n,OFFSET_X_SIZE:o,CLIENT_SIZE:l,CLIENT_X_SIZE:s,SCROLL_SIZE:r,START:d}=t.orientationProps;let{widget:c,container:a,scrollBody:h}=t,S=a[l],f=a[r];c[i](S),h||c.css(d,`${a.getBoundingClientRect()[d]}px`),e("div",c)[i](f),f>S&&c[n](c[0][o]-c[0][s]+1),t.syncWidget(),t.checkVisibility()},destroyAPI(){let e=this;e.eventHandlers.forEach((({$el:e,handlers:t})=>e.unbind(t))),e.widget.remove(),e.eventHandlers=e.widget=e.container=e.scrollBody=null},destroyDetachedAPI(){e.contains(document.body,this.container)||this.destroyAPI()}};e.fn.floatingScroll=function(o="init",l={}){if("init"===o){let{orientation:o=t}=l;if(o!==t&&o!==i)throw new Error(`Scrollbar orientation should be either “${t}” or “vertical”`);this.each(((t,i)=>Object.create(n).init(e(i),o)))}else Object.prototype.hasOwnProperty.call(n,`${o}API`)&&this.trigger(`${o}.fscroll`);return this},e((()=>{e("body [data-fl-scrolls]").each(((t,i)=>{let n=e(i);n.floatingScroll("init",n.data("flScrolls")||{})}))}))})); diff --git a/dist/jquery.floatingscroll.min.js b/dist/jquery.floatingscroll.min.js index dcb3380..13747ef 100644 --- a/dist/jquery.floatingscroll.min.js +++ b/dist/jquery.floatingscroll.min.js @@ -1,6 +1,6 @@ /*! -floating-scroll v3.1.1 +floating-scroll v3.2.0 https://amphiluke.github.io/floating-scroll/ (c) 2021 Amphiluke */ -!function(i,t){"object"==typeof exports&&"undefined"!=typeof module?t(require("jquery")):"function"==typeof define&&define.amd?define(["jquery"],t):t((i="undefined"!=typeof globalThis?globalThis:i||self).jQuery)}(this,(function(i){"use strict";var t="horizontal",n="vertical",e={init:function(i,n){var e=this;e.orientationProps=function(i){var n=i===t;return{ORIENTATION:i,SIZE:n?"width":"height",X_SIZE:n?"height":"width",OFFSET_SIZE:n?"offsetWidth":"offsetHeight",OFFSET_X_SIZE:n?"offsetHeight":"offsetWidth",CLIENT_SIZE:n?"clientWidth":"clientHeight",CLIENT_X_SIZE:n?"clientHeight":"clientWidth",INNER_X_SIZE:n?"innerHeight":"innerWidth",SCROLL_SIZE:n?"scrollWidth":"scrollHeight",SCROLL_POS:n?"scrollLeft":"scrollTop",START:n?"left":"top",X_START:n?"top":"left",X_END:n?"bottom":"right"}}(n);var o=i.closest(".fl-scrolls-body");o.length&&(e.scrollBody=o),e.container=i[0],e.visible=!0,e.initWidget(),e.updateAPI(),e.addEventHandlers(),e.skipSyncContainer=e.skipSyncWidget=!1},initWidget:function(){var t=this,n=t.orientationProps,e=n.ORIENTATION,o=n.SIZE,r=n.SCROLL_SIZE,l=t.widget=i('');i("").appendTo(l)[o](t.container[r]),l.appendTo(t.container)},addEventHandlers:function(){var t=this;(t.eventHandlers=[{$el:t.scrollBody||i(window),handlers:{scroll:function(){t.updateAPI()},resize:function(){t.updateAPI()}}},{$el:t.widget,handlers:{scroll:function(){t.visible&&!t.skipSyncContainer&&t.syncContainer(),t.skipSyncContainer=!1}}},{$el:i(t.container),handlers:{scroll:function(){t.skipSyncWidget||t.syncWidget(),t.skipSyncWidget=!1},focusin:function(){setTimeout((function(){t.widget&&t.syncWidget()}),0)},"update.fscroll":function(i){"fscroll"===i.namespace&&t.updateAPI()},"destroy.fscroll":function(i){"fscroll"===i.namespace&&t.destroyAPI()}}}]).forEach((function(i){var t=i.$el,n=i.handlers;return t.bind(n)}))},checkVisibility:function(){var i=this,t=i.widget,n=i.container,e=i.scrollBody,o=i.orientationProps,r=o.SCROLL_SIZE,l=o.OFFSET_SIZE,c=o.X_START,s=o.X_END,d=o.INNER_X_SIZE,a=o.CLIENT_X_SIZE,f=t[0][r]<=t[0][l];if(!f){var u=n.getBoundingClientRect(),h=e?e[0].getBoundingClientRect()[s]:window[d]||document.documentElement[a];f=u[s]<=h||u[c]>h}i.visible===f&&(i.visible=!f,t.toggleClass("fl-scrolls-hidden"))},syncContainer:function(){var i=this,t=i.orientationProps.SCROLL_POS,n=i.widget[0][t];i.container[t]!==n&&(i.skipSyncWidget=!0,i.container[t]=n)},syncWidget:function(){var i=this,t=i.orientationProps.SCROLL_POS,n=i.container[t];i.widget[0][t]!==n&&(i.skipSyncContainer=!0,i.widget[0][t]=n)},updateAPI:function(){var t=this,n=t.orientationProps,e=n.SIZE,o=n.X_SIZE,r=n.OFFSET_X_SIZE,l=n.CLIENT_SIZE,c=n.CLIENT_X_SIZE,s=n.SCROLL_SIZE,d=n.START,a=t.widget,f=t.container,u=t.scrollBody,h=f[l],S=f[s];a[e](h),u||a.css(d,f.getBoundingClientRect()[d]+"px"),i("div",a)[e](S),S>h&&a[o](a[0][r]-a[0][c]+1),t.syncWidget(),t.checkVisibility()},destroyAPI:function(){var i=this;i.eventHandlers.forEach((function(i){var t=i.$el,n=i.handlers;return t.unbind(n)})),i.widget.remove(),i.eventHandlers=i.widget=i.container=i.scrollBody=null}};i.fn.floatingScroll=function(o,r){if(void 0===o&&(o="init"),void 0===r&&(r={}),"init"===o){var l=r.orientation,c=void 0===l?t:l;if(c!==t&&c!==n)throw new Error("Scrollbar orientation should be either “horizontal” or “vertical”");this.each((function(t,n){return Object.create(e).init(i(n),c)}))}else Object.prototype.hasOwnProperty.call(e,o+"API")&&this.trigger(o+".fscroll");return this},i((function(){i("body [data-fl-scrolls]").each((function(t,n){var e=i(n);e.floatingScroll("init",e.data("flScrolls")||{})}))}))})); +!function(t,i){"object"==typeof exports&&"undefined"!=typeof module?i(require("jquery")):"function"==typeof define&&define.amd?define(["jquery"],i):i((t="undefined"!=typeof globalThis?globalThis:t||self).jQuery)}(this,(function(t){"use strict";var i="horizontal",n="vertical",e={init:function(t,n){var e=this;e.orientationProps=function(t){var n=t===i;return{ORIENTATION:t,SIZE:n?"width":"height",X_SIZE:n?"height":"width",OFFSET_SIZE:n?"offsetWidth":"offsetHeight",OFFSET_X_SIZE:n?"offsetHeight":"offsetWidth",CLIENT_SIZE:n?"clientWidth":"clientHeight",CLIENT_X_SIZE:n?"clientHeight":"clientWidth",INNER_X_SIZE:n?"innerHeight":"innerWidth",SCROLL_SIZE:n?"scrollWidth":"scrollHeight",SCROLL_POS:n?"scrollLeft":"scrollTop",START:n?"left":"top",X_START:n?"top":"left",X_END:n?"bottom":"right"}}(n);var o=t.closest(".fl-scrolls-body");o.length&&(e.scrollBody=o),e.container=t[0],e.visible=!0,e.initWidget(),e.updateAPI(),e.addEventHandlers(),e.skipSyncContainer=e.skipSyncWidget=!1},initWidget:function(){var i=this,n=i.orientationProps,e=n.ORIENTATION,o=n.SIZE,r=n.SCROLL_SIZE,c=i.widget=t('');t("").appendTo(c)[o](i.container[r]),c.appendTo(i.container)},addEventHandlers:function(){var i=this;(i.eventHandlers=[{$el:t(window),handlers:{"destroyDetached.fscroll":function(t){"fscroll"===t.namespace&&i.destroyDetachedAPI()}}},{$el:i.scrollBody||t(window),handlers:{scroll:function(){i.updateAPI()},resize:function(){i.updateAPI()}}},{$el:i.widget,handlers:{scroll:function(){i.visible&&!i.skipSyncContainer&&i.syncContainer(),i.skipSyncContainer=!1}}},{$el:t(i.container),handlers:{scroll:function(){i.skipSyncWidget||i.syncWidget(),i.skipSyncWidget=!1},focusin:function(){setTimeout((function(){i.widget&&i.syncWidget()}),0)},"update.fscroll":function(t){"fscroll"===t.namespace&&i.updateAPI()},"destroy.fscroll":function(t){"fscroll"===t.namespace&&i.destroyAPI()}}}]).forEach((function(t){var i=t.$el,n=t.handlers;return i.bind(n)}))},checkVisibility:function(){var t=this,i=t.widget,n=t.container,e=t.scrollBody,o=t.orientationProps,r=o.SCROLL_SIZE,c=o.OFFSET_SIZE,l=o.X_START,s=o.X_END,d=o.INNER_X_SIZE,a=o.CLIENT_X_SIZE,f=i[0][r]<=i[0][c];if(!f){var h=n.getBoundingClientRect(),u=e?e[0].getBoundingClientRect()[s]:window[d]||document.documentElement[a];f=h[s]<=u||h[l]>u}t.visible===f&&(t.visible=!f,i.toggleClass("fl-scrolls-hidden"))},syncContainer:function(){var t=this,i=t.orientationProps.SCROLL_POS,n=t.widget[0][i];t.container[i]!==n&&(t.skipSyncWidget=!0,t.container[i]=n)},syncWidget:function(){var t=this,i=t.orientationProps.SCROLL_POS,n=t.container[i];t.widget[0][i]!==n&&(t.skipSyncContainer=!0,t.widget[0][i]=n)},updateAPI:function(){var i=this,n=i.orientationProps,e=n.SIZE,o=n.X_SIZE,r=n.OFFSET_X_SIZE,c=n.CLIENT_SIZE,l=n.CLIENT_X_SIZE,s=n.SCROLL_SIZE,d=n.START,a=i.widget,f=i.container,h=i.scrollBody,u=f[c],S=f[s];a[e](u),h||a.css(d,f.getBoundingClientRect()[d]+"px"),t("div",a)[e](S),S>u&&a[o](a[0][r]-a[0][l]+1),i.syncWidget(),i.checkVisibility()},destroyAPI:function(){var t=this;t.eventHandlers.forEach((function(t){var i=t.$el,n=t.handlers;return i.unbind(n)})),t.widget.remove(),t.eventHandlers=t.widget=t.container=t.scrollBody=null},destroyDetachedAPI:function(){t.contains(document.body,this.container)||this.destroyAPI()}};t.fn.floatingScroll=function(o,r){if(void 0===o&&(o="init"),void 0===r&&(r={}),"init"===o){var c=r.orientation,l=void 0===c?i:c;if(l!==i&&l!==n)throw new Error("Scrollbar orientation should be either “horizontal” or “vertical”");this.each((function(i,n){return Object.create(e).init(t(n),l)}))}else Object.prototype.hasOwnProperty.call(e,o+"API")&&this.trigger(o+".fscroll");return this},t((function(){t("body [data-fl-scrolls]").each((function(i,n){var e=t(n);e.floatingScroll("init",e.data("flScrolls")||{})}))}))})); diff --git a/floating-scroll.jquery.json b/floating-scroll.jquery.json index 8402302..a39873a 100644 --- a/floating-scroll.jquery.json +++ b/floating-scroll.jquery.json @@ -1,7 +1,7 @@ { "name": "floating-scroll", "title": "floatingScroll", - "version": "3.1.0", + "version": "3.2.0", "description": "A lightweight jQuery plugin providing floating scrollbar functionality", "keywords": [ "scrollbar", @@ -19,4 +19,4 @@ "dependencies": { "jquery": ">=1.4.3" } -} \ No newline at end of file +} diff --git a/package-lock.json b/package-lock.json index bdb479c..8b71e39 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "floating-scroll", - "version": "3.1.1", + "version": "3.2.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 5197858..a390700 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,14 @@ { "name": "floating-scroll", - "version": "3.1.1", + "version": "3.2.0", "description": "A lightweight jQuery plugin providing floating scrollbar functionality", "main": "dist/jquery.floatingscroll.min.js", "module": "src/jquery.floatingscroll.js", "style": "dist/jquery.floatingscroll.css", + "files": [ + "dist", + "src" + ], "scripts": { "prepare": "husky install", "lint": "eslint src/jquery.floatingscroll.js", diff --git a/src/jquery.floatingscroll.js b/src/jquery.floatingscroll.js index 1fe28b1..1781eae 100644 --- a/src/jquery.floatingscroll.js +++ b/src/jquery.floatingscroll.js @@ -51,6 +51,16 @@ let floatingScrollProto = { addEventHandlers() { let instance = this; let eventHandlers = instance.eventHandlers = [ + { + $el: $(window), + handlers: { + "destroyDetached.fscroll"({namespace}) { + if (namespace === "fscroll") { + instance.destroyDetachedAPI(); + } + } + } + }, { $el: instance.scrollBody || $(window), handlers: { @@ -182,6 +192,12 @@ let floatingScrollProto = { instance.eventHandlers.forEach(({$el, handlers}) => $el.unbind(handlers)); instance.widget.remove(); instance.eventHandlers = instance.widget = instance.container = instance.scrollBody = null; + }, + + destroyDetachedAPI() { + if (!$.contains(document.body, this.container)) { + this.destroyAPI(); + } } };