UNPKG

responsivewebframework

Version:

Jalasoft Foundation Front End Framework ========================================

843 lines (723 loc) 31.1 kB
(function ($) { $.fn.customScrollbar = function (options, args) { var defaultOptions = { skin: undefined, hScroll: true, vScroll: true, updateOnWindowResize: false, animationSpeed: 300, onCustomScroll: undefined, swipeSpeed: 1, wheelSpeed: 40, fixedThumbWidth: undefined, fixedThumbHeight: undefined }; var Scrollable = function (element, options) { this.$element = $(element); this.options = options; this.addScrollableClass(); this.addSkinClass(); this.addScrollBarComponents(); if (this.options.vScroll) { this.vScrollbar = new Scrollbar(this, new VSizing()); } if (this.options.hScroll) { this.hScrollbar = new Scrollbar(this, new HSizing()); } this.$element.data("scrollable", this); this.initKeyboardScrolling(); this.bindEvents(); }; Scrollable.prototype = { addScrollableClass: function () { if (!this.$element.hasClass("scrollable")) { this.scrollableAdded = true; this.$element.addClass("scrollable"); } }, removeScrollableClass: function () { if (this.scrollableAdded) { this.$element.removeClass("scrollable"); } }, addSkinClass: function () { if (typeof(this.options.skin) === "string" && !this.$element.hasClass(this.options.skin)) { this.skinClassAdded = true; this.$element.addClass(this.options.skin); } }, removeSkinClass: function () { if (this.skinClassAdded) { this.$element.removeClass(this.options.skin); } }, addScrollBarComponents: function () { this.assignViewPort(); if (this.$viewPort.length === 0) { this.$element.wrapInner("<div class=\"viewport\" />"); this.assignViewPort(); this.viewPortAdded = true; } this.assignOverview(); if (this.$overview.length === 0) { this.$viewPort.wrapInner("<div class=\"overview\" />"); this.assignOverview(); this.overviewAdded = true; } this.addScrollBar("vertical", "prepend"); this.addScrollBar("horizontal", "append"); }, removeScrollbarComponents: function () { this.removeScrollbar("vertical"); this.removeScrollbar("horizontal"); if (this.overviewAdded) { this.$element.unwrap(); } if (this.viewPortAdded) { this.$element.unwrap(); } }, removeScrollbar: function (orientation) { if (this[orientation + "ScrollbarAdded"]) { this.$element.find(".scroll-bar." + orientation).remove(); } }, assignViewPort: function () { this.$viewPort = this.$element.find(".viewport"); }, assignOverview: function () { this.$overview = this.$viewPort.find(".overview"); }, addScrollBar: function (orientation, fun) { if (this.$element.find(".scroll-bar." + orientation).length === 0) { this.$element[fun]("<div class='scroll-bar " + orientation + "'><div class='thumb'></div></div>") this[orientation + "ScrollbarAdded"] = true; } }, resize: function (keepPosition) { if (this.vScrollbar) { this.vScrollbar.resize(keepPosition); } if (this.hScrollbar) { this.hScrollbar.resize(keepPosition); } }, scrollTo: function (element) { if (this.vScrollbar) { this.vScrollbar.scrollToElement(element); } if (this.hScrollbar) { this.hScrollbar.scrollToElement(element); } }, scrollToXY: function (x, y) { this.scrollToX(x); this.scrollToY(y); }, scrollToX: function (x) { if (this.hScrollbar) { this.hScrollbar.scrollOverviewTo(x, true); } }, scrollToY: function (y) { if (this.vScrollbar) { this.vScrollbar.scrollOverviewTo(y, true); } }, remove: function () { this.removeScrollableClass(); this.removeSkinClass(); this.removeScrollbarComponents(); this.$element.data("scrollable", null); this.removeKeyboardScrolling(); if (this.vScrollbar) { this.vScrollbar.remove(); } if (this.hScrollbar) { this.hScrollbar.remove(); } }, setAnimationSpeed: function (speed) { this.options.animationSpeed = speed; }, isInside: function (element, wrappingElement) { var $element = $(element); var $wrappingElement = $(wrappingElement); var elementOffset = $element.offset(); var wrappingElementOffset = $wrappingElement.offset(); return (elementOffset.top >= wrappingElementOffset.top) && (elementOffset.left >= wrappingElementOffset.left) && (elementOffset.top + $element.height() <= wrappingElementOffset.top + $wrappingElement.height()) && (elementOffset.left + $element.width() <= wrappingElementOffset.left + $wrappingElement.width()) }, initKeyboardScrolling: function () { var _this = this; this.elementKeydown = function (event) { if (document.activeElement === _this.$element[0]) { if (_this.vScrollbar) { _this.vScrollbar.keyScroll(event); } if (_this.hScrollbar) { _this.hScrollbar.keyScroll(event); } } }; this.$element .attr('tabindex', '-1') .keydown(this.elementKeydown); }, removeKeyboardScrolling: function () { this.$element .removeAttr('tabindex') .unbind("keydown", this.elementKeydown); }, bindEvents: function () { if (this.options.onCustomScroll) { this.$element.on("customScroll", this.options.onCustomScroll); } } }; var Scrollbar = function (scrollable, sizing) { this.scrollable = scrollable; this.sizing = sizing; this.$scrollBar = this.sizing.scrollBar(this.scrollable.$element); this.$thumb = this.$scrollBar.find(".thumb"); this.setScrollPosition(0, 0); this.resize(); this.initMouseMoveScrolling(); this.initMouseWheelScrolling(); this.initTouchScrolling(); this.initMouseClickScrolling(); this.initWindowResize(); }; Scrollbar.prototype = { resize: function (keepPosition) { this.scrollable.$viewPort.height(this.scrollable.$element.height()); this.sizing.size(this.scrollable.$viewPort, this.sizing.size(this.scrollable.$element)); this.viewPortSize = this.sizing.size(this.scrollable.$viewPort); this.overviewSize = this.sizing.size(this.scrollable.$overview); this.ratio = this.viewPortSize / this.overviewSize; this.sizing.size(this.$scrollBar, this.viewPortSize); this.thumbSize = this.calculateThumbSize(); this.sizing.size(this.$thumb, this.thumbSize); this.maxThumbPosition = this.calculateMaxThumbPosition(); this.maxOverviewPosition = this.calculateMaxOverviewPosition(); this.enabled = (this.overviewSize > this.viewPortSize); if (this.scrollPercent === undefined) { this.scrollPercent = 0.0; } if (this.enabled) { this.rescroll(keepPosition); } else { this.setScrollPosition(0, 0); } this.$scrollBar.toggle(this.enabled); }, calculateThumbSize: function () { var fixedSize = this.sizing.fixedThumbSize(this.scrollable.options); var size; if (fixedSize) { size = fixedSize; } else { size = this.ratio * this.viewPortSize; } return Math.max(size, this.sizing.minSize(this.$thumb)); }, initMouseMoveScrolling: function () { var _this = this; this.$thumb.mousedown(function (event) { if (_this.enabled) { _this.startMouseMoveScrolling(event); } }); this.documentMouseup = function (event) { _this.stopMouseMoveScrolling(event); }; $(document).mouseup(this.documentMouseup); this.documentMousemove = function (event) { _this.mouseMoveScroll(event); }; $(document).mousemove(this.documentMousemove); this.$thumb.click(function (event) { event.stopPropagation(); }); }, removeMouseMoveScrolling: function () { this.$thumb.unbind(); $(document).unbind("mouseup", this.documentMouseup); $(document).unbind("mousemove", this.documentMousemove); }, initMouseWheelScrolling: function () { var _this = this; this.scrollable.$element.mousewheel(function (event, delta, deltaX, deltaY) { if (_this.enabled) { if (_this.mouseWheelScroll(deltaX, deltaY)) { event.stopPropagation(); event.preventDefault(); } } }); }, removeMouseWheelScrolling: function () { this.scrollable.$element.unbind("mousewheel"); }, initTouchScrolling: function () { if (document.addEventListener) { var _this = this; this.elementTouchstart = function (event) { if (_this.enabled) { _this.startTouchScrolling(event); } }; this.scrollable.$element[0].addEventListener("touchstart", this.elementTouchstart); this.documentTouchmove = function (event) { _this.touchScroll(event); }; document.addEventListener("touchmove", this.documentTouchmove); this.elementTouchend = function (event) { _this.stopTouchScrolling(event); }; this.scrollable.$element[0].addEventListener("touchend", this.elementTouchend); } }, removeTouchScrolling: function () { if (document.addEventListener) { this.scrollable.$element[0].removeEventListener("touchstart", this.elementTouchstart); document.removeEventListener("touchmove", this.documentTouchmove); this.scrollable.$element[0].removeEventListener("touchend", this.elementTouchend); } }, initMouseClickScrolling: function () { var _this = this; this.scrollBarClick = function (event) { _this.mouseClickScroll(event); }; this.$scrollBar.click(this.scrollBarClick); }, removeMouseClickScrolling: function () { this.$scrollBar.unbind("click", this.scrollBarClick); }, initWindowResize: function () { if (this.scrollable.options.updateOnWindowResize) { var _this = this; this.windowResize = function () { _this.resize(); }; $(window).resize(this.windowResize); } }, removeWindowResize: function () { $(window).unbind("resize", this.windowResize); }, isKeyScrolling: function (key) { return this.keyScrollDelta(key) != null; }, keyScrollDelta: function (key) { for (var scrollingKey in this.sizing.scrollingKeys) if (scrollingKey === key) { return this.sizing.scrollingKeys[key](this.viewPortSize); } return null; }, startMouseMoveScrolling: function (event) { this.mouseMoveScrolling = true; $("html").addClass("not-selectable"); this.setUnselectable($("html"), "on"); this.setScrollEvent(event); }, stopMouseMoveScrolling: function (event) { this.mouseMoveScrolling = false; $("html").removeClass("not-selectable"); this.setUnselectable($("html"), null); }, setUnselectable: function (element, value) { if (element.attr("unselectable") != value) { element.attr("unselectable", value); element.find(':not(input)').attr('unselectable', value); } }, mouseMoveScroll: function (event) { if (this.mouseMoveScrolling) { var delta = this.sizing.mouseDelta(this.scrollEvent, event); this.scrollThumbBy(delta); this.setScrollEvent(event); } }, startTouchScrolling: function (event) { if (event.touches && event.touches.length === 1) { this.setScrollEvent(event.touches[0]); this.touchScrolling = true; event.stopPropagation(); } }, touchScroll: function (event) { if (this.touchScrolling && event.touches && event.touches.length === 1) { var delta = -this.sizing.mouseDelta(this.scrollEvent, event.touches[0]) * this.scrollable.options.swipeSpeed; var scrolled = this.scrollOverviewBy(delta); if (scrolled) { event.stopPropagation(); event.preventDefault(); this.setScrollEvent(event.touches[0]); } } }, stopTouchScrolling: function (event) { this.touchScrolling = false; event.stopPropagation(); }, mouseWheelScroll: function (deltaX, deltaY) { var delta = -this.sizing.wheelDelta(deltaX, deltaY) * this.scrollable.options.wheelSpeed; if (delta !== 0) { return this.scrollOverviewBy(delta); } }, mouseClickScroll: function (event) { var delta = this.viewPortSize - 20; if (event["page" + this.sizing.scrollAxis()] < this.$thumb.offset()[this.sizing.offsetComponent()]){ // mouse click over thumb delta = -delta; } this.scrollOverviewBy(delta); }, keyScroll: function (event) { var keyDown = event.which; if (this.enabled && this.isKeyScrolling(keyDown)) { if (this.scrollOverviewBy(this.keyScrollDelta(keyDown))) { event.preventDefault(); } } }, scrollThumbBy: function (delta) { var thumbPosition = this.thumbPosition(); thumbPosition += delta; thumbPosition = this.positionOrMax(thumbPosition, this.maxThumbPosition); var oldScrollPercent = this.scrollPercent; this.scrollPercent = thumbPosition / this.maxThumbPosition; var overviewPosition = (thumbPosition * this.maxOverviewPosition) / this.maxThumbPosition; this.setScrollPosition(overviewPosition, thumbPosition); if (oldScrollPercent !== this.scrollPercent) { this.triggerCustomScroll(oldScrollPercent); return true; } else { return false; } }, thumbPosition: function () { return this.$thumb.position()[this.sizing.offsetComponent()]; }, scrollOverviewBy: function (delta) { var overviewPosition = this.overviewPosition() + delta; return this.scrollOverviewTo(overviewPosition, false); }, overviewPosition: function () { return -this.scrollable.$overview.position()[this.sizing.offsetComponent()]; }, scrollOverviewTo: function (overviewPosition, animate) { overviewPosition = this.positionOrMax(overviewPosition, this.maxOverviewPosition); var oldScrollPercent = this.scrollPercent; this.scrollPercent = overviewPosition / this.maxOverviewPosition; var thumbPosition = this.scrollPercent * this.maxThumbPosition; if (animate) { this.setScrollPositionWithAnimation(overviewPosition, thumbPosition); } else { this.setScrollPosition(overviewPosition, thumbPosition); } if (oldScrollPercent !== this.scrollPercent) { this.triggerCustomScroll(oldScrollPercent); return true; } else { return false; } }, positionOrMax: function (p, max) { if (p < 0) { return 0; } else if (p > max) { return max; } else { return p; } }, triggerCustomScroll: function (oldScrollPercent) { this.scrollable.$element.trigger("customScroll", { scrollAxis: this.sizing.scrollAxis(), direction: this.sizing.scrollDirection(oldScrollPercent, this.scrollPercent), scrollPercent: this.scrollPercent * 100 } ); }, rescroll: function (keepPosition) { if (keepPosition) { var overviewPosition = this.positionOrMax(this.overviewPosition(), this.maxOverviewPosition); this.scrollPercent = overviewPosition / this.maxOverviewPosition; var thumbPosition = this.scrollPercent * this.maxThumbPosition; this.setScrollPosition(overviewPosition, thumbPosition); } else { var thumbPosition = this.scrollPercent * this.maxThumbPosition; var overviewPosition = this.scrollPercent * this.maxOverviewPosition; this.setScrollPosition(overviewPosition, thumbPosition); } }, setScrollPosition: function (overviewPosition, thumbPosition) { this.$thumb.css(this.sizing.offsetComponent(), thumbPosition + "px"); this.scrollable.$overview.css(this.sizing.offsetComponent(), -overviewPosition + "px"); }, setScrollPositionWithAnimation: function (overviewPosition, thumbPosition) { var thumbAnimationOpts = {}; var overviewAnimationOpts = {}; thumbAnimationOpts[this.sizing.offsetComponent()] = thumbPosition + "px"; this.$thumb.animate(thumbAnimationOpts, this.scrollable.options.animationSpeed); overviewAnimationOpts[this.sizing.offsetComponent()] = -overviewPosition + "px"; this.scrollable.$overview.animate(overviewAnimationOpts, this.scrollable.options.animationSpeed); }, calculateMaxThumbPosition: function () { return this.sizing.size(this.$scrollBar) - this.thumbSize; }, calculateMaxOverviewPosition: function () { return this.sizing.size(this.scrollable.$overview) - this.sizing.size(this.scrollable.$viewPort); }, setScrollEvent: function (event) { var attr = "page" + this.sizing.scrollAxis(); if (!this.scrollEvent || this.scrollEvent[attr] !== event[attr]) { this.scrollEvent = {pageX: event.pageX, pageY: event.pageY}; } }, scrollToElement: function (element) { var $element = $(element); if (this.sizing.isInside($element, this.scrollable.$overview) && !this.sizing.isInside($element, this.scrollable.$viewPort)) { var elementOffset = $element.offset(); var overviewOffset = this.scrollable.$overview.offset(); var viewPortOffset = this.scrollable.$viewPort.offset(); this.scrollOverviewTo(elementOffset[this.sizing.offsetComponent()] - overviewOffset[this.sizing.offsetComponent()], true); } }, remove: function () { this.removeMouseMoveScrolling(); this.removeMouseWheelScrolling(); this.removeTouchScrolling(); this.removeMouseClickScrolling(); this.removeWindowResize(); } }; var HSizing = function () { }; HSizing.prototype = { size: function ($el, arg) { if (arg) { return $el.width(arg); } else { return $el.width(); } }, minSize: function ($el) { return parseInt($el.css("min-width")) || 0; }, fixedThumbSize: function (options) { return options.fixedThumbWidth; }, scrollBar: function ($el) { return $el.find(".scroll-bar.horizontal"); }, mouseDelta: function (event1, event2) { return event2.pageX - event1.pageX; }, offsetComponent: function () { return "left"; }, wheelDelta: function (deltaX, deltaY) { return deltaX; }, scrollAxis: function () { return "X"; }, scrollDirection: function (oldPercent, newPercent) { return oldPercent < newPercent ? "right" : "left"; }, scrollingKeys: { 37: function (viewPortSize) { return -10; //arrow left }, 39: function (viewPortSize) { return 10; //arrow right } }, isInside: function (element, wrappingElement) { var $element = $(element); var $wrappingElement = $(wrappingElement); var elementOffset = $element.offset(); var wrappingElementOffset = $wrappingElement.offset(); return (elementOffset.left >= wrappingElementOffset.left) && (elementOffset.left + $element.width() <= wrappingElementOffset.left + $wrappingElement.width()); } }; var VSizing = function () { }; VSizing.prototype = { size: function ($el, arg) { if (arg) { return $el.height(arg); } else { return $el.height(); } }, minSize: function ($el) { return parseInt($el.css("min-height")) || 0; }, fixedThumbSize: function (options) { return options.fixedThumbHeight; }, scrollBar: function ($el) { return $el.find(".scroll-bar.vertical"); }, mouseDelta: function (event1, event2) { return event2.pageY - event1.pageY; }, offsetComponent: function () { return "top"; }, wheelDelta: function (deltaX, deltaY) { return deltaY; }, scrollAxis: function () { return "Y"; }, scrollDirection: function (oldPercent, newPercent) { return oldPercent < newPercent ? "down" : "up"; }, scrollingKeys: { 38: function (viewPortSize) { return -10; //arrow up }, 40: function (viewPortSize) { return 10; //arrow down }, 33: function (viewPortSize) { return -(viewPortSize - 20); //page up }, 34: function (viewPortSize) { return viewPortSize - 20; //page down } }, isInside: function (element, wrappingElement) { var $element = $(element); var $wrappingElement = $(wrappingElement); var elementOffset = $element.offset(); var wrappingElementOffset = $wrappingElement.offset(); return (elementOffset.top >= wrappingElementOffset.top) && (elementOffset.top + $element.height() <= wrappingElementOffset.top + $wrappingElement.height()); } }; return this.each(function () { if (options === undefined) { options = defaultOptions; } if (typeof(options) === "string") { var scrollable = $(this).data("scrollable"); if (scrollable) { scrollable[options](args); } } else if (typeof(options) === "object") { options = $.extend(defaultOptions, options); new Scrollable($(this), options); } else { throw "Invalid type of options"; } }); }; })(jQuery); (function ($) { var types = ['DOMMouseScroll', 'mousewheel']; if ($.event.fixHooks) { for (var i = types.length; i;) { $.event.fixHooks[ types[--i] ] = $.event.mouseHooks; } } $.event.special.mousewheel = { setup: function () { if (this.addEventListener) { for (var i = types.length; i;) { this.addEventListener(types[--i], handler, false); } } else { this.onmousewheel = handler; } }, teardown: function () { if (this.removeEventListener) { for (var i = types.length; i;) { this.removeEventListener(types[--i], handler, false); } } else { this.onmousewheel = null; } } }; $.fn.extend({ mousewheel: function (fn) { return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel"); }, unmousewheel: function (fn) { return this.unbind("mousewheel", fn); } }); function handler(event) { var orgEvent = event || window.event, args = [].slice.call(arguments, 1), delta = 0, returnValue = true, deltaX = 0, deltaY = 0; event = $.event.fix(orgEvent); event.type = "mousewheel"; // Old school scrollwheel delta if (orgEvent.wheelDelta) { delta = orgEvent.wheelDelta / 120; } if (orgEvent.detail) { delta = -orgEvent.detail / 3; } // New school multidimensional scroll (touchpads) deltas deltaY = delta; // Gecko if (orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS) { deltaY = 0; deltaX = delta; } // Webkit if (orgEvent.wheelDeltaY !== undefined) { deltaY = orgEvent.wheelDeltaY / 120; } if (orgEvent.wheelDeltaX !== undefined) { deltaX = orgEvent.wheelDeltaX / 120; } // Add event and delta to the front of the arguments args.unshift(event, delta, deltaX, deltaY); return ($.event.dispatch || $.event.handle).apply(this, args); } })(jQuery); $.fn.extend({ jlScroll: function() { $(this).find('.jl-scrollbar').each(function(index, element) { $(element).addClass('scroll-default'); $(element).customScrollbar({ updateOnWindowResize: true }); }); $(this).find('.jl-scrollbar-inner').each(function(index, element) { $(element).addClass('scroll-inner'); $(element).customScrollbar({ updateOnWindowResize: true, hScroll: false }); }) } }); $(function () { $('body').jlScroll(); });