diff --git a/css/OverlayScrollbars.css b/css/OverlayScrollbars.css index cbe232f..158ca36 100644 --- a/css/OverlayScrollbars.css +++ b/css/OverlayScrollbars.css @@ -2,13 +2,13 @@ * OverlayScrollbars * https://github.com/KingSora/OverlayScrollbars * - * Version: 1.7.3 + * Version: 1.8.0 * - * Copyright KingSora. + * Copyright KingSora | Rene Haas. * https://github.com/KingSora * * Released under the MIT license. - * Date: 23.06.2019 + * Date: 08.07.2019 */ /* diff --git a/css/OverlayScrollbars.min.css b/css/OverlayScrollbars.min.css index 02f819f..a07843e 100644 --- a/css/OverlayScrollbars.min.css +++ b/css/OverlayScrollbars.min.css @@ -2,12 +2,12 @@ * OverlayScrollbars * https://github.com/KingSora/OverlayScrollbars * - * Version: 1.7.3 + * Version: 1.8.0 * - * Copyright KingSora. + * Copyright KingSora | Rene Haas. * https://github.com/KingSora * * Released under the MIT license. - * Date: 23.06.2019 + * Date: 08.07.2019 */ html.os-html,html.os-html>.os-host{display:block;overflow:hidden;box-sizing:border-box;height:100%!important;width:100%!important;min-width:100%!important;min-height:100%!important;margin:0!important;position:absolute!important}html.os-html>.os-host>.os-padding{position:absolute}body.os-dragging,body.os-dragging *{cursor:default}.os-host,.os-host-textarea{position:relative;overflow:visible!important;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-ms-flex-wrap:nowrap;flex-wrap:nowrap;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start;-ms-flex-line-pack:start;align-content:flex-start;-webkit-box-align:start;-ms-flex-align:start;-ms-grid-row-align:flex-start;align-items:flex-start}.os-host-flexbox{overflow:hidden!important;display:-webkit-box;display:-ms-flexbox;display:flex}.os-host-flexbox>.os-size-auto-observer{height:inherit!important}.os-host-flexbox>.os-content-glue{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;-ms-flex-negative:0;flex-shrink:0}.os-host-flexbox>.os-size-auto-observer,.os-host-flexbox>.os-content-glue{min-height:0;min-width:0;-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0;-ms-flex-negative:1;flex-shrink:1;-ms-flex-preferred-size:auto;flex-basis:auto}#os-dummy-scrollbar-size{position:fixed;opacity:0;-ms-filter:'progid:DXImageTransform.Microsoft.Alpha(Opacity=0)';visibility:hidden;overflow:scroll;height:500px;width:500px}#os-dummy-scrollbar-size>div{width:200%;height:200%;margin:10px 0}#os-dummy-scrollbar-size,.os-viewport{-ms-overflow-style:scrollbar!important}.os-viewport-native-scrollbars-invisible#os-dummy-scrollbar-size,.os-viewport-native-scrollbars-invisible.os-viewport{scrollbar-width:none!important}.os-viewport-native-scrollbars-invisible#os-dummy-scrollbar-size::-webkit-scrollbar,.os-viewport-native-scrollbars-invisible.os-viewport::-webkit-scrollbar,.os-viewport-native-scrollbars-invisible#os-dummy-scrollbar-size::-webkit-scrollbar-corner,.os-viewport-native-scrollbars-invisible.os-viewport::-webkit-scrollbar-corner{display:none!important;width:0px!important;height:0px!important;visibility:hidden!important;background:transparent!important}.os-content-glue{box-sizing:inherit;max-height:100%;max-width:100%;width:100%;pointer-events:none}.os-padding{box-sizing:inherit;direction:inherit;position:absolute;overflow:visible;padding:0;margin:0;left:0;top:0;bottom:0;right:0;width:auto!important;height:auto!important;z-index:1}.os-host-overflow>.os-padding{overflow:hidden}.os-viewport{direction:inherit!important;box-sizing:inherit!important;resize:none!important;outline:none!important;position:absolute;overflow:hidden;top:0;left:0;bottom:0;right:0;padding:0;margin:0;-webkit-overflow-scrolling:touch}.os-content-arrange{position:absolute;z-index:-1;min-height:1px;min-width:1px;pointer-events:none}.os-content{direction:inherit;box-sizing:border-box!important;position:relative;display:block;height:100%;width:100%;height:100%;width:100%;visibility:visible}.os-content:before,.os-content:after{content:'';display:table;width:0;height:0;line-height:0;font-size:0}.os-content>.os-textarea{box-sizing:border-box!important;direction:inherit!important;background:transparent!important;outline:0 none transparent!important;overflow:hidden!important;position:absolute!important;display:block!important;top:0!important;left:0!important;margin:0!important;border-radius:0px!important;float:none!important;-webkit-filter:none!important;filter:none!important;border:none!important;resize:none!important;-webkit-transform:none!important;transform:none!important;max-width:none!important;max-height:none!important;box-shadow:none!important;-webkit-perspective:none!important;perspective:none!important;opacity:1!important;z-index:1!important;clip:auto!important;vertical-align:baseline!important;padding:0}.os-host-rtl>.os-padding>.os-viewport>.os-content>.os-textarea{right:0!important}.os-content>.os-textarea-cover{z-index:-1;pointer-events:none}.os-content>.os-textarea[wrap='off']{white-space:pre!important;margin:0px!important}.os-text-inherit{font-family:inherit;font-size:inherit;font-weight:inherit;font-style:inherit;font-variant:inherit;text-transform:inherit;text-decoration:inherit;text-indent:inherit;text-align:inherit;text-shadow:inherit;text-overflow:inherit;letter-spacing:inherit;word-spacing:inherit;line-height:inherit;unicode-bidi:inherit;direction:inherit;color:inherit;cursor:text}.os-resize-observer,.os-resize-observer-host{box-sizing:inherit;display:block;opacity:0;position:absolute;top:0;left:0;height:100%;width:100%;overflow:hidden;pointer-events:none;z-index:-1}.os-resize-observer-host{padding:inherit;border:inherit;border-color:transparent;border-style:solid;box-sizing:border-box}.os-resize-observer-host:after{content:''}.os-resize-observer-host>.os-resize-observer,.os-resize-observer-host:after{height:200%;width:200%;padding:inherit;border:inherit;margin:0;display:block;box-sizing:content-box}.os-resize-observer.observed,object.os-resize-observer{box-sizing:border-box!important}.os-size-auto-observer{box-sizing:inherit!important;height:100%;width:inherit;max-width:1px;position:relative;float:left;max-height:1px;overflow:hidden;z-index:-1;padding:0;margin:0;pointer-events:none;-webkit-box-flex:inherit;-ms-flex-positive:inherit;flex-grow:inherit;-ms-flex-negative:0;flex-shrink:0;-ms-flex-preferred-size:0;flex-basis:0%}.os-size-auto-observer>.os-resize-observer{width:1000%;height:1000%;min-height:1px;min-width:1px}.os-resize-observer-item{position:absolute;top:0;right:0;bottom:0;left:0;overflow:hidden;z-index:-1;opacity:0;direction:ltr!important;-webkit-box-flex:0!important;-ms-flex:none!important;flex:none!important}.os-resize-observer-item-final{position:absolute;left:0;top:0;-webkit-transition:none!important;transition:none!important;-webkit-box-flex:0!important;-ms-flex:none!important;flex:none!important}.os-resize-observer{-webkit-animation-duration:0.001s;animation-duration:0.001s;-webkit-animation-name:hs-resize-observer-dummy-animation;animation-name:hs-resize-observer-dummy-animation}.os-host-transition>.os-scrollbar,.os-host-transition>.os-scrollbar-corner{-webkit-transition:opacity 0.3s,visibility 0.3s,top 0.3s,right 0.3s,bottom 0.3s,left 0.3s;transition:opacity 0.3s,visibility 0.3s,top 0.3s,right 0.3s,bottom 0.3s,left 0.3s}html.os-html>.os-host>.os-scrollbar{position:absolute;z-index:999999}.os-scrollbar,.os-scrollbar-corner{position:absolute;opacity:1;-ms-filter:'progid:DXImageTransform.Microsoft.Alpha(Opacity=100)';z-index:1}.os-scrollbar-corner{bottom:0;right:0}.os-scrollbar{pointer-events:none}.os-scrollbar-track{pointer-events:auto;position:relative;height:100%;width:100%;padding:0!important;border:none!important}.os-scrollbar-handle{pointer-events:auto;position:absolute;width:100%;height:100%}.os-scrollbar-handle-off,.os-scrollbar-track-off{pointer-events:none}.os-scrollbar.os-scrollbar-unusable,.os-scrollbar.os-scrollbar-unusable *{pointer-events:none!important}.os-scrollbar.os-scrollbar-unusable .os-scrollbar-handle{opacity:0!important}.os-scrollbar-horizontal{bottom:0;left:0}.os-scrollbar-vertical{top:0;right:0}.os-host-rtl>.os-scrollbar-horizontal{right:0}.os-host-rtl>.os-scrollbar-vertical{right:auto;left:0}.os-host-rtl>.os-scrollbar-corner{right:auto;left:0}.os-scrollbar-auto-hidden,.os-padding + .os-scrollbar-corner,.os-host-resize-disabled.os-host-scrollbar-horizontal-hidden>.os-scrollbar-corner,.os-host-scrollbar-horizontal-hidden>.os-scrollbar-horizontal,.os-host-resize-disabled.os-host-scrollbar-vertical-hidden>.os-scrollbar-corner,.os-host-scrollbar-vertical-hidden>.os-scrollbar-vertical,.os-scrollbar-horizontal.os-scrollbar-auto-hidden + .os-scrollbar-vertical + .os-scrollbar-corner,.os-scrollbar-horizontal + .os-scrollbar-vertical.os-scrollbar-auto-hidden + .os-scrollbar-corner,.os-scrollbar-horizontal.os-scrollbar-auto-hidden + .os-scrollbar-vertical.os-scrollbar-auto-hidden + .os-scrollbar-corner{opacity:0;visibility:hidden;pointer-events:none}.os-scrollbar-corner-resize-both{cursor:nwse-resize}.os-host-rtl>.os-scrollbar-corner-resize-both{cursor:nesw-resize}.os-scrollbar-corner-resize-horizontal{cursor:ew-resize}.os-scrollbar-corner-resize-vertical{cursor:ns-resize}.os-dragging .os-scrollbar-corner.os-scrollbar-corner-resize{cursor:default}.os-host-resize-disabled.os-host-scrollbar-horizontal-hidden>.os-scrollbar-vertical{top:0;bottom:0}.os-host-resize-disabled.os-host-scrollbar-vertical-hidden>.os-scrollbar-horizontal,.os-host-rtl.os-host-resize-disabled.os-host-scrollbar-vertical-hidden>.os-scrollbar-horizontal{right:0;left:0}.os-scrollbar:hover,.os-scrollbar-corner.os-scrollbar-corner-resize{opacity:1!important;visibility:visible!important}.os-scrollbar-corner.os-scrollbar-corner-resize{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIgICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgICB3aWR0aD0iMTAiICAgaGVpZ2h0PSIxMCIgICB2ZXJzaW9uPSIxLjEiPiAgPGcgICAgIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAsLTEwNDIuMzYyMikiICAgICBzdHlsZT0iZGlzcGxheTppbmxpbmUiPiAgICA8cGF0aCAgICAgICBzdHlsZT0iZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eTowLjQ5NDExNzY1O2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTpub25lIiAgICAgICBkPSJtIDcuNDI0MjE4NywxMDQyLjM2MjIgYyAtMC43MjM1NzkyLDAgLTEuMzEwMTU2MiwwLjU4NjYgLTEuMzEwMTU2MiwxLjMxMDIgMCwwLjI5OSAwLjEwNDM0MTksMC41NzEgMC4yNzI5NDkyLDAuNzkxNSAwLjIwOTEwMjQsMC4xNDEzIDAuNDY1NjIwNiwwLjIxODQgMC43MzY5NjI5LDAuMjE4NCAwLjcyMzU3OTMsMCAxLjMxMDE1NjMsLTAuNTg2NiAxLjMxMDE1NjMsLTEuMzEwMiAwLC0wLjI3MTMgLTAuMDc3MDkzLC0wLjUyNzggLTAuMjE4MzU5NCwtMC43MzcgLTAuMjIwNDk0MSwtMC4xNjg2IC0wLjQ5MjU0NDMsLTAuMjcyOSAtMC43OTE1NTI4LC0wLjI3MjkgeiBtIDAsMy4wODQzIGMgLTAuNzIzNTc5MiwwIC0xLjMxMDE1NjIsMC41ODY2IC0xLjMxMDE1NjIsMS4zMTAyIDAsMC4yOTkgMC4xMDQzNDE5LDAuNTcxIDAuMjcyOTQ5MiwwLjc5MTUgMC4yMDkxMDI0LDAuMTQxMyAwLjQ2NTYyMDYsMC4yMTg0IDAuNzM2OTYyOSwwLjIxODQgMC43MjM1NzkzLDAgMS4zMTAxNTYzLC0wLjU4NjYgMS4zMTAxNTYzLC0xLjMxMDIgMCwtMC4yNzEzIC0wLjA3NzA5MywtMC41Mjc4IC0wLjIxODM1OTQsLTAuNzM2OSAtMC4yMjA0OTQxLC0wLjE2ODYgLTAuNDkyNTQ0MywtMC4yNzMgLTAuNzkxNTUyOCwtMC4yNzMgeiBtIC0zLjA4NDMyNjEsMCBjIC0wLjcyMzU3OTMsMCAtMS4zMTAxNTYzLDAuNTg2NiAtMS4zMTAxNTYzLDEuMzEwMiAwLDAuMjk5IDAuMTA0MzQxOSwwLjU3MSAwLjI3Mjk0OTIsMC43OTE1IDAuMjA5MTAyNCwwLjE0MTMgMC40NjU2MjA3LDAuMjE4NCAwLjczNjk2MjksMC4yMTg0IDAuNzIzNTc5MywwIDEuMzEwMTU2MywtMC41ODY2IDEuMzEwMTU2MywtMS4zMTAyIDAsLTAuMjcxMyAtMC4wNzcwOTMsLTAuNTI3OCAtMC4yMTgzNTk0LC0wLjczNjkgLTAuMjIwNDk0LC0wLjE2ODYgLTAuNDkyNTQ0MiwtMC4yNzMgLTAuNzkxNTUyNywtMC4yNzMgeiBtIC0zLjAyOTczNjQsMy4wMjk4IEMgMC41ODY1NzY5MywxMDQ4LjQ3NjMgMCwxMDQ5LjA2MjggMCwxMDQ5Ljc4NjQgYyAwLDAuMjk5IDAuMTA0MzQxOSwwLjU3MTEgMC4yNzI5NDkyMiwwLjc5MTYgMC4yMDkxMDIyOSwwLjE0MTIgMC40NjU2MjA2NSwwLjIxODMgMC43MzY5NjI4OCwwLjIxODMgMC43MjM1NzkzLDAgMS4zMTAxNTYzLC0wLjU4NjUgMS4zMTAxNTYzLC0xLjMxMDEgMCwtMC4yNzE0IC0wLjA3NzA5MywtMC41Mjc5IC0wLjIxODM1OTQsLTAuNzM3IC0wLjIyMDQ5NDEsLTAuMTY4NiAtMC40OTI1NDQzLC0wLjI3MjkgLTAuNzkxNTUyOCwtMC4yNzI5IHogbSAzLjAyOTczNjQsMCBjIC0wLjcyMzU3OTMsMCAtMS4zMTAxNTYzLDAuNTg2NSAtMS4zMTAxNTYzLDEuMzEwMSAwLDAuMjk5IDAuMTA0MzQxOSwwLjU3MTEgMC4yNzI5NDkyLDAuNzkxNiAwLjIwOTEwMjQsMC4xNDEyIDAuNDY1NjIwNywwLjIxODMgMC43MzY5NjI5LDAuMjE4MyAwLjcyMzU3OTMsMCAxLjMxMDE1NjMsLTAuNTg2NSAxLjMxMDE1NjMsLTEuMzEwMSAwLC0wLjI3MTQgLTAuMDc3MDkzLC0wLjUyNzkgLTAuMjE4MzU5NCwtMC43MzcgLTAuMjIwNDk0LC0wLjE2ODYgLTAuNDkyNTQ0MiwtMC4yNzI5IC0wLjc5MTU1MjcsLTAuMjcyOSB6IG0gMy4wODQzMjYxLDAgYyAtMC43MjM1NzkyLDAgLTEuMzEwMTU2MiwwLjU4NjUgLTEuMzEwMTU2MiwxLjMxMDEgMCwwLjI5OSAwLjEwNDM0MTksMC41NzExIDAuMjcyOTQ5MiwwLjc5MTYgMC4yMDkxMDI0LDAuMTQxMiAwLjQ2NTYyMDYsMC4yMTgzIDAuNzM2OTYyOSwwLjIxODMgMC43MjM1NzkzLDAgMS4zMTAxNTYzLC0wLjU4NjUgMS4zMTAxNTYzLC0xLjMxMDEgMCwtMC4yNzE0IC0wLjA3NzA5MywtMC41Mjc5IC0wLjIxODM1OTQsLTAuNzM3IC0wLjIyMDQ5NDEsLTAuMTY4NiAtMC40OTI1NDQzLC0wLjI3MjkgLTAuNzkxNTUyOCwtMC4yNzI5IHoiLz4gIDwvZz4gIDxnICAgICBzdHlsZT0iZGlzcGxheTppbmxpbmUiPiAgICA8cGF0aCAgICAgICBzdHlsZT0iZmlsbDojZmZmZmZmO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTpub25lIiAgICAgICBkPSJtIDguMjE1NzcxNSwwLjI3Mjk0OTIyIGMgMC4xNDEyNjY3LDAuMjA5MTAyMjkgMC4yMTgzNTk0LDAuNDY1NjIwNjUgMC4yMTgzNTk0LDAuNzM2OTYyODggMCwwLjcyMzU3OTMgLTAuNTg2NTc3LDEuMzEwMTU2MyAtMS4zMTAxNTYzLDEuMzEwMTU2MyAtMC4yNzEzNDIzLDAgLTAuNTI3ODYwNSwtMC4wNzcwOTMgLTAuNzM2OTYyOSwtMC4yMTgzNTk0IDAuMjM5NDEwNCwwLjMxMzA4NTkgMC42MTI2MzYyLDAuNTE4NjAzNSAxLjAzNzIwNywwLjUxODYwMzUgMC43MjM1NzkzLDAgMS4zMTAxNTYzLC0wLjU4NjU3NyAxLjMxMDE1NjMsLTEuMzEwMTU2MyAwLC0wLjQyNDU3MDc2IC0wLjIwNTUxNzYsLTAuNzk3Nzk2NTkgLTAuNTE4NjAzNSwtMS4wMzcyMDY5OCB6IG0gMCwzLjA4NDMyNjE4IGMgMC4xNDEyNjY3LDAuMjA5MTAyMyAwLjIxODM1OTQsMC40NjU2MjA2IDAuMjE4MzU5NCwwLjczNjk2MjkgMCwwLjcyMzU3OTMgLTAuNTg2NTc3LDEuMzEwMTU2MiAtMS4zMTAxNTYzLDEuMzEwMTU2MiAtMC4yNzEzNDIzLDAgLTAuNTI3ODYwNSwtMC4wNzcwOTMgLTAuNzM2OTYyOSwtMC4yMTgzNTkzIDAuMjM5NDEwNCwwLjMxMzA4NTkgMC42MTI2MzYyLDAuNTE4NjAzNSAxLjAzNzIwNywwLjUxODYwMzUgMC43MjM1NzkzLDAgMS4zMTAxNTYzLC0wLjU4NjU3NyAxLjMxMDE1NjMsLTEuMzEwMTU2MyAwLC0wLjQyNDU3MDggLTAuMjA1NTE3NiwtMC43OTc3OTY3IC0wLjUxODYwMzUsLTEuMDM3MjA3IHogbSAtMy4wODQzMjYyLDAgYyAwLjE0MTI2NjcsMC4yMDkxMDIzIDAuMjE4MzU5NCwwLjQ2NTYyMDYgMC4yMTgzNTk0LDAuNzM2OTYyOSAwLDAuNzIzNTc5MyAtMC41ODY1NzcsMS4zMTAxNTYyIC0xLjMxMDE1NjMsMS4zMTAxNTYyIC0wLjI3MTM0MjIsMCAtMC41Mjc4NjA1LC0wLjA3NzA5MyAtMC43MzY5NjI5LC0wLjIxODM1OTMgMC4yMzk0MTA0LDAuMzEzMDg1OSAwLjYxMjYzNjMsMC41MTg2MDM1IDEuMDM3MjA3MSwwLjUxODYwMzUgMC43MjM1NzkzLDAgMS4zMTAxNTYyLC0wLjU4NjU3NyAxLjMxMDE1NjIsLTEuMzEwMTU2MyAwLC0wLjQyNDU3MDggLTAuMjA1NTE3NSwtMC43OTc3OTY3IC0wLjUxODYwMzUsLTEuMDM3MjA3IHogTSAyLjEwMTcwOSw2LjM4NzAxMTcgYyAwLjE0MTI2NjcsMC4yMDkxMDI0IDAuMjE4MzU5NCwwLjQ2NTYyMDYgMC4yMTgzNTk0LDAuNzM2OTYyOSAwLDAuNzIzNTc5MyAtMC41ODY1NzcsMS4zMTAxNTYzIC0xLjMxMDE1NjMsMS4zMTAxNTYzIC0wLjI3MTM0MjIzLDAgLTAuNTI3ODYwNTksLTAuMDc3MDkzIC0wLjczNjk2Mjg4LC0wLjIxODM1OTQgMC4yMzk0MTAzOSwwLjMxMzA4NTkgMC42MTI2MzYyMiwwLjUxODYwMzUgMS4wMzcyMDY5OCwwLjUxODYwMzUgMC43MjM1NzkzLDAgMS4zMTAxNTYzLC0wLjU4NjU3NyAxLjMxMDE1NjMsLTEuMzEwMTU2MyAwLC0wLjQyNDU3MDggLTAuMjA1NTE3NiwtMC43OTc3OTY2IC0wLjUxODYwMzUsLTEuMDM3MjA3IHogbSAzLjAyOTczNjMsMCBjIDAuMTQxMjY2NywwLjIwOTEwMjQgMC4yMTgzNTk0LDAuNDY1NjIwNiAwLjIxODM1OTQsMC43MzY5NjI5IDAsMC43MjM1NzkzIC0wLjU4NjU3NywxLjMxMDE1NjMgLTEuMzEwMTU2MywxLjMxMDE1NjMgLTAuMjcxMzQyMiwwIC0wLjUyNzg2MDUsLTAuMDc3MDkzIC0wLjczNjk2MjksLTAuMjE4MzU5NCAwLjIzOTQxMDQsMC4zMTMwODU5IDAuNjEyNjM2MywwLjUxODYwMzUgMS4wMzcyMDcxLDAuNTE4NjAzNSAwLjcyMzU3OTMsMCAxLjMxMDE1NjIsLTAuNTg2NTc3IDEuMzEwMTU2MiwtMS4zMTAxNTYzIDAsLTAuNDI0NTcwOCAtMC4yMDU1MTc1LC0wLjc5Nzc5NjYgLTAuNTE4NjAzNSwtMS4wMzcyMDcgeiBtIDMuMDg0MzI2MiwwIGMgMC4xNDEyNjY3LDAuMjA5MTAyNCAwLjIxODM1OTQsMC40NjU2MjA2IDAuMjE4MzU5NCwwLjczNjk2MjkgMCwwLjcyMzU3OTMgLTAuNTg2NTc3LDEuMzEwMTU2MyAtMS4zMTAxNTYzLDEuMzEwMTU2MyAtMC4yNzEzNDIzLDAgLTAuNTI3ODYwNSwtMC4wNzcwOTMgLTAuNzM2OTYyOSwtMC4yMTgzNTk0IDAuMjM5NDEwNCwwLjMxMzA4NTkgMC42MTI2MzYyLDAuNTE4NjAzNSAxLjAzNzIwNywwLjUxODYwMzUgMC43MjM1NzkzLDAgMS4zMTAxNTYzLC0wLjU4NjU3NyAxLjMxMDE1NjMsLTEuMzEwMTU2MyAwLC0wLjQyNDU3MDggLTAuMjA1NTE3NiwtMC43OTc3OTY2IC0wLjUxODYwMzUsLTEuMDM3MjA3IHoiIC8+ICA8L2c+PC9zdmc+);background-repeat:no-repeat;background-position:100% 100%;pointer-events:auto!important}.os-host-rtl>.os-scrollbar-corner.os-scrollbar-corner-resize{-webkit-transform:scale(-1,1);transform:scale(-1,1)}.os-host-overflow{overflow:hidden!important}@-webkit-keyframes hs-resize-observer-dummy-animation{from{z-index:0}to{z-index:-1}}@keyframes hs-resize-observer-dummy-animation{from{z-index:0}to{z-index:-1}}.os-theme-none>.os-scrollbar-horizontal,.os-theme-none>.os-scrollbar-vertical,.os-theme-none>.os-scrollbar-corner{display:none!important}.os-theme-none>.os-scrollbar-corner-resize{display:block!important;min-width:10px;min-height:10px}.os-theme-dark>.os-scrollbar-horizontal,.os-theme-light>.os-scrollbar-horizontal{right:10px;height:10px}.os-theme-dark>.os-scrollbar-vertical,.os-theme-light>.os-scrollbar-vertical{bottom:10px;width:10px}.os-theme-dark.os-host-rtl>.os-scrollbar-horizontal,.os-theme-light.os-host-rtl>.os-scrollbar-horizontal{left:10px;right:0}.os-theme-dark>.os-scrollbar-corner,.os-theme-light>.os-scrollbar-corner{height:10px;width:10px}.os-theme-dark>.os-scrollbar-corner,.os-theme-light>.os-scrollbar-corner{background-color:transparent}.os-theme-dark>.os-scrollbar,.os-theme-light>.os-scrollbar{padding:2px;box-sizing:border-box;background:transparent}.os-theme-dark>.os-scrollbar.os-scrollbar-unusable,.os-theme-light>.os-scrollbar.os-scrollbar-unusable{background:transparent}.os-theme-dark>.os-scrollbar>.os-scrollbar-track,.os-theme-light>.os-scrollbar>.os-scrollbar-track{background:transparent}.os-theme-dark>.os-scrollbar-horizontal>.os-scrollbar-track>.os-scrollbar-handle,.os-theme-light>.os-scrollbar-horizontal>.os-scrollbar-track>.os-scrollbar-handle{min-width:30px}.os-theme-dark>.os-scrollbar-vertical>.os-scrollbar-track>.os-scrollbar-handle,.os-theme-light>.os-scrollbar-vertical>.os-scrollbar-track>.os-scrollbar-handle{min-height:30px}.os-theme-dark.os-host-transition>.os-scrollbar>.os-scrollbar-track>.os-scrollbar-handle,.os-theme-light.os-host-transition>.os-scrollbar>.os-scrollbar-track>.os-scrollbar-handle{-webkit-transition:background-color 0.3s;transition:background-color 0.3s}.os-theme-dark>.os-scrollbar>.os-scrollbar-track>.os-scrollbar-handle,.os-theme-light>.os-scrollbar>.os-scrollbar-track>.os-scrollbar-handle,.os-theme-dark>.os-scrollbar>.os-scrollbar-track,.os-theme-light>.os-scrollbar>.os-scrollbar-track{border-radius:10px}.os-theme-dark>.os-scrollbar>.os-scrollbar-track>.os-scrollbar-handle{background:rgba(0,0,0,.4)}.os-theme-light>.os-scrollbar>.os-scrollbar-track>.os-scrollbar-handle{background:rgba(255,255,255,.4)}.os-theme-dark>.os-scrollbar:hover>.os-scrollbar-track>.os-scrollbar-handle{background:rgba(0,0,0,.55)}.os-theme-light>.os-scrollbar:hover>.os-scrollbar-track>.os-scrollbar-handle{background:rgba(255,255,255,.55)}.os-theme-dark>.os-scrollbar>.os-scrollbar-track>.os-scrollbar-handle.active{background:rgba(0,0,0,.7)}.os-theme-light>.os-scrollbar>.os-scrollbar-track>.os-scrollbar-handle.active{background:rgba(255,255,255,.7)}.os-theme-dark>.os-scrollbar-horizontal .os-scrollbar-handle:before,.os-theme-dark>.os-scrollbar-vertical .os-scrollbar-handle:before,.os-theme-light>.os-scrollbar-horizontal .os-scrollbar-handle:before,.os-theme-light>.os-scrollbar-vertical .os-scrollbar-handle:before{content:'';position:absolute;left:0;right:0;top:0;bottom:0;display:block}.os-theme-dark.os-host-scrollbar-horizontal-hidden>.os-scrollbar-horizontal .os-scrollbar-handle:before,.os-theme-dark.os-host-scrollbar-vertical-hidden>.os-scrollbar-vertical .os-scrollbar-handle:before,.os-theme-light.os-host-scrollbar-horizontal-hidden>.os-scrollbar-horizontal .os-scrollbar-handle:before,.os-theme-light.os-host-scrollbar-vertical-hidden>.os-scrollbar-vertical .os-scrollbar-handle:before{display:none}.os-theme-dark>.os-scrollbar-horizontal .os-scrollbar-handle:before,.os-theme-light>.os-scrollbar-horizontal .os-scrollbar-handle:before{top:-6px;bottom:-2px}.os-theme-dark>.os-scrollbar-vertical .os-scrollbar-handle:before,.os-theme-light>.os-scrollbar-vertical .os-scrollbar-handle:before{left:-6px;right:-2px}.os-host-rtl.os-theme-dark>.os-scrollbar-vertical .os-scrollbar-handle:before,.os-host-rtl.os-theme-light>.os-scrollbar-vertical .os-scrollbar-handle:before{right:-6px;left:-2px} \ No newline at end of file diff --git a/js/OverlayScrollbars.js b/js/OverlayScrollbars.js index 8527ef3..36dee34 100644 --- a/js/OverlayScrollbars.js +++ b/js/OverlayScrollbars.js @@ -2,13 +2,13 @@ * OverlayScrollbars * https://github.com/KingSora/OverlayScrollbars * - * Version: 1.7.3 + * Version: 1.8.0 * - * Copyright KingSora. + * Copyright KingSora | Rene Haas. * https://github.com/KingSora * * Released under the MIT license. - * Date: 23.06.2019 + * Date: 08.07.2019 */ (function (global, factory) { @@ -47,7 +47,8 @@ sH : 'scrollHeight', oW : 'offsetWidth', cW : 'clientWidth', - sW : 'scrollWidth' + sW : 'scrollWidth', + hOP : 'hasOwnProperty' }; var VENDORS = { //https://developer.mozilla.org/en-US/docs/Glossary/Vendor_Prefix @@ -1443,6 +1444,7 @@ var _pluginsAutoUpdateLoop; var _pluginsExtensions = [ ]; var _pluginsOptions = (function() { + var type = COMPATIBILITY.type; var possibleTemplateTypes = [ TYPES.b, //boolean TYPES.n, //number @@ -1517,10 +1519,10 @@ var val; var valType; for(key in obj) { - if(!obj.hasOwnProperty(key)) + if(!obj[LEXICON.hOP](key)) continue; val = obj[key]; - valType = COMPATIBILITY.type(val); + valType = type(val); if(valType == TYPES.a) obj[key] = val[template ? 1 : 0]; else if(valType == TYPES.o) @@ -1541,23 +1543,27 @@ * @param obj The object which shall be validated. * @param template The template which defines the allowed values and types. * @param writeErrors True if errors shall be logged to the console. - * @param usePreparedValues True if the validated main values shall be returned in the validated object, false otherwise. - * @param keepForeignProps True if properties which aren't in the template shall be added to the validated object, false otherwise. - * @returns {{}} A object which contains only the valid properties of the passed original object. + * @param diffObj If a object is passed then only valid differences to this object will be returned. + * @returns {{}} A object which contains two objects called "default" and "prepared" which contains only the valid properties of the passed original object and discards not different values compared to the passed diffObj. */ - _validate : function (obj, template, writeErrors, usePreparedValues, keepForeignProps) { + _validate : function (obj, template, writeErrors, diffObj) { var validatedOptions = { }; + var validatedOptionsPrepared = { }; var objectCopy = FRAMEWORK.extend(true, { }, obj); - var checkObjectProps = function(data, template, validatedOptions, prevPropName) { + var inArray = FRAMEWORK.inArray; + var isEmptyObj = FRAMEWORK.isEmptyObject; + var checkObjectProps = function(data, template, diffData, validatedOptions, validatedOptionsPrepared, prevPropName) { for (var prop in template) { - if (template.hasOwnProperty(prop) && data.hasOwnProperty(prop)) { + if (template[LEXICON.hOP](prop) && data[LEXICON.hOP](prop)) { var isValid = false; + var isDiff = false; var templateValue = template[prop]; - var templateValueType = COMPATIBILITY.type(templateValue); - var templateIsComplext = templateValueType == TYPES.o; - var templateTypes = COMPATIBILITY.type(templateValue) != TYPES.a ? [ templateValue ] : templateValue; + var templateValueType = type(templateValue); + var templateIsComplex = templateValueType == TYPES.o; + var templateTypes = type(templateValue) != TYPES.a ? [ templateValue ] : templateValue; + var dataDiffValue = diffData[prop]; var dataValue = data[prop]; - var dataValueType = COMPATIBILITY.type(dataValue); + var dataValueType = type(dataValue); var propPrefix = prevPropName ? prevPropName + "." : ""; var error = "The option \"" + propPrefix + prop + "\" wasn't set, because"; var errorPossibleTypes = [ ]; @@ -1571,30 +1577,32 @@ var v; var j; + dataDiffValue = dataDiffValue === undefined ? { } : dataDiffValue; + //if the template has a object as value, it means that the options are complex (verschachtelt) - if(templateIsComplext && dataValueType == TYPES.o) { - validatedOptions[prop] = { }; - checkObjectProps(dataValue, templateValue, validatedOptions[prop], propPrefix + prop); - if(FRAMEWORK.isEmptyObject(dataValue)) + if(templateIsComplex && dataValueType == TYPES.o) { + validatedOptions[prop] = validatedOptionsPrepared[prop] = { }; + checkObjectProps(dataValue, templateValue, dataDiffValue, validatedOptions[prop], validatedOptionsPrepared[prop], propPrefix + prop); + if(isEmptyObj(dataValue)) delete data[prop]; } - else if(!templateIsComplext) { - for(i = 0; i < templateTypes.length; i++) { + else if(!templateIsComplex) { + for(i = 0; i < templateTypes[LEXICON.l]; i++) { currType = templateTypes[i]; - templateValueType = COMPATIBILITY.type(currType); + templateValueType = type(currType); //if currtype is string and starts with restrictedStringPrefix and end with restrictedStringSuffix - isRestrictedValue = templateValueType == TYPES.s && FRAMEWORK.inArray(currType, possibleTemplateTypes) === -1; + isRestrictedValue = templateValueType == TYPES.s && inArray(currType, possibleTemplateTypes) === -1; if(isRestrictedValue) { errorPossibleTypes.push(TYPES.s); //split it into a array which contains all possible values for example: ["y:yes", "n:no", "m:maybe"] restrictedStringValuesSplit = currType.split(restrictedStringsSplit); errorRestrictedStrings = errorRestrictedStrings.concat(restrictedStringValuesSplit); - for(v = 0; v < restrictedStringValuesSplit.length; v++) { + for(v = 0; v < restrictedStringValuesSplit[LEXICON.l]; v++) { //split the possible values into their possibiliteis for example: ["y", "yes"] -> the first is always the mainPossibility restrictedStringValuesPossibilitiesSplit = restrictedStringValuesSplit[v].split(restrictedStringsPossibilitiesSplit); mainPossibility = restrictedStringValuesPossibilitiesSplit[0]; - for(j = 0; j < restrictedStringValuesPossibilitiesSplit.length; j++) { + for(j = 0; j < restrictedStringValuesPossibilitiesSplit[LEXICON.l]; j++) { //if any possibility matches with the dataValue, its valid if(dataValue === restrictedStringValuesPossibilitiesSplit[j]) { isValid = true; @@ -1616,27 +1624,41 @@ } if(isValid) { - validatedOptions[prop] = isRestrictedValue && usePreparedValues ? mainPossibility : dataValue; + isDiff = dataValue !== dataDiffValue; + + if(isDiff) + validatedOptions[prop] = dataValue; + + if(isRestrictedValue ? inArray(dataDiffValue, restrictedStringValuesPossibilitiesSplit) < 0 : isDiff) + validatedOptionsPrepared[prop] = isRestrictedValue ? mainPossibility : dataValue; } else if(writeErrors) { console.warn(error + " it doesn't accept the type [ " + dataValueType.toUpperCase() + " ] with the value of \"" + dataValue + "\".\r\n" + "Accepted types are: [ " + errorPossibleTypes.join(", ").toUpperCase() + " ]." + - (errorRestrictedStrings.length > 0 ? "\r\nValid strings are: [ " + errorRestrictedStrings.join(", ").split(restrictedStringsPossibilitiesSplit).join(", ") + " ]." : "")); + (errorRestrictedStrings[length] > 0 ? "\r\nValid strings are: [ " + errorRestrictedStrings.join(", ").split(restrictedStringsPossibilitiesSplit).join(", ") + " ]." : "")); } delete data[prop]; } } } }; - checkObjectProps(objectCopy, template, validatedOptions); + checkObjectProps(objectCopy, template, diffObj || { }, validatedOptions, validatedOptionsPrepared); //add values which aren't specified in the template to the finished validated object to prevent them from being discarded - if(keepForeignProps) + /* + if(keepForeignProps) { FRAMEWORK.extend(true, validatedOptions, objectCopy); - else if(!FRAMEWORK.isEmptyObject(objectCopy) && writeErrors) + FRAMEWORK.extend(true, validatedOptionsPrepared, objectCopy); + } + */ + + if(!isEmptyObj(objectCopy) && writeErrors) console.warn("The following options are discarded due to invalidity:\r\n" + window.JSON.stringify(objectCopy, null, 2)); - return validatedOptions; + return { + _default : validatedOptions, + _prepared : validatedOptionsPrepared + }; } } }()); @@ -1665,7 +1687,6 @@ var scrollbarDummyElement = FRAMEWORK('
'); var scrollbarDummyElement0 = scrollbarDummyElement[0]; var dummyContainerChild = FRAMEWORK(scrollbarDummyElement.children('div').eq(0)); - var getCptStyle = window.getComputedStyle; bodyElement.append(scrollbarDummyElement); scrollbarDummyElement.hide().show(); //fix IE8 bug (incorrect measuring) @@ -1683,14 +1704,18 @@ nativeScrollbarSize : nativeScrollbarSize, nativeScrollbarIsOverlaid : nativeScrollbarIsOverlaid, nativeScrollbarStyling : (function() { + var result = false; scrollbarDummyElement.addClass('os-viewport-native-scrollbars-invisible'); - + try { + result = scrollbarDummyElement.css('scrollbar-width') === 'none' || window.getComputedStyle(scrollbarDummyElement0, '::-webkit-scrollbar').getPropertyValue('display') === 'none'; + } catch (ex) { } + //fix opera bug: scrollbar styles will only appear if overflow value is scroll or auto during the activation of the style. //and set overflow to scroll //scrollbarDummyElement.css(strOverflow, strHidden).hide().css(strOverflow, strScroll).show(); //return (scrollbarDummyElement0[LEXICON.oH] - scrollbarDummyElement0[LEXICON.cH]) === 0 && (scrollbarDummyElement0[LEXICON.oW] - scrollbarDummyElement0[LEXICON.cW]) === 0; - return scrollbarDummyElement.css('scrollbar-width') === 'none' || (getCptStyle ? getCptStyle(scrollbarDummyElement0, '::-webkit-scrollbar').getPropertyValue('display') === 'none' : false); + return result; })(), overlayScrollbarDummySize : { x: 30, y: 30 }, msie : (function() { @@ -1866,6 +1891,8 @@ */ function OverlayScrollbarsAutoUpdateLoop(globals) { var _base = this; + var _inArray = FRAMEWORK.inArray; + var _getNow = COMPATIBILITY.now; var _strAutoUpdate = 'autoUpdate'; var _strAutoUpdateInterval = _strAutoUpdate + 'Interval'; var _strLength = LEXICON.l; @@ -1874,8 +1901,9 @@ var _loopIsActive = false; var _loopIntervalDefault = 33; var _loopInterval = _loopIntervalDefault; - var _loopTimeOld = COMPATIBILITY.now(); + var _loopTimeOld = _getNow(); var _loopID; + /** * The auto update loop which will run every 50 milliseconds or less if the update interval of a instance is lower than 50 milliseconds. @@ -1885,7 +1913,7 @@ _loopID = COMPATIBILITY.rAF()(function () { loop(); }); - var timeNew = COMPATIBILITY.now(); + var timeNew = _getNow(); var timeDelta = timeNew - _loopTimeOld; var lowestInterval; var instance; @@ -1903,7 +1931,7 @@ instanceOptions = instance.options(); instanceAutoUpdateAllowed = instanceOptions[_strAutoUpdate]; instanceAutoUpdateInterval = MATH.max(1, instanceOptions[_strAutoUpdateInterval]); - now = COMPATIBILITY.now(); + now = _getNow(); if ((instanceAutoUpdateAllowed === true || instanceAutoUpdateAllowed === null) && (now - _loopingInstancesIntervalCache[i]) > instanceAutoUpdateInterval) { instance.update('auto'); @@ -1925,9 +1953,9 @@ * @param instance The instance which shall be updated in a loop automatically. */ _base.add = function(instance) { - if(FRAMEWORK.inArray(instance, _loopingInstances) === -1) { + if(_inArray(instance, _loopingInstances) === -1) { _loopingInstances.push(instance); - _loopingInstancesIntervalCache.push(COMPATIBILITY.now()); + _loopingInstancesIntervalCache.push(_getNow()); if (_loopingInstances[_strLength] > 0 && !_loopIsActive) { _loopIsActive = true; globals.autoUpdateLoop = _loopIsActive; @@ -1941,7 +1969,7 @@ * @param instance The instance which shall be updated in a loop automatically. */ _base.remove = function(instance) { - var index = FRAMEWORK.inArray(instance, _loopingInstances); + var index = _inArray(instance, _loopingInstances); if(index > -1) { //remove from loopingInstances list _loopingInstancesIntervalCache.splice(index, 1); @@ -1971,10 +1999,19 @@ * @constructor */ function OverlayScrollbarsInstance(pluginTargetElement, options, extensions, globals, autoUpdateLoop) { + //shortcuts + var type = COMPATIBILITY.type; + var inArray = FRAMEWORK.inArray; + var each = FRAMEWORK.each; + + //make correct instanceof + var _base = new window[PLUGINNAME](); + var _frameworkProto = FRAMEWORK[LEXICON.p]; + //if passed element is no HTML element: skip and return if(!isHTMLElement(pluginTargetElement)) return; - + //if passed element is already initialized: set passed options if there are any and return its instance if(INSTANCES(pluginTargetElement)) { var inst = INSTANCES(pluginTargetElement); @@ -1982,10 +2019,6 @@ return inst; } - //make correct instanceof - var _base = new window[PLUGINNAME](); - var _frameworkProto = FRAMEWORK[LEXICON.p]; - //globals: var _nativeScrollbarIsOverlaid; var _overlayScrollbarDummySize; @@ -2020,7 +2053,7 @@ var _marginX; var _marginY; var _isRTL; - var _isSleeping; + var _sleeping; var _contentBorderSize = { }; var _scrollHorizontalInfo = { }; var _scrollVerticalInfo = { }; @@ -2043,6 +2076,7 @@ var _strFloat = 'float'; var _strEmpty = ''; var _strAuto = 'auto'; + var _strSync = 'sync'; var _strScroll = 'scroll'; var _strHundredPercent = '100%'; var _strX = 'x'; @@ -2120,11 +2154,11 @@ //extensions: var _extensions = { }; - var _extensionsPrivateMethods = "added removed on contract"; + var _extensionsPrivateMethods = 'added removed on contract'; //update var _lastUpdateTime; - var _swallowedUpdateParams = { }; + var _swallowedUpdateHints = { }; var _swallowedUpdateTimeout; var _swallowUpdateLag = 42; var _imgs = [ ]; @@ -2186,13 +2220,6 @@ var _sizeAutoCapableCache; var _textareaAutoWrappingCache; var _textareaInfoCache; - var _updateAutoHostElementIdCache; - var _updateAutoHostElementClassCache; - var _updateAutoHostElementStyleCache; - var _updateAutoHostElementVisibleCache; - var _updateAutoTargetElementRowsCache; - var _updateAutoTargetElementColsCache; - var _updateAutoTargetElementWrapCache; var _contentElementScrollSizeChangeDetectedCache; var _hostElementSizeChangeDetectedCache; var _scrollbarsVisibilityCache; @@ -2208,6 +2235,7 @@ var _bodyMinSizeCache; var _viewportScrollSizeCache; var _displayIsHiddenCache; + var _updateAutoCache = { }; //MutationObserver: var _mutationObserverHost; @@ -2215,6 +2243,8 @@ var _mutationObserverHostCallback; var _mutationObserverContentCallback; var _mutationObserversConnected; + var _mutationObserverAttrsTextarea = ['wrap', 'cols', 'rows']; + var _mutationObserverAttrsHost = [LEXICON.i, LEXICON.c, LEXICON.s, 'open']; //textarea: var _textareaEvents; @@ -2229,7 +2259,7 @@ var _scrollbarsAutoHideMove; var _scrollbarsAutoHideLeave; var _scrollbarsHandleHovered; - var _scrollbarsHandleAsync; + var _scrollbarsHandlesDefineScrollPos; //resize var _resizeReconnectMutationObserver; @@ -2238,272 +2268,262 @@ var _resizeHorizontal; var _resizeVertical; var _resizeOnMouseTouchDown; - - + + //==== Passive Event Listener ====// /** - * Adds a passive event listener to the given element. - * @param element The element to which the event listener shall be applied. - * @param eventNames The name(s) of the event listener. - * @param listener The listener method which shall be called. + * Adds or removes a passive event listener from the given element. + * @param element The element to which the event listener shall be applied or removed. + * @param eventNames The name(s) of the events. + * @param listener The method which shall be called. + * @param remove True if the handler shall be removed, false or undefined if the handler shall be added. */ - function addPassiveEventListener(element, eventNames, listener) { + function setupPassiveEventListener(element, eventNames, listener, remove, notPassive) { + var method = remove ? 'removeEventListener' : 'addEventListener'; var events = eventNames.split(_strSpace); - for (var i = 0; i < events.length; i++) - element[0].addEventListener(events[i], listener, {passive: true}); - } + var i = 0; - /** - * Removes a passive event listener to the given element. - * @param element The element from which the event listener shall be removed. - * @param eventNames The name(s) of the event listener. - * @param listener The listener method which shall be removed. - */ - function removePassiveEventListener(element, eventNames, listener) { - var events = eventNames.split(_strSpace); - for (var i = 0; i < events.length; i++) - element[0].removeEventListener(events[i], listener, {passive: true}); + for (; i < events[LEXICON.l]; i++) { + element[0][method](events[i], listener, { passive: !notPassive }); + } } //==== Resize Observer ====// /** - * Adds a resize observer to the given element. - * @param targetElement The element to which the resize observer shall be applied. - * @param onElementResizedCallback The callback which is fired every time the resize observer registers a size change. + * Adds or removes a resize observer from the given element. + * @param targetElement The element to which the resize observer shall be added or removed. + * @param onElementResizedCallback The callback which is fired every time the resize observer registers a size change or false / undefined if the resizeObserver shall be removed. */ - function addResizeObserver(targetElement, onElementResizedCallback) { - var constMaximum = 3333333; - var resizeObserver = COMPATIBILITY.rO(); - var strAnimationStartEvent = 'animationstart mozAnimationStart webkitAnimationStart MSAnimationStart'; - var strChildNodes = 'childNodes'; - var callback = function () { - targetElement[_strScrollTop](constMaximum)[_strScrollLeft](_isRTL ? _rtlScrollBehavior.n ? -constMaximum : _rtlScrollBehavior.i ? 0 : constMaximum : constMaximum); - onElementResizedCallback(); - }; - if (_supportResizeObserver) { - var element = targetElement.append(generateDiv(_classNameResizeObserverElement + ' observed')).contents()[0]; - var observer = element[_strResizeObserverProperty] = new resizeObserver(callback); - observer.observe(element); - } - else { - if (_msieVersion > 9 || !_autoUpdateRecommended) { - targetElement.prepend( - generateDiv(_classNameResizeObserverElement, - generateDiv({ className : _classNameResizeObserverItemElement, dir : "ltr" }, - generateDiv(_classNameResizeObserverItemElement, - generateDiv(_classNameResizeObserverItemFinalElement) - ) + - generateDiv(_classNameResizeObserverItemElement, - generateDiv({ className : _classNameResizeObserverItemFinalElement, style : 'width: 200%; height: 200%' }) - ) - ) - ) - ); - - var observerElement = targetElement[0][strChildNodes][0][strChildNodes][0]; - var shrinkElement = FRAMEWORK(observerElement[strChildNodes][1]); - var expandElement = FRAMEWORK(observerElement[strChildNodes][0]); - var expandElementChild = FRAMEWORK(expandElement[0][strChildNodes][0]); - var widthCache = observerElement[LEXICON.oW]; - var heightCache = observerElement[LEXICON.oH]; - var isDirty; - var rAFId; - var currWidth; - var currHeight; - var factor = 2; - var nativeScrollbarSize = globals.nativeScrollbarSize; //care don't make changes to this object!!! - var reset = function () { - /* - var sizeResetWidth = observerElement[LEXICON.oW] + nativeScrollbarSize.x * factor + nativeScrollbarSize.y * factor + _overlayScrollbarDummySize.x + _overlayScrollbarDummySize.y; - var sizeResetHeight = observerElement[LEXICON.oH] + nativeScrollbarSize.x * factor + nativeScrollbarSize.y * factor + _overlayScrollbarDummySize.x + _overlayScrollbarDummySize.y; - var expandChildCSS = {}; - expandChildCSS[_strWidth] = sizeResetWidth; - expandChildCSS[_strHeight] = sizeResetHeight; - expandElementChild.css(expandChildCSS); - - - expandElement[_strScrollLeft](sizeResetWidth)[_strScrollTop](sizeResetHeight); - shrinkElement[_strScrollLeft](sizeResetWidth)[_strScrollTop](sizeResetHeight); - */ - expandElement[_strScrollLeft](constMaximum)[_strScrollTop](constMaximum); - shrinkElement[_strScrollLeft](constMaximum)[_strScrollTop](constMaximum); + function setupResizeObserver(targetElement, onElementResizedCallback) { + if(targetElement) { + //add resize observer: + if(onElementResizedCallback) { + var constMaximum = 3333333; + var resizeObserver = COMPATIBILITY.rO(); + var strAnimationStartEvent = 'animationstart mozAnimationStart webkitAnimationStart MSAnimationStart'; + var strChildNodes = 'childNodes'; + var callback = function () { + targetElement[_strScrollTop](constMaximum)[_strScrollLeft](_isRTL ? _rtlScrollBehavior.n ? -constMaximum : _rtlScrollBehavior.i ? 0 : constMaximum : constMaximum); + onElementResizedCallback(); }; - var onResized = function () { - rAFId = 0; - if (!isDirty) - return; - - widthCache = currWidth; - heightCache = currHeight; - callback(); - }; - var onScroll = function (event) { - currWidth = observerElement[LEXICON.oW]; - currHeight = observerElement[LEXICON.oH]; - isDirty = currWidth != widthCache || currHeight != heightCache; - - if (event && isDirty && !rAFId) { - COMPATIBILITY.cAF()(rAFId); - rAFId = COMPATIBILITY.rAF()(onResized); - } - else if(!event) - onResized(); - - reset(); - if (event) { - COMPATIBILITY.prvD(event); - COMPATIBILITY.stpP(event); - } - return false; - }; - var expandChildCSS = {}; - var observerElementCSS = {}; - - setTopRightBottomLeft(observerElementCSS, _strEmpty, [ - -((nativeScrollbarSize.y + 1) * factor), - nativeScrollbarSize.x * -factor, - nativeScrollbarSize.y * -factor, - -((nativeScrollbarSize.x + 1) * factor) - ]); - - FRAMEWORK(observerElement).css(observerElementCSS); - expandElement.on(_strScroll, onScroll); - shrinkElement.on(_strScroll, onScroll); - targetElement.on(strAnimationStartEvent, function () { - onScroll(false); - }); - //lets assume that the divs will never be that large and a constant value is enough - expandChildCSS[_strWidth] = constMaximum; - expandChildCSS[_strHeight] = constMaximum; - expandElementChild.css(expandChildCSS); - - reset(); - } - else { - var attachEvent = _documentElementNative.attachEvent; - var isIE = _msieVersion !== undefined; - if (attachEvent) { - targetElement.prepend(generateDiv(_classNameResizeObserverElement)); - findFirst(targetElement, _strDot + _classNameResizeObserverElement)[0].attachEvent('onresize', callback); + if (_supportResizeObserver) { + var element = targetElement.append(generateDiv(_classNameResizeObserverElement + ' observed')).contents()[0]; + var observer = element[_strResizeObserverProperty] = new resizeObserver(callback); + observer.observe(element); } else { - var obj = _documentElementNative.createElement(TYPES.o); - obj.setAttribute('tabindex', '-1'); - obj.setAttribute(LEXICON.c, _classNameResizeObserverElement); - obj.onload = function () { - var wnd = this.contentDocument.defaultView; - wnd.addEventListener('resize', callback); - wnd.document.documentElement.style.display = 'none'; - }; - obj.type = 'text/html'; - if (isIE) - targetElement.prepend(obj); - obj.data = 'about:blank'; - if (!isIE) - targetElement.prepend(obj); - targetElement.on(strAnimationStartEvent, callback); - } - } - } + if (_msieVersion > 9 || !_autoUpdateRecommended) { + targetElement.prepend( + generateDiv(_classNameResizeObserverElement, + generateDiv({ className : _classNameResizeObserverItemElement, dir : "ltr" }, + generateDiv(_classNameResizeObserverItemElement, + generateDiv(_classNameResizeObserverItemFinalElement) + ) + + generateDiv(_classNameResizeObserverItemElement, + generateDiv({ className : _classNameResizeObserverItemFinalElement, style : 'width: 200%; height: 200%' }) + ) + ) + ) + ); - //direction change detection: - if (targetElement[0] === _sizeObserverElementNative) { - var directionChanged = function () { - var dir = _hostElement.css('direction'); - var css = {}; - var scrollLeftValue = 0; - var result = false; - if (dir !== _cssDirectionDetectedCache) { - if (dir === 'ltr') { - css[_strLeft] = 0; - css[_strRight] = _strAuto; - scrollLeftValue = constMaximum; + var observerElement = targetElement[0][strChildNodes][0][strChildNodes][0]; + var shrinkElement = FRAMEWORK(observerElement[strChildNodes][1]); + var expandElement = FRAMEWORK(observerElement[strChildNodes][0]); + var expandElementChild = FRAMEWORK(expandElement[0][strChildNodes][0]); + var widthCache = observerElement[LEXICON.oW]; + var heightCache = observerElement[LEXICON.oH]; + var isDirty; + var rAFId; + var currWidth; + var currHeight; + var factor = 2; + var nativeScrollbarSize = globals.nativeScrollbarSize; //care don't make changes to this object!!! + var reset = function () { + /* + var sizeResetWidth = observerElement[LEXICON.oW] + nativeScrollbarSize.x * factor + nativeScrollbarSize.y * factor + _overlayScrollbarDummySize.x + _overlayScrollbarDummySize.y; + var sizeResetHeight = observerElement[LEXICON.oH] + nativeScrollbarSize.x * factor + nativeScrollbarSize.y * factor + _overlayScrollbarDummySize.x + _overlayScrollbarDummySize.y; + var expandChildCSS = {}; + expandChildCSS[_strWidth] = sizeResetWidth; + expandChildCSS[_strHeight] = sizeResetHeight; + expandElementChild.css(expandChildCSS); + + + expandElement[_strScrollLeft](sizeResetWidth)[_strScrollTop](sizeResetHeight); + shrinkElement[_strScrollLeft](sizeResetWidth)[_strScrollTop](sizeResetHeight); + */ + expandElement[_strScrollLeft](constMaximum)[_strScrollTop](constMaximum); + shrinkElement[_strScrollLeft](constMaximum)[_strScrollTop](constMaximum); + }; + var onResized = function () { + rAFId = 0; + if (!isDirty) + return; + + widthCache = currWidth; + heightCache = currHeight; + callback(); + }; + var onScroll = function (event) { + currWidth = observerElement[LEXICON.oW]; + currHeight = observerElement[LEXICON.oH]; + isDirty = currWidth != widthCache || currHeight != heightCache; + + if (event && isDirty && !rAFId) { + COMPATIBILITY.cAF()(rAFId); + rAFId = COMPATIBILITY.rAF()(onResized); + } + else if(!event) + onResized(); + + reset(); + if (event) { + COMPATIBILITY.prvD(event); + COMPATIBILITY.stpP(event); + } + return false; + }; + var expandChildCSS = {}; + var observerElementCSS = {}; + + setTopRightBottomLeft(observerElementCSS, _strEmpty, [ + -((nativeScrollbarSize.y + 1) * factor), + nativeScrollbarSize.x * -factor, + nativeScrollbarSize.y * -factor, + -((nativeScrollbarSize.x + 1) * factor) + ]); + + FRAMEWORK(observerElement).css(observerElementCSS); + expandElement.on(_strScroll, onScroll); + shrinkElement.on(_strScroll, onScroll); + targetElement.on(strAnimationStartEvent, function () { + onScroll(false); + }); + //lets assume that the divs will never be that large and a constant value is enough + expandChildCSS[_strWidth] = constMaximum; + expandChildCSS[_strHeight] = constMaximum; + expandElementChild.css(expandChildCSS); + + reset(); } else { - css[_strLeft] = _strAuto; - css[_strRight] = 0; - scrollLeftValue = _rtlScrollBehavior.n ? -constMaximum : _rtlScrollBehavior.i ? 0 : constMaximum; + var attachEvent = _documentElementNative.attachEvent; + var isIE = _msieVersion !== undefined; + if (attachEvent) { + targetElement.prepend(generateDiv(_classNameResizeObserverElement)); + findFirst(targetElement, _strDot + _classNameResizeObserverElement)[0].attachEvent('onresize', callback); + } + else { + var obj = _documentElementNative.createElement(TYPES.o); + obj.setAttribute('tabindex', '-1'); + obj.setAttribute(LEXICON.c, _classNameResizeObserverElement); + obj.onload = function () { + var wnd = this.contentDocument.defaultView; + wnd.addEventListener('resize', callback); + wnd.document.documentElement.style.display = 'none'; + }; + obj.type = 'text/html'; + if (isIE) + targetElement.prepend(obj); + obj.data = 'about:blank'; + if (!isIE) + targetElement.prepend(obj); + targetElement.on(strAnimationStartEvent, callback); + } } - _sizeObserverElement.children().eq(0).css(css); - targetElement[_strScrollLeft](scrollLeftValue)[_strScrollTop](constMaximum); - _cssDirectionDetectedCache = dir; - result = true; } - return result; - }; - directionChanged(); - targetElement.on(_strScroll, function (event) { - if (directionChanged()) - update(); - COMPATIBILITY.prvD(event); - COMPATIBILITY.stpP(event); - return false; - }); + + //direction change detection: + if (targetElement[0] === _sizeObserverElementNative) { + var directionChanged = function () { + var dir = _hostElement.css('direction'); + var css = {}; + var scrollLeftValue = 0; + var result = false; + if (dir !== _cssDirectionDetectedCache) { + if (dir === 'ltr') { + css[_strLeft] = 0; + css[_strRight] = _strAuto; + scrollLeftValue = constMaximum; + } + else { + css[_strLeft] = _strAuto; + css[_strRight] = 0; + scrollLeftValue = _rtlScrollBehavior.n ? -constMaximum : _rtlScrollBehavior.i ? 0 : constMaximum; + } + _sizeObserverElement.children().eq(0).css(css); + targetElement[_strScrollLeft](scrollLeftValue)[_strScrollTop](constMaximum); + _cssDirectionDetectedCache = dir; + result = true; + } + return result; + }; + directionChanged(); + targetElement.on(_strScroll, function (event) { + if (directionChanged()) + update(); + COMPATIBILITY.prvD(event); + COMPATIBILITY.stpP(event); + return false; + }); + } + } + //remove resize observer: + else { + if (_supportResizeObserver) { + var element = targetElement.contents()[0]; + var resizeObserverObj = element[_strResizeObserverProperty]; + if(resizeObserverObj) { + resizeObserverObj.disconnect(); + delete element[_strResizeObserverProperty]; + } + } + else { + remove(targetElement.children(_strDot + _classNameResizeObserverElement).eq(0)); + } + } } } /** - * Removes a resize observer from the given element. + * Freezes or unfreezes the given resize observer. * @param targetElement The element to which the target resize observer is applied. - */ - function removeResizeObserver(targetElement) { - if (_supportResizeObserver) { - var element = targetElement.contents()[0]; - element[_strResizeObserverProperty].disconnect(); - delete element[_strResizeObserverProperty]; - } - else { - remove(targetElement.children(_strDot + _classNameResizeObserverElement).eq(0)); - } - } - - /** - * Freezes the given resize observer. - * @param targetElement The element to which the target resize observer is applied. - */ - function freezeResizeObserver(targetElement) { + * @param freeze True if the resize observer shall be frozen, false otherwise. + + function freezeResizeObserver(targetElement, freeze) { if (targetElement !== undefined) { - /* - if (_supportResizeObserver) { - var element = targetElement.contents()[0]; - element[_strResizeObserverProperty].unobserve(element); + if(freeze) { + if (_supportResizeObserver) { + var element = targetElement.contents()[0]; + element[_strResizeObserverProperty].unobserve(element); + } + else { + targetElement = targetElement.children(_strDot + _classNameResizeObserverElement).eq(0); + var w = targetElement.css(_strWidth); + var h = targetElement.css(_strHeight); + var css = {}; + css[_strWidth] = w; + css[_strHeight] = h; + targetElement.css(css); + } } else { - targetElement = targetElement.children(_strDot + _classNameResizeObserverElement).eq(0); - var w = targetElement.css(_strWidth); - var h = targetElement.css(_strHeight); - var css = {}; - css[_strWidth] = w; - css[_strHeight] = h; - targetElement.css(css); + if (_supportResizeObserver) { + var element = targetElement.contents()[0]; + element[_strResizeObserverProperty].observe(element); + } + else { + var css = { }; + css[_strHeight] = _strEmpty; + css[_strWidth] = _strEmpty; + targetElement.children(_strDot + _classNameResizeObserverElement).eq(0).css(css); + } } - */ - } - } - - /** - * Unfreezes the given resize observer. - * @param targetElement The element to which the target resize observer is applied. - */ - function unfreezeResizeObserver(targetElement) { - if (targetElement !== undefined) { - /* - if (_supportResizeObserver) { - var element = targetElement.contents()[0]; - element[_strResizeObserverProperty].observe(element); - } - else { - var css = { }; - css[_strHeight] = _strEmpty; - css[_strWidth] = _strEmpty; - targetElement.children(_strDot + _classNameResizeObserverElement).eq(0).css(css); - } - */ } } + */ //==== Mutation Observers ====// @@ -2527,8 +2547,8 @@ var doUpdate = false; var mutation; - if (_initialized && !_isSleeping) { - FRAMEWORK.each(mutations, function () { + if (_initialized && !_sleeping) { + each(mutations, function () { mutation = this; mutationTarget = mutation.target; mutationAttrName = mutation.attributeName; @@ -2553,8 +2573,8 @@ var doUpdate = false; var mutation; - if (_initialized && !_isSleeping) { - FRAMEWORK.each(mutations, function () { + if (_initialized && !_sleeping) { + each(mutations, function () { mutation = this; doUpdate = isUnknownMutation(mutation); return !doUpdate; @@ -2600,7 +2620,7 @@ _mutationObserverHost.observe(_hostElementNative, { attributes: true, attributeOldValue: true, - attributeFilter: [LEXICON.i, LEXICON.c, LEXICON.s] + attributeFilter: _mutationObserverAttrsHost }); _mutationObserverContent.observe(_isTextarea ? _targetElementNative : _contentElementNative, { @@ -2609,7 +2629,7 @@ subtree: !_isTextarea, childList: !_isTextarea, characterData: !_isTextarea, - attributeFilter: _isTextarea ? ['wrap', 'cols', 'rows'] : [LEXICON.i, LEXICON.c, LEXICON.s, 'open'] + attributeFilter: _isTextarea ? _mutationObserverAttrsTextarea : _mutationObserverAttrsHost }); _mutationObserversConnected = true; @@ -2628,19 +2648,6 @@ } } - /** - * Disconnects the MutationObservers if they are supported. - * @returns {boolean|undefined} True if the MutationObservers needed to be synchronized, false or undefined otherwise. - */ - function synchronizeMutationObservers() { - if(_mutationObserversConnected) { - var mutHost = _mutationObserverHostCallback(_mutationObserverHost.takeRecords()); - var mutContent = _mutationObserverContentCallback(_mutationObserverContent.takeRecords()); - - return mutHost || mutContent; - } - } - //==== Events of elements ====// @@ -2650,23 +2657,17 @@ * If there are any size changes, the update method gets called. */ function hostOnResized() { - if (_isSleeping) - return; - - var changed; - var hostSize = { - w: _sizeObserverElementNative[LEXICON.sW], - h: _sizeObserverElementNative[LEXICON.sH] - }; - - if (_initialized) { - changed = checkCacheDouble(hostSize, _hostElementSizeChangeDetectedCache); + if (!_sleeping) { + var changed; + var hostSize = { + w: _sizeObserverElementNative[LEXICON.sW], + h: _sizeObserverElementNative[LEXICON.sH] + }; + + changed = checkCache(hostSize, _hostElementSizeChangeDetectedCache); _hostElementSizeChangeDetectedCache = hostSize; if (changed) - update(true, false); - } - else { - _hostElementSizeChangeDetectedCache = hostSize; + update({ _hostSizeChanged : true }); } } @@ -2705,11 +2706,10 @@ * @param destroy Indicates whether the events shall be added or removed. */ function setupHostMouseTouchEvents(destroy) { - var passiveEvent = destroy ? removePassiveEventListener : addPassiveEventListener; var strOnOff = destroy ? 'off' : 'on'; var setupEvent = function(target, name, listener) { if(_supportPassiveEvents) - passiveEvent(target, name, listener); + setupPassiveEventListener(target, name, listener, destroy); else target[strOnOff](name, listener); }; @@ -2741,7 +2741,7 @@ * A callback which will be called after a img element has downloaded its src asynchronous. */ function imgOnLoad() { - update(false, true); + update({ _contentSizeChanged : true }); } @@ -2756,11 +2756,11 @@ if (_isBody && _contentArrangeElement) { bodyMinSize.w = parseToZeroOrNumber(_contentArrangeElement.css(_strMinMinus + _strWidth)); bodyMinSize.h = parseToZeroOrNumber(_contentArrangeElement.css(_strMinMinus + _strHeight)); - bodyMinSize.c = checkCacheDouble(bodyMinSize, _bodyMinSizeCache); + bodyMinSize.c = checkCache(bodyMinSize, _bodyMinSizeCache); bodyMinSize.f = true; //flag for "measured at least once" } _bodyMinSizeCache = bodyMinSize; - return bodyMinSize.c || false; + return !!bodyMinSize.c; } /** @@ -2780,7 +2780,7 @@ var currClassNames = _classNameCache !== undefined && _classNameCache !== null ? _classNameCache.split(_strSpace) : [_strEmpty]; //remove none theme from diff list to prevent update - var idx = FRAMEWORK.inArray(_classNameThemeNone, diff); + var idx = inArray(_classNameThemeNone, diff); var curr; var i; var v; @@ -2851,20 +2851,22 @@ * @returns {boolean} True if the content size was changed, false otherwise. */ function updateAutoContentSizeChanged() { - if (_isSleeping) + if (_sleeping) return false; - - var float; + + var contentMeasureElement = getContentMeasureElement(); var textareaValueLength = _isTextarea && _widthAutoCache && !_textareaAutoWrappingCache ? _targetElement.val().length : 0; var setCSS = !_mutationObserversConnected && _widthAutoCache && !_isTextarea; var viewportScrollSize = { }; var css = { }; + var float; var bodyMinSizeC; var changed; var viewportScrollSizeChanged; + var contentElementScrollSize; //fix for https://bugzilla.mozilla.org/show_bug.cgi?id=1439305, it only works with "clipAlways : true" - //it can work with "clipAlways : false" too, but we had to set the overflow of the viewportElement to hidden every time before measuring + //it can work with "clipAlways : false" too, but I had to set the overflow of the viewportElement to hidden every time before measuring if(_restrictedMeasuring) { viewportScrollSize = { x : _viewportElementNative[LEXICON.sW], @@ -2877,9 +2879,9 @@ css[_strWidth] = _strAuto; _contentElement.css(css); } - var contentElementScrollSize = { - w: getContentMeasureElement()[LEXICON.sW] + textareaValueLength, - h: getContentMeasureElement()[LEXICON.sH] + textareaValueLength + contentElementScrollSize = { + w: contentMeasureElement[LEXICON.sW] + textareaValueLength, + h: contentMeasureElement[LEXICON.sH] + textareaValueLength }; if (setCSS) { css[_strFloat] = float; @@ -2888,8 +2890,8 @@ } bodyMinSizeC = bodyMinSizeChanged(); - changed = checkCacheDouble(contentElementScrollSize, _contentElementScrollSizeChangeDetectedCache); - viewportScrollSizeChanged = checkCacheDouble(viewportScrollSize, _viewportScrollSizeCache, _strX, _strY); + changed = checkCache(contentElementScrollSize, _contentElementScrollSizeChangeDetectedCache); + viewportScrollSizeChanged = checkCache(viewportScrollSize, _viewportScrollSizeCache); _contentElementScrollSizeChangeDetectedCache = contentElementScrollSize; _viewportScrollSizeCache = viewportScrollSize; @@ -2898,39 +2900,43 @@ } /** - * Returns true if the host element attributes (id, class, style) was changed since the last time this method was called. - * @returns {boolean} + * Returns true when a attribute which the MutationObserver would observe has changed. + * @returns {boolean} True if one of the attributes which a MutationObserver would observe has changed, false or undefined otherwise. */ function meaningfulAttrsChanged() { - if (_isSleeping || _mutationObserversConnected) - return false; - - var hostElementId = _hostElement.attr(LEXICON.i) || _strEmpty; - var hostElementIdChanged = checkCacheSingle(hostElementId, _updateAutoHostElementIdCache); - var hostElementClass = _hostElement.attr(LEXICON.c) || _strEmpty; - var hostElementClassChanged = checkCacheSingle(hostElementClass, _updateAutoHostElementClassCache); - var hostElementStyle = _hostElement.attr(LEXICON.s) || _strEmpty; - var hostElementStyleChanged = checkCacheSingle(hostElementStyle, _updateAutoHostElementStyleCache); - var hostElementVisible = _hostElement.is(':visible') || _strEmpty; - var hostElementVisibleChanged = checkCacheSingle(hostElementVisible, _updateAutoHostElementVisibleCache); - var targetElementRows = _isTextarea ? (_targetElement.attr('rows') || _strEmpty) : _strEmpty; - var targetElementRowsChanged = checkCacheSingle(targetElementRows, _updateAutoTargetElementRowsCache); - var targetElementCols = _isTextarea ? (_targetElement.attr('cols') || _strEmpty) : _strEmpty; - var targetElementColsChanged = checkCacheSingle(targetElementCols, _updateAutoTargetElementColsCache); - var targetElementWrap = _isTextarea ? (_targetElement.attr('wrap') || _strEmpty) : _strEmpty; - var targetElementWrapChanged = checkCacheSingle(targetElementWrap, _updateAutoTargetElementWrapCache); - - _updateAutoHostElementIdCache = hostElementId; - if (hostElementClassChanged) - hostElementClassChanged = hostClassNamesChanged(_updateAutoHostElementClassCache, hostElementClass); - _updateAutoHostElementClassCache = hostElementClass; - _updateAutoHostElementStyleCache = hostElementStyle; - _updateAutoHostElementVisibleCache = hostElementVisible; - _updateAutoTargetElementRowsCache = targetElementRows; - _updateAutoTargetElementColsCache = targetElementCols; - _updateAutoTargetElementWrapCache = targetElementWrap; - - return hostElementIdChanged || hostElementClassChanged || hostElementStyleChanged || hostElementVisibleChanged || targetElementRowsChanged || targetElementColsChanged || targetElementWrapChanged; + if (_sleeping || _mutationObserversConnected) + return; + + var changed; + var elem; + var curr; + var cache; + var checks = [ + { + _elem: _hostElement, + _props : _mutationObserverAttrsHost.concat(':visible') + }, + { + _elem: _isTextarea ? _targetElement : undefined, + _props : _mutationObserverAttrsTextarea + } + ]; + + each(checks, function(index, check) { + elem = check._elem; + if(elem) { + each(check._props, function(index, prop) { + curr = prop.charAt(0) === ':' ? elem.is(prop) : elem.attr(prop); + cache = _updateAutoCache[prop]; + + changed = changed || checkCache(curr, cache); + + _updateAutoCache[prop] = curr; + }); + } + }); + + return changed; } /** @@ -3016,103 +3022,101 @@ * Updates the variables and size of the textarea element, and manages the scroll on new line or new character. */ function textareaUpdate() { - if (_isSleeping) - return; + if (!_sleeping) { + var wrapAttrOff = !_textareaAutoWrappingCache; + var minWidth = _viewportSize.w; + var minHeight = _viewportSize.h; + var css = { }; + var doMeasure = _widthAutoCache || wrapAttrOff; + var origWidth; + var width; + var origHeight; + var height; - var wrapAttrOff = !_textareaAutoWrappingCache; - var minWidth = _viewportSize.w /* - (!_isBorderBox && !_paddingAbsoluteCache && _widthAutoCache ? _paddingY + _borderY : 0) */; - var minHeight = _viewportSize.h /* - (!_isBorderBox && !_paddingAbsoluteCache && _heightAutoCache ? _paddingY + _borderY : 0) */; - var css = { }; - var doMeasure = _widthAutoCache || wrapAttrOff; - var origWidth; - var width; - var origHeight; - var height; + //reset min size + css[_strMinMinus + _strWidth] = _strEmpty; + css[_strMinMinus + _strHeight] = _strEmpty; - //reset min size - css[_strMinMinus + _strWidth] = _strEmpty; - css[_strMinMinus + _strHeight] = _strEmpty; + //set width auto + css[_strWidth] = _strAuto; + _targetElement.css(css); - //set width auto - css[_strWidth] = _strAuto; - _targetElement.css(css); + //measure width + origWidth = _targetElementNative[LEXICON.oW]; + width = doMeasure ? MATH.max(origWidth, _targetElementNative[LEXICON.sW] - 1) : 1; + /*width += (_widthAutoCache ? _marginX + (!_isBorderBox ? wrapAttrOff ? 0 : _paddingX + _borderX : 0) : 0);*/ - //measure width - origWidth = _targetElementNative[LEXICON.oW]; - width = doMeasure ? MATH.max(origWidth, _targetElementNative[LEXICON.sW] - 1) : 1; - /*width += (_widthAutoCache ? _marginX + (!_isBorderBox ? wrapAttrOff ? 0 : _paddingX + _borderX : 0) : 0);*/ + //set measured width + css[_strWidth] = _widthAutoCache ? _strAuto /*width*/ : _strHundredPercent; + css[_strMinMinus + _strWidth] = _strHundredPercent; - //set measured width - css[_strWidth] = _widthAutoCache ? _strAuto /*width*/ : _strHundredPercent; - css[_strMinMinus + _strWidth] = _strHundredPercent; + //set height auto + css[_strHeight] = _strAuto; + _targetElement.css(css); - //set height auto - css[_strHeight] = _strAuto; - _targetElement.css(css); + //measure height + origHeight = _targetElementNative[LEXICON.oH]; + height = MATH.max(origHeight, _targetElementNative[LEXICON.sH] - 1); - //measure height - origHeight = _targetElementNative[LEXICON.oH]; - height = MATH.max(origHeight, _targetElementNative[LEXICON.sH] - 1); + //append correct size values + css[_strWidth] = width; + css[_strHeight] = height; + _textareaCoverElement.css(css); - //append correct size values - css[_strWidth] = width; - css[_strHeight] = height; - _textareaCoverElement.css(css); + //apply min width / min height to prevent textarea collapsing + css[_strMinMinus + _strWidth] = minWidth /*+ (!_isBorderBox && _widthAutoCache ? _paddingX + _borderX : 0)*/; + css[_strMinMinus + _strHeight] = minHeight /*+ (!_isBorderBox && _heightAutoCache ? _paddingY + _borderY : 0)*/; + _targetElement.css(css); - //apply min width / min height to prevent textarea collapsing - css[_strMinMinus + _strWidth] = minWidth /*+ (!_isBorderBox && _widthAutoCache ? _paddingX + _borderX : 0)*/; - css[_strMinMinus + _strHeight] = minHeight /*+ (!_isBorderBox && _heightAutoCache ? _paddingY + _borderY : 0)*/; - _targetElement.css(css); - - return { - _originalWidth: origWidth, - _originalHeight: origHeight, - _dynamicWidth: width, - _dynamicHeight: height - }; + return { + _originalWidth: origWidth, + _originalHeight: origHeight, + _dynamicWidth: width, + _dynamicHeight: height + }; + } } /** * Updates the plugin and DOM to the current options. * This method should only be called if a update is 100% required. - * @param hostSizeChanged True if this method was called due to a host size change. - * @param contentSizeChanged True if this method was called due to a content size change. - * @param force True if every property shall be updated and the cache shall be ignored. - * @param preventSwallowing True if this method shall be executed even if it could be swallowed. + * @param updateHints A objects which contains hints for this update: + * { + * _hostSizeChanged : boolean, + * _contentSizeChanged : boolean, + * _force : boolean, == preventSwallowing + * _changedOptions : { }, == preventSwallowing && preventSleep + * } */ - function update(hostSizeChanged, contentSizeChanged, force, preventSwallowing) { - var now = COMPATIBILITY.now(); - var swallow = _swallowUpdateLag > 0 && _initialized && (now - _lastUpdateTime) < _swallowUpdateLag && (!_heightAutoCache && !_widthAutoCache) && !preventSwallowing; - var displayIsHidden = _hostElement.is(':hidden'); - var displayIsHiddenChanged = checkCacheSingle(displayIsHidden, _displayIsHiddenCache, force); - _displayIsHiddenCache = displayIsHidden; + function update(updateHints) { clearTimeout(_swallowedUpdateTimeout); + updateHints = updateHints || { }; + _swallowedUpdateHints._hostSizeChanged |= updateHints._hostSizeChanged; + _swallowedUpdateHints._contentSizeChanged |= updateHints._contentSizeChanged; + _swallowedUpdateHints._force |= updateHints._force; + + var now = COMPATIBILITY.now(); + var hostSizeChanged = !!_swallowedUpdateHints._hostSizeChanged; + var contentSizeChanged = !!_swallowedUpdateHints._contentSizeChanged; + var force = !!_swallowedUpdateHints._force; + var changedOptions = updateHints._changedOptions; + var swallow = _swallowUpdateLag > 0 && _initialized && !_destroyed && !force && !changedOptions && (now - _lastUpdateTime) < _swallowUpdateLag && (!_heightAutoCache && !_widthAutoCache); + var displayIsHidden; - if (swallow) { - _swallowedUpdateParams.h = _swallowedUpdateParams.h || hostSizeChanged; - _swallowedUpdateParams.c = _swallowedUpdateParams.c || contentSizeChanged; - _swallowedUpdateParams.f = _swallowedUpdateParams.f || force; + if(swallow) _swallowedUpdateTimeout = setTimeout(update, _swallowUpdateLag); - } //abort update due to: //destroyed //swallowing //sleeping //host is hidden or has false display - if (_destroyed || swallow || _isSleeping || (_initialized && !force && displayIsHidden) || _hostElement.css('display') === 'inline') + if (_destroyed || swallow || (_sleeping && !changedOptions) || (_initialized && !force && (displayIsHidden = _hostElement.is(':hidden'))) || _hostElement.css('display') === 'inline') return; _lastUpdateTime = now; - hostSizeChanged = hostSizeChanged || _swallowedUpdateParams.h; - contentSizeChanged = contentSizeChanged || _swallowedUpdateParams.c; - force = force || _swallowedUpdateParams.f; - _swallowedUpdateParams = {}; - - hostSizeChanged = hostSizeChanged === undefined ? false : hostSizeChanged; - contentSizeChanged = contentSizeChanged === undefined ? false : contentSizeChanged; - force = force === undefined ? false : force; - + _swallowedUpdateHints = { }; + //if scrollbar styling is possible and native scrollbars aren't overlaid the scrollbar styling will be applied which hides the native scrollbars completely. if (_nativeScrollbarStyling && !(_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y)) { //native scrollbars are hidden, so change the values to zero @@ -3132,77 +3136,79 @@ x: (_nativeScrollbarSize.x + (_nativeScrollbarIsOverlaid.x ? 0 : 3)) * 3, y: (_nativeScrollbarSize.y + (_nativeScrollbarIsOverlaid.y ? 0 : 3)) * 3 }; - - freezeResizeObserver(_sizeObserverElement); - freezeResizeObserver(_sizeAutoObserverElement); - + + //changedOptions = changedOptions || { }; + //freezeResizeObserver(_sizeObserverElement, true); + //freezeResizeObserver(_sizeAutoObserverElement, true); + + var checkCacheAutoForce = function () { + return checkCache.apply(this, [].slice.call(arguments).concat([ force ])); + }; + //save current scroll offset var currScroll = { x: _viewportElement[_strScrollLeft](), y: _viewportElement[_strScrollTop]() }; + var currentPreparedOptionsScrollbars = _currentPreparedOptions.scrollbars; var currentPreparedOptionsTextarea = _currentPreparedOptions.textarea; //scrollbars visibility: var scrollbarsVisibility = currentPreparedOptionsScrollbars.visibility; - var scrollbarsVisibilityChanged = checkCacheSingle(scrollbarsVisibility, _scrollbarsVisibilityCache, force); + var scrollbarsVisibilityChanged = checkCacheAutoForce(scrollbarsVisibility, _scrollbarsVisibilityCache); //scrollbars autoHide: var scrollbarsAutoHide = currentPreparedOptionsScrollbars.autoHide; - var scrollbarsAutoHideChanged = checkCacheSingle(scrollbarsAutoHide, _scrollbarsAutoHideCache, force); + var scrollbarsAutoHideChanged = checkCacheAutoForce(scrollbarsAutoHide, _scrollbarsAutoHideCache); //scrollbars click scrolling var scrollbarsClickScrolling = currentPreparedOptionsScrollbars.clickScrolling; - var scrollbarsClickScrollingChanged = checkCacheSingle(scrollbarsClickScrolling, _scrollbarsClickScrollingCache, force); + var scrollbarsClickScrollingChanged = checkCacheAutoForce(scrollbarsClickScrolling, _scrollbarsClickScrollingCache); //scrollbars drag scrolling var scrollbarsDragScrolling = currentPreparedOptionsScrollbars.dragScrolling; - var scrollbarsDragScrollingChanged = checkCacheSingle(scrollbarsDragScrolling, _scrollbarsDragScrollingCache, force); + var scrollbarsDragScrollingChanged = checkCacheAutoForce(scrollbarsDragScrolling, _scrollbarsDragScrollingCache); //className var className = _currentPreparedOptions.className; - var classNameChanged = checkCacheSingle(className, _classNameCache, force); + var classNameChanged = checkCacheAutoForce(className, _classNameCache); //resize var resize = _currentPreparedOptions.resize; - var resizeChanged = checkCacheSingle(resize, _resizeCache, force) && !_isBody; //body can't be resized since the window itself acts as resize possibility. - - //textarea AutoWrapping - var textareaAutoWrapping = _isTextarea ? _targetElement.attr('wrap') !== 'off' : false; - var textareaAutoWrappingChanged = checkCacheSingle(textareaAutoWrapping, _textareaAutoWrappingCache, force); + var resizeChanged = checkCacheAutoForce(resize, _resizeCache) && !_isBody; //body can't be resized since the window itself acts as resize possibility. //paddingAbsolute var paddingAbsolute = _currentPreparedOptions.paddingAbsolute; - var paddingAbsoluteChanged = checkCacheSingle(paddingAbsolute, _paddingAbsoluteCache, force); + var paddingAbsoluteChanged = checkCacheAutoForce(paddingAbsolute, _paddingAbsoluteCache); //clipAlways var clipAlways = _currentPreparedOptions.clipAlways; - var clipAlwaysChanged = checkCacheSingle(clipAlways, _clipAlwaysCache, force); + var clipAlwaysChanged = checkCacheAutoForce(clipAlways, _clipAlwaysCache); //sizeAutoCapable var sizeAutoCapable = _currentPreparedOptions.sizeAutoCapable && !_isBody; //body can never be size auto, because it shall be always as big as the viewport. - var sizeAutoCapableChanged = checkCacheSingle(sizeAutoCapable, _sizeAutoCapableCache, force); + var sizeAutoCapableChanged = checkCacheAutoForce(sizeAutoCapable, _sizeAutoCapableCache); //showNativeScrollbars var ignoreOverlayScrollbarHiding = _currentPreparedOptions.nativeScrollbarsOverlaid.showNativeScrollbars; - var ignoreOverlayScrollbarHidingChanged = checkCacheSingle(ignoreOverlayScrollbarHiding, _ignoreOverlayScrollbarHidingCache); + var ignoreOverlayScrollbarHidingChanged = checkCacheAutoForce(ignoreOverlayScrollbarHiding, _ignoreOverlayScrollbarHidingCache); //autoUpdate var autoUpdate = _currentPreparedOptions.autoUpdate; - var autoUpdateChanged = checkCacheSingle(autoUpdate, _autoUpdateCache); + var autoUpdateChanged = checkCacheAutoForce(autoUpdate, _autoUpdateCache); //overflowBehavior var overflowBehavior = _currentPreparedOptions.overflowBehavior; - var overflowBehaviorChanged = checkCacheDouble(overflowBehavior, _overflowBehaviorCache, _strX, _strY, force); + var overflowBehaviorChanged = checkCacheAutoForce(overflowBehavior, _overflowBehaviorCache, force); //dynWidth: var textareaDynWidth = currentPreparedOptionsTextarea.dynWidth; - var textareaDynWidthChanged = checkCacheSingle(_textareaDynWidthCache, textareaDynWidth); + var textareaDynWidthChanged = checkCacheAutoForce(_textareaDynWidthCache, textareaDynWidth); //dynHeight: var textareaDynHeight = currentPreparedOptionsTextarea.dynHeight; - var textareaDynHeightChanged = checkCacheSingle(_textareaDynHeightCache, textareaDynHeight); + var textareaDynHeightChanged = checkCacheAutoForce(_textareaDynHeightCache, textareaDynHeight); //scrollbars visibility _scrollbarsAutoHideNever = scrollbarsAutoHide === 'n'; @@ -3235,7 +3241,6 @@ _scrollbarsDragScrollingCache = scrollbarsDragScrolling; _classNameCache = className; _resizeCache = resize; - _textareaAutoWrappingCache = textareaAutoWrapping; _paddingAbsoluteCache = paddingAbsolute; _clipAlwaysCache = clipAlways; _sizeAutoCapableCache = sizeAutoCapable; @@ -3293,12 +3298,12 @@ _contentGlueElement.before(_sizeAutoObserverElement); var oldSize = {w: -1, h: -1}; - addResizeObserver(_sizeAutoObserverElement, function () { + setupResizeObserver(_sizeAutoObserverElement, function () { var newSize = { w: _sizeAutoObserverElementNative[LEXICON.oW], h: _sizeAutoObserverElementNative[LEXICON.oH] }; - if (checkCacheDouble(newSize, oldSize)) { + if (checkCache(newSize, oldSize)) { if (_initialized && (_heightAutoCache && newSize.h > 0) || (_widthAutoCache && newSize.w > 0)) { update(); } @@ -3330,13 +3335,21 @@ _sizeAutoObserverElement.find('*').trigger(_strScroll); } + //display hidden: + displayIsHidden = displayIsHidden === undefined ? _hostElement.is(':hidden') : displayIsHidden; + var displayIsHiddenChanged = checkCacheAutoForce(displayIsHidden, _displayIsHiddenCache); + + //textarea AutoWrapping: + var textareaAutoWrapping = _isTextarea ? _targetElement.attr('wrap') !== 'off' : false; + var textareaAutoWrappingChanged = checkCacheAutoForce(textareaAutoWrapping, _textareaAutoWrappingCache); + //detect direction: var cssDirection = _hostElement.css('direction'); - var cssDirectionChanged = checkCacheSingle(cssDirection, _cssDirectionCache, force); + var cssDirectionChanged = checkCacheAutoForce(cssDirection, _cssDirectionCache); //detect box-sizing: var boxSizing = _hostElement.css('box-sizing'); - var boxSizingChanged = checkCacheSingle(boxSizing, _cssBoxSizingCache, force); + var boxSizingChanged = checkCacheAutoForce(boxSizing, _cssBoxSizingCache); //detect padding: var padding = { @@ -3346,7 +3359,7 @@ b: parseToZeroOrNumber(_hostElement.css(_strPaddingMinus + _strBottom)), l: parseToZeroOrNumber(_hostElement.css(_strPaddingMinus + _strLeft)) }; - + //width + height auto detecting var: var sizeAutoObserverElementBCRect; //exception occurs in IE8 sometimes (unknown exception) @@ -3380,12 +3393,12 @@ } } var widthAuto = (widthAutoObserverDetection || widthAutoResizeDetection) && sizeAutoCapable && !displayIsHidden; - var widthAutoChanged = checkCacheSingle(widthAuto, _widthAutoCache, force); + var widthAutoChanged = checkCacheAutoForce(widthAuto, _widthAutoCache); var wasWidthAuto = !widthAuto && _widthAutoCache; //detect height auto: var heightAuto = _sizeAutoObserverAdded && sizeAutoCapable && !displayIsHidden ? (MATH.round(sizeAutoObserverElementBCRect.bottom - sizeAutoObserverElementBCRect.top) === 0) /* && (!paddingAbsolute && (_msieVersion > 9 || !_msieVersion) ? true : true) */ : false; - var heightAutoChanged = checkCacheSingle(heightAuto, _heightAutoCache, force); + var heightAutoChanged = checkCacheAutoForce(heightAuto, _heightAutoCache); var wasHeightAuto = !heightAuto && _heightAutoCache; //detect border: @@ -3443,26 +3456,28 @@ var paddingAbsoluteY = _paddingY = padding.t + padding.b; paddingAbsoluteX *= paddingAbsolute ? 1 : 0; paddingAbsoluteY *= paddingAbsolute ? 1 : 0; - padding.c = checkCacheTRBL(padding, _cssPaddingCache); + padding.c = checkCacheAutoForce(padding, _cssPaddingCache); //set info for border _borderX = border.l + border.r; _borderY = border.t + border.b; - border.c = checkCacheTRBL(border, _cssBorderCache); + border.c = checkCacheAutoForce(border, _cssBorderCache); //set info for margin _marginX = margin.l + margin.r; _marginY = margin.t + margin.b; - margin.c = checkCacheTRBL(margin, _cssMarginCache); + margin.c = checkCacheAutoForce(margin, _cssMarginCache); //set info for css max value cssMaxValue.ih = parseToZeroOrNumber(cssMaxValue.h); //ih = integer height cssMaxValue.iw = parseToZeroOrNumber(cssMaxValue.w); //iw = integer width cssMaxValue.ch = cssMaxValue.h.indexOf('px') > -1; //ch = correct height cssMaxValue.cw = cssMaxValue.w.indexOf('px') > -1; //cw = correct width - cssMaxValue.c = checkCacheDouble(cssMaxValue, _cssMaxValueCache, force); + cssMaxValue.c = checkCacheAutoForce(cssMaxValue, _cssMaxValueCache); //refresh cache + _displayIsHiddenCache = displayIsHidden; + _textareaAutoWrappingCache = textareaAutoWrapping; _cssDirectionCache = cssDirection; _cssBoxSizingCache = boxSizing; _widthAutoCache = widthAuto; @@ -3471,7 +3486,7 @@ _cssBorderCache = border; _cssMarginCache = margin; _cssMaxValueCache = cssMaxValue; - + //IEFix direction changed if (cssDirectionChanged && _sizeAutoObserverAdded) _sizeAutoObserverElement.css(_strFloat, isRTLRight); @@ -3566,7 +3581,7 @@ contentGlueElementCSS = {}; //if [content(host) client / scroll size, or target element direction, or content(host) max-sizes] changed, or force is true - if (hostSizeChanged || contentSizeChanged || cssDirectionChanged || boxSizingChanged || paddingAbsoluteChanged || widthAutoChanged || widthAuto || heightAutoChanged || heightAuto || cssMaxValue.c || ignoreOverlayScrollbarHidingChanged || overflowBehaviorChanged || clipAlwaysChanged || resizeChanged || scrollbarsVisibilityChanged || scrollbarsAutoHideChanged || scrollbarsDragScrollingChanged || scrollbarsClickScrollingChanged || textareaDynWidthChanged || textareaDynHeightChanged || textareaAutoWrappingChanged || force) { + if (hostSizeChanged || contentSizeChanged || cssDirectionChanged || boxSizingChanged || paddingAbsoluteChanged || widthAutoChanged || widthAuto || heightAutoChanged || heightAuto || cssMaxValue.c || ignoreOverlayScrollbarHidingChanged || overflowBehaviorChanged || clipAlwaysChanged || resizeChanged || scrollbarsVisibilityChanged || scrollbarsAutoHideChanged || scrollbarsDragScrollingChanged || scrollbarsClickScrollingChanged || textareaDynWidthChanged || textareaDynHeightChanged || textareaAutoWrappingChanged) { var strOverflow = 'overflow'; var strOverflowX = strOverflow + '-x'; var strOverflowY = strOverflow + '-y'; @@ -3576,7 +3591,7 @@ var hideOverflow4CorrectMeasuring = _restrictedMeasuring ? (_nativeScrollbarIsOverlaid.x || _nativeScrollbarIsOverlaid.y) || //it must be hidden if native scrollbars are overlaid (_viewportSize.w < _nativeScrollbarMinSize.y || _viewportSize.h < _nativeScrollbarMinSize.x) || //it must be hidden if host-element is too small - heightAuto || displayIsHiddenChanged //it must be hidden if height is auto or display was change + heightAuto || displayIsHiddenChanged //it must be hidden if height is auto or display was changed : heightAuto; //if there is not the restricted Measuring bug, it must be hidden if the height is auto //Reset the viewport (very important for natively overlaid scrollbars and zoom change @@ -3617,7 +3632,7 @@ w: MATH.max((widthAuto ? contentSize.w : scrollSize.w) + paddingAbsoluteX, hostSize.w), h: MATH.max((heightAuto ? contentSize.h : scrollSize.h) + paddingAbsoluteY, hostSize.h) }; - contentGlueSize.c = checkCacheDouble(contentGlueSize, _contentGlueSizeCache, force); + contentGlueSize.c = checkCacheAutoForce(contentGlueSize, _contentGlueSizeCache); _contentGlueSizeCache = contentGlueSize; //apply correct contentGlue size @@ -3687,7 +3702,7 @@ w: MATH.max(contentMeasureElement[LEXICON.sW], contentMeasureElementGuaranty[LEXICON.sW]), h: MATH.max(contentMeasureElement[LEXICON.sH], contentMeasureElementGuaranty[LEXICON.sH]) }; - contentScrollSize.c = contentSizeChanged = checkCacheDouble(contentScrollSize, _contentScrollSizeCache, force); + contentScrollSize.c = contentSizeChanged = checkCacheAutoForce(contentScrollSize, _contentScrollSizeCache); _contentScrollSizeCache = contentScrollSize; //remove overflow hidden to restore overflow @@ -3698,7 +3713,7 @@ _viewportSize = getViewportSize(); hostSize = getHostSize(); - hostSizeChanged = checkCacheDouble(hostSize, _hostSizeCache); + hostSizeChanged = checkCacheAutoForce(hostSize, _hostSizeCache); _hostSizeCache = hostSize; var hideOverflowForceTextarea = _isTextarea && (_viewportSize.w === 0 || _viewportSize.h === 0); @@ -3738,11 +3753,11 @@ setOverflowVariables(true); setOverflowVariables(false); - overflowAmount.c = checkCacheDouble(overflowAmount, _overflowAmountCache, _strX, _strY, force); + overflowAmount.c = checkCacheAutoForce(overflowAmount, _overflowAmountCache); _overflowAmountCache = overflowAmount; - hasOverflow.c = checkCacheDouble(hasOverflow, _hasOverflowCache, _strX, _strY, force); + hasOverflow.c = checkCacheAutoForce(hasOverflow, _hasOverflowCache); _hasOverflowCache = hasOverflow; - hideOverflow.c = checkCacheDouble(hideOverflow, _hideOverflowCache, _strX, _strY, force); + hideOverflow.c = checkCacheAutoForce(hideOverflow, _hideOverflowCache); _hideOverflowCache = hideOverflow; //if native scrollbar is overlay at x OR y axis, prepare DOM @@ -3756,7 +3771,7 @@ if (hasOverflow.x || hasOverflow.y) { arrangeContent.w = _nativeScrollbarIsOverlaid.y && hasOverflow.y ? contentScrollSize.w + _overlayScrollbarDummySize.y : _strEmpty; arrangeContent.h = _nativeScrollbarIsOverlaid.x && hasOverflow.x ? contentScrollSize.h + _overlayScrollbarDummySize.x : _strEmpty; - arrangeChanged = checkCacheSingle(arrangeContent, _arrangeContentSizeCache, force); + arrangeChanged = checkCacheAutoForce(arrangeContent, _arrangeContentSizeCache); _arrangeContentSizeCache = arrangeContent; } @@ -3994,8 +4009,12 @@ if (_isBody) addClass(_hostElement, _classNameHostResizeDisabled); if (resizeChanged) { - var addCornerEvents = function () { _scrollbarCornerElement.on(_strMouseTouchDownEvent, _resizeOnMouseTouchDown); }; - var removeCornerEvents = function () { _scrollbarCornerElement.off(_strMouseTouchDownEvent, _resizeOnMouseTouchDown); }; + var setupCornerEvents = function(remove) { + if(_supportPassiveEvents) + setupPassiveEventListener(_scrollbarCornerElement, _strMouseTouchDownEvent, _resizeOnMouseTouchDown, remove, true); + else + _scrollbarCornerElement[remove ? 'off' : 'on'](_strMouseTouchDownEvent, _resizeOnMouseTouchDown); + }; removeClass(_scrollbarCornerElement, [ _classNameHostResizeDisabled, _classNameScrollbarCornerResize, @@ -4004,7 +4023,7 @@ _classNameScrollbarCornerResizeV].join(_strSpace)); if (_resizeNone) { addClass(_hostElement, _classNameHostResizeDisabled); - removeCornerEvents(); + setupCornerEvents(true); } else { addClass(_scrollbarCornerElement, _classNameScrollbarCornerResize); @@ -4015,8 +4034,8 @@ else if (_resizeVertical) addClass(_scrollbarCornerElement, _classNameScrollbarCornerResizeV); - removeCornerEvents(); - addCornerEvents(); + setupCornerEvents(true); + setupCornerEvents(); } } @@ -4119,7 +4138,7 @@ } //fix body min size - if (_isBody && (_hasOverflowCache.c || _bodyMinSizeCache.c)) { + if (_isBody && _bodyMinSizeCache && (_hasOverflowCache.c || _bodyMinSizeCache.c)) { //its possible that no min size was measured until now, because the content arrange element was just added now, in this case, measure now the min size. if (!_bodyMinSizeCache.f) bodyMinSizeChanged(); @@ -4130,8 +4149,8 @@ _bodyMinSizeCache.c = false; } - unfreezeResizeObserver(_sizeObserverElement); - unfreezeResizeObserver(_sizeAutoObserverElement); + //freezeResizeObserver(_sizeObserverElement, false); + //freezeResizeObserver(_sizeAutoObserverElement, false); dispatchCallback("onUpdated", { forced: force }); } @@ -4142,10 +4161,15 @@ /** * Sets new options but doesn't call the update method. * @param newOptions The object which contains the new options. + * @returns {*} A object which contains the changed options. */ function setOptions(newOptions) { - _currentOptions = extendDeep({}, _currentOptions, _pluginsOptions._validate(newOptions, _pluginsOptions._template, true)); - _currentPreparedOptions = extendDeep({}, _currentPreparedOptions, _pluginsOptions._validate(newOptions, _pluginsOptions._template, false, true)); + var validatedOpts = _pluginsOptions._validate(newOptions, _pluginsOptions._template, true, _currentOptions) + + _currentOptions = extendDeep({}, _currentOptions, validatedOpts._default); + _currentPreparedOptions = extendDeep({}, _currentPreparedOptions, validatedOpts._prepared); + + return validatedOpts._prepared; } @@ -4160,7 +4184,7 @@ var adoptAttrsMap = { }; var applyAdoptedAttrs = function() { var applyAdoptedAttrsElm = destroy ? _targetElement : _hostElement; - FRAMEWORK.each(adoptAttrsMap, function(k, v) { + each(adoptAttrsMap, function(k, v) { if(type(v) == TYPES.s) { if(k == LEXICON.c) applyAdoptedAttrsElm.addClass(v); @@ -4187,7 +4211,7 @@ _classNameCache].join(_strSpace); adoptAttrs = type(adoptAttrs) == TYPES.s ? adoptAttrs.split(' ') : adoptAttrs; if(type(adoptAttrs) == TYPES.a) { - FRAMEWORK.each(adoptAttrs, function(i, v) { + each(adoptAttrs, function(i, v) { if(type(v) == TYPES.s) adoptAttrsMap[v] = destroy ? _hostElement.attr(v) : _targetElement.attr(v); }); @@ -4341,20 +4365,20 @@ else { _textareaEvents[_strKeyDownEvent] = function textareaOnKeyDown(event) { var keyCode = event.keyCode; - if (FRAMEWORK.inArray(keyCode, textareaKeyDownRestrictedKeyCodes) > -1) + if (inArray(keyCode, textareaKeyDownRestrictedKeyCodes) > -1) return; if (!textareaKeyDownKeyCodesList.length) { updateTextarea(); textareaUpdateIntervalID = setInterval(updateTextarea, 1000 / 60); } - if (FRAMEWORK.inArray(keyCode, textareaKeyDownKeyCodesList) === -1) + if (inArray(keyCode, textareaKeyDownKeyCodesList) === -1) textareaKeyDownKeyCodesList.push(keyCode); }; _textareaEvents[_strKeyUpEvent] = function(event) { var keyCode = event.keyCode; - var index = FRAMEWORK.inArray(keyCode, textareaKeyDownKeyCodesList); + var index = inArray(keyCode, textareaKeyDownKeyCodesList); - if (FRAMEWORK.inArray(keyCode, textareaKeyDownRestrictedKeyCodes) > -1) + if (inArray(keyCode, textareaKeyDownRestrictedKeyCodes) > -1) return; if (index > -1) textareaKeyDownKeyCodesList.splice(index, 1); @@ -4365,7 +4389,7 @@ } if (_isTextarea) { - FRAMEWORK.each(_textareaEvents, function(key, value) { + each(_textareaEvents, function(key, value) { _targetElement[strOnOff](key, value); }); } @@ -4375,55 +4399,54 @@ return; event = event.originalEvent || event; if (isSizeAffectingCSSProperty(event.propertyName)) - update(_strAuto); + _base.update(_strAuto); }); } if(!destroy) { viewportOnScroll = function(event) { - if (_isSleeping) - return; - - if (scrollStopTimeoutId !== undefined) - clearTimeout(scrollStopTimeoutId); - else { - if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove) - refreshScrollbarsAutoHide(true); - - if (!nativeOverlayScrollbarsAreActive()) - addClass(_hostElement, _classNameHostScrolling); - - dispatchCallback("onScrollStart", event); - } - - //if a scrollbars handle gets dragged, the mousemove event is responsible for refreshing the handle offset - //because if CSS scroll-snap is used, the handle offset gets only refreshed on every snap point - //this looks laggy & clunky, it looks much better if the offset refreshes with the mousemove - if(!_scrollbarsHandleAsync) { - refreshScrollbarHandleOffset(true); - refreshScrollbarHandleOffset(false); - } - dispatchCallback("onScroll", event); - - scrollStopTimeoutId = setTimeout(function () { - if(!_destroyed) { - //OnScrollStop: + if (!_sleeping) { + if (scrollStopTimeoutId !== undefined) clearTimeout(scrollStopTimeoutId); - scrollStopTimeoutId = undefined; - + else { if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove) - refreshScrollbarsAutoHide(false); + refreshScrollbarsAutoHide(true); if (!nativeOverlayScrollbarsAreActive()) - removeClass(_hostElement, _classNameHostScrolling); + addClass(_hostElement, _classNameHostScrolling); - dispatchCallback("onScrollStop", event); + dispatchCallback("onScrollStart", event); } - }, scrollStopDelay); + + //if a scrollbars handle gets dragged, the mousemove event is responsible for refreshing the handle offset + //because if CSS scroll-snap is used, the handle offset gets only refreshed on every snap point + //this looks laggy & clunky, it looks much better if the offset refreshes with the mousemove + if(!_scrollbarsHandlesDefineScrollPos) { + refreshScrollbarHandleOffset(true); + refreshScrollbarHandleOffset(false); + } + dispatchCallback("onScroll", event); + + scrollStopTimeoutId = setTimeout(function () { + if(!_destroyed) { + //OnScrollStop: + clearTimeout(scrollStopTimeoutId); + scrollStopTimeoutId = undefined; + + if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove) + refreshScrollbarsAutoHide(false); + + if (!nativeOverlayScrollbarsAreActive()) + removeClass(_hostElement, _classNameHostScrolling); + + dispatchCallback("onScrollStop", event); + } + }, scrollStopDelay); + } }; if (_supportPassiveEvents) - addPassiveEventListener(_viewportElement, _strScroll, viewportOnScroll); + setupPassiveEventListener(_viewportElement, _strScroll, viewportOnScroll); else _viewportElement.on(_strScroll, viewportOnScroll); } @@ -4479,7 +4502,22 @@ var mouseDownScroll; var mouseDownOffset; var mouseDownInvertedScale; - + + function setupEvent(element, eventNames, listener) { + var collected = type(eventNames) == TYPES.a && type(listener) == TYPES.a; + var i = 0; + + if(collected) { + for (; i < eventNames[LEXICON.l]; i++) + setupEvent(element, eventNames[i], listener[i]); + } + else { + if(_supportPassiveEvents) + setupPassiveEventListener(element, eventNames, listener, false, true); + else + element.on(eventNames, listener); + } + } function getPointerPosition(event) { return _msieVersion && insideIFrame ? event['screen' + XY] : COMPATIBILITY.page(event)[xy]; //use screen coordinates in EDGE & IE because the page values are incorrect in frames. } @@ -4493,17 +4531,17 @@ scrollDurationFactor = 1; } function documentKeyDown(event) { - if (FRAMEWORK.inArray(event.keyCode, increaseDecreaseScrollAmountKeyCodes) > -1) + if (inArray(event.keyCode, increaseDecreaseScrollAmountKeyCodes) > -1) increaseTrackScrollAmount(); } function documentKeyUp(event) { - if (FRAMEWORK.inArray(event.keyCode, increaseDecreaseScrollAmountKeyCodes) > -1) + if (inArray(event.keyCode, increaseDecreaseScrollAmountKeyCodes) > -1) decreaseTrackScrollAmount(); } function onMouseTouchDownContinue(event) { var originalEvent = event.originalEvent || event; var isTouchEvent = originalEvent.touches !== undefined; - return _isSleeping || _destroyed || nativeOverlayScrollbarsAreActive() || !_scrollbarsDragScrollingCache || (isTouchEvent && !getPreparedScrollbarsOption('touchSupport')) ? false : COMPATIBILITY.mBtn(event) === 1 || isTouchEvent; + return _sleeping || _destroyed || nativeOverlayScrollbarsAreActive() || !_scrollbarsDragScrollingCache || (isTouchEvent && !getPreparedScrollbarsOption('touchSupport')) ? false : COMPATIBILITY.mBtn(event) === 1 || isTouchEvent; } function documentDragMove(event) { if(onMouseTouchDownContinue(event)) { @@ -4519,7 +4557,7 @@ _viewportElement[scroll](MATH.round(mouseDownScroll + scrollDelta)); - if(_scrollbarsHandleAsync) + if(_scrollbarsHandlesDefineScrollPos) refreshScrollbarHandleOffset(isHorizontal, mouseDownScroll + scrollDelta); if (!_supportPassiveEvents) @@ -4537,10 +4575,10 @@ .off(_strKeyUpEvent, documentKeyUp) .off(_strSelectStartEvent, documentOnSelectStart); - if(_scrollbarsHandleAsync) + if(_scrollbarsHandlesDefineScrollPos) refreshScrollbarHandleOffset(isHorizontal, true); - _scrollbarsHandleAsync = false; + _scrollbarsHandlesDefineScrollPos = false; removeClass(_bodyElement, _classNameDragging); removeClass(scrollbarVars._handle, strActive); removeClass(scrollbarVars._track, strActive); @@ -4571,6 +4609,10 @@ } } function onHandleMouseTouchDown(event) { + if (onMouseTouchDownContinue(event)) + onHandleMouseTouchDownAction(event); + } + function onHandleMouseTouchDownAction(event) { mouseDownScroll = _viewportElement[scroll](); mouseDownScroll = isNaN(mouseDownScroll) ? 0 : mouseDownScroll; if (_isRTL && isHorizontal && !_rtlScrollBehavior.n || !_isRTL) @@ -4579,7 +4621,7 @@ mouseDownInvertedScale = getHostElementInvertedScale()[xy]; mouseDownOffset = getPointerPosition(event); - _scrollbarsHandleAsync = !getPreparedScrollbarsOption(strSnapHandle); + _scrollbarsHandlesDefineScrollPos = !getPreparedScrollbarsOption(strSnapHandle); addClass(_bodyElement, _classNameDragging); addClass(scrollbarVars._handle, strActive); addClass(scrollbarVars._scrollbar, strActive); @@ -4592,11 +4634,7 @@ COMPATIBILITY.prvD(event); COMPATIBILITY.stpP(event); } - scrollbarVars._handle.on(_strMouseTouchDownEvent, function(event) { - if (onMouseTouchDownContinue(event)) - onHandleMouseTouchDown(event); - }); - scrollbarVars._track.on(_strMouseTouchDownEvent, function(event) { + function onTrackMouseTouchDown(event) { if (onMouseTouchDownContinue(event)) { var scrollDistance = MATH.round(_viewportSize[scrollbarVars._w_h]); var trackOffset = scrollbarVars._track.offset()[scrollbarVars._left_top]; @@ -4608,12 +4646,12 @@ var decreaseScroll; var finishedCondition; var scrollActionFinsished = function(transition) { - if(_scrollbarsHandleAsync) + if(_scrollbarsHandlesDefineScrollPos) refreshScrollbarHandleOffset(isHorizontal, transition); }; var scrollActionInstantFinished = function() { scrollActionFinsished(); - onHandleMouseTouchDown(event); + onHandleMouseTouchDownAction(event); }; var scrollAction = function () { if(!_destroyed) { @@ -4632,7 +4670,7 @@ var animationObj = { easing : easing, step : function(now) { - if(_scrollbarsHandleAsync) { + if(_scrollbarsHandlesDefineScrollPos) { _viewportElement[scroll](now); //https://github.com/jquery/jquery/issues/4340 refreshScrollbarHandleOffset(isHorizontal, now); } @@ -4694,7 +4732,7 @@ mouseDownInvertedScale = getHostElementInvertedScale()[xy]; mouseDownOffset = COMPATIBILITY.page(event)[xy]; - _scrollbarsHandleAsync = !getPreparedScrollbarsOption(strSnapHandle); + _scrollbarsHandlesDefineScrollPos = !getPreparedScrollbarsOption(strSnapHandle); addClass(_bodyElement, _classNameDragging); addClass(scrollbarVars._track, strActive); addClass(scrollbarVars._scrollbar, strActive); @@ -4708,19 +4746,32 @@ COMPATIBILITY.prvD(event); COMPATIBILITY.stpP(event); } - }).on(_strMouseTouchEnter, function() { //make sure both scrollbars will stay visible if one scrollbar is hovered if autoHide is "scroll" or "move". + } + function onTrackMouseTouchEnter(event) { + //make sure both scrollbars will stay visible if one scrollbar is hovered if autoHide is "scroll" or "move". _scrollbarsHandleHovered = true; if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove) refreshScrollbarsAutoHide(true); - - }).on(_strMouseTouchLeave, function() { + } + function onTrackMouseTouchLeave(event) { _scrollbarsHandleHovered = false; if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove) refreshScrollbarsAutoHide(false); - }); - scrollbarVars._scrollbar.on(_strMouseTouchDownEvent, function(event) { + } + function onScrollbarMouseTouchDown(event) { COMPATIBILITY.stpP(event); - }); + } + + setupEvent(scrollbarVars._handle, + _strMouseTouchDownEvent, + onHandleMouseTouchDown); + setupEvent(scrollbarVars._track, + [_strMouseTouchDownEvent, _strMouseTouchEnter, _strMouseTouchLeave], + [onTrackMouseTouchDown, onTrackMouseTouchEnter, onTrackMouseTouchLeave]); + setupEvent(scrollbarVars._scrollbar, + _strMouseTouchDownEvent, + onScrollbarMouseTouchDown); + if (_supportTransition) { scrollbarVars._scrollbar.on(_strTransitionEndEvent, function(event) { if (event.target !== scrollbarVars._scrollbar[0]) @@ -5010,7 +5061,7 @@ function onMouseTouchDownContinue(event) { var originalEvent = event.originalEvent || event; var isTouchEvent = originalEvent.touches !== undefined; - return _isSleeping || _destroyed ? false : COMPATIBILITY.mBtn(event) === 1 || isTouchEvent; + return _sleeping || _destroyed ? false : COMPATIBILITY.mBtn(event) === 1 || isTouchEvent; } function getCoordinates(event) { return _msieVersion && insideIFrame ? { x : event.screenX , y : event.screenY } : COMPATIBILITY.page(event); @@ -5031,13 +5082,13 @@ var extensionOnName = name; var ext; - if(extensionOnName.substr(0, 2) === "on") + if(extensionOnName.substr(0, 2) === 'on') extensionOnName = extensionOnName.substr(2, 1).toLowerCase() + extensionOnName.substr(3); if(type(callback) == TYPES.f) callback.call(_base, args); - FRAMEWORK.each(_extensions, function() { + each(_extensions, function() { ext = this; if(type(ext.on) == TYPES.f) ext.on(extensionOnName, args); @@ -5173,22 +5224,21 @@ if (textareaCursorPosition === undefined) return; - var strLength = 'length'; var textareaValue = _targetElement.val(); - var textareaLength = textareaValue[strLength]; - var textareaRowSplit = textareaValue.split("\n"); - var textareaLastRow = textareaRowSplit[strLength]; - var textareaCurrentCursorRowSplit = textareaValue.substr(0, textareaCursorPosition).split("\n"); + var textareaLength = textareaValue[LEXICON.l]; + var textareaRowSplit = textareaValue.split('\n'); + var textareaLastRow = textareaRowSplit[LEXICON.l]; + var textareaCurrentCursorRowSplit = textareaValue.substr(0, textareaCursorPosition).split('\n'); var widestRow = 0; var textareaLastCol = 0; - var cursorRow = textareaCurrentCursorRowSplit[strLength]; - var cursorCol = textareaCurrentCursorRowSplit[textareaCurrentCursorRowSplit[strLength] - 1][strLength]; + var cursorRow = textareaCurrentCursorRowSplit[LEXICON.l]; + var cursorCol = textareaCurrentCursorRowSplit[textareaCurrentCursorRowSplit[LEXICON.l] - 1][LEXICON.l]; var rowCols; var i; //get widest Row and the last column of the textarea - for (i = 0; i < textareaRowSplit[strLength]; i++) { - rowCols = textareaRowSplit[i][strLength]; + for (i = 0; i < textareaRowSplit[LEXICON.l]; i++) { + rowCols = textareaRowSplit[i][LEXICON.l]; if (rowCols > textareaLastCol) { widestRow = i + 1; textareaLastCol = rowCols; @@ -5257,7 +5307,7 @@ var i = 0; var val; for(; i < splits.length; i++) { - if(!obj.hasOwnProperty(splits[i])) + if(!obj[LEXICON.hOP](splits[i])) return; val = obj[splits[i]]; if(i < splits.length && type(val) == TYPES.o) @@ -5287,76 +5337,37 @@ //==== Utils Cache ====// /** - * Compares two values and returns the result of the comparison as a boolean. - * @param current The first value which shall be compared. - * @param cache The second value which shall be compared. + * Compares two values or objects and returns true if they aren't equal. + * @param current The first value or object which shall be compared. + * @param cache The second value or object which shall be compared. * @param force If true the returned value is always true. - * @returns {boolean} True if both variables aren't equal or some of them is undefined or when the force parameter is true, false otherwise. + * @returns {boolean} True if both values or objects aren't equal or force is true, false otherwise. */ - function checkCacheSingle(current, cache, force) { - if (force === true) + function checkCache(current, cache, force) { + if (force) return force; - if (cache === undefined) - return true; - else if (current !== cache) - return true; - return false; - } - - /** - * Compares two objects with two properties and returns the result of the comparison as a boolean. - * @param current The first object which shall be compared. - * @param cache The second object which shall be compared. - * @param prop1 The name of the first property of the objects which shall be compared. - * @param prop2 The name of the second property of the objects which shall be compared. - * @param force If true the returned value is always true. - * @returns {boolean} True if both variables aren't equal or some of them is undefined or when the force parameter is true, false otherwise. - */ - function checkCacheDouble(current, cache, prop1, prop2, force) { - if (force === true) - return force; - if (prop2 === undefined && force === undefined) { - if (prop1 === true) - return prop1; - else - prop1 = undefined; + if(type(current) == TYPES.o && type(cache) == TYPES.o) { + for (var prop in current) { + if(prop !== 'c') { + if (current[LEXICON.hOP](prop) && cache[LEXICON.hOP](prop)) { + if(checkCache(current[prop], cache[prop])) + return true; + } + else { + return true; + } + } + } + } + else { + return current !== cache; } - prop1 = prop1 === undefined ? 'w' : prop1; - prop2 = prop2 === undefined ? 'h' : prop2; - if (cache === undefined) - return true; - else if (current[prop1] !== cache[prop1] || current[prop2] !== cache[prop2]) - return true; - return false; - } - - /** - * Compares two objects which have four properties and returns the result of the comparison as a boolean. - * @param current The first object with four properties. - * @param cache The second object with four properties. - * @returns {boolean} True if both objects aren't equal or some of them is undefined, false otherwise. - */ - function checkCacheTRBL(current, cache) { - if (cache === undefined) - return true; - else if (current.t !== cache.t || - current.r !== cache.r || - current.b !== cache.b || - current.l !== cache.l) - return true; return false; } //==== Shortcuts ====// - /** - * jQuery type method shortcut. - */ - function type(obj) { - return COMPATIBILITY.type(obj); - } - /** * jQuery extend method shortcut with a appended "true" as first argument. */ @@ -5403,15 +5414,21 @@ * This behavior can be reset by calling the update method. */ _base.sleep = function () { - _isSleeping = true; + _sleeping = true; }; /** * Updates the plugin and DOM to the current options. * This method should only be called if a update is 100% required. * @param force True if every property shall be updated and the cache shall be ignored. - * !INTERNAL USAGE! : force can be a string "auto", "auto+" or "zoom" too - * if this is the case then before a real update the content size and host element attributes gets checked, and if they changed only then the update method will be called. + * !INTERNAL USAGE! : force can be a string "auto", "sync" or "zoom" too + * if "auto" then before a real update the content size and host element attributes gets checked, and if they changed only then the update method will be called. + * if "sync" then the async update process (MutationObserver or UpdateLoop) gets synchronized and a corresponding update takes place if one was needed due to pending changes. + * if "zoom" then a update takes place where it's assumed that content and host size changed + * @returns {boolean|undefined} + * If force is "sync" then a boolean is returned which indicates whether a update was needed due to pending changes. + * If force is "auto" then a boolean is returned whether a update was needed due to attribute or size changes. + * undefined otherwise. */ _base.update = function (force) { var attrsChanged; @@ -5419,21 +5436,42 @@ var isString = type(force) == TYPES.s; var imgElementSelector = 'img'; var imgElementLoadEvent = 'load'; - + var doUpdateAuto; + var mutHost; + var mutContent; if(isString) { if (force === _strAuto) { attrsChanged = meaningfulAttrsChanged(); contentSizeC = updateAutoContentSizeChanged(); - if (attrsChanged || contentSizeC) - update(false, contentSizeC, false); + doUpdateAuto = attrsChanged || contentSizeC; + if (doUpdateAuto) { + update({ + _contentSizeChanged : contentSizeC, + _changedOptions : _initialized ? undefined : _currentPreparedOptions + }); + } + } + else if (force === _strSync) { + if(_mutationObserversConnected) { + mutHost = _mutationObserverHostCallback(_mutationObserverHost.takeRecords()); + mutContent = _mutationObserverContentCallback(_mutationObserverContent.takeRecords()); + } + else { + mutHost = _base.update(_strAuto); + } + } + else if (force === 'zoom') { + update({ + _hostSizeChanged : true, + _contentSizeChanged : true + }); } - else if (force === 'zoom') - update(true, true); } - else if(!synchronizeMutationObservers() || force) { - force = _isSleeping || force; - _isSleeping = false; - update(false, false, force, true); + else { + force = _sleeping || force; + _sleeping = false; + if(!_base.update(_strSync) || force) + update({ _force : force }); } if(!_isTextarea) { _contentElement.find(imgElementSelector).each(function(i, el) { @@ -5442,7 +5480,7 @@ FRAMEWORK(el).off(imgElementLoadEvent, imgOnLoad).on(imgElementLoadEvent, imgOnLoad); }); } - + return doUpdateAuto || mutHost || mutContent; }; /** @@ -5452,15 +5490,15 @@ * @returns {*} */ _base.options = function (newOptions, value) { + var option = { }; + var changedOps; + //return current options if newOptions are undefined or empty if (FRAMEWORK.isEmptyObject(newOptions) || !FRAMEWORK.isPlainObject(newOptions)) { if (type(newOptions) == TYPES.s) { if (arguments.length > 1) { - var option = { }; setObjectPropVal(option, newOptions, value); - setOptions(option); - update(); - return; + changedOps = setOptions(option); } else return getObjectPropVal(_currentOptions, newOptions); @@ -5468,19 +5506,19 @@ else return _currentOptions; } - setOptions(newOptions); - var isSleepingTmp = _isSleeping || false; - _isSleeping = false; - update(); - _isSleeping = isSleepingTmp; + else { + changedOps = setOptions(newOptions); + } + + if(!FRAMEWORK.isEmptyObject(changedOps)) { + update({ _changedOptions : changedOps }); + } }; /** - * Restore the DOM, disconnects all observers, remove all resize observers and destroy all methods. + * Restore the DOM, disconnects all observers, remove all resize observers and put the instance to sleep. */ _base.destroy = function () { - _destroyed = true; - //remove this instance from auto update loop autoUpdateLoop.remove(_base); @@ -5488,9 +5526,8 @@ disconnectMutationObservers(); //remove all resize observers - removeResizeObserver(_sizeObserverElement); - if (_sizeAutoObserverAdded) - removeResizeObserver(_sizeAutoObserverElement); + setupResizeObserver(_sizeObserverElement); + setupResizeObserver(_sizeAutoObserverElement); //remove all extensions for(var extName in _extensions) @@ -5520,14 +5557,17 @@ FRAMEWORK(_imgs[i]).off('load', imgOnLoad); _imgs = undefined; + _destroyed = true; + _sleeping = true; + //remove this instance from the instances list INSTANCES(pluginTargetElement, 0); dispatchCallback("onDestroyed"); //remove all properties and methods - for (var property in _base) - delete _base[property]; - _base = undefined; + //for (var property in _base) + // delete _base[property]; + //_base = undefined; }; /** @@ -5651,7 +5691,7 @@ }; } - synchronizeMutationObservers(); + _base.update(_strSync); var normalizeRTL = _normalizeRTLCache; var coordinatesXAxisProps = [_strX, _strLeft, 'l']; @@ -5681,7 +5721,7 @@ var elementObjSettingsAxisValues = [_strX, _strY, 'xy', 'yx']; var elementObjSettingsBlockValues = [strBegin, strEnd, strCenter, strNearest]; var elementObjSettingsScrollValues = [strAlways, strNever, strIfNeeded]; - var coordinatesIsElementObj = coordinates.hasOwnProperty('el'); + var coordinatesIsElementObj = coordinates[LEXICON.hOP]('el'); var possibleElement = coordinatesIsElementObj ? coordinates.el : coordinates; var possibleElementIsJQuery = possibleElement instanceof FRAMEWORK || JQUERY ? possibleElement instanceof JQUERY : false; var possibleElementIsHTMLElement = possibleElementIsJQuery ? false : isHTMLElement(possibleElement); @@ -5731,7 +5771,7 @@ //check operator if (rawScroll[strLength] > 2) { possibleOperator = rawScroll.substr(0, 2); - if(FRAMEWORK.inArray(possibleOperator, coordinatesOperators) > -1) + if(inArray(possibleOperator, coordinatesOperators) > -1) operator = possibleOperator; } @@ -6026,12 +6066,12 @@ * @returns {{widthAuto, heightAuto, overflowAmount, hideOverflow, hasOverflow, contentScrollSize, viewportSize, hostSize, autoUpdate} | *} */ _base.getState = function (stateProperty) { - var prepare = function (obj) { + function prepare(obj) { if (!FRAMEWORK.isPlainObject(obj)) return obj; var extended = extendDeep({}, obj); var changePropertyName = function (from, to) { - if (extended.hasOwnProperty(from)) { + if (extended[LEXICON.hOP](from)) { extended[to] = extended[from]; delete extended[from]; } @@ -6042,7 +6082,8 @@ return extended; }; var obj = { - sleeping: prepare(_isSleeping) || false, + destroyed: !!prepare(_destroyed), + sleeping: !!prepare(_sleeping), autoUpdate: prepare(!_mutationObserversConnected), widthAuto: prepare(_widthAutoCache), heightAuto: prepare(_heightAutoCache), @@ -6068,7 +6109,7 @@ var privateMethods = _extensionsPrivateMethods.split(' '); var i = 0; if(type(extName) == TYPES.s) { - if(_extensions.hasOwnProperty(extName)) { + if(_extensions[LEXICON.hOP](extName)) { result = extendDeep({}, _extensions[extName]); for (; i < privateMethods.length; i++) delete result[privateMethods[i]]; @@ -6096,7 +6137,7 @@ var contractResult; var contractFulfilled = true; if(registeredExtensionObj) { - if(!_extensions.hasOwnProperty(extName)) { + if(!_extensions[LEXICON.hOP](extName)) { instance = registeredExtensionObj.extensionFactory.call(_base, extendDeep({ }, registeredExtensionObj.defaultOptions), FRAMEWORK, @@ -6161,7 +6202,7 @@ _rtlScrollBehavior = extendDeep({}, globals.rtlScrollBehavior); //parse & set options but don't update - setOptions(extendDeep({ }, _defaultOptions, _pluginsOptions._validate(options, _pluginsOptions._template, true))); + setOptions(extendDeep({ }, _defaultOptions, options)); //check if the plugin hasn't to be initialized if (_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.x && !_currentPreparedOptions.nativeScrollbarsOverlaid.initialize) { @@ -6233,27 +6274,26 @@ } //build resize observer for the host element - addResizeObserver(_sizeObserverElement, hostOnResized); + setupResizeObserver(_sizeObserverElement, hostOnResized); - //update for the first time - hostOnResized(); //initialize cache for host size - _base.update(_strAuto); //initialize cache for content + //update for the first time & initialize cache + _base.update(_strAuto); //the plugin is initialized now! _initialized = true; dispatchCallback("onInitialized"); //call all callbacks which would fire before the initialized was complete - FRAMEWORK.each(_callbacksInitQeueue, function(index, value) { dispatchCallback(value.n, value.a); }); + each(_callbacksInitQeueue, function(index, value) { dispatchCallback(value.n, value.a); }); _callbacksInitQeueue = [ ]; //add extensions if(type(extensions) == TYPES.s) extensions = [ extensions ]; if(COMPATIBILITY.isA(extensions)) - FRAMEWORK.each(extensions, function (index, value) {_base.addExt(value); }); + each(extensions, function (index, value) {_base.addExt(value); }); else if(FRAMEWORK.isPlainObject(extensions)) - FRAMEWORK.each(extensions, function (key, value) { _base.addExt(key, value); }); + each(extensions, function (key, value) { _base.addExt(key, value); }); //add the transition class for transitions AFTER the first update & AFTER the applied extensions (for preventing unwanted transitions) setTimeout(function () { @@ -6345,7 +6385,7 @@ return FRAMEWORK.extend(true, { }, currDefaultOptions); //set the new default options - _pluginsGlobals.defaultOptions = FRAMEWORK.extend(true, { }, currDefaultOptions , _pluginsOptions._validate(newDefaultOptions, _pluginsOptions._template, true)); + _pluginsGlobals.defaultOptions = FRAMEWORK.extend(true, { }, currDefaultOptions , _pluginsOptions._validate(newDefaultOptions, _pluginsOptions._template, true, currDefaultOptions)._default); }; /** diff --git a/js/OverlayScrollbars.min.js b/js/OverlayScrollbars.min.js index 4c110dc..a2bbbd0 100644 --- a/js/OverlayScrollbars.min.js +++ b/js/OverlayScrollbars.min.js @@ -2,12 +2,12 @@ * OverlayScrollbars * https://github.com/KingSora/OverlayScrollbars * - * Version: 1.7.3 + * Version: 1.8.0 * - * Copyright KingSora. + * Copyright KingSora | Rene Haas. * https://github.com/KingSora * * Released under the MIT license. - * Date: 23.06.2019 + * Date: 08.07.2019 */ -!function(n,t){"function"==typeof define&&define.amd?define(function(){return t(n,n.document,undefined)}):"object"==typeof module&&"object"==typeof module.exports?module.exports=t(n,n.document,undefined):t(n,n.document,undefined)}("undefined"!=typeof window?window:this,function(bt,mt,Se){"use strict";var a,e,o,wt="OverlayScrollbars",gt="object",yt="function",xt="array",Ot="string",St="boolean",_t="number",p="undefined",h="null",zt="class",_e="style",Tt="id",ze="length",Te="prototype",ke="offsetHeight",Ie="clientHeight",Ce="scrollHeight",Ae="offsetWidth",He="clientWidth",Ne="scrollWidth",Ee={u:{},v:{},m:["-webkit-","-moz-","-o-","-ms-"],g:["WebKit","Moz","O","MS"],O:function(n){var t=this.v;if(t[n])return t[n];for(var r,i,e=this.m,o=this.S(n),u=mt.createElement("div")[_e],f=0,a=0;f
'),o=_[0],i=Me(_.children("div").eq(0)),t=bt.getComputedStyle;S.append(_),_.hide().show();var r,u,f,a,c,s,l,v,h,d=z(o),p={x:0===d.x,y:0===d.y};function z(n){return{x:n[ke]-n[Ie],y:n[Ae]-n[He]}}Me.extend(O,{defaultOptions:n,autoUpdateLoop:!1,autoUpdateRecommended:!Le.mO(),nativeScrollbarSize:d,nativeScrollbarIsOverlaid:p,nativeScrollbarStyling:(_.addClass("os-viewport-native-scrollbars-invisible"),"none"===_.css("scrollbar-width")||!!t&&"none"===t(o,"::-webkit-scrollbar").getPropertyValue("display")),overlayScrollbarDummySize:{x:30,y:30},msie:(u=bt.navigator.userAgent,f="indexOf",a="substring",c=u[f]("MSIE "),s=u[f]("Trident/"),l=u[f]("Edge/"),v=u[f]("rv:"),h=parseInt,0e&&(t.update("auto"),h[a]=new Date(o+=e)),n=Re.max(1,Re.min(n,e)));p=n}}else p=33};this.add=function(n){-1===Me.inArray(n,v)&&(v.push(n),h.push(Le.now()),0/g,(l?"-":Ti)+Ci)[v](/px/g,Ti)[v](/%/g," * "+c*(s&&Ht.n?-1:1)/100)[v](/vw/g," * "+vi.w)[v](/vh/g," * "+vi.h),de(isNaN(t)?de(h(t),!0).toFixed():t)):t)!==Se&&!isNaN(i)&<(i)==_t){var d=y&&s,p=a*(d&&Ht.n?-1:1),b=d&&Ht.i,m=d&&Ht.n;switch(p=b?c-p:p,r){case"+=":e=p+i;break;case"-=":e=p-i;break;case"*=":e=p*i;break;case"/=":e=p/i;break;default:e=i}e=b?c-e:e,e*=m?-1:1,e=s&&Ht.n?Re.min(0,Re.max(c,e)):Re.max(0,Re.min(c,e))}return e===a?Se:e},U=function(n,t,r,i){var e,o,u=[r,r],f=lt(n);if(f==t)n=[n,n];else if(f==xt){if(2<(e=n[N])||e<1)n=u;else for(1===e&&(n[1]=r),l=0;l=t.left&&n.clientX<=t.right&&n.clientY>=t.top&&n.clientY<=t.bottom||Gn(),(ri||ii)&&fe(!1)}}function E(n){e=or[I](),e=isNaN(e)?0:e,($t&&O&&!Ht.n||!$t)&&(e=e<0?0:e),z=ft()[k],_=a(n),V=!c(u),xe(M,jn),xe(r.en,o),xe(r.an,o),D.on(nn,h).on(Z,N).on(un,Jn),!L&&p||Le.prvD(n),Le.stpP(n)}r.en.on(Ri,function(n){H(n)&&E(n)}),r.un.on(Ri,function(n){if(H(n)){var h,d=Re.round(vi[r.W]),p=r.un.offset()[r.j],t=n.ctrlKey,b=n.shiftKey,m=b&&t,w=!0,g=function(n){V&&ce(O,n)},y=function(){g(),E(n)},x=function(){if(!Wt){var n=(_-p)*z,t=T.N,r=T.D,i=T.L,e=T.H,o=T.C,u=270*C,f=w?Re.max(400,u):u,a=e*((n-i/2)/(r-i)),c=$t&&O&&(!Ht.i&&!Ht.n||Vr),s=c?t"+(n||Ti)+""}function st(n,t){for(var r,i=t.split($),e=0;e
'),o=S[0],e=Ni(S.children("div").eq(0));O.append(S),S.hide().show();var t,r,u,f,a,c,s,l,v,h=z(o),d={x:0===h.x,y:0===h.y};function z(n){return{x:n[Ci]-n[Ti],y:n[Ii]-n[Ai]}}Ni.extend(_,{defaultOptions:n,autoUpdateLoop:!1,autoUpdateRecommended:!Hi.mO(),nativeScrollbarSize:h,nativeScrollbarIsOverlaid:d,nativeScrollbarStyling:function(){var n=!1;S.addClass("os-viewport-native-scrollbars-invisible");try{n="none"===S.css("scrollbar-width")||"none"===vt.getComputedStyle(o,"::-webkit-scrollbar").getPropertyValue("display")}catch(t){}return n}(),overlayScrollbarDummySize:{x:30,y:30},msie:(r=vt.navigator.userAgent,u="indexOf",f="substring",a=r[u]("MSIE "),c=r[u]("Trident/"),s=r[u]("Edge/"),l=r[u]("rv:"),v=parseInt,0i&&(t.update("auto"),d[a]=new Date(o+=i)),n=Li.max(1,Li.min(n,i)));b=n}}else b=33};this.add=function(n){-1===e(n,h)&&(h.push(n),d.push(s()),0/g,(l?"-":Ie)+He)[v](/px/g,Ie)[v](/%/g," * "+c*(s&&Nt.n?-1:1)/100)[v](/vw/g," * "+pe.w)[v](/vh/g," * "+pe.h),bi(isNaN(t)?bi(h(t),!0).toFixed():t)):t)!==Oi&&!isNaN(e)&&sn(e)==yt){var d=y&&s,p=a*(d&&Nt.n?-1:1),b=d&&Nt.i,m=d&&Nt.n;switch(p=b?c-p:p,r){case"+=":i=p+e;break;case"-=":i=p-e;break;case"*=":i=p*e;break;case"/=":i=p/e;break;default:i=e}i=b?c-i:i,i*=m?-1:1,i=s&&Nt.n?Li.min(0,Li.max(c,i)):Li.max(0,Li.min(c,i))}return i===a?Oi:i},U=function(n,t,r,e){var i,o,u=[r,r],f=sn(n);if(f==t)n=[n,n];else if(f==mt){if(2<(i=n[H])||i<1)n=u;else for(1===i&&(n[1]=r),l=0;l=t.left&&n.clientX<=t.right&&n.clientY>=t.top&&n.clientY<=t.bottom||Xn(),(ue||fe)&&ci(!1)}}function N(n){i=cr[k](),i=isNaN(i)?0:i,(Zt&&_&&!Nt.n||!Zt)&&(i=i<0?0:i),z=it()[T],S=c(n),P=!s(u),xi(j,Mn),xi(r.dn,o),xi(r.bn,o),W.on(X,h).on(q,L).on(J,$n),!D&&g||Hi.prvD(n),Hi.stpP(n)}a(r.dn,De,function d(n){H(n)&&N(n)}),a(r.pn,[De,Y,$],[function R(n){if(H(n)){var h,d=Li.round(pe[r.Y]),p=r.pn.offset()[r.$],t=n.ctrlKey,b=n.shiftKey,m=b&&t,g=!0,w=function(n){P&&li(_,n)},y=function(){w(),N(n)},x=function(){if(!Bt){var n=(S-p)*z,t=C.P,r=C.V,e=C.B,i=C.F,o=C.W,u=270*I,f=g?Li.max(400,u):u,a=i*((n-e/2)/(r-e)),c=Zt&&_&&(!Nt.i&&!Nt.n||$r),s=c?t"+(n||Ie)+""}function ft(n,t){for(var r,e=t.split(B),i=0;i the first is always the mainPossibility restrictedStringValuesPossibilitiesSplit = restrictedStringValuesSplit[v].split(restrictedStringsPossibilitiesSplit); mainPossibility = restrictedStringValuesPossibilitiesSplit[0]; - for(j = 0; j < restrictedStringValuesPossibilitiesSplit.length; j++) { + for(j = 0; j < restrictedStringValuesPossibilitiesSplit[LEXICON.l]; j++) { //if any possibility matches with the dataValue, its valid if(dataValue === restrictedStringValuesPossibilitiesSplit[j]) { isValid = true; @@ -539,27 +547,41 @@ } if(isValid) { - validatedOptions[prop] = isRestrictedValue && usePreparedValues ? mainPossibility : dataValue; + isDiff = dataValue !== dataDiffValue; + + if(isDiff) + validatedOptions[prop] = dataValue; + + if(isRestrictedValue ? inArray(dataDiffValue, restrictedStringValuesPossibilitiesSplit) < 0 : isDiff) + validatedOptionsPrepared[prop] = isRestrictedValue ? mainPossibility : dataValue; } else if(writeErrors) { console.warn(error + " it doesn't accept the type [ " + dataValueType.toUpperCase() + " ] with the value of \"" + dataValue + "\".\r\n" + "Accepted types are: [ " + errorPossibleTypes.join(", ").toUpperCase() + " ]." + - (errorRestrictedStrings.length > 0 ? "\r\nValid strings are: [ " + errorRestrictedStrings.join(", ").split(restrictedStringsPossibilitiesSplit).join(", ") + " ]." : "")); + (errorRestrictedStrings[length] > 0 ? "\r\nValid strings are: [ " + errorRestrictedStrings.join(", ").split(restrictedStringsPossibilitiesSplit).join(", ") + " ]." : "")); } delete data[prop]; } } } }; - checkObjectProps(objectCopy, template, validatedOptions); + checkObjectProps(objectCopy, template, diffObj || { }, validatedOptions, validatedOptionsPrepared); //add values which aren't specified in the template to the finished validated object to prevent them from being discarded - if(keepForeignProps) + /* + if(keepForeignProps) { FRAMEWORK.extend(true, validatedOptions, objectCopy); - else if(!FRAMEWORK.isEmptyObject(objectCopy) && writeErrors) + FRAMEWORK.extend(true, validatedOptionsPrepared, objectCopy); + } + */ + + if(!isEmptyObj(objectCopy) && writeErrors) console.warn("The following options are discarded due to invalidity:\r\n" + window.JSON.stringify(objectCopy, null, 2)); - return validatedOptions; + return { + _default : validatedOptions, + _prepared : validatedOptionsPrepared + }; } } }()); @@ -588,7 +610,6 @@ var scrollbarDummyElement = FRAMEWORK('
'); var scrollbarDummyElement0 = scrollbarDummyElement[0]; var dummyContainerChild = FRAMEWORK(scrollbarDummyElement.children('div').eq(0)); - var getCptStyle = window.getComputedStyle; bodyElement.append(scrollbarDummyElement); scrollbarDummyElement.hide().show(); //fix IE8 bug (incorrect measuring) @@ -606,14 +627,18 @@ nativeScrollbarSize : nativeScrollbarSize, nativeScrollbarIsOverlaid : nativeScrollbarIsOverlaid, nativeScrollbarStyling : (function() { + var result = false; scrollbarDummyElement.addClass('os-viewport-native-scrollbars-invisible'); - + try { + result = scrollbarDummyElement.css('scrollbar-width') === 'none' || window.getComputedStyle(scrollbarDummyElement0, '::-webkit-scrollbar').getPropertyValue('display') === 'none'; + } catch (ex) { } + //fix opera bug: scrollbar styles will only appear if overflow value is scroll or auto during the activation of the style. //and set overflow to scroll //scrollbarDummyElement.css(strOverflow, strHidden).hide().css(strOverflow, strScroll).show(); //return (scrollbarDummyElement0[LEXICON.oH] - scrollbarDummyElement0[LEXICON.cH]) === 0 && (scrollbarDummyElement0[LEXICON.oW] - scrollbarDummyElement0[LEXICON.cW]) === 0; - return scrollbarDummyElement.css('scrollbar-width') === 'none' || (getCptStyle ? getCptStyle(scrollbarDummyElement0, '::-webkit-scrollbar').getPropertyValue('display') === 'none' : false); + return result; })(), overlayScrollbarDummySize : { x: 30, y: 30 }, msie : (function() { @@ -789,6 +814,8 @@ */ function OverlayScrollbarsAutoUpdateLoop(globals) { var _base = this; + var _inArray = FRAMEWORK.inArray; + var _getNow = COMPATIBILITY.now; var _strAutoUpdate = 'autoUpdate'; var _strAutoUpdateInterval = _strAutoUpdate + 'Interval'; var _strLength = LEXICON.l; @@ -797,8 +824,9 @@ var _loopIsActive = false; var _loopIntervalDefault = 33; var _loopInterval = _loopIntervalDefault; - var _loopTimeOld = COMPATIBILITY.now(); + var _loopTimeOld = _getNow(); var _loopID; + /** * The auto update loop which will run every 50 milliseconds or less if the update interval of a instance is lower than 50 milliseconds. @@ -808,7 +836,7 @@ _loopID = COMPATIBILITY.rAF()(function () { loop(); }); - var timeNew = COMPATIBILITY.now(); + var timeNew = _getNow(); var timeDelta = timeNew - _loopTimeOld; var lowestInterval; var instance; @@ -826,7 +854,7 @@ instanceOptions = instance.options(); instanceAutoUpdateAllowed = instanceOptions[_strAutoUpdate]; instanceAutoUpdateInterval = MATH.max(1, instanceOptions[_strAutoUpdateInterval]); - now = COMPATIBILITY.now(); + now = _getNow(); if ((instanceAutoUpdateAllowed === true || instanceAutoUpdateAllowed === null) && (now - _loopingInstancesIntervalCache[i]) > instanceAutoUpdateInterval) { instance.update('auto'); @@ -848,9 +876,9 @@ * @param instance The instance which shall be updated in a loop automatically. */ _base.add = function(instance) { - if(FRAMEWORK.inArray(instance, _loopingInstances) === -1) { + if(_inArray(instance, _loopingInstances) === -1) { _loopingInstances.push(instance); - _loopingInstancesIntervalCache.push(COMPATIBILITY.now()); + _loopingInstancesIntervalCache.push(_getNow()); if (_loopingInstances[_strLength] > 0 && !_loopIsActive) { _loopIsActive = true; globals.autoUpdateLoop = _loopIsActive; @@ -864,7 +892,7 @@ * @param instance The instance which shall be updated in a loop automatically. */ _base.remove = function(instance) { - var index = FRAMEWORK.inArray(instance, _loopingInstances); + var index = _inArray(instance, _loopingInstances); if(index > -1) { //remove from loopingInstances list _loopingInstancesIntervalCache.splice(index, 1); @@ -894,10 +922,19 @@ * @constructor */ function OverlayScrollbarsInstance(pluginTargetElement, options, extensions, globals, autoUpdateLoop) { + //shortcuts + var type = COMPATIBILITY.type; + var inArray = FRAMEWORK.inArray; + var each = FRAMEWORK.each; + + //make correct instanceof + var _base = new window[PLUGINNAME](); + var _frameworkProto = FRAMEWORK[LEXICON.p]; + //if passed element is no HTML element: skip and return if(!isHTMLElement(pluginTargetElement)) return; - + //if passed element is already initialized: set passed options if there are any and return its instance if(INSTANCES(pluginTargetElement)) { var inst = INSTANCES(pluginTargetElement); @@ -905,10 +942,6 @@ return inst; } - //make correct instanceof - var _base = new window[PLUGINNAME](); - var _frameworkProto = FRAMEWORK[LEXICON.p]; - //globals: var _nativeScrollbarIsOverlaid; var _overlayScrollbarDummySize; @@ -943,7 +976,7 @@ var _marginX; var _marginY; var _isRTL; - var _isSleeping; + var _sleeping; var _contentBorderSize = { }; var _scrollHorizontalInfo = { }; var _scrollVerticalInfo = { }; @@ -966,6 +999,7 @@ var _strFloat = 'float'; var _strEmpty = ''; var _strAuto = 'auto'; + var _strSync = 'sync'; var _strScroll = 'scroll'; var _strHundredPercent = '100%'; var _strX = 'x'; @@ -1043,11 +1077,11 @@ //extensions: var _extensions = { }; - var _extensionsPrivateMethods = "added removed on contract"; + var _extensionsPrivateMethods = 'added removed on contract'; //update var _lastUpdateTime; - var _swallowedUpdateParams = { }; + var _swallowedUpdateHints = { }; var _swallowedUpdateTimeout; var _swallowUpdateLag = 42; var _imgs = [ ]; @@ -1109,13 +1143,6 @@ var _sizeAutoCapableCache; var _textareaAutoWrappingCache; var _textareaInfoCache; - var _updateAutoHostElementIdCache; - var _updateAutoHostElementClassCache; - var _updateAutoHostElementStyleCache; - var _updateAutoHostElementVisibleCache; - var _updateAutoTargetElementRowsCache; - var _updateAutoTargetElementColsCache; - var _updateAutoTargetElementWrapCache; var _contentElementScrollSizeChangeDetectedCache; var _hostElementSizeChangeDetectedCache; var _scrollbarsVisibilityCache; @@ -1131,6 +1158,7 @@ var _bodyMinSizeCache; var _viewportScrollSizeCache; var _displayIsHiddenCache; + var _updateAutoCache = { }; //MutationObserver: var _mutationObserverHost; @@ -1138,6 +1166,8 @@ var _mutationObserverHostCallback; var _mutationObserverContentCallback; var _mutationObserversConnected; + var _mutationObserverAttrsTextarea = ['wrap', 'cols', 'rows']; + var _mutationObserverAttrsHost = [LEXICON.i, LEXICON.c, LEXICON.s, 'open']; //textarea: var _textareaEvents; @@ -1152,7 +1182,7 @@ var _scrollbarsAutoHideMove; var _scrollbarsAutoHideLeave; var _scrollbarsHandleHovered; - var _scrollbarsHandleAsync; + var _scrollbarsHandlesDefineScrollPos; //resize var _resizeReconnectMutationObserver; @@ -1161,272 +1191,262 @@ var _resizeHorizontal; var _resizeVertical; var _resizeOnMouseTouchDown; - - + + //==== Passive Event Listener ====// /** - * Adds a passive event listener to the given element. - * @param element The element to which the event listener shall be applied. - * @param eventNames The name(s) of the event listener. - * @param listener The listener method which shall be called. + * Adds or removes a passive event listener from the given element. + * @param element The element to which the event listener shall be applied or removed. + * @param eventNames The name(s) of the events. + * @param listener The method which shall be called. + * @param remove True if the handler shall be removed, false or undefined if the handler shall be added. */ - function addPassiveEventListener(element, eventNames, listener) { + function setupPassiveEventListener(element, eventNames, listener, remove, notPassive) { + var method = remove ? 'removeEventListener' : 'addEventListener'; var events = eventNames.split(_strSpace); - for (var i = 0; i < events.length; i++) - element[0].addEventListener(events[i], listener, {passive: true}); - } + var i = 0; - /** - * Removes a passive event listener to the given element. - * @param element The element from which the event listener shall be removed. - * @param eventNames The name(s) of the event listener. - * @param listener The listener method which shall be removed. - */ - function removePassiveEventListener(element, eventNames, listener) { - var events = eventNames.split(_strSpace); - for (var i = 0; i < events.length; i++) - element[0].removeEventListener(events[i], listener, {passive: true}); + for (; i < events[LEXICON.l]; i++) { + element[0][method](events[i], listener, { passive: !notPassive }); + } } //==== Resize Observer ====// /** - * Adds a resize observer to the given element. - * @param targetElement The element to which the resize observer shall be applied. - * @param onElementResizedCallback The callback which is fired every time the resize observer registers a size change. + * Adds or removes a resize observer from the given element. + * @param targetElement The element to which the resize observer shall be added or removed. + * @param onElementResizedCallback The callback which is fired every time the resize observer registers a size change or false / undefined if the resizeObserver shall be removed. */ - function addResizeObserver(targetElement, onElementResizedCallback) { - var constMaximum = 3333333; - var resizeObserver = COMPATIBILITY.rO(); - var strAnimationStartEvent = 'animationstart mozAnimationStart webkitAnimationStart MSAnimationStart'; - var strChildNodes = 'childNodes'; - var callback = function () { - targetElement[_strScrollTop](constMaximum)[_strScrollLeft](_isRTL ? _rtlScrollBehavior.n ? -constMaximum : _rtlScrollBehavior.i ? 0 : constMaximum : constMaximum); - onElementResizedCallback(); - }; - if (_supportResizeObserver) { - var element = targetElement.append(generateDiv(_classNameResizeObserverElement + ' observed')).contents()[0]; - var observer = element[_strResizeObserverProperty] = new resizeObserver(callback); - observer.observe(element); - } - else { - if (_msieVersion > 9 || !_autoUpdateRecommended) { - targetElement.prepend( - generateDiv(_classNameResizeObserverElement, - generateDiv({ className : _classNameResizeObserverItemElement, dir : "ltr" }, - generateDiv(_classNameResizeObserverItemElement, - generateDiv(_classNameResizeObserverItemFinalElement) - ) + - generateDiv(_classNameResizeObserverItemElement, - generateDiv({ className : _classNameResizeObserverItemFinalElement, style : 'width: 200%; height: 200%' }) - ) - ) - ) - ); - - var observerElement = targetElement[0][strChildNodes][0][strChildNodes][0]; - var shrinkElement = FRAMEWORK(observerElement[strChildNodes][1]); - var expandElement = FRAMEWORK(observerElement[strChildNodes][0]); - var expandElementChild = FRAMEWORK(expandElement[0][strChildNodes][0]); - var widthCache = observerElement[LEXICON.oW]; - var heightCache = observerElement[LEXICON.oH]; - var isDirty; - var rAFId; - var currWidth; - var currHeight; - var factor = 2; - var nativeScrollbarSize = globals.nativeScrollbarSize; //care don't make changes to this object!!! - var reset = function () { - /* - var sizeResetWidth = observerElement[LEXICON.oW] + nativeScrollbarSize.x * factor + nativeScrollbarSize.y * factor + _overlayScrollbarDummySize.x + _overlayScrollbarDummySize.y; - var sizeResetHeight = observerElement[LEXICON.oH] + nativeScrollbarSize.x * factor + nativeScrollbarSize.y * factor + _overlayScrollbarDummySize.x + _overlayScrollbarDummySize.y; - var expandChildCSS = {}; - expandChildCSS[_strWidth] = sizeResetWidth; - expandChildCSS[_strHeight] = sizeResetHeight; - expandElementChild.css(expandChildCSS); - - - expandElement[_strScrollLeft](sizeResetWidth)[_strScrollTop](sizeResetHeight); - shrinkElement[_strScrollLeft](sizeResetWidth)[_strScrollTop](sizeResetHeight); - */ - expandElement[_strScrollLeft](constMaximum)[_strScrollTop](constMaximum); - shrinkElement[_strScrollLeft](constMaximum)[_strScrollTop](constMaximum); + function setupResizeObserver(targetElement, onElementResizedCallback) { + if(targetElement) { + //add resize observer: + if(onElementResizedCallback) { + var constMaximum = 3333333; + var resizeObserver = COMPATIBILITY.rO(); + var strAnimationStartEvent = 'animationstart mozAnimationStart webkitAnimationStart MSAnimationStart'; + var strChildNodes = 'childNodes'; + var callback = function () { + targetElement[_strScrollTop](constMaximum)[_strScrollLeft](_isRTL ? _rtlScrollBehavior.n ? -constMaximum : _rtlScrollBehavior.i ? 0 : constMaximum : constMaximum); + onElementResizedCallback(); }; - var onResized = function () { - rAFId = 0; - if (!isDirty) - return; - - widthCache = currWidth; - heightCache = currHeight; - callback(); - }; - var onScroll = function (event) { - currWidth = observerElement[LEXICON.oW]; - currHeight = observerElement[LEXICON.oH]; - isDirty = currWidth != widthCache || currHeight != heightCache; - - if (event && isDirty && !rAFId) { - COMPATIBILITY.cAF()(rAFId); - rAFId = COMPATIBILITY.rAF()(onResized); - } - else if(!event) - onResized(); - - reset(); - if (event) { - COMPATIBILITY.prvD(event); - COMPATIBILITY.stpP(event); - } - return false; - }; - var expandChildCSS = {}; - var observerElementCSS = {}; - - setTopRightBottomLeft(observerElementCSS, _strEmpty, [ - -((nativeScrollbarSize.y + 1) * factor), - nativeScrollbarSize.x * -factor, - nativeScrollbarSize.y * -factor, - -((nativeScrollbarSize.x + 1) * factor) - ]); - - FRAMEWORK(observerElement).css(observerElementCSS); - expandElement.on(_strScroll, onScroll); - shrinkElement.on(_strScroll, onScroll); - targetElement.on(strAnimationStartEvent, function () { - onScroll(false); - }); - //lets assume that the divs will never be that large and a constant value is enough - expandChildCSS[_strWidth] = constMaximum; - expandChildCSS[_strHeight] = constMaximum; - expandElementChild.css(expandChildCSS); - - reset(); - } - else { - var attachEvent = _documentElementNative.attachEvent; - var isIE = _msieVersion !== undefined; - if (attachEvent) { - targetElement.prepend(generateDiv(_classNameResizeObserverElement)); - findFirst(targetElement, _strDot + _classNameResizeObserverElement)[0].attachEvent('onresize', callback); + if (_supportResizeObserver) { + var element = targetElement.append(generateDiv(_classNameResizeObserverElement + ' observed')).contents()[0]; + var observer = element[_strResizeObserverProperty] = new resizeObserver(callback); + observer.observe(element); } else { - var obj = _documentElementNative.createElement(TYPES.o); - obj.setAttribute('tabindex', '-1'); - obj.setAttribute(LEXICON.c, _classNameResizeObserverElement); - obj.onload = function () { - var wnd = this.contentDocument.defaultView; - wnd.addEventListener('resize', callback); - wnd.document.documentElement.style.display = 'none'; - }; - obj.type = 'text/html'; - if (isIE) - targetElement.prepend(obj); - obj.data = 'about:blank'; - if (!isIE) - targetElement.prepend(obj); - targetElement.on(strAnimationStartEvent, callback); - } - } - } + if (_msieVersion > 9 || !_autoUpdateRecommended) { + targetElement.prepend( + generateDiv(_classNameResizeObserverElement, + generateDiv({ className : _classNameResizeObserverItemElement, dir : "ltr" }, + generateDiv(_classNameResizeObserverItemElement, + generateDiv(_classNameResizeObserverItemFinalElement) + ) + + generateDiv(_classNameResizeObserverItemElement, + generateDiv({ className : _classNameResizeObserverItemFinalElement, style : 'width: 200%; height: 200%' }) + ) + ) + ) + ); - //direction change detection: - if (targetElement[0] === _sizeObserverElementNative) { - var directionChanged = function () { - var dir = _hostElement.css('direction'); - var css = {}; - var scrollLeftValue = 0; - var result = false; - if (dir !== _cssDirectionDetectedCache) { - if (dir === 'ltr') { - css[_strLeft] = 0; - css[_strRight] = _strAuto; - scrollLeftValue = constMaximum; + var observerElement = targetElement[0][strChildNodes][0][strChildNodes][0]; + var shrinkElement = FRAMEWORK(observerElement[strChildNodes][1]); + var expandElement = FRAMEWORK(observerElement[strChildNodes][0]); + var expandElementChild = FRAMEWORK(expandElement[0][strChildNodes][0]); + var widthCache = observerElement[LEXICON.oW]; + var heightCache = observerElement[LEXICON.oH]; + var isDirty; + var rAFId; + var currWidth; + var currHeight; + var factor = 2; + var nativeScrollbarSize = globals.nativeScrollbarSize; //care don't make changes to this object!!! + var reset = function () { + /* + var sizeResetWidth = observerElement[LEXICON.oW] + nativeScrollbarSize.x * factor + nativeScrollbarSize.y * factor + _overlayScrollbarDummySize.x + _overlayScrollbarDummySize.y; + var sizeResetHeight = observerElement[LEXICON.oH] + nativeScrollbarSize.x * factor + nativeScrollbarSize.y * factor + _overlayScrollbarDummySize.x + _overlayScrollbarDummySize.y; + var expandChildCSS = {}; + expandChildCSS[_strWidth] = sizeResetWidth; + expandChildCSS[_strHeight] = sizeResetHeight; + expandElementChild.css(expandChildCSS); + + + expandElement[_strScrollLeft](sizeResetWidth)[_strScrollTop](sizeResetHeight); + shrinkElement[_strScrollLeft](sizeResetWidth)[_strScrollTop](sizeResetHeight); + */ + expandElement[_strScrollLeft](constMaximum)[_strScrollTop](constMaximum); + shrinkElement[_strScrollLeft](constMaximum)[_strScrollTop](constMaximum); + }; + var onResized = function () { + rAFId = 0; + if (!isDirty) + return; + + widthCache = currWidth; + heightCache = currHeight; + callback(); + }; + var onScroll = function (event) { + currWidth = observerElement[LEXICON.oW]; + currHeight = observerElement[LEXICON.oH]; + isDirty = currWidth != widthCache || currHeight != heightCache; + + if (event && isDirty && !rAFId) { + COMPATIBILITY.cAF()(rAFId); + rAFId = COMPATIBILITY.rAF()(onResized); + } + else if(!event) + onResized(); + + reset(); + if (event) { + COMPATIBILITY.prvD(event); + COMPATIBILITY.stpP(event); + } + return false; + }; + var expandChildCSS = {}; + var observerElementCSS = {}; + + setTopRightBottomLeft(observerElementCSS, _strEmpty, [ + -((nativeScrollbarSize.y + 1) * factor), + nativeScrollbarSize.x * -factor, + nativeScrollbarSize.y * -factor, + -((nativeScrollbarSize.x + 1) * factor) + ]); + + FRAMEWORK(observerElement).css(observerElementCSS); + expandElement.on(_strScroll, onScroll); + shrinkElement.on(_strScroll, onScroll); + targetElement.on(strAnimationStartEvent, function () { + onScroll(false); + }); + //lets assume that the divs will never be that large and a constant value is enough + expandChildCSS[_strWidth] = constMaximum; + expandChildCSS[_strHeight] = constMaximum; + expandElementChild.css(expandChildCSS); + + reset(); } else { - css[_strLeft] = _strAuto; - css[_strRight] = 0; - scrollLeftValue = _rtlScrollBehavior.n ? -constMaximum : _rtlScrollBehavior.i ? 0 : constMaximum; + var attachEvent = _documentElementNative.attachEvent; + var isIE = _msieVersion !== undefined; + if (attachEvent) { + targetElement.prepend(generateDiv(_classNameResizeObserverElement)); + findFirst(targetElement, _strDot + _classNameResizeObserverElement)[0].attachEvent('onresize', callback); + } + else { + var obj = _documentElementNative.createElement(TYPES.o); + obj.setAttribute('tabindex', '-1'); + obj.setAttribute(LEXICON.c, _classNameResizeObserverElement); + obj.onload = function () { + var wnd = this.contentDocument.defaultView; + wnd.addEventListener('resize', callback); + wnd.document.documentElement.style.display = 'none'; + }; + obj.type = 'text/html'; + if (isIE) + targetElement.prepend(obj); + obj.data = 'about:blank'; + if (!isIE) + targetElement.prepend(obj); + targetElement.on(strAnimationStartEvent, callback); + } } - _sizeObserverElement.children().eq(0).css(css); - targetElement[_strScrollLeft](scrollLeftValue)[_strScrollTop](constMaximum); - _cssDirectionDetectedCache = dir; - result = true; } - return result; - }; - directionChanged(); - targetElement.on(_strScroll, function (event) { - if (directionChanged()) - update(); - COMPATIBILITY.prvD(event); - COMPATIBILITY.stpP(event); - return false; - }); + + //direction change detection: + if (targetElement[0] === _sizeObserverElementNative) { + var directionChanged = function () { + var dir = _hostElement.css('direction'); + var css = {}; + var scrollLeftValue = 0; + var result = false; + if (dir !== _cssDirectionDetectedCache) { + if (dir === 'ltr') { + css[_strLeft] = 0; + css[_strRight] = _strAuto; + scrollLeftValue = constMaximum; + } + else { + css[_strLeft] = _strAuto; + css[_strRight] = 0; + scrollLeftValue = _rtlScrollBehavior.n ? -constMaximum : _rtlScrollBehavior.i ? 0 : constMaximum; + } + _sizeObserverElement.children().eq(0).css(css); + targetElement[_strScrollLeft](scrollLeftValue)[_strScrollTop](constMaximum); + _cssDirectionDetectedCache = dir; + result = true; + } + return result; + }; + directionChanged(); + targetElement.on(_strScroll, function (event) { + if (directionChanged()) + update(); + COMPATIBILITY.prvD(event); + COMPATIBILITY.stpP(event); + return false; + }); + } + } + //remove resize observer: + else { + if (_supportResizeObserver) { + var element = targetElement.contents()[0]; + var resizeObserverObj = element[_strResizeObserverProperty]; + if(resizeObserverObj) { + resizeObserverObj.disconnect(); + delete element[_strResizeObserverProperty]; + } + } + else { + remove(targetElement.children(_strDot + _classNameResizeObserverElement).eq(0)); + } + } } } /** - * Removes a resize observer from the given element. + * Freezes or unfreezes the given resize observer. * @param targetElement The element to which the target resize observer is applied. - */ - function removeResizeObserver(targetElement) { - if (_supportResizeObserver) { - var element = targetElement.contents()[0]; - element[_strResizeObserverProperty].disconnect(); - delete element[_strResizeObserverProperty]; - } - else { - remove(targetElement.children(_strDot + _classNameResizeObserverElement).eq(0)); - } - } - - /** - * Freezes the given resize observer. - * @param targetElement The element to which the target resize observer is applied. - */ - function freezeResizeObserver(targetElement) { + * @param freeze True if the resize observer shall be frozen, false otherwise. + + function freezeResizeObserver(targetElement, freeze) { if (targetElement !== undefined) { - /* - if (_supportResizeObserver) { - var element = targetElement.contents()[0]; - element[_strResizeObserverProperty].unobserve(element); + if(freeze) { + if (_supportResizeObserver) { + var element = targetElement.contents()[0]; + element[_strResizeObserverProperty].unobserve(element); + } + else { + targetElement = targetElement.children(_strDot + _classNameResizeObserverElement).eq(0); + var w = targetElement.css(_strWidth); + var h = targetElement.css(_strHeight); + var css = {}; + css[_strWidth] = w; + css[_strHeight] = h; + targetElement.css(css); + } } else { - targetElement = targetElement.children(_strDot + _classNameResizeObserverElement).eq(0); - var w = targetElement.css(_strWidth); - var h = targetElement.css(_strHeight); - var css = {}; - css[_strWidth] = w; - css[_strHeight] = h; - targetElement.css(css); + if (_supportResizeObserver) { + var element = targetElement.contents()[0]; + element[_strResizeObserverProperty].observe(element); + } + else { + var css = { }; + css[_strHeight] = _strEmpty; + css[_strWidth] = _strEmpty; + targetElement.children(_strDot + _classNameResizeObserverElement).eq(0).css(css); + } } - */ - } - } - - /** - * Unfreezes the given resize observer. - * @param targetElement The element to which the target resize observer is applied. - */ - function unfreezeResizeObserver(targetElement) { - if (targetElement !== undefined) { - /* - if (_supportResizeObserver) { - var element = targetElement.contents()[0]; - element[_strResizeObserverProperty].observe(element); - } - else { - var css = { }; - css[_strHeight] = _strEmpty; - css[_strWidth] = _strEmpty; - targetElement.children(_strDot + _classNameResizeObserverElement).eq(0).css(css); - } - */ } } + */ //==== Mutation Observers ====// @@ -1450,8 +1470,8 @@ var doUpdate = false; var mutation; - if (_initialized && !_isSleeping) { - FRAMEWORK.each(mutations, function () { + if (_initialized && !_sleeping) { + each(mutations, function () { mutation = this; mutationTarget = mutation.target; mutationAttrName = mutation.attributeName; @@ -1476,8 +1496,8 @@ var doUpdate = false; var mutation; - if (_initialized && !_isSleeping) { - FRAMEWORK.each(mutations, function () { + if (_initialized && !_sleeping) { + each(mutations, function () { mutation = this; doUpdate = isUnknownMutation(mutation); return !doUpdate; @@ -1523,7 +1543,7 @@ _mutationObserverHost.observe(_hostElementNative, { attributes: true, attributeOldValue: true, - attributeFilter: [LEXICON.i, LEXICON.c, LEXICON.s] + attributeFilter: _mutationObserverAttrsHost }); _mutationObserverContent.observe(_isTextarea ? _targetElementNative : _contentElementNative, { @@ -1532,7 +1552,7 @@ subtree: !_isTextarea, childList: !_isTextarea, characterData: !_isTextarea, - attributeFilter: _isTextarea ? ['wrap', 'cols', 'rows'] : [LEXICON.i, LEXICON.c, LEXICON.s, 'open'] + attributeFilter: _isTextarea ? _mutationObserverAttrsTextarea : _mutationObserverAttrsHost }); _mutationObserversConnected = true; @@ -1551,19 +1571,6 @@ } } - /** - * Disconnects the MutationObservers if they are supported. - * @returns {boolean|undefined} True if the MutationObservers needed to be synchronized, false or undefined otherwise. - */ - function synchronizeMutationObservers() { - if(_mutationObserversConnected) { - var mutHost = _mutationObserverHostCallback(_mutationObserverHost.takeRecords()); - var mutContent = _mutationObserverContentCallback(_mutationObserverContent.takeRecords()); - - return mutHost || mutContent; - } - } - //==== Events of elements ====// @@ -1573,23 +1580,17 @@ * If there are any size changes, the update method gets called. */ function hostOnResized() { - if (_isSleeping) - return; - - var changed; - var hostSize = { - w: _sizeObserverElementNative[LEXICON.sW], - h: _sizeObserverElementNative[LEXICON.sH] - }; - - if (_initialized) { - changed = checkCacheDouble(hostSize, _hostElementSizeChangeDetectedCache); + if (!_sleeping) { + var changed; + var hostSize = { + w: _sizeObserverElementNative[LEXICON.sW], + h: _sizeObserverElementNative[LEXICON.sH] + }; + + changed = checkCache(hostSize, _hostElementSizeChangeDetectedCache); _hostElementSizeChangeDetectedCache = hostSize; if (changed) - update(true, false); - } - else { - _hostElementSizeChangeDetectedCache = hostSize; + update({ _hostSizeChanged : true }); } } @@ -1628,11 +1629,10 @@ * @param destroy Indicates whether the events shall be added or removed. */ function setupHostMouseTouchEvents(destroy) { - var passiveEvent = destroy ? removePassiveEventListener : addPassiveEventListener; var strOnOff = destroy ? 'off' : 'on'; var setupEvent = function(target, name, listener) { if(_supportPassiveEvents) - passiveEvent(target, name, listener); + setupPassiveEventListener(target, name, listener, destroy); else target[strOnOff](name, listener); }; @@ -1664,7 +1664,7 @@ * A callback which will be called after a img element has downloaded its src asynchronous. */ function imgOnLoad() { - update(false, true); + update({ _contentSizeChanged : true }); } @@ -1679,11 +1679,11 @@ if (_isBody && _contentArrangeElement) { bodyMinSize.w = parseToZeroOrNumber(_contentArrangeElement.css(_strMinMinus + _strWidth)); bodyMinSize.h = parseToZeroOrNumber(_contentArrangeElement.css(_strMinMinus + _strHeight)); - bodyMinSize.c = checkCacheDouble(bodyMinSize, _bodyMinSizeCache); + bodyMinSize.c = checkCache(bodyMinSize, _bodyMinSizeCache); bodyMinSize.f = true; //flag for "measured at least once" } _bodyMinSizeCache = bodyMinSize; - return bodyMinSize.c || false; + return !!bodyMinSize.c; } /** @@ -1703,7 +1703,7 @@ var currClassNames = _classNameCache !== undefined && _classNameCache !== null ? _classNameCache.split(_strSpace) : [_strEmpty]; //remove none theme from diff list to prevent update - var idx = FRAMEWORK.inArray(_classNameThemeNone, diff); + var idx = inArray(_classNameThemeNone, diff); var curr; var i; var v; @@ -1774,20 +1774,22 @@ * @returns {boolean} True if the content size was changed, false otherwise. */ function updateAutoContentSizeChanged() { - if (_isSleeping) + if (_sleeping) return false; - - var float; + + var contentMeasureElement = getContentMeasureElement(); var textareaValueLength = _isTextarea && _widthAutoCache && !_textareaAutoWrappingCache ? _targetElement.val().length : 0; var setCSS = !_mutationObserversConnected && _widthAutoCache && !_isTextarea; var viewportScrollSize = { }; var css = { }; + var float; var bodyMinSizeC; var changed; var viewportScrollSizeChanged; + var contentElementScrollSize; //fix for https://bugzilla.mozilla.org/show_bug.cgi?id=1439305, it only works with "clipAlways : true" - //it can work with "clipAlways : false" too, but we had to set the overflow of the viewportElement to hidden every time before measuring + //it can work with "clipAlways : false" too, but I had to set the overflow of the viewportElement to hidden every time before measuring if(_restrictedMeasuring) { viewportScrollSize = { x : _viewportElementNative[LEXICON.sW], @@ -1800,9 +1802,9 @@ css[_strWidth] = _strAuto; _contentElement.css(css); } - var contentElementScrollSize = { - w: getContentMeasureElement()[LEXICON.sW] + textareaValueLength, - h: getContentMeasureElement()[LEXICON.sH] + textareaValueLength + contentElementScrollSize = { + w: contentMeasureElement[LEXICON.sW] + textareaValueLength, + h: contentMeasureElement[LEXICON.sH] + textareaValueLength }; if (setCSS) { css[_strFloat] = float; @@ -1811,8 +1813,8 @@ } bodyMinSizeC = bodyMinSizeChanged(); - changed = checkCacheDouble(contentElementScrollSize, _contentElementScrollSizeChangeDetectedCache); - viewportScrollSizeChanged = checkCacheDouble(viewportScrollSize, _viewportScrollSizeCache, _strX, _strY); + changed = checkCache(contentElementScrollSize, _contentElementScrollSizeChangeDetectedCache); + viewportScrollSizeChanged = checkCache(viewportScrollSize, _viewportScrollSizeCache); _contentElementScrollSizeChangeDetectedCache = contentElementScrollSize; _viewportScrollSizeCache = viewportScrollSize; @@ -1821,39 +1823,43 @@ } /** - * Returns true if the host element attributes (id, class, style) was changed since the last time this method was called. - * @returns {boolean} + * Returns true when a attribute which the MutationObserver would observe has changed. + * @returns {boolean} True if one of the attributes which a MutationObserver would observe has changed, false or undefined otherwise. */ function meaningfulAttrsChanged() { - if (_isSleeping || _mutationObserversConnected) - return false; - - var hostElementId = _hostElement.attr(LEXICON.i) || _strEmpty; - var hostElementIdChanged = checkCacheSingle(hostElementId, _updateAutoHostElementIdCache); - var hostElementClass = _hostElement.attr(LEXICON.c) || _strEmpty; - var hostElementClassChanged = checkCacheSingle(hostElementClass, _updateAutoHostElementClassCache); - var hostElementStyle = _hostElement.attr(LEXICON.s) || _strEmpty; - var hostElementStyleChanged = checkCacheSingle(hostElementStyle, _updateAutoHostElementStyleCache); - var hostElementVisible = _hostElement.is(':visible') || _strEmpty; - var hostElementVisibleChanged = checkCacheSingle(hostElementVisible, _updateAutoHostElementVisibleCache); - var targetElementRows = _isTextarea ? (_targetElement.attr('rows') || _strEmpty) : _strEmpty; - var targetElementRowsChanged = checkCacheSingle(targetElementRows, _updateAutoTargetElementRowsCache); - var targetElementCols = _isTextarea ? (_targetElement.attr('cols') || _strEmpty) : _strEmpty; - var targetElementColsChanged = checkCacheSingle(targetElementCols, _updateAutoTargetElementColsCache); - var targetElementWrap = _isTextarea ? (_targetElement.attr('wrap') || _strEmpty) : _strEmpty; - var targetElementWrapChanged = checkCacheSingle(targetElementWrap, _updateAutoTargetElementWrapCache); - - _updateAutoHostElementIdCache = hostElementId; - if (hostElementClassChanged) - hostElementClassChanged = hostClassNamesChanged(_updateAutoHostElementClassCache, hostElementClass); - _updateAutoHostElementClassCache = hostElementClass; - _updateAutoHostElementStyleCache = hostElementStyle; - _updateAutoHostElementVisibleCache = hostElementVisible; - _updateAutoTargetElementRowsCache = targetElementRows; - _updateAutoTargetElementColsCache = targetElementCols; - _updateAutoTargetElementWrapCache = targetElementWrap; - - return hostElementIdChanged || hostElementClassChanged || hostElementStyleChanged || hostElementVisibleChanged || targetElementRowsChanged || targetElementColsChanged || targetElementWrapChanged; + if (_sleeping || _mutationObserversConnected) + return; + + var changed; + var elem; + var curr; + var cache; + var checks = [ + { + _elem: _hostElement, + _props : _mutationObserverAttrsHost.concat(':visible') + }, + { + _elem: _isTextarea ? _targetElement : undefined, + _props : _mutationObserverAttrsTextarea + } + ]; + + each(checks, function(index, check) { + elem = check._elem; + if(elem) { + each(check._props, function(index, prop) { + curr = prop.charAt(0) === ':' ? elem.is(prop) : elem.attr(prop); + cache = _updateAutoCache[prop]; + + changed = changed || checkCache(curr, cache); + + _updateAutoCache[prop] = curr; + }); + } + }); + + return changed; } /** @@ -1939,103 +1945,101 @@ * Updates the variables and size of the textarea element, and manages the scroll on new line or new character. */ function textareaUpdate() { - if (_isSleeping) - return; + if (!_sleeping) { + var wrapAttrOff = !_textareaAutoWrappingCache; + var minWidth = _viewportSize.w; + var minHeight = _viewportSize.h; + var css = { }; + var doMeasure = _widthAutoCache || wrapAttrOff; + var origWidth; + var width; + var origHeight; + var height; - var wrapAttrOff = !_textareaAutoWrappingCache; - var minWidth = _viewportSize.w /* - (!_isBorderBox && !_paddingAbsoluteCache && _widthAutoCache ? _paddingY + _borderY : 0) */; - var minHeight = _viewportSize.h /* - (!_isBorderBox && !_paddingAbsoluteCache && _heightAutoCache ? _paddingY + _borderY : 0) */; - var css = { }; - var doMeasure = _widthAutoCache || wrapAttrOff; - var origWidth; - var width; - var origHeight; - var height; + //reset min size + css[_strMinMinus + _strWidth] = _strEmpty; + css[_strMinMinus + _strHeight] = _strEmpty; - //reset min size - css[_strMinMinus + _strWidth] = _strEmpty; - css[_strMinMinus + _strHeight] = _strEmpty; + //set width auto + css[_strWidth] = _strAuto; + _targetElement.css(css); - //set width auto - css[_strWidth] = _strAuto; - _targetElement.css(css); + //measure width + origWidth = _targetElementNative[LEXICON.oW]; + width = doMeasure ? MATH.max(origWidth, _targetElementNative[LEXICON.sW] - 1) : 1; + /*width += (_widthAutoCache ? _marginX + (!_isBorderBox ? wrapAttrOff ? 0 : _paddingX + _borderX : 0) : 0);*/ - //measure width - origWidth = _targetElementNative[LEXICON.oW]; - width = doMeasure ? MATH.max(origWidth, _targetElementNative[LEXICON.sW] - 1) : 1; - /*width += (_widthAutoCache ? _marginX + (!_isBorderBox ? wrapAttrOff ? 0 : _paddingX + _borderX : 0) : 0);*/ + //set measured width + css[_strWidth] = _widthAutoCache ? _strAuto /*width*/ : _strHundredPercent; + css[_strMinMinus + _strWidth] = _strHundredPercent; - //set measured width - css[_strWidth] = _widthAutoCache ? _strAuto /*width*/ : _strHundredPercent; - css[_strMinMinus + _strWidth] = _strHundredPercent; + //set height auto + css[_strHeight] = _strAuto; + _targetElement.css(css); - //set height auto - css[_strHeight] = _strAuto; - _targetElement.css(css); + //measure height + origHeight = _targetElementNative[LEXICON.oH]; + height = MATH.max(origHeight, _targetElementNative[LEXICON.sH] - 1); - //measure height - origHeight = _targetElementNative[LEXICON.oH]; - height = MATH.max(origHeight, _targetElementNative[LEXICON.sH] - 1); + //append correct size values + css[_strWidth] = width; + css[_strHeight] = height; + _textareaCoverElement.css(css); - //append correct size values - css[_strWidth] = width; - css[_strHeight] = height; - _textareaCoverElement.css(css); + //apply min width / min height to prevent textarea collapsing + css[_strMinMinus + _strWidth] = minWidth /*+ (!_isBorderBox && _widthAutoCache ? _paddingX + _borderX : 0)*/; + css[_strMinMinus + _strHeight] = minHeight /*+ (!_isBorderBox && _heightAutoCache ? _paddingY + _borderY : 0)*/; + _targetElement.css(css); - //apply min width / min height to prevent textarea collapsing - css[_strMinMinus + _strWidth] = minWidth /*+ (!_isBorderBox && _widthAutoCache ? _paddingX + _borderX : 0)*/; - css[_strMinMinus + _strHeight] = minHeight /*+ (!_isBorderBox && _heightAutoCache ? _paddingY + _borderY : 0)*/; - _targetElement.css(css); - - return { - _originalWidth: origWidth, - _originalHeight: origHeight, - _dynamicWidth: width, - _dynamicHeight: height - }; + return { + _originalWidth: origWidth, + _originalHeight: origHeight, + _dynamicWidth: width, + _dynamicHeight: height + }; + } } /** * Updates the plugin and DOM to the current options. * This method should only be called if a update is 100% required. - * @param hostSizeChanged True if this method was called due to a host size change. - * @param contentSizeChanged True if this method was called due to a content size change. - * @param force True if every property shall be updated and the cache shall be ignored. - * @param preventSwallowing True if this method shall be executed even if it could be swallowed. + * @param updateHints A objects which contains hints for this update: + * { + * _hostSizeChanged : boolean, + * _contentSizeChanged : boolean, + * _force : boolean, == preventSwallowing + * _changedOptions : { }, == preventSwallowing && preventSleep + * } */ - function update(hostSizeChanged, contentSizeChanged, force, preventSwallowing) { - var now = COMPATIBILITY.now(); - var swallow = _swallowUpdateLag > 0 && _initialized && (now - _lastUpdateTime) < _swallowUpdateLag && (!_heightAutoCache && !_widthAutoCache) && !preventSwallowing; - var displayIsHidden = _hostElement.is(':hidden'); - var displayIsHiddenChanged = checkCacheSingle(displayIsHidden, _displayIsHiddenCache, force); - _displayIsHiddenCache = displayIsHidden; + function update(updateHints) { clearTimeout(_swallowedUpdateTimeout); + updateHints = updateHints || { }; + _swallowedUpdateHints._hostSizeChanged |= updateHints._hostSizeChanged; + _swallowedUpdateHints._contentSizeChanged |= updateHints._contentSizeChanged; + _swallowedUpdateHints._force |= updateHints._force; + + var now = COMPATIBILITY.now(); + var hostSizeChanged = !!_swallowedUpdateHints._hostSizeChanged; + var contentSizeChanged = !!_swallowedUpdateHints._contentSizeChanged; + var force = !!_swallowedUpdateHints._force; + var changedOptions = updateHints._changedOptions; + var swallow = _swallowUpdateLag > 0 && _initialized && !_destroyed && !force && !changedOptions && (now - _lastUpdateTime) < _swallowUpdateLag && (!_heightAutoCache && !_widthAutoCache); + var displayIsHidden; - if (swallow) { - _swallowedUpdateParams.h = _swallowedUpdateParams.h || hostSizeChanged; - _swallowedUpdateParams.c = _swallowedUpdateParams.c || contentSizeChanged; - _swallowedUpdateParams.f = _swallowedUpdateParams.f || force; + if(swallow) _swallowedUpdateTimeout = setTimeout(update, _swallowUpdateLag); - } //abort update due to: //destroyed //swallowing //sleeping //host is hidden or has false display - if (_destroyed || swallow || _isSleeping || (_initialized && !force && displayIsHidden) || _hostElement.css('display') === 'inline') + if (_destroyed || swallow || (_sleeping && !changedOptions) || (_initialized && !force && (displayIsHidden = _hostElement.is(':hidden'))) || _hostElement.css('display') === 'inline') return; _lastUpdateTime = now; - hostSizeChanged = hostSizeChanged || _swallowedUpdateParams.h; - contentSizeChanged = contentSizeChanged || _swallowedUpdateParams.c; - force = force || _swallowedUpdateParams.f; - _swallowedUpdateParams = {}; - - hostSizeChanged = hostSizeChanged === undefined ? false : hostSizeChanged; - contentSizeChanged = contentSizeChanged === undefined ? false : contentSizeChanged; - force = force === undefined ? false : force; - + _swallowedUpdateHints = { }; + //if scrollbar styling is possible and native scrollbars aren't overlaid the scrollbar styling will be applied which hides the native scrollbars completely. if (_nativeScrollbarStyling && !(_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y)) { //native scrollbars are hidden, so change the values to zero @@ -2055,77 +2059,79 @@ x: (_nativeScrollbarSize.x + (_nativeScrollbarIsOverlaid.x ? 0 : 3)) * 3, y: (_nativeScrollbarSize.y + (_nativeScrollbarIsOverlaid.y ? 0 : 3)) * 3 }; - - freezeResizeObserver(_sizeObserverElement); - freezeResizeObserver(_sizeAutoObserverElement); - + + //changedOptions = changedOptions || { }; + //freezeResizeObserver(_sizeObserverElement, true); + //freezeResizeObserver(_sizeAutoObserverElement, true); + + var checkCacheAutoForce = function () { + return checkCache.apply(this, [].slice.call(arguments).concat([ force ])); + }; + //save current scroll offset var currScroll = { x: _viewportElement[_strScrollLeft](), y: _viewportElement[_strScrollTop]() }; + var currentPreparedOptionsScrollbars = _currentPreparedOptions.scrollbars; var currentPreparedOptionsTextarea = _currentPreparedOptions.textarea; //scrollbars visibility: var scrollbarsVisibility = currentPreparedOptionsScrollbars.visibility; - var scrollbarsVisibilityChanged = checkCacheSingle(scrollbarsVisibility, _scrollbarsVisibilityCache, force); + var scrollbarsVisibilityChanged = checkCacheAutoForce(scrollbarsVisibility, _scrollbarsVisibilityCache); //scrollbars autoHide: var scrollbarsAutoHide = currentPreparedOptionsScrollbars.autoHide; - var scrollbarsAutoHideChanged = checkCacheSingle(scrollbarsAutoHide, _scrollbarsAutoHideCache, force); + var scrollbarsAutoHideChanged = checkCacheAutoForce(scrollbarsAutoHide, _scrollbarsAutoHideCache); //scrollbars click scrolling var scrollbarsClickScrolling = currentPreparedOptionsScrollbars.clickScrolling; - var scrollbarsClickScrollingChanged = checkCacheSingle(scrollbarsClickScrolling, _scrollbarsClickScrollingCache, force); + var scrollbarsClickScrollingChanged = checkCacheAutoForce(scrollbarsClickScrolling, _scrollbarsClickScrollingCache); //scrollbars drag scrolling var scrollbarsDragScrolling = currentPreparedOptionsScrollbars.dragScrolling; - var scrollbarsDragScrollingChanged = checkCacheSingle(scrollbarsDragScrolling, _scrollbarsDragScrollingCache, force); + var scrollbarsDragScrollingChanged = checkCacheAutoForce(scrollbarsDragScrolling, _scrollbarsDragScrollingCache); //className var className = _currentPreparedOptions.className; - var classNameChanged = checkCacheSingle(className, _classNameCache, force); + var classNameChanged = checkCacheAutoForce(className, _classNameCache); //resize var resize = _currentPreparedOptions.resize; - var resizeChanged = checkCacheSingle(resize, _resizeCache, force) && !_isBody; //body can't be resized since the window itself acts as resize possibility. - - //textarea AutoWrapping - var textareaAutoWrapping = _isTextarea ? _targetElement.attr('wrap') !== 'off' : false; - var textareaAutoWrappingChanged = checkCacheSingle(textareaAutoWrapping, _textareaAutoWrappingCache, force); + var resizeChanged = checkCacheAutoForce(resize, _resizeCache) && !_isBody; //body can't be resized since the window itself acts as resize possibility. //paddingAbsolute var paddingAbsolute = _currentPreparedOptions.paddingAbsolute; - var paddingAbsoluteChanged = checkCacheSingle(paddingAbsolute, _paddingAbsoluteCache, force); + var paddingAbsoluteChanged = checkCacheAutoForce(paddingAbsolute, _paddingAbsoluteCache); //clipAlways var clipAlways = _currentPreparedOptions.clipAlways; - var clipAlwaysChanged = checkCacheSingle(clipAlways, _clipAlwaysCache, force); + var clipAlwaysChanged = checkCacheAutoForce(clipAlways, _clipAlwaysCache); //sizeAutoCapable var sizeAutoCapable = _currentPreparedOptions.sizeAutoCapable && !_isBody; //body can never be size auto, because it shall be always as big as the viewport. - var sizeAutoCapableChanged = checkCacheSingle(sizeAutoCapable, _sizeAutoCapableCache, force); + var sizeAutoCapableChanged = checkCacheAutoForce(sizeAutoCapable, _sizeAutoCapableCache); //showNativeScrollbars var ignoreOverlayScrollbarHiding = _currentPreparedOptions.nativeScrollbarsOverlaid.showNativeScrollbars; - var ignoreOverlayScrollbarHidingChanged = checkCacheSingle(ignoreOverlayScrollbarHiding, _ignoreOverlayScrollbarHidingCache); + var ignoreOverlayScrollbarHidingChanged = checkCacheAutoForce(ignoreOverlayScrollbarHiding, _ignoreOverlayScrollbarHidingCache); //autoUpdate var autoUpdate = _currentPreparedOptions.autoUpdate; - var autoUpdateChanged = checkCacheSingle(autoUpdate, _autoUpdateCache); + var autoUpdateChanged = checkCacheAutoForce(autoUpdate, _autoUpdateCache); //overflowBehavior var overflowBehavior = _currentPreparedOptions.overflowBehavior; - var overflowBehaviorChanged = checkCacheDouble(overflowBehavior, _overflowBehaviorCache, _strX, _strY, force); + var overflowBehaviorChanged = checkCacheAutoForce(overflowBehavior, _overflowBehaviorCache, force); //dynWidth: var textareaDynWidth = currentPreparedOptionsTextarea.dynWidth; - var textareaDynWidthChanged = checkCacheSingle(_textareaDynWidthCache, textareaDynWidth); + var textareaDynWidthChanged = checkCacheAutoForce(_textareaDynWidthCache, textareaDynWidth); //dynHeight: var textareaDynHeight = currentPreparedOptionsTextarea.dynHeight; - var textareaDynHeightChanged = checkCacheSingle(_textareaDynHeightCache, textareaDynHeight); + var textareaDynHeightChanged = checkCacheAutoForce(_textareaDynHeightCache, textareaDynHeight); //scrollbars visibility _scrollbarsAutoHideNever = scrollbarsAutoHide === 'n'; @@ -2158,7 +2164,6 @@ _scrollbarsDragScrollingCache = scrollbarsDragScrolling; _classNameCache = className; _resizeCache = resize; - _textareaAutoWrappingCache = textareaAutoWrapping; _paddingAbsoluteCache = paddingAbsolute; _clipAlwaysCache = clipAlways; _sizeAutoCapableCache = sizeAutoCapable; @@ -2216,12 +2221,12 @@ _contentGlueElement.before(_sizeAutoObserverElement); var oldSize = {w: -1, h: -1}; - addResizeObserver(_sizeAutoObserverElement, function () { + setupResizeObserver(_sizeAutoObserverElement, function () { var newSize = { w: _sizeAutoObserverElementNative[LEXICON.oW], h: _sizeAutoObserverElementNative[LEXICON.oH] }; - if (checkCacheDouble(newSize, oldSize)) { + if (checkCache(newSize, oldSize)) { if (_initialized && (_heightAutoCache && newSize.h > 0) || (_widthAutoCache && newSize.w > 0)) { update(); } @@ -2253,13 +2258,21 @@ _sizeAutoObserverElement.find('*').trigger(_strScroll); } + //display hidden: + displayIsHidden = displayIsHidden === undefined ? _hostElement.is(':hidden') : displayIsHidden; + var displayIsHiddenChanged = checkCacheAutoForce(displayIsHidden, _displayIsHiddenCache); + + //textarea AutoWrapping: + var textareaAutoWrapping = _isTextarea ? _targetElement.attr('wrap') !== 'off' : false; + var textareaAutoWrappingChanged = checkCacheAutoForce(textareaAutoWrapping, _textareaAutoWrappingCache); + //detect direction: var cssDirection = _hostElement.css('direction'); - var cssDirectionChanged = checkCacheSingle(cssDirection, _cssDirectionCache, force); + var cssDirectionChanged = checkCacheAutoForce(cssDirection, _cssDirectionCache); //detect box-sizing: var boxSizing = _hostElement.css('box-sizing'); - var boxSizingChanged = checkCacheSingle(boxSizing, _cssBoxSizingCache, force); + var boxSizingChanged = checkCacheAutoForce(boxSizing, _cssBoxSizingCache); //detect padding: var padding = { @@ -2269,7 +2282,7 @@ b: parseToZeroOrNumber(_hostElement.css(_strPaddingMinus + _strBottom)), l: parseToZeroOrNumber(_hostElement.css(_strPaddingMinus + _strLeft)) }; - + //width + height auto detecting var: var sizeAutoObserverElementBCRect; //exception occurs in IE8 sometimes (unknown exception) @@ -2303,12 +2316,12 @@ } } var widthAuto = (widthAutoObserverDetection || widthAutoResizeDetection) && sizeAutoCapable && !displayIsHidden; - var widthAutoChanged = checkCacheSingle(widthAuto, _widthAutoCache, force); + var widthAutoChanged = checkCacheAutoForce(widthAuto, _widthAutoCache); var wasWidthAuto = !widthAuto && _widthAutoCache; //detect height auto: var heightAuto = _sizeAutoObserverAdded && sizeAutoCapable && !displayIsHidden ? (MATH.round(sizeAutoObserverElementBCRect.bottom - sizeAutoObserverElementBCRect.top) === 0) /* && (!paddingAbsolute && (_msieVersion > 9 || !_msieVersion) ? true : true) */ : false; - var heightAutoChanged = checkCacheSingle(heightAuto, _heightAutoCache, force); + var heightAutoChanged = checkCacheAutoForce(heightAuto, _heightAutoCache); var wasHeightAuto = !heightAuto && _heightAutoCache; //detect border: @@ -2366,26 +2379,28 @@ var paddingAbsoluteY = _paddingY = padding.t + padding.b; paddingAbsoluteX *= paddingAbsolute ? 1 : 0; paddingAbsoluteY *= paddingAbsolute ? 1 : 0; - padding.c = checkCacheTRBL(padding, _cssPaddingCache); + padding.c = checkCacheAutoForce(padding, _cssPaddingCache); //set info for border _borderX = border.l + border.r; _borderY = border.t + border.b; - border.c = checkCacheTRBL(border, _cssBorderCache); + border.c = checkCacheAutoForce(border, _cssBorderCache); //set info for margin _marginX = margin.l + margin.r; _marginY = margin.t + margin.b; - margin.c = checkCacheTRBL(margin, _cssMarginCache); + margin.c = checkCacheAutoForce(margin, _cssMarginCache); //set info for css max value cssMaxValue.ih = parseToZeroOrNumber(cssMaxValue.h); //ih = integer height cssMaxValue.iw = parseToZeroOrNumber(cssMaxValue.w); //iw = integer width cssMaxValue.ch = cssMaxValue.h.indexOf('px') > -1; //ch = correct height cssMaxValue.cw = cssMaxValue.w.indexOf('px') > -1; //cw = correct width - cssMaxValue.c = checkCacheDouble(cssMaxValue, _cssMaxValueCache, force); + cssMaxValue.c = checkCacheAutoForce(cssMaxValue, _cssMaxValueCache); //refresh cache + _displayIsHiddenCache = displayIsHidden; + _textareaAutoWrappingCache = textareaAutoWrapping; _cssDirectionCache = cssDirection; _cssBoxSizingCache = boxSizing; _widthAutoCache = widthAuto; @@ -2394,7 +2409,7 @@ _cssBorderCache = border; _cssMarginCache = margin; _cssMaxValueCache = cssMaxValue; - + //IEFix direction changed if (cssDirectionChanged && _sizeAutoObserverAdded) _sizeAutoObserverElement.css(_strFloat, isRTLRight); @@ -2489,7 +2504,7 @@ contentGlueElementCSS = {}; //if [content(host) client / scroll size, or target element direction, or content(host) max-sizes] changed, or force is true - if (hostSizeChanged || contentSizeChanged || cssDirectionChanged || boxSizingChanged || paddingAbsoluteChanged || widthAutoChanged || widthAuto || heightAutoChanged || heightAuto || cssMaxValue.c || ignoreOverlayScrollbarHidingChanged || overflowBehaviorChanged || clipAlwaysChanged || resizeChanged || scrollbarsVisibilityChanged || scrollbarsAutoHideChanged || scrollbarsDragScrollingChanged || scrollbarsClickScrollingChanged || textareaDynWidthChanged || textareaDynHeightChanged || textareaAutoWrappingChanged || force) { + if (hostSizeChanged || contentSizeChanged || cssDirectionChanged || boxSizingChanged || paddingAbsoluteChanged || widthAutoChanged || widthAuto || heightAutoChanged || heightAuto || cssMaxValue.c || ignoreOverlayScrollbarHidingChanged || overflowBehaviorChanged || clipAlwaysChanged || resizeChanged || scrollbarsVisibilityChanged || scrollbarsAutoHideChanged || scrollbarsDragScrollingChanged || scrollbarsClickScrollingChanged || textareaDynWidthChanged || textareaDynHeightChanged || textareaAutoWrappingChanged) { var strOverflow = 'overflow'; var strOverflowX = strOverflow + '-x'; var strOverflowY = strOverflow + '-y'; @@ -2499,7 +2514,7 @@ var hideOverflow4CorrectMeasuring = _restrictedMeasuring ? (_nativeScrollbarIsOverlaid.x || _nativeScrollbarIsOverlaid.y) || //it must be hidden if native scrollbars are overlaid (_viewportSize.w < _nativeScrollbarMinSize.y || _viewportSize.h < _nativeScrollbarMinSize.x) || //it must be hidden if host-element is too small - heightAuto || displayIsHiddenChanged //it must be hidden if height is auto or display was change + heightAuto || displayIsHiddenChanged //it must be hidden if height is auto or display was changed : heightAuto; //if there is not the restricted Measuring bug, it must be hidden if the height is auto //Reset the viewport (very important for natively overlaid scrollbars and zoom change @@ -2540,7 +2555,7 @@ w: MATH.max((widthAuto ? contentSize.w : scrollSize.w) + paddingAbsoluteX, hostSize.w), h: MATH.max((heightAuto ? contentSize.h : scrollSize.h) + paddingAbsoluteY, hostSize.h) }; - contentGlueSize.c = checkCacheDouble(contentGlueSize, _contentGlueSizeCache, force); + contentGlueSize.c = checkCacheAutoForce(contentGlueSize, _contentGlueSizeCache); _contentGlueSizeCache = contentGlueSize; //apply correct contentGlue size @@ -2610,7 +2625,7 @@ w: MATH.max(contentMeasureElement[LEXICON.sW], contentMeasureElementGuaranty[LEXICON.sW]), h: MATH.max(contentMeasureElement[LEXICON.sH], contentMeasureElementGuaranty[LEXICON.sH]) }; - contentScrollSize.c = contentSizeChanged = checkCacheDouble(contentScrollSize, _contentScrollSizeCache, force); + contentScrollSize.c = contentSizeChanged = checkCacheAutoForce(contentScrollSize, _contentScrollSizeCache); _contentScrollSizeCache = contentScrollSize; //remove overflow hidden to restore overflow @@ -2621,7 +2636,7 @@ _viewportSize = getViewportSize(); hostSize = getHostSize(); - hostSizeChanged = checkCacheDouble(hostSize, _hostSizeCache); + hostSizeChanged = checkCacheAutoForce(hostSize, _hostSizeCache); _hostSizeCache = hostSize; var hideOverflowForceTextarea = _isTextarea && (_viewportSize.w === 0 || _viewportSize.h === 0); @@ -2661,11 +2676,11 @@ setOverflowVariables(true); setOverflowVariables(false); - overflowAmount.c = checkCacheDouble(overflowAmount, _overflowAmountCache, _strX, _strY, force); + overflowAmount.c = checkCacheAutoForce(overflowAmount, _overflowAmountCache); _overflowAmountCache = overflowAmount; - hasOverflow.c = checkCacheDouble(hasOverflow, _hasOverflowCache, _strX, _strY, force); + hasOverflow.c = checkCacheAutoForce(hasOverflow, _hasOverflowCache); _hasOverflowCache = hasOverflow; - hideOverflow.c = checkCacheDouble(hideOverflow, _hideOverflowCache, _strX, _strY, force); + hideOverflow.c = checkCacheAutoForce(hideOverflow, _hideOverflowCache); _hideOverflowCache = hideOverflow; //if native scrollbar is overlay at x OR y axis, prepare DOM @@ -2679,7 +2694,7 @@ if (hasOverflow.x || hasOverflow.y) { arrangeContent.w = _nativeScrollbarIsOverlaid.y && hasOverflow.y ? contentScrollSize.w + _overlayScrollbarDummySize.y : _strEmpty; arrangeContent.h = _nativeScrollbarIsOverlaid.x && hasOverflow.x ? contentScrollSize.h + _overlayScrollbarDummySize.x : _strEmpty; - arrangeChanged = checkCacheSingle(arrangeContent, _arrangeContentSizeCache, force); + arrangeChanged = checkCacheAutoForce(arrangeContent, _arrangeContentSizeCache); _arrangeContentSizeCache = arrangeContent; } @@ -2917,8 +2932,12 @@ if (_isBody) addClass(_hostElement, _classNameHostResizeDisabled); if (resizeChanged) { - var addCornerEvents = function () { _scrollbarCornerElement.on(_strMouseTouchDownEvent, _resizeOnMouseTouchDown); }; - var removeCornerEvents = function () { _scrollbarCornerElement.off(_strMouseTouchDownEvent, _resizeOnMouseTouchDown); }; + var setupCornerEvents = function(remove) { + if(_supportPassiveEvents) + setupPassiveEventListener(_scrollbarCornerElement, _strMouseTouchDownEvent, _resizeOnMouseTouchDown, remove, true); + else + _scrollbarCornerElement[remove ? 'off' : 'on'](_strMouseTouchDownEvent, _resizeOnMouseTouchDown); + }; removeClass(_scrollbarCornerElement, [ _classNameHostResizeDisabled, _classNameScrollbarCornerResize, @@ -2927,7 +2946,7 @@ _classNameScrollbarCornerResizeV].join(_strSpace)); if (_resizeNone) { addClass(_hostElement, _classNameHostResizeDisabled); - removeCornerEvents(); + setupCornerEvents(true); } else { addClass(_scrollbarCornerElement, _classNameScrollbarCornerResize); @@ -2938,8 +2957,8 @@ else if (_resizeVertical) addClass(_scrollbarCornerElement, _classNameScrollbarCornerResizeV); - removeCornerEvents(); - addCornerEvents(); + setupCornerEvents(true); + setupCornerEvents(); } } @@ -3042,7 +3061,7 @@ } //fix body min size - if (_isBody && (_hasOverflowCache.c || _bodyMinSizeCache.c)) { + if (_isBody && _bodyMinSizeCache && (_hasOverflowCache.c || _bodyMinSizeCache.c)) { //its possible that no min size was measured until now, because the content arrange element was just added now, in this case, measure now the min size. if (!_bodyMinSizeCache.f) bodyMinSizeChanged(); @@ -3053,8 +3072,8 @@ _bodyMinSizeCache.c = false; } - unfreezeResizeObserver(_sizeObserverElement); - unfreezeResizeObserver(_sizeAutoObserverElement); + //freezeResizeObserver(_sizeObserverElement, false); + //freezeResizeObserver(_sizeAutoObserverElement, false); dispatchCallback("onUpdated", { forced: force }); } @@ -3065,10 +3084,15 @@ /** * Sets new options but doesn't call the update method. * @param newOptions The object which contains the new options. + * @returns {*} A object which contains the changed options. */ function setOptions(newOptions) { - _currentOptions = extendDeep({}, _currentOptions, _pluginsOptions._validate(newOptions, _pluginsOptions._template, true)); - _currentPreparedOptions = extendDeep({}, _currentPreparedOptions, _pluginsOptions._validate(newOptions, _pluginsOptions._template, false, true)); + var validatedOpts = _pluginsOptions._validate(newOptions, _pluginsOptions._template, true, _currentOptions) + + _currentOptions = extendDeep({}, _currentOptions, validatedOpts._default); + _currentPreparedOptions = extendDeep({}, _currentPreparedOptions, validatedOpts._prepared); + + return validatedOpts._prepared; } @@ -3083,7 +3107,7 @@ var adoptAttrsMap = { }; var applyAdoptedAttrs = function() { var applyAdoptedAttrsElm = destroy ? _targetElement : _hostElement; - FRAMEWORK.each(adoptAttrsMap, function(k, v) { + each(adoptAttrsMap, function(k, v) { if(type(v) == TYPES.s) { if(k == LEXICON.c) applyAdoptedAttrsElm.addClass(v); @@ -3110,7 +3134,7 @@ _classNameCache].join(_strSpace); adoptAttrs = type(adoptAttrs) == TYPES.s ? adoptAttrs.split(' ') : adoptAttrs; if(type(adoptAttrs) == TYPES.a) { - FRAMEWORK.each(adoptAttrs, function(i, v) { + each(adoptAttrs, function(i, v) { if(type(v) == TYPES.s) adoptAttrsMap[v] = destroy ? _hostElement.attr(v) : _targetElement.attr(v); }); @@ -3264,20 +3288,20 @@ else { _textareaEvents[_strKeyDownEvent] = function textareaOnKeyDown(event) { var keyCode = event.keyCode; - if (FRAMEWORK.inArray(keyCode, textareaKeyDownRestrictedKeyCodes) > -1) + if (inArray(keyCode, textareaKeyDownRestrictedKeyCodes) > -1) return; if (!textareaKeyDownKeyCodesList.length) { updateTextarea(); textareaUpdateIntervalID = setInterval(updateTextarea, 1000 / 60); } - if (FRAMEWORK.inArray(keyCode, textareaKeyDownKeyCodesList) === -1) + if (inArray(keyCode, textareaKeyDownKeyCodesList) === -1) textareaKeyDownKeyCodesList.push(keyCode); }; _textareaEvents[_strKeyUpEvent] = function(event) { var keyCode = event.keyCode; - var index = FRAMEWORK.inArray(keyCode, textareaKeyDownKeyCodesList); + var index = inArray(keyCode, textareaKeyDownKeyCodesList); - if (FRAMEWORK.inArray(keyCode, textareaKeyDownRestrictedKeyCodes) > -1) + if (inArray(keyCode, textareaKeyDownRestrictedKeyCodes) > -1) return; if (index > -1) textareaKeyDownKeyCodesList.splice(index, 1); @@ -3288,7 +3312,7 @@ } if (_isTextarea) { - FRAMEWORK.each(_textareaEvents, function(key, value) { + each(_textareaEvents, function(key, value) { _targetElement[strOnOff](key, value); }); } @@ -3298,55 +3322,54 @@ return; event = event.originalEvent || event; if (isSizeAffectingCSSProperty(event.propertyName)) - update(_strAuto); + _base.update(_strAuto); }); } if(!destroy) { viewportOnScroll = function(event) { - if (_isSleeping) - return; - - if (scrollStopTimeoutId !== undefined) - clearTimeout(scrollStopTimeoutId); - else { - if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove) - refreshScrollbarsAutoHide(true); - - if (!nativeOverlayScrollbarsAreActive()) - addClass(_hostElement, _classNameHostScrolling); - - dispatchCallback("onScrollStart", event); - } - - //if a scrollbars handle gets dragged, the mousemove event is responsible for refreshing the handle offset - //because if CSS scroll-snap is used, the handle offset gets only refreshed on every snap point - //this looks laggy & clunky, it looks much better if the offset refreshes with the mousemove - if(!_scrollbarsHandleAsync) { - refreshScrollbarHandleOffset(true); - refreshScrollbarHandleOffset(false); - } - dispatchCallback("onScroll", event); - - scrollStopTimeoutId = setTimeout(function () { - if(!_destroyed) { - //OnScrollStop: + if (!_sleeping) { + if (scrollStopTimeoutId !== undefined) clearTimeout(scrollStopTimeoutId); - scrollStopTimeoutId = undefined; - + else { if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove) - refreshScrollbarsAutoHide(false); + refreshScrollbarsAutoHide(true); if (!nativeOverlayScrollbarsAreActive()) - removeClass(_hostElement, _classNameHostScrolling); + addClass(_hostElement, _classNameHostScrolling); - dispatchCallback("onScrollStop", event); + dispatchCallback("onScrollStart", event); } - }, scrollStopDelay); + + //if a scrollbars handle gets dragged, the mousemove event is responsible for refreshing the handle offset + //because if CSS scroll-snap is used, the handle offset gets only refreshed on every snap point + //this looks laggy & clunky, it looks much better if the offset refreshes with the mousemove + if(!_scrollbarsHandlesDefineScrollPos) { + refreshScrollbarHandleOffset(true); + refreshScrollbarHandleOffset(false); + } + dispatchCallback("onScroll", event); + + scrollStopTimeoutId = setTimeout(function () { + if(!_destroyed) { + //OnScrollStop: + clearTimeout(scrollStopTimeoutId); + scrollStopTimeoutId = undefined; + + if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove) + refreshScrollbarsAutoHide(false); + + if (!nativeOverlayScrollbarsAreActive()) + removeClass(_hostElement, _classNameHostScrolling); + + dispatchCallback("onScrollStop", event); + } + }, scrollStopDelay); + } }; if (_supportPassiveEvents) - addPassiveEventListener(_viewportElement, _strScroll, viewportOnScroll); + setupPassiveEventListener(_viewportElement, _strScroll, viewportOnScroll); else _viewportElement.on(_strScroll, viewportOnScroll); } @@ -3402,7 +3425,22 @@ var mouseDownScroll; var mouseDownOffset; var mouseDownInvertedScale; - + + function setupEvent(element, eventNames, listener) { + var collected = type(eventNames) == TYPES.a && type(listener) == TYPES.a; + var i = 0; + + if(collected) { + for (; i < eventNames[LEXICON.l]; i++) + setupEvent(element, eventNames[i], listener[i]); + } + else { + if(_supportPassiveEvents) + setupPassiveEventListener(element, eventNames, listener, false, true); + else + element.on(eventNames, listener); + } + } function getPointerPosition(event) { return _msieVersion && insideIFrame ? event['screen' + XY] : COMPATIBILITY.page(event)[xy]; //use screen coordinates in EDGE & IE because the page values are incorrect in frames. } @@ -3416,17 +3454,17 @@ scrollDurationFactor = 1; } function documentKeyDown(event) { - if (FRAMEWORK.inArray(event.keyCode, increaseDecreaseScrollAmountKeyCodes) > -1) + if (inArray(event.keyCode, increaseDecreaseScrollAmountKeyCodes) > -1) increaseTrackScrollAmount(); } function documentKeyUp(event) { - if (FRAMEWORK.inArray(event.keyCode, increaseDecreaseScrollAmountKeyCodes) > -1) + if (inArray(event.keyCode, increaseDecreaseScrollAmountKeyCodes) > -1) decreaseTrackScrollAmount(); } function onMouseTouchDownContinue(event) { var originalEvent = event.originalEvent || event; var isTouchEvent = originalEvent.touches !== undefined; - return _isSleeping || _destroyed || nativeOverlayScrollbarsAreActive() || !_scrollbarsDragScrollingCache || (isTouchEvent && !getPreparedScrollbarsOption('touchSupport')) ? false : COMPATIBILITY.mBtn(event) === 1 || isTouchEvent; + return _sleeping || _destroyed || nativeOverlayScrollbarsAreActive() || !_scrollbarsDragScrollingCache || (isTouchEvent && !getPreparedScrollbarsOption('touchSupport')) ? false : COMPATIBILITY.mBtn(event) === 1 || isTouchEvent; } function documentDragMove(event) { if(onMouseTouchDownContinue(event)) { @@ -3442,7 +3480,7 @@ _viewportElement[scroll](MATH.round(mouseDownScroll + scrollDelta)); - if(_scrollbarsHandleAsync) + if(_scrollbarsHandlesDefineScrollPos) refreshScrollbarHandleOffset(isHorizontal, mouseDownScroll + scrollDelta); if (!_supportPassiveEvents) @@ -3460,10 +3498,10 @@ .off(_strKeyUpEvent, documentKeyUp) .off(_strSelectStartEvent, documentOnSelectStart); - if(_scrollbarsHandleAsync) + if(_scrollbarsHandlesDefineScrollPos) refreshScrollbarHandleOffset(isHorizontal, true); - _scrollbarsHandleAsync = false; + _scrollbarsHandlesDefineScrollPos = false; removeClass(_bodyElement, _classNameDragging); removeClass(scrollbarVars._handle, strActive); removeClass(scrollbarVars._track, strActive); @@ -3494,6 +3532,10 @@ } } function onHandleMouseTouchDown(event) { + if (onMouseTouchDownContinue(event)) + onHandleMouseTouchDownAction(event); + } + function onHandleMouseTouchDownAction(event) { mouseDownScroll = _viewportElement[scroll](); mouseDownScroll = isNaN(mouseDownScroll) ? 0 : mouseDownScroll; if (_isRTL && isHorizontal && !_rtlScrollBehavior.n || !_isRTL) @@ -3502,7 +3544,7 @@ mouseDownInvertedScale = getHostElementInvertedScale()[xy]; mouseDownOffset = getPointerPosition(event); - _scrollbarsHandleAsync = !getPreparedScrollbarsOption(strSnapHandle); + _scrollbarsHandlesDefineScrollPos = !getPreparedScrollbarsOption(strSnapHandle); addClass(_bodyElement, _classNameDragging); addClass(scrollbarVars._handle, strActive); addClass(scrollbarVars._scrollbar, strActive); @@ -3515,11 +3557,7 @@ COMPATIBILITY.prvD(event); COMPATIBILITY.stpP(event); } - scrollbarVars._handle.on(_strMouseTouchDownEvent, function(event) { - if (onMouseTouchDownContinue(event)) - onHandleMouseTouchDown(event); - }); - scrollbarVars._track.on(_strMouseTouchDownEvent, function(event) { + function onTrackMouseTouchDown(event) { if (onMouseTouchDownContinue(event)) { var scrollDistance = MATH.round(_viewportSize[scrollbarVars._w_h]); var trackOffset = scrollbarVars._track.offset()[scrollbarVars._left_top]; @@ -3531,12 +3569,12 @@ var decreaseScroll; var finishedCondition; var scrollActionFinsished = function(transition) { - if(_scrollbarsHandleAsync) + if(_scrollbarsHandlesDefineScrollPos) refreshScrollbarHandleOffset(isHorizontal, transition); }; var scrollActionInstantFinished = function() { scrollActionFinsished(); - onHandleMouseTouchDown(event); + onHandleMouseTouchDownAction(event); }; var scrollAction = function () { if(!_destroyed) { @@ -3555,7 +3593,7 @@ var animationObj = { easing : easing, step : function(now) { - if(_scrollbarsHandleAsync) { + if(_scrollbarsHandlesDefineScrollPos) { _viewportElement[scroll](now); //https://github.com/jquery/jquery/issues/4340 refreshScrollbarHandleOffset(isHorizontal, now); } @@ -3617,7 +3655,7 @@ mouseDownInvertedScale = getHostElementInvertedScale()[xy]; mouseDownOffset = COMPATIBILITY.page(event)[xy]; - _scrollbarsHandleAsync = !getPreparedScrollbarsOption(strSnapHandle); + _scrollbarsHandlesDefineScrollPos = !getPreparedScrollbarsOption(strSnapHandle); addClass(_bodyElement, _classNameDragging); addClass(scrollbarVars._track, strActive); addClass(scrollbarVars._scrollbar, strActive); @@ -3631,19 +3669,32 @@ COMPATIBILITY.prvD(event); COMPATIBILITY.stpP(event); } - }).on(_strMouseTouchEnter, function() { //make sure both scrollbars will stay visible if one scrollbar is hovered if autoHide is "scroll" or "move". + } + function onTrackMouseTouchEnter(event) { + //make sure both scrollbars will stay visible if one scrollbar is hovered if autoHide is "scroll" or "move". _scrollbarsHandleHovered = true; if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove) refreshScrollbarsAutoHide(true); - - }).on(_strMouseTouchLeave, function() { + } + function onTrackMouseTouchLeave(event) { _scrollbarsHandleHovered = false; if (_scrollbarsAutoHideScroll || _scrollbarsAutoHideMove) refreshScrollbarsAutoHide(false); - }); - scrollbarVars._scrollbar.on(_strMouseTouchDownEvent, function(event) { + } + function onScrollbarMouseTouchDown(event) { COMPATIBILITY.stpP(event); - }); + } + + setupEvent(scrollbarVars._handle, + _strMouseTouchDownEvent, + onHandleMouseTouchDown); + setupEvent(scrollbarVars._track, + [_strMouseTouchDownEvent, _strMouseTouchEnter, _strMouseTouchLeave], + [onTrackMouseTouchDown, onTrackMouseTouchEnter, onTrackMouseTouchLeave]); + setupEvent(scrollbarVars._scrollbar, + _strMouseTouchDownEvent, + onScrollbarMouseTouchDown); + if (_supportTransition) { scrollbarVars._scrollbar.on(_strTransitionEndEvent, function(event) { if (event.target !== scrollbarVars._scrollbar[0]) @@ -3933,7 +3984,7 @@ function onMouseTouchDownContinue(event) { var originalEvent = event.originalEvent || event; var isTouchEvent = originalEvent.touches !== undefined; - return _isSleeping || _destroyed ? false : COMPATIBILITY.mBtn(event) === 1 || isTouchEvent; + return _sleeping || _destroyed ? false : COMPATIBILITY.mBtn(event) === 1 || isTouchEvent; } function getCoordinates(event) { return _msieVersion && insideIFrame ? { x : event.screenX , y : event.screenY } : COMPATIBILITY.page(event); @@ -3954,13 +4005,13 @@ var extensionOnName = name; var ext; - if(extensionOnName.substr(0, 2) === "on") + if(extensionOnName.substr(0, 2) === 'on') extensionOnName = extensionOnName.substr(2, 1).toLowerCase() + extensionOnName.substr(3); if(type(callback) == TYPES.f) callback.call(_base, args); - FRAMEWORK.each(_extensions, function() { + each(_extensions, function() { ext = this; if(type(ext.on) == TYPES.f) ext.on(extensionOnName, args); @@ -4096,22 +4147,21 @@ if (textareaCursorPosition === undefined) return; - var strLength = 'length'; var textareaValue = _targetElement.val(); - var textareaLength = textareaValue[strLength]; - var textareaRowSplit = textareaValue.split("\n"); - var textareaLastRow = textareaRowSplit[strLength]; - var textareaCurrentCursorRowSplit = textareaValue.substr(0, textareaCursorPosition).split("\n"); + var textareaLength = textareaValue[LEXICON.l]; + var textareaRowSplit = textareaValue.split('\n'); + var textareaLastRow = textareaRowSplit[LEXICON.l]; + var textareaCurrentCursorRowSplit = textareaValue.substr(0, textareaCursorPosition).split('\n'); var widestRow = 0; var textareaLastCol = 0; - var cursorRow = textareaCurrentCursorRowSplit[strLength]; - var cursorCol = textareaCurrentCursorRowSplit[textareaCurrentCursorRowSplit[strLength] - 1][strLength]; + var cursorRow = textareaCurrentCursorRowSplit[LEXICON.l]; + var cursorCol = textareaCurrentCursorRowSplit[textareaCurrentCursorRowSplit[LEXICON.l] - 1][LEXICON.l]; var rowCols; var i; //get widest Row and the last column of the textarea - for (i = 0; i < textareaRowSplit[strLength]; i++) { - rowCols = textareaRowSplit[i][strLength]; + for (i = 0; i < textareaRowSplit[LEXICON.l]; i++) { + rowCols = textareaRowSplit[i][LEXICON.l]; if (rowCols > textareaLastCol) { widestRow = i + 1; textareaLastCol = rowCols; @@ -4180,7 +4230,7 @@ var i = 0; var val; for(; i < splits.length; i++) { - if(!obj.hasOwnProperty(splits[i])) + if(!obj[LEXICON.hOP](splits[i])) return; val = obj[splits[i]]; if(i < splits.length && type(val) == TYPES.o) @@ -4210,76 +4260,37 @@ //==== Utils Cache ====// /** - * Compares two values and returns the result of the comparison as a boolean. - * @param current The first value which shall be compared. - * @param cache The second value which shall be compared. + * Compares two values or objects and returns true if they aren't equal. + * @param current The first value or object which shall be compared. + * @param cache The second value or object which shall be compared. * @param force If true the returned value is always true. - * @returns {boolean} True if both variables aren't equal or some of them is undefined or when the force parameter is true, false otherwise. + * @returns {boolean} True if both values or objects aren't equal or force is true, false otherwise. */ - function checkCacheSingle(current, cache, force) { - if (force === true) + function checkCache(current, cache, force) { + if (force) return force; - if (cache === undefined) - return true; - else if (current !== cache) - return true; - return false; - } - - /** - * Compares two objects with two properties and returns the result of the comparison as a boolean. - * @param current The first object which shall be compared. - * @param cache The second object which shall be compared. - * @param prop1 The name of the first property of the objects which shall be compared. - * @param prop2 The name of the second property of the objects which shall be compared. - * @param force If true the returned value is always true. - * @returns {boolean} True if both variables aren't equal or some of them is undefined or when the force parameter is true, false otherwise. - */ - function checkCacheDouble(current, cache, prop1, prop2, force) { - if (force === true) - return force; - if (prop2 === undefined && force === undefined) { - if (prop1 === true) - return prop1; - else - prop1 = undefined; + if(type(current) == TYPES.o && type(cache) == TYPES.o) { + for (var prop in current) { + if(prop !== 'c') { + if (current[LEXICON.hOP](prop) && cache[LEXICON.hOP](prop)) { + if(checkCache(current[prop], cache[prop])) + return true; + } + else { + return true; + } + } + } + } + else { + return current !== cache; } - prop1 = prop1 === undefined ? 'w' : prop1; - prop2 = prop2 === undefined ? 'h' : prop2; - if (cache === undefined) - return true; - else if (current[prop1] !== cache[prop1] || current[prop2] !== cache[prop2]) - return true; - return false; - } - - /** - * Compares two objects which have four properties and returns the result of the comparison as a boolean. - * @param current The first object with four properties. - * @param cache The second object with four properties. - * @returns {boolean} True if both objects aren't equal or some of them is undefined, false otherwise. - */ - function checkCacheTRBL(current, cache) { - if (cache === undefined) - return true; - else if (current.t !== cache.t || - current.r !== cache.r || - current.b !== cache.b || - current.l !== cache.l) - return true; return false; } //==== Shortcuts ====// - /** - * jQuery type method shortcut. - */ - function type(obj) { - return COMPATIBILITY.type(obj); - } - /** * jQuery extend method shortcut with a appended "true" as first argument. */ @@ -4326,15 +4337,21 @@ * This behavior can be reset by calling the update method. */ _base.sleep = function () { - _isSleeping = true; + _sleeping = true; }; /** * Updates the plugin and DOM to the current options. * This method should only be called if a update is 100% required. * @param force True if every property shall be updated and the cache shall be ignored. - * !INTERNAL USAGE! : force can be a string "auto", "auto+" or "zoom" too - * if this is the case then before a real update the content size and host element attributes gets checked, and if they changed only then the update method will be called. + * !INTERNAL USAGE! : force can be a string "auto", "sync" or "zoom" too + * if "auto" then before a real update the content size and host element attributes gets checked, and if they changed only then the update method will be called. + * if "sync" then the async update process (MutationObserver or UpdateLoop) gets synchronized and a corresponding update takes place if one was needed due to pending changes. + * if "zoom" then a update takes place where it's assumed that content and host size changed + * @returns {boolean|undefined} + * If force is "sync" then a boolean is returned which indicates whether a update was needed due to pending changes. + * If force is "auto" then a boolean is returned whether a update was needed due to attribute or size changes. + * undefined otherwise. */ _base.update = function (force) { var attrsChanged; @@ -4342,21 +4359,42 @@ var isString = type(force) == TYPES.s; var imgElementSelector = 'img'; var imgElementLoadEvent = 'load'; - + var doUpdateAuto; + var mutHost; + var mutContent; if(isString) { if (force === _strAuto) { attrsChanged = meaningfulAttrsChanged(); contentSizeC = updateAutoContentSizeChanged(); - if (attrsChanged || contentSizeC) - update(false, contentSizeC, false); + doUpdateAuto = attrsChanged || contentSizeC; + if (doUpdateAuto) { + update({ + _contentSizeChanged : contentSizeC, + _changedOptions : _initialized ? undefined : _currentPreparedOptions + }); + } + } + else if (force === _strSync) { + if(_mutationObserversConnected) { + mutHost = _mutationObserverHostCallback(_mutationObserverHost.takeRecords()); + mutContent = _mutationObserverContentCallback(_mutationObserverContent.takeRecords()); + } + else { + mutHost = _base.update(_strAuto); + } + } + else if (force === 'zoom') { + update({ + _hostSizeChanged : true, + _contentSizeChanged : true + }); } - else if (force === 'zoom') - update(true, true); } - else if(!synchronizeMutationObservers() || force) { - force = _isSleeping || force; - _isSleeping = false; - update(false, false, force, true); + else { + force = _sleeping || force; + _sleeping = false; + if(!_base.update(_strSync) || force) + update({ _force : force }); } if(!_isTextarea) { _contentElement.find(imgElementSelector).each(function(i, el) { @@ -4365,7 +4403,7 @@ FRAMEWORK(el).off(imgElementLoadEvent, imgOnLoad).on(imgElementLoadEvent, imgOnLoad); }); } - + return doUpdateAuto || mutHost || mutContent; }; /** @@ -4375,15 +4413,15 @@ * @returns {*} */ _base.options = function (newOptions, value) { + var option = { }; + var changedOps; + //return current options if newOptions are undefined or empty if (FRAMEWORK.isEmptyObject(newOptions) || !FRAMEWORK.isPlainObject(newOptions)) { if (type(newOptions) == TYPES.s) { if (arguments.length > 1) { - var option = { }; setObjectPropVal(option, newOptions, value); - setOptions(option); - update(); - return; + changedOps = setOptions(option); } else return getObjectPropVal(_currentOptions, newOptions); @@ -4391,19 +4429,19 @@ else return _currentOptions; } - setOptions(newOptions); - var isSleepingTmp = _isSleeping || false; - _isSleeping = false; - update(); - _isSleeping = isSleepingTmp; + else { + changedOps = setOptions(newOptions); + } + + if(!FRAMEWORK.isEmptyObject(changedOps)) { + update({ _changedOptions : changedOps }); + } }; /** - * Restore the DOM, disconnects all observers, remove all resize observers and destroy all methods. + * Restore the DOM, disconnects all observers, remove all resize observers and put the instance to sleep. */ _base.destroy = function () { - _destroyed = true; - //remove this instance from auto update loop autoUpdateLoop.remove(_base); @@ -4411,9 +4449,8 @@ disconnectMutationObservers(); //remove all resize observers - removeResizeObserver(_sizeObserverElement); - if (_sizeAutoObserverAdded) - removeResizeObserver(_sizeAutoObserverElement); + setupResizeObserver(_sizeObserverElement); + setupResizeObserver(_sizeAutoObserverElement); //remove all extensions for(var extName in _extensions) @@ -4443,14 +4480,17 @@ FRAMEWORK(_imgs[i]).off('load', imgOnLoad); _imgs = undefined; + _destroyed = true; + _sleeping = true; + //remove this instance from the instances list INSTANCES(pluginTargetElement, 0); dispatchCallback("onDestroyed"); //remove all properties and methods - for (var property in _base) - delete _base[property]; - _base = undefined; + //for (var property in _base) + // delete _base[property]; + //_base = undefined; }; /** @@ -4574,7 +4614,7 @@ }; } - synchronizeMutationObservers(); + _base.update(_strSync); var normalizeRTL = _normalizeRTLCache; var coordinatesXAxisProps = [_strX, _strLeft, 'l']; @@ -4604,7 +4644,7 @@ var elementObjSettingsAxisValues = [_strX, _strY, 'xy', 'yx']; var elementObjSettingsBlockValues = [strBegin, strEnd, strCenter, strNearest]; var elementObjSettingsScrollValues = [strAlways, strNever, strIfNeeded]; - var coordinatesIsElementObj = coordinates.hasOwnProperty('el'); + var coordinatesIsElementObj = coordinates[LEXICON.hOP]('el'); var possibleElement = coordinatesIsElementObj ? coordinates.el : coordinates; var possibleElementIsJQuery = possibleElement instanceof FRAMEWORK || JQUERY ? possibleElement instanceof JQUERY : false; var possibleElementIsHTMLElement = possibleElementIsJQuery ? false : isHTMLElement(possibleElement); @@ -4654,7 +4694,7 @@ //check operator if (rawScroll[strLength] > 2) { possibleOperator = rawScroll.substr(0, 2); - if(FRAMEWORK.inArray(possibleOperator, coordinatesOperators) > -1) + if(inArray(possibleOperator, coordinatesOperators) > -1) operator = possibleOperator; } @@ -4949,12 +4989,12 @@ * @returns {{widthAuto, heightAuto, overflowAmount, hideOverflow, hasOverflow, contentScrollSize, viewportSize, hostSize, autoUpdate} | *} */ _base.getState = function (stateProperty) { - var prepare = function (obj) { + function prepare(obj) { if (!FRAMEWORK.isPlainObject(obj)) return obj; var extended = extendDeep({}, obj); var changePropertyName = function (from, to) { - if (extended.hasOwnProperty(from)) { + if (extended[LEXICON.hOP](from)) { extended[to] = extended[from]; delete extended[from]; } @@ -4965,7 +5005,8 @@ return extended; }; var obj = { - sleeping: prepare(_isSleeping) || false, + destroyed: !!prepare(_destroyed), + sleeping: !!prepare(_sleeping), autoUpdate: prepare(!_mutationObserversConnected), widthAuto: prepare(_widthAutoCache), heightAuto: prepare(_heightAutoCache), @@ -4991,7 +5032,7 @@ var privateMethods = _extensionsPrivateMethods.split(' '); var i = 0; if(type(extName) == TYPES.s) { - if(_extensions.hasOwnProperty(extName)) { + if(_extensions[LEXICON.hOP](extName)) { result = extendDeep({}, _extensions[extName]); for (; i < privateMethods.length; i++) delete result[privateMethods[i]]; @@ -5019,7 +5060,7 @@ var contractResult; var contractFulfilled = true; if(registeredExtensionObj) { - if(!_extensions.hasOwnProperty(extName)) { + if(!_extensions[LEXICON.hOP](extName)) { instance = registeredExtensionObj.extensionFactory.call(_base, extendDeep({ }, registeredExtensionObj.defaultOptions), FRAMEWORK, @@ -5084,7 +5125,7 @@ _rtlScrollBehavior = extendDeep({}, globals.rtlScrollBehavior); //parse & set options but don't update - setOptions(extendDeep({ }, _defaultOptions, _pluginsOptions._validate(options, _pluginsOptions._template, true))); + setOptions(extendDeep({ }, _defaultOptions, options)); //check if the plugin hasn't to be initialized if (_nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.x && !_currentPreparedOptions.nativeScrollbarsOverlaid.initialize) { @@ -5156,27 +5197,26 @@ } //build resize observer for the host element - addResizeObserver(_sizeObserverElement, hostOnResized); + setupResizeObserver(_sizeObserverElement, hostOnResized); - //update for the first time - hostOnResized(); //initialize cache for host size - _base.update(_strAuto); //initialize cache for content + //update for the first time & initialize cache + _base.update(_strAuto); //the plugin is initialized now! _initialized = true; dispatchCallback("onInitialized"); //call all callbacks which would fire before the initialized was complete - FRAMEWORK.each(_callbacksInitQeueue, function(index, value) { dispatchCallback(value.n, value.a); }); + each(_callbacksInitQeueue, function(index, value) { dispatchCallback(value.n, value.a); }); _callbacksInitQeueue = [ ]; //add extensions if(type(extensions) == TYPES.s) extensions = [ extensions ]; if(COMPATIBILITY.isA(extensions)) - FRAMEWORK.each(extensions, function (index, value) {_base.addExt(value); }); + each(extensions, function (index, value) {_base.addExt(value); }); else if(FRAMEWORK.isPlainObject(extensions)) - FRAMEWORK.each(extensions, function (key, value) { _base.addExt(key, value); }); + each(extensions, function (key, value) { _base.addExt(key, value); }); //add the transition class for transitions AFTER the first update & AFTER the applied extensions (for preventing unwanted transitions) setTimeout(function () { @@ -5268,7 +5308,7 @@ return FRAMEWORK.extend(true, { }, currDefaultOptions); //set the new default options - _pluginsGlobals.defaultOptions = FRAMEWORK.extend(true, { }, currDefaultOptions , _pluginsOptions._validate(newDefaultOptions, _pluginsOptions._template, true)); + _pluginsGlobals.defaultOptions = FRAMEWORK.extend(true, { }, currDefaultOptions , _pluginsOptions._validate(newDefaultOptions, _pluginsOptions._template, true, currDefaultOptions)._default); }; /** diff --git a/js/jquery.overlayScrollbars.min.js b/js/jquery.overlayScrollbars.min.js index ef7fa25..b55d044 100644 --- a/js/jquery.overlayScrollbars.min.js +++ b/js/jquery.overlayScrollbars.min.js @@ -2,12 +2,12 @@ * OverlayScrollbars * https://github.com/KingSora/OverlayScrollbars * - * Version: 1.7.3 + * Version: 1.8.0 * - * Copyright KingSora. + * Copyright KingSora | Rene Haas. * https://github.com/KingSora * * Released under the MIT license. - * Date: 23.06.2019 + * Date: 08.07.2019 */ -!function(t,r){"function"==typeof define&&define.amd?define(["jquery"],function(n){return r(t,t.document,undefined,n)}):"object"==typeof module&&"object"==typeof module.exports?module.exports=r(t,t.document,undefined,require("jquery")):r(t,t.document,undefined,t.jQuery)}("undefined"!=typeof window?window:this,function(bt,mt,Si,n){"use strict";var i,o,wt="OverlayScrollbars",yt="object",gt="function",xt="array",_t="string",St="boolean",zt="number",d="null",Tt="class",zi="style",kt="id",Ti="length",ki="prototype",Oi="offsetHeight",Ai="clientHeight",Ci="scrollHeight",Ni="offsetWidth",Hi="clientWidth",Li="scrollWidth",Ri={o:{},u:{},s:["-webkit-","-moz-","-o-","-ms-"],v:["WebKit","Moz","O","MS"],p:function(n){var t=this.u;if(t[n])return t[n];for(var r,e,i=this.s,o=this.m(n),a=mt.createElement("div")[zi],u=0,f=0;u
'),o=z[0],e=Wi(z.children("div").eq(0)),t=bt.getComputedStyle;S.append(z),z.hide().show();var r,a,u,f,c,l,s,v,d,h=T(o),p={x:0===h.x,y:0===h.y};function T(n){return{x:n[Oi]-n[Ai],y:n[Ni]-n[Hi]}}Wi.extend(_,{defaultOptions:n,autoUpdateLoop:!1,autoUpdateRecommended:!Di.mO(),nativeScrollbarSize:h,nativeScrollbarIsOverlaid:p,nativeScrollbarStyling:(z.addClass("os-viewport-native-scrollbars-invisible"),"none"===z.css("scrollbar-width")||!!t&&"none"===t(o,"::-webkit-scrollbar").getPropertyValue("display")),overlayScrollbarDummySize:{x:30,y:30},msie:(a=bt.navigator.userAgent,u="indexOf",f="substring",c=a[u]("MSIE "),l=a[u]("Trident/"),s=a[u]("Edge/"),v=a[u]("rv:"),d=parseInt,0i&&(t.update("auto"),d[f]=new Date(o+=i)),n=Ii.max(1,Ii.min(n,i)));p=n}}else p=33};this.add=function(n){-1===Wi.inArray(n,v)&&(v.push(n),d.push(Di.now()),0/g,(s?"-":ke)+Ce)[v](/px/g,ke)[v](/%/g," * "+c*(l&&Ht.n?-1:1)/100)[v](/vw/g," * "+ve.w)[v](/vh/g," * "+ve.h),hi(isNaN(t)?hi(d(t),!0).toFixed():t)):t)!==Si&&!isNaN(e)&&st(e)==zt){var h=g&&l,p=f*(h&&Ht.n?-1:1),b=h&&Ht.i,m=h&&Ht.n;switch(p=b?c-p:p,r){case"+=":i=p+e;break;case"-=":i=p-e;break;case"*=":i=p*e;break;case"/=":i=p/e;break;default:i=e}i=b?c-i:i,i*=m?-1:1,i=l&&Ht.n?Ii.min(0,Ii.max(c,i)):Ii.max(0,Ii.min(c,i))}return i===f?Si:i},V=function(n,t,r,e){var i,o,a=[r,r],u=st(n);if(u==t)n=[n,n];else if(u==xt){if(2<(i=n[L])||i<1)n=a;else for(1===i&&(n[1]=r),s=0;s=t.left&&n.clientX<=t.right&&n.clientY>=t.top&&n.clientY<=t.bottom||Gn(),(re||ee)&&ui(!1)}}function R(n){i=or[A](),i=isNaN(i)?0:i,(Kt&&_&&!Ht.n||!Kt)&&(i=i<0?0:i),T=ut()[O],z=f(n),B=!c(a),xi(W,Fn),xi(r.nn,o),xi(r.rn,o),M.on(nn,d).on(Z,L).on(an,Qn),!D&&p||Di.prvD(n),Di.stpP(n)}r.nn.on(Ie,function(n){H(n)&&R(n)}),r.tn.on(Ie,function(n){if(H(n)){var d,h=Ii.round(ve[r.D]),p=r.tn.offset()[r.I],t=n.ctrlKey,b=n.shiftKey,m=b&&t,w=!0,y=function(n){B&&ci(_,n)},g=function(){y(),R(n)},x=function(){if(!jt){var n=(z-p)*T,t=k.C,r=k.L,e=k.N,i=k.A,o=k.k,a=270*C,u=w?Ii.max(400,a):a,f=i*((n-e/2)/(r-e)),c=Kt&&_&&(!Ht.i&&!Ht.n||Br),l=c?t"+(n||ke)+""}function lt(n,t){for(var r,e=t.split(K),i=0;i
'),o=z[0],e=Di(z.children("div").eq(0));S.append(z),z.hide().show();var t,r,a,u,f,c,l,s,v,d=T(o),h={x:0===d.x,y:0===d.y};function T(n){return{x:n[Oi]-n[ki],y:n[Ai]-n[Ni]}}Di.extend(_,{defaultOptions:n,autoUpdateLoop:!1,autoUpdateRecommended:!Li.mO(),nativeScrollbarSize:d,nativeScrollbarIsOverlaid:h,nativeScrollbarStyling:function(){var n=!1;z.addClass("os-viewport-native-scrollbars-invisible");try{n="none"===z.css("scrollbar-width")||"none"===vt.getComputedStyle(o,"::-webkit-scrollbar").getPropertyValue("display")}catch(t){}return n}(),overlayScrollbarDummySize:{x:30,y:30},msie:(r=vt.navigator.userAgent,a="indexOf",u="substring",f=r[a]("MSIE "),c=r[a]("Trident/"),l=r[a]("Edge/"),s=r[a]("rv:"),v=parseInt,0i&&(t.update("auto"),h[f]=new Date(o+=i)),n=Ri.max(1,Ri.min(n,i)));b=n}}else b=33};this.add=function(n){-1===e(n,d)&&(d.push(n),h.push(l()),0/g,(s?"-":Ae)+Le)[v](/px/g,Ae)[v](/%/g," * "+c*(l&&Dt.n?-1:1)/100)[v](/vw/g," * "+pe.w)[v](/vh/g," * "+pe.h),bi(isNaN(t)?bi(d(t),!0).toFixed():t)):t)!==Si&&!isNaN(e)&&ln(e)==wt){var h=w&&l,p=f*(h&&Dt.n?-1:1),b=h&&Dt.i,m=h&&Dt.n;switch(p=b?c-p:p,r){case"+=":i=p+e;break;case"-=":i=p-e;break;case"*=":i=p*e;break;case"/=":i=p/e;break;default:i=e}i=b?c-i:i,i*=m?-1:1,i=l&&Dt.n?Ri.min(0,Ri.max(c,i)):Ri.max(0,Ri.min(c,i))}return i===f?Si:i},V=function(n,t,r,e){var i,o,a=[r,r],u=ln(n);if(u==t)n=[n,n];else if(u==mt){if(2<(i=n[L])||i<1)n=a;else for(1===i&&(n[1]=r),s=0;s=t.left&&n.clientX<=t.right&&n.clientY>=t.top&&n.clientY<=t.bottom||Yn(),(ae||ue)&&ci(!1)}}function D(n){i=cr[C](),i=isNaN(i)?0:i,(Zt&&_&&!Dt.n||!Zt)&&(i=i<0?0:i),T=it()[k],z=c(n),U=!l(a),xi(E,Wn),xi(r.ln,o),xi(r.vn,o),j.on(Y,d).on(X,R).on(Q,Kn),!M&&y||Li.prvD(n),Li.stpP(n)}f(r.ln,Me,function h(n){L(n)&&D(n)}),f(r.sn,[Me,$,K],[function I(n){if(L(n)){var d,h=Ri.round(pe[r.q]),p=r.sn.offset()[r.V],t=n.ctrlKey,b=n.shiftKey,m=b&&t,y=!0,g=function(n){U&&si(_,n)},w=function(){g(),D(n)},x=function(){if(!Pt){var n=(z-p)*T,t=O.W,r=O.U,e=O.j,i=O.M,o=O.D,a=270*A,u=y?Ri.max(400,a):a,f=i*((n-e/2)/(r-e)),c=Zt&&_&&(!Dt.i&&!Dt.n||Kr),l=c?t"+(n||Ae)+""}function ut(n,t){for(var r,e=t.split(P),i=0;i