fix #502: add smoothscroll polyfill

This commit is contained in:
juliandescottes 2016-10-02 00:23:26 +02:00
parent 9538e03928
commit 71ec809aea
4 changed files with 301 additions and 1 deletions

View File

@ -35,7 +35,7 @@
// Ensure the currently the selected layer is visible.
var currentLayerEl = this.layersListEl.querySelector('.current-layer-item');
if (currentLayerEl) {
currentLayerEl.scrollIntoView();
currentLayerEl.scrollIntoView({behavior: 'smooth'});
}
};

View File

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2013 Dustan Kasten
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.

View File

@ -0,0 +1,277 @@
/*
* smoothscroll polyfill - v0.3.3
* https://iamdustan.github.io/smoothscroll
* 2016 (c) Dustan Kasten, Jeremias Menichelli - MIT License
*/
(function(w, d, undefined) {
'use strict';
/*
* aliases
* w: window global object
* d: document
* undefined: undefined
*/
// polyfill
function polyfill() {
// return when scrollBehavior interface is supported
if ('scrollBehavior' in d.documentElement.style) {
return;
}
/*
* globals
*/
var Element = w.HTMLElement || w.Element;
var SCROLL_TIME = 468;
/*
* object gathering original scroll methods
*/
var original = {
scroll: w.scroll || w.scrollTo,
scrollBy: w.scrollBy,
scrollIntoView: Element.prototype.scrollIntoView
};
/*
* define timing method
*/
var now = w.performance && w.performance.now
? w.performance.now.bind(w.performance) : Date.now;
/**
* changes scroll position inside an element
* @method scrollElement
* @param {Number} x
* @param {Number} y
*/
function scrollElement(x, y) {
this.scrollLeft = x;
this.scrollTop = y;
}
/**
* returns result of applying ease math function to a number
* @method ease
* @param {Number} k
* @returns {Number}
*/
function ease(k) {
return 0.5 * (1 - Math.cos(Math.PI * k));
}
/**
* indicates if a smooth behavior should be applied
* @method shouldBailOut
* @param {Number|Object} x
* @returns {Boolean}
*/
function shouldBailOut(x) {
if (typeof x !== 'object'
|| x.behavior === undefined
|| x.behavior === 'auto'
|| x.behavior === 'instant') {
// first arg not an object, or behavior is auto, instant or undefined
return true;
}
if (typeof x === 'object'
&& x.behavior === 'smooth') {
// first argument is an object and behavior is smooth
return false;
}
// throw error when behavior is not supported
throw new TypeError('behavior not valid');
}
/**
* finds scrollable parent of an element
* @method findScrollableParent
* @param {Node} el
* @returns {Node} el
*/
function findScrollableParent(el) {
do {
el = el.parentNode;
} while (el !== d.body
&& !(el.clientHeight < el.scrollHeight
|| el.clientWidth < el.scrollWidth));
return el;
}
/**
* self invoked function that, given a context, steps through scrolling
* @method step
* @param {Object} context
*/
function step(context) {
// call method again on next available frame
context.frame = w.requestAnimationFrame(step.bind(w, context));
var time = now();
var value;
var currentX;
var currentY;
var elapsed = (time - context.startTime) / SCROLL_TIME;
// avoid elapsed times higher than one
elapsed = elapsed > 1 ? 1 : elapsed;
// apply easing to elapsed time
value = ease(elapsed);
currentX = context.startX + (context.x - context.startX) * value;
currentY = context.startY + (context.y - context.startY) * value;
context.method.call(context.scrollable, currentX, currentY);
// return when end points have been reached
if (currentX === context.x && currentY === context.y) {
w.cancelAnimationFrame(context.frame);
return;
}
}
/**
* scrolls window with a smooth behavior
* @method smoothScroll
* @param {Object|Node} el
* @param {Number} x
* @param {Number} y
*/
function smoothScroll(el, x, y) {
var scrollable;
var startX;
var startY;
var method;
var startTime = now();
var frame;
// define scroll context
if (el === d.body) {
scrollable = w;
startX = w.scrollX || w.pageXOffset;
startY = w.scrollY || w.pageYOffset;
method = original.scroll;
} else {
scrollable = el;
startX = el.scrollLeft;
startY = el.scrollTop;
method = scrollElement;
}
// cancel frame when a scroll event's happening
if (frame) {
w.cancelAnimationFrame(frame);
}
// scroll looping over a frame
step({
scrollable: scrollable,
method: method,
startTime: startTime,
startX: startX,
startY: startY,
x: x,
y: y,
frame: frame
});
}
/*
* ORIGINAL METHODS OVERRIDES
*/
// w.scroll and w.scrollTo
w.scroll = w.scrollTo = function() {
// avoid smooth behavior if not required
if (shouldBailOut(arguments[0])) {
original.scroll.call(
w,
arguments[0].left || arguments[0],
arguments[0].top || arguments[1]
);
return;
}
// LET THE SMOOTHNESS BEGIN!
smoothScroll.call(
w,
d.body,
~~arguments[0].left,
~~arguments[0].top
);
};
// w.scrollBy
w.scrollBy = function() {
// avoid smooth behavior if not required
if (shouldBailOut(arguments[0])) {
original.scrollBy.call(
w,
arguments[0].left || arguments[0],
arguments[0].top || arguments[1]
);
return;
}
// LET THE SMOOTHNESS BEGIN!
smoothScroll.call(
w,
d.body,
~~arguments[0].left + (w.scrollX || w.pageXOffset),
~~arguments[0].top + (w.scrollY || w.pageYOffset)
);
};
// Element.prototype.scrollIntoView
Element.prototype.scrollIntoView = function() {
// avoid smooth behavior if not required
if (shouldBailOut(arguments[0])) {
original.scrollIntoView.call(this, arguments[0] || true);
return;
}
// LET THE SMOOTHNESS BEGIN!
var scrollableParent = findScrollableParent(this);
var parentRects = scrollableParent.getBoundingClientRect();
var clientRects = this.getBoundingClientRect();
if (scrollableParent !== d.body) {
// reveal element inside parent
smoothScroll.call(
this,
scrollableParent,
scrollableParent.scrollLeft + clientRects.left - parentRects.left,
scrollableParent.scrollTop + clientRects.top - parentRects.top
);
// reveal parent in viewport
w.scrollBy({
left: parentRects.left,
top: parentRects.top,
behavior: 'smooth'
});
} else {
// reveal element in viewport
w.scrollBy({
left: clientRects.left,
top: clientRects.top,
behavior: 'smooth'
});
}
};
}
if (typeof exports === 'object') {
// commonjs
module.exports = { polyfill: polyfill };
} else {
// global
polyfill();
}
})(window, document);

View File

@ -53,6 +53,9 @@
// JSZip https://github.com/Stuk/jszip
"js/lib/jszip/jszip.min.js",
// Smoothscroll: https://github.com/iamdustan/smoothscroll
"js/lib/smoothscroll/smoothscroll.js",
// Spectrum color-picker library
"js/lib/spectrum/spectrum.js",