This repository has been archived on 2018-10-12. You can view files and clone it, but cannot push or open issues or pull requests.
node-task/public/js/ink.smoothscroller.js

200 lines
6.7 KiB
JavaScript

/**
* Scroll to content
* @module Ink.UI.SmoothScroller_1
* @version 1
*/
Ink.createModule('Ink.UI.SmoothScroller', '1', ['Ink.UI.Common_1', 'Ink.Dom.Event_1', 'Ink.Dom.Element_1', 'Ink.Dom.Selector_1','Ink.Dom.Css_1'], function(Common, Event, InkElement, Selector, Css) {
'use strict';
var requestAnimationFrame =
window.requestAnimationFrame ||
function (cb) { return setTimeout(cb, 10); };
var cancelAnimationFrame =
window.cancelAnimationFrame ||
function (id) { clearTimeout(id); };
/**
* @namespace SmoothScroller
* @version 1
* @static
*
* SmoothScroller is a component which replaces the default scroll-to behaviour of `<a>` tags which refer to IDs on the page.
*
* For example, when you have this:
*
* <a href="#todo">Todo</a>
* [...]
* <section id="todo">
* [...]
*
* You can click the `<a>` and the page will scroll until the section you pointed to.
*
* When you use SmoothScroller, instead of immediately scrolling to the element, you get a smooth motion.
*
* Also, you can define the data-margin option if you have a `position:fixed` top menu ruining the behaviour.
*
* @example
*
*/
var SmoothScroller = {
/**
* The default scrolling speed. Higher is slower. Defaults to 10.
*
* @property speed
* @type {Number}
* @default 10
* @static
*/
speed: 10,
/**
* Change the URL hash (location.hash) when done scrolling? Defaults to true.
*
* @property changeHash
* @default true
* @type {Boolean}
* @static
*/
changeHash: true,
/**
* The default top margin.
* Use this when you want the scroll motion to stop before it reaches its destination, for example when you want to add some breathing space or have a position:fixed top bar in front of your content.
*
* @property margin
* @default 0
* @type {Number}
* @static
*/
margin: 0,
/**
* Moves the scrollbar to the target element. This is the function
* which animates the scroll position bit by bit. It calls itself in
* the end through requestAnimationFrame
*
* @method scroll
* @param {Number} d Y coordinate value to stop
* @private
* @static
*/
scroll: function(d, options) {
var a = Math.round(InkElement.scrollHeight());
var endPos = Math.round(d - options.margin);
if (endPos > a) {
a += Math.ceil((endPos - a) / options.speed);
} else {
a = a + (endPos - a) / options.speed;
}
cancelAnimationFrame(SmoothScroller.interval);
if (!((a) === endPos || SmoothScroller.offsetTop === a)) {
SmoothScroller.interval = requestAnimationFrame(
Ink.bindMethod(SmoothScroller, 'scroll', d, options), document.body);
} else {
SmoothScroller.onDone(options);
}
window.scrollTo(0, a);
SmoothScroller.offsetTop = a;
},
/**
* Has smooth scrolling applied to relevant elements upon page load.
* Listens to the click event on the document.
* Anything which matches the selector will be considered a "link" by SmoothScroller and handled as such.
*
* When a link is clicked, it is checked for several options:
* - `data-margin="0"` - A margin in pixels -- useful when you have a position:fixed top bar.
* - `data-speed="10"` - Inverse speed of the scrolling motion. Smaller is faster.
* - `data-change-hash="true"` - Change the URL hash (location.hash) when done scrolling.
*
* @method init
* @param [selector='a.scrollableLink,a.ink-smooth-scroll'] {String} Selector string for finding links with smooth scrolling enabled.
* @static
* @sample Ink_UI_SmoothScroller_1.html
*/
init: function(selector) {
Event.on(document, 'click', selector || 'a.scrollableLink, a.ink-smooth-scroll', SmoothScroller.onClick);
},
// Deprecated. Kept around just in case someone is still calling this.
render: function() {},
/**
* Handles clicks on link elements
*
* @method onClick
* @private
* @static
*/
onClick: function(event) {
var link = event.currentTarget;
var thisDocument = (location + '').replace(/#.*?$/, '');
var linkedDocument = (link.href + '').replace(/#.*?$/, '');
if (linkedDocument !== thisDocument) {
return; // It's an external link.
}
var hash = link.getAttribute('data-hash') || (link.getAttribute('href') || '')
.replace(/^.*?#/, '');
if(hash) {
event.preventDefault();
var activeLiSelector = 'ul > li.active > ' + selector;
var selector = 'a[name="' + hash + '"],#' + hash;
var elm = Ink.s(selector);
var activeLi = Ink.s(activeLiSelector);
activeLi = activeLi && activeLi.parentNode;
if (elm) {
if (!Css.hasClassName(link.parentNode, 'active')) {
if (activeLi) {
Css.removeClassName(activeLi, 'active');
}
Css.addClassName(link.parentNode, 'active');
}
var options = Common.options('SmoothScroller link options', {
margin: ['Number', SmoothScroller.margin],
speed: ['Number', SmoothScroller.speed],
changeHash: ['Boolean', SmoothScroller.changeHash]
}, {}, link);
SmoothScroller.hash = hash;
SmoothScroller.scroll(InkElement.offsetTop(elm), options);
}
}
},
/**
* Called when the scroll movement is done. Updates browser address.
*
* @method onDone
* @param {Object} options Options object from the element.
* @private
*/
onDone: function (options) {
if (options.changeHash === true) {
window.location.hash = SmoothScroller.hash;
}
SmoothScroller.hash = SmoothScroller.offsetTop = null;
}
};
return SmoothScroller;
});