﻿/**
* MooScroll beta [for mootools 1.2]
* @author Jason J. Jaeger | greengeckodesign.com
* @version 0.59
* @license MIT-style License
*			Permission is hereby granted, free of charge, to any person obtaining a copy
*			of this software and associated documentation files (the "Software"), to deal
*			in the Software without restriction, including without limitation the rights
*			to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
*			copies of the Software, and to permit persons to whom the Software is
*			furnished to do so, subject to the following conditions:
*	
*			The above copyright notice and this permission notice shall be included in
*			all copies or substantial portions of the Software.
*	
*			THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
*			IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
*			FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
*			AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
*			LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
*			OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
*			THE SOFTWARE.
**/
var MooScroll = new Class({ Implements: Options, options: { selector: ".scroll", increment: 30, upBtnClass: "upBtn", downBtnClass: "downBtn", scrollBarClass: "scrollBar", scrollHandleClass: "scrollHandle", scrollHandleBGClass: "scrollHandleBG", scrollHandleTopClass: "scrollHandleTop", scrollHandleMiddleClass: "scrollHandleMiddle", scrollHandleBottomClass: "scrollHandleBottom", scrollControlsYClass: "scrollControlsY", handleOpacity: 1, handleActiveOpacity: 0.85, disabledOpacity: 0.5, fullWindowMode: false, smoothMooScroll: { toAnchor: true, toMooScrollArea: true }, restrictedBrowsers: [Browser.Engine.presto925, Browser.Platform.ipod, Browser.Engine.webkit419] }, initialize: function(a) { if (this.options.restrictedBrowsers.contains(true)) { return } this.setOptions(a); this.mooScrollAreas = []; this.windowFxScroll = new Fx.Scroll(document.window, { wait: false }); $(document.body).getElements(this.options.selector).each(function(c, b) { var d = new MooScrollArea(this.options, c, this.windowFxScroll); this.mooScrollAreas.include(d); if (this.options.smoothMooScroll.toAnchor || this.options.smoothMooScroll.toMooScrollArea) { this.smoothMooScroll = new SmoothMooScroll({ toAnchor: this.options.smoothMooScroll.toAnchor, toMooScrollArea: this.options.smoothMooScroll.toMooScrollArea }, d.contentEl, this.windowFxScroll) } } .bind(this)) }, loadContent: function(a) { this.mooScrollAreas.each(function(c, b) { c.loadContent(a) }) }, refresh: function() { this.mooScrollAreas.each(function(b, a) { b.refresh() }) }, setSlider: function(a) { this.mooScrollAreas.each(function(c, b) { c.setSlider(a) }) } }); var MooScrollArea = new Class({ Implements: Options, initialize: function(a, b, c) { this.windowFxScroll = c; this.setOptions(a); this.parentEl = b.setProperty("rel", "MooScrollArea"); this.viewPort = { x: $(window).getSize().x, y: $(window).getSize().y }; this.parentElPadding = this.parentEl.getStyles("padding-top", "padding-right", "padding-bottom", "padding-left"); this.paddingHeight = parseFloat(this.parentEl.getStyle("padding-top")) + parseFloat(this.parentEl.getStyle("padding-bottom")); this.paddingWidth = parseFloat(this.parentEl.getStyle("padding-left")) + parseFloat(this.parentEl.getStyle("padding-right")); this.contentEl = new Element("div", { "class": "contentEl" }).adopt(this.parentEl.getChildren()).inject(this.parentEl, "top"); this.parentEl.setStyle("overflow", "hidden").setStyles({ padding: 0, width: parseFloat(this.parentEl.getStyle("width")) + this.paddingWidth, height: parseFloat(this.parentEl.getStyle("height")) + this.paddingHeight }); this.borderHeight = parseFloat(this.parentEl.getStyle("border-top-width")) + parseFloat(this.parentEl.getStyle("border-bottom-width")); this.contentEl.setStyles({ height: this.parentEl.getSize().y - this.borderHeight, overflow: "hidden", padding: 0 }); this.paddingEl = new Element("div", { "class": "paddingEl" }).adopt(this.contentEl.getChildren()).inject(this.contentEl, "top").setStyles(this.parentElPadding); if (this.options.fullWindowMode) { $(document).getElement("html").setStyle("overflow", "hidden"); this.parentEl.setStyles({ height: "100%", width: "100%", position: "absolute" }); this.contentEl.setStyles({ height: "100%", width: "100%", position: "absolute" }) } this.scrollControlsYWrapper = new Element("div", { "class": this.options.scrollControlsYClass }).inject(this.parentEl, "bottom"); this.upBtn = new Element("div", { "class": this.options.upBtnClass }).inject(this.scrollControlsYWrapper, "bottom"); this.downBtn = new Element("div", { "class": this.options.downBtnClass }).inject(this.scrollControlsYWrapper, "bottom"); this.scrollBar = new Element("div", { "class": this.options.scrollBarClass }).inject(this.scrollControlsYWrapper, "bottom"); this.scrollHandle = new Element("div", { "class": this.options.scrollHandleClass }).inject(this.scrollBar, "inside"); this.scrollHandleTop = new Element("div", { "class": this.options.scrollHandleTopClass }).inject(this.scrollHandle, "inside"); this.scrollHandleBG = new Element("div", { "class": this.options.scrollHandleBGClass }).inject(this.scrollHandle, "inside"); this.scrollHandleMiddle = new Element("div", { "class": this.options.scrollHandleMiddleClass }).inject(this.scrollHandle, "inside"); this.scrollHandleBottom = new Element("div", { "class": this.options.scrollHandleBottomClass }).inject(this.scrollHandle, "inside"); this.coverUp = new Element("div").inject(this.scrollControlsYWrapper, "bottom"); this.fixIE6CSSbugs(); this.overHang = this.paddingEl.getSize().y - this.parentEl.getSize().y; this.setHandleHeight(); if (this.overHang <= 0) { this.greyOut(); return } this.initSlider(); this.parentEl.addEvents({ mousewheel: function(d) { d = new Event(d).stop(); if (d.wheel > 0) { this.scrollUp(true) } else { if (d.wheel < 0) { this.scrollDown(true) } } } .bind(this), keydown: function(d) { if (d.key === "up") { d = new Event(d).stop(); this.scrollUp(true) } else { if (d.key === "down" || d.key === "space") { d = new Event(d).stop(); this.scrollDown(true) } } } .bind(this), click: function(d) { this.hasFocus = true; this.hasFocusTimeout = (function() { $clear(this.hasFocusTimeout); this.hasFocus = true } .bind(this)).delay(50) } .bind(this) }); this.contentEl.addEvents({ scroll: function(d) { this.slider.set(this.contentEl.getScroll().y) } .bind(this) }); this.scrollHandle.addEvents({ mousedown: function(d) { this.scrollHandle.addClass(this.options.scrollHandleClass + "-Active").setStyle("opacity", this.options.handleActiveOpacity) } .bind(this) }); document.addEvents({ mouseup: function(d) { this.scrollHandle.removeClass(this.options.scrollHandleClass + "-Active").setStyle("opacity", this.options.handleOpacity); this.upBtn.removeClass(this.options.upBtnClass + "-Active"); this.downBtn.removeClass(this.options.downBtnClass + "-Active") } .bind(this), keydown: function(d) { if ((this.hasFocus || this.options.fullWindowMode) && (d.key === "down" || d.key === "space" || d.key === "up")) { this.parentEl.fireEvent("keydown", d) } } .bind(this), click: function(d) { this.hasFocus = false } .bind(this) }); window.addEvent("resize", function() { $clear(this.refreshTimeout); if (this.options.fullWindowMode) { this.refreshTimeout = (function() { $clear(this.refreshTimeout); if (this.viewPort.x != $(window).getSize().x || this.viewPort.y != $(window).getSize().y) { this.refresh(); this.viewPort.x = $(window).getSize().x; this.viewPort.y = $(window).getSize().y } } .bind(this)).delay(250) } } .bind(this)); this.upBtn.addEvents({ mousedown: function(d) { $clear(this.upInterval); $clear(this.downInterval); this.upInterval = this.scrollUp.periodical(10, this); this.upBtn.addClass(this.options.upBtnClass + "-Active") } .bind(this), mouseup: function(d) { $clear(this.upInterval); $clear(this.downInterval) } .bind(this), mouseout: function(d) { $clear(this.upInterval); $clear(this.downInterval) } .bind(this) }); this.downBtn.addEvents({ mousedown: function(d) { $clear(this.upInterval); $clear(this.downInterval); this.downInterval = this.scrollDown.periodical(10, this); this.downBtn.addClass(this.options.downBtnClass + "-Active") } .bind(this), mouseup: function(d) { $clear(this.upInterval); $clear(this.downInterval) } .bind(this), mouseout: function(d) { $clear(this.upInterval); $clear(this.downInterval) } .bind(this) }) }, initSlider: function() { this.slider = new Slider(this.scrollBar, this.scrollHandle, { range: [0, Math.round(this.overHang)], mode: "vertical", onChange: function(a, b) { this.contentEl.scrollTo(0, a); this.webKitKludge(a) } .bind(this) }).set(0) }, webKitKludge: function(a) { if (!Browser.Engine.webkit) { return } if (this.step > a) { this.step = a; return } $clear(this.sliderTimeout); this.sliderTimeout = (function() { $clear(this.sliderTimeout); var b = (1 * this.paddingEl.getSize().y) / 100; if ((b + a) >= this.overHang) { if (this.paddingElTopMargin == null) { this.paddingElTopMargin = parseFloat(this.paddingEl.getStyle("margin-top")) } this.paddingEl.setStyle("margin-top", this.paddingElTopMargin - b); if (!this.scrollHandleTopMargin) { this.scrollHandleTopMargin = parseFloat(this.scrollHandle.getStyle("margin-top")) } this.scrollHandle.setStyle("margin-top", this.scrollHandleTopMargin + 2); this.contentEl.scrollTo(0, this.overHang); this.step = this.overHang } else { this.paddingEl.setStyle("margin-top", this.paddingElTopMargin); this.scrollHandle.setStyle("margin-top", this.scrollHandleTopMargin); this.contentEl.scrollTo(0, a); this.step = a } } .bind(this)).delay(10) }, scrollUp: function(a) { var b = this.contentEl.getScroll().y - 30; this.slider.set(b); if (this.contentEl.getScroll().y <= 0 && a) { document.window.scrollTo(0, document.window.getScroll().y - this.options.increment) } }, scrollDown: function(c) { var d = this.contentEl.getScroll().y + this.options.increment; this.slider.set(d); var a = (1 * this.paddingEl.getSize().y) / 100; var b = (this.paddingEl.getSize().y - this.parentEl.getSize().y) <= (this.contentEl.getScroll().y + a); if (b && c) { document.window.scrollTo(0, document.window.getScroll().y + this.options.increment) } }, fixIE6CSSbugs: function() { if (Browser.Engine.trident4) { this.parentEl.setStyle("height", this.parentEl.getStyle("height")); this.contentEl.setStyle("height", this.parentEl.getStyle("height")); var c = this.scrollBar.getStyle("top").toInt(); var a = this.scrollBar.getStyle("bottom").toInt(); var b = this.parentEl.getSize().y - this.borderHeight; this.scrollControlsYWrapper.setStyles({ height: b }); this.scrollBar.setStyles({ height: b - c - a }) } }, setHandleHeight: function() { var a = (100 - ((this.overHang * 100) / this.paddingEl.getSize().y)); this.handleHeight = ((a * this.parentEl.getSize().y) / 100) - (this.scrollHandleTop.getSize().y + this.scrollHandleBottom.getSize().y); if ((this.handleHeight + this.scrollHandleTop.getSize().y + this.scrollHandleBottom.getSize().y) >= this.scrollBar.getSize().y) { this.handleHeight -= (this.scrollHandleTop.getSize().y + this.scrollHandleBottom.getSize().y) * 2 } if (this.scrollHandle.getStyle("min-height") && this.handleHeight < parseFloat(this.scrollHandle.getStyle("min-height"))) { this.handleHeight = parseFloat(this.scrollHandle.getStyle("min-height")) + this.scrollHandleBottom.getSize().y + this.scrollHandleTop.getSize().y } this.scrollHandle.setStyles({ height: this.handleHeight }) }, greyOut: function() { this.scrollHandle.setStyles({ display: "none" }); this.upBtn.setStyles({ opacity: this.options.disabledOpacity }); this.scrollControlsYWrapper.setStyles({ opacity: this.options.disabledOpacity }); this.downBtn.setStyles({ opacity: this.options.disabledOpacity }); this.scrollBar.setStyles({ opacity: this.options.disabledOpacity }); this.coverUp.setStyles({ display: "block", position: "absolute", background: "white", opacity: 0.01, right: "0", top: "0", width: "100%", height: this.scrollControlsYWrapper.getSize().y }) }, unGrey: function() { this.scrollHandle.setStyles({ display: "block", height: "auto" }); this.scrollControlsYWrapper.setStyles({ opacity: 1 }); this.upBtn.setStyles({ opacity: 1 }); this.downBtn.setStyles({ opacity: 1 }); this.scrollBar.setStyles({ opacity: 1 }); this.coverUp.setStyles({ display: "none", width: 0, height: 0 }); this.setHandleHeight() }, loadContent: function(a) { this.slider.set(0); this.paddingEl.empty().set("html", a); this.refresh() }, refresh: function() { var a = Math.round(((100 * this.step) / this.overHang)); if (this.options.fullWindowMode) { var b = $(window).getSize(); this.parentEl.setStyles({ width: "100%", height: "100%" }) } this.fixIE6CSSbugs(); this.overHang = this.paddingEl.getSize().y - this.parentEl.getSize().y; this.setHandleHeight(); if (this.overHang <= 0) { this.greyOut(); return } else { this.unGrey() } this.scrollHandle.removeEvents(); var c = Math.round((a * this.overHang) / 100); this.initSlider(); this.slider.set(c); if (Browser.Engine.trident4) { this.scrollHandleBG.setStyle("height", "0").setStyle("height", "100%") } if (this.options.smoothMooScroll.toAnchor || this.options.smoothMooScroll.toMooScrollArea) { this.smoothMooScroll = new SmoothMooScroll({ toAnchor: this.options.smoothMooScroll.toAnchor, toMooScrollArea: this.options.smoothMooScroll.toMooScrollArea }, this.contentEl, this.windowFxScroll) } }, setSlider: function(a) { if (a == "top") { this.slider.set(0) } else { if (a == "bottom") { this.slider.set("100%") } else { this.slider.set(a) } } } }); var SmoothMooScroll = new Class({ Extends: Fx.Scroll, initialize: function(b, c, d) { this.setOptions(b); this.windowFxScroll = d; this.context = c; c = c || document; this.context = c; var f = c.getDocument(), e = c.getWindow(); this.parent(c, b); this.links = (this.options.links) ? $$(this.options.links) : $$(f.links); var a = e.location.href.match(/^[^#]*/)[0] + "#"; this.links.each(function(h) { if (h.href.indexOf(a) != 0) { return } var g = h.href.substr(a.length); if (g && $(g) && $(g).getParents().contains($(this.context))) { this.useLink(h, g, true) } else { if (g && $(g) && !this.inMooScrollArea($(g))) { this.useLink(h, g, false) } } }, this); if (!Browser.Engine.webkit419) { this.addEvent("complete", function() { e.location.hash = this.anchor }, true) } }, inMooScrollArea: function(a) { return a.getParents().filter(function(c, b) { return c.match("[rel=MooScrollArea]") }).length > 0 }, putAnchorInAddressBar: function(a) { window.location.href = "#" + a }, useLink: function(b, a, c) { b.removeEvents("click"); b.addEvent("click", function(d) { if (!a || !$(a)) { return } this.anchor = a; if (c) { if (this.options.toMooScrollArea && this.options.toAnchor) { this.windowFxScroll.toElement(this.context.getParent()).chain(function(f, e) { this.toElement(a).chain(function() { this.putAnchorInAddressBar(a) } .bind(this)) } .bind(this)) } else { if (this.options.toMooScrollArea) { this.windowFxScroll.toElement(this.context.getParent()).chain(function() { this.putAnchorInAddressBar(a) } .bind(this)) } else { if (this.options.toAnchor) { this.toElement(a).chain(function() { this.putAnchorInAddressBar(a) } .bind(this)) } } } } else { this.windowFxScroll.toElement(a).chain(function() { this.putAnchorInAddressBar(a) } .bind(this)) } d.stop() } .bind(this)) } });
