summaryrefslogtreecommitdiff
path: root/_includes/scripts/lib
diff options
context:
space:
mode:
Diffstat (limited to '_includes/scripts/lib')
-rw-r--r--_includes/scripts/lib/affix.js111
-rw-r--r--_includes/scripts/lib/gallery.js192
-rw-r--r--_includes/scripts/lib/lazyload.js143
-rw-r--r--_includes/scripts/lib/modal.js64
-rw-r--r--_includes/scripts/lib/scroll-to.js13
-rw-r--r--_includes/scripts/lib/swiper.js203
-rw-r--r--_includes/scripts/lib/throttle.js28
-rw-r--r--_includes/scripts/lib/toc.js107
8 files changed, 861 insertions, 0 deletions
diff --git a/_includes/scripts/lib/affix.js b/_includes/scripts/lib/affix.js
new file mode 100644
index 0000000..779442f
--- /dev/null
+++ b/_includes/scripts/lib/affix.js
@@ -0,0 +1,111 @@
+(function() {
+ var SOURCES = window.TEXT_VARIABLES.sources;
+ window.Lazyload.js(SOURCES.jquery, function() {
+ function affix(options) {
+ var $root = this, $window = $(window), $scrollTarget, $scroll,
+ offsetBottom = 0, scrollTarget = window, scroll = window.document, disabled = false, isOverallScroller = true,
+ rootTop, rootLeft, rootHeight, scrollBottom, rootBottomTop,
+ hasInit = false, curState;
+
+ function setOptions(options) {
+ var _options = options || {};
+ _options.offsetBottom && (offsetBottom = _options.offsetBottom);
+ _options.scrollTarget && (scrollTarget = _options.scrollTarget);
+ _options.scroll && (scroll = _options.scroll);
+ _options.disabled !== undefined && (disabled = _options.disabled);
+ $scrollTarget = $(scrollTarget);
+ isOverallScroller = window.isOverallScroller($scrollTarget[0]);
+ $scroll = $(scroll);
+ }
+ function preCalc() {
+ top();
+ rootHeight = $root.outerHeight();
+ rootTop = $root.offset().top + (isOverallScroller ? 0 : $scrollTarget.scrollTop());
+ rootLeft = $root.offset().left;
+ }
+ function calc(needPreCalc) {
+ needPreCalc && preCalc();
+ scrollBottom = $scroll.outerHeight() - offsetBottom - rootHeight;
+ rootBottomTop = scrollBottom - rootTop;
+ }
+ function top() {
+ if (curState !== 'top') {
+ $root.removeClass('fixed').css({
+ left: 0,
+ top: 0
+ });
+ curState = 'top';
+ }
+ }
+ function fixed() {
+ if (curState !== 'fixed') {
+ $root.addClass('fixed').css({
+ left: rootLeft + 'px',
+ top: 0
+ });
+ curState = 'fixed';
+ }
+ }
+ function bottom() {
+ if (curState !== 'bottom') {
+ $root.removeClass('fixed').css({
+ left: 0,
+ top: rootBottomTop + 'px'
+ });
+ curState = 'bottom';
+ }
+ }
+ function setState() {
+ var scrollTop = $scrollTarget.scrollTop();
+ if (scrollTop >= rootTop && scrollTop <= scrollBottom) {
+ fixed();
+ } else if (scrollTop < rootTop) {
+ top();
+ } else {
+ bottom();
+ }
+ }
+ function init() {
+ if(!hasInit) {
+ var interval, timeout;
+ calc(true); setState();
+ // run calc every 100 millisecond
+ interval = setInterval(function() {
+ calc();
+ }, 100);
+ timeout = setTimeout(function() {
+ clearInterval(interval);
+ }, 45000);
+ window.pageLoad.then(function() {
+ setTimeout(function() {
+ clearInterval(interval);
+ clearTimeout(timeout);
+ }, 3000);
+ });
+ $scrollTarget.on('scroll', function() {
+ disabled || setState();
+ });
+ $window.on('resize', function() {
+ disabled || (calc(true), setState());
+ });
+ hasInit = true;
+ }
+ }
+
+ setOptions(options);
+ if (!disabled) {
+ init();
+ }
+ $window.on('resize', window.throttle(function() {
+ init();
+ }, 200));
+ return {
+ setOptions: setOptions,
+ refresh: function() {
+ calc(true, { animation: false }); setState();
+ }
+ };
+ }
+ $.fn.affix = affix;
+ });
+})();
diff --git a/_includes/scripts/lib/gallery.js b/_includes/scripts/lib/gallery.js
new file mode 100644
index 0000000..1793f04
--- /dev/null
+++ b/_includes/scripts/lib/gallery.js
@@ -0,0 +1,192 @@
+(function() {
+ {%- include scripts/lib/swiper.js -%}
+ var SOURCES = window.TEXT_VARIABLES.sources;
+ window.Lazyload.js(SOURCES.jquery, function() {
+ var template =
+ '<div class="swiper gallery__swiper">' +
+ '<div class="swiper__wrapper">' +
+ '</div>' +
+ '<div class="swiper__button swiper__button--prev fas fa-chevron-left"></div>' +
+ '<div class="swiper__button swiper__button--next fas fa-chevron-right"></div>' +
+ '</div>';
+ function setState($item, zoom, translate) {
+ $item.css('transform', 'scale(' + zoom + ') translate(' + translate.x + 'px,' + translate.y + 'px)');
+ }
+ function Gallery(root, items) {
+ this.$root = $(root);
+ this.$swiper = null;
+ this.$swiperWrapper = null;
+ this.$activeItem = null;
+ this.$items = [];
+ this.contentWidth = 0;
+ this.contentHeight = 0;
+ this.swiper = null;
+ this.items = items;
+ this.disabled = false;
+ this.curIndex = 0;
+ this.touchCenter = null;
+ this.lastTouchCenter = null;
+ this.zoomRect = null;
+ this.lastZoomRect = null;
+ this.lastTranslate = null;
+ this.translate = null;
+ this.lastZoom = 1;
+ this.preZoom = 1;
+ this.zoom = 1;
+ }
+ Gallery.prototype.init = function() {
+ var i, item, items = this.items, size, self = this, touchstartFingerCount = 0;
+ this.$root.append(template);
+ this.$swiper = this.$root.find('.gallery__swiper');
+ this.$swiperWrapper = this.$root.find('.swiper__wrapper');
+ this.contentWidth = this.$swiperWrapper && this.$swiperWrapper.width();
+ this.contentHeight = this.$swiperWrapper && this.$swiperWrapper.height();
+ for (i = 0; i < items.length; i++) {
+ item = items[i];
+ size = this._calculateImageSize(item.w, item.h);
+ this.$items.push($(
+ '<div class="swiper__slide">' +
+ '<div class="gallery-item">' +
+ '<div class="gallery-item__content">' +
+ '<img src="' + item.src + '" style="width:' + size.w + 'px;height:' + size.h + 'px"/>' +
+ '</div>' +
+ '</div>' +
+ '</div>'
+ ));
+ }
+ this.$swiperWrapper && this.$swiperWrapper.append(this.$items);
+ this.swiper = this.$swiper && this.$swiper.swiper({
+ onChangeEnd: function() {
+ self._handleChangeEnd.apply(self, Array.prototype.slice.call(arguments));
+ }
+ });
+ $(window).on('resize', function() {
+ if (self.disabled) { return; }
+ self._resizeImageSize();
+ });
+ // Char Code: 37 ⬅, 39 ➡
+ $(window).on('keyup', function(e) {
+ if (window.isFormElement(e.target || e.srcElement) || self.disabled) { return; }
+ if (e.which === 37) {
+ self.swiper && self.swiper.previous();
+ } else if (e.which === 39) {
+ self.swiper && self.swiper.next();
+ }
+ });
+ function getRect(touch0, touch1) {
+ return {
+ o: {
+ x: (touch0.pageX + touch1.pageX) / 2,
+ y: (touch0.pageY + touch1.pageY) / 2
+ },
+ w: Math.abs(touch0.pageX - touch1.pageX),
+ h: Math.abs(touch0.pageY - touch1.pageY)
+ };
+ }
+ function getTouches(e) {
+ return e.touches || e;
+ }
+ function getTouchesCount(e) {
+ if (e.touches) {
+ return e.touches.length;
+ } else {
+ return 1;
+ }
+ }
+ this.$swiperWrapper.on('touchstart', function(e) {
+ var touch0, touch1, rect;
+ touchstartFingerCount = getTouchesCount(e);
+ if (touchstartFingerCount > 1) {
+ touch0 = e.touches[0];
+ touch1 = e.touches[1];
+ rect = getRect(touch0, touch1);
+ self.lastZoomRect = { w: rect.w, h: rect.h };
+ self.lastTouchCenter = rect.o;
+ } else {
+ var touch = getTouches(e)[0];
+ self.lastTouchCenter = { x: touch.pageX, y: touch.pageY };
+ }
+ });
+ this.$swiperWrapper.on('touchmove', function(e) {
+ if (touchstartFingerCount === getTouchesCount(e)) {
+ if (touchstartFingerCount > 1) {
+ var touch0 = e.touches[0];
+ var touch1 = e.touches[1];
+ var rect = getRect(touch0, touch1);
+ self.zoomRect = { w: rect.w, h: rect.h };
+ self.touchCenter = rect.o;
+ self._zoom(); self._translate();
+ setState(self.$activeItem, self.zoom, self.translate);
+ } else {
+ var touch = getTouches(e)[0];
+ self.touchCenter = { x: touch.pageX, y: touch.pageY };
+ self._translate();
+ setState(self.$activeItem, self.zoom, self.translate);
+ }
+ }
+ });
+ this.$swiperWrapper.on('touchend', function(e) {
+ self.lastZoom = self.zoom;
+ self.lastTranslate = self.translate;
+ touchstartFingerCount = 0;
+ });
+ this.$root.on('touchmove', function(e) {
+ if (self.disabled) { return; }
+ e.preventDefault();
+ });
+ };
+
+ Gallery.prototype._translate = function() {
+ this.translate = this.touchCenter && this.lastTouchCenter && this.lastTranslate ? {
+ x: (this.touchCenter.x - this.lastTouchCenter.x) / this.zoom + this.lastTranslate.x,
+ y: (this.touchCenter.y - this.lastTouchCenter.y) / this.zoom + this.lastTranslate.y
+ } : { x: 0, y: 0 };
+ }
+ Gallery.prototype._zoom = function() {
+ this.zoom = (this.zoomRect.w + this.zoomRect.h) / (this.lastZoomRect.w + this.lastZoomRect.h) * this.lastZoom;
+ this.zoom > 1 ? this.$activeItem.addClass('zoom') : this.$activeItem.removeClass('zoom');
+ this.preZoom = this.zoom;
+ }
+
+ Gallery.prototype._calculateImageSize = function(w, h) {
+ var scale = 1;
+ if (this.contentWidth > 0 && this.contentHeight > 0 && w > 0 && h > 0) {
+ scale = Math.min(
+ Math.min(w, this.contentWidth) / w,
+ Math.min(h, this.contentHeight) / h);
+ }
+ return { w: Math.floor(w * scale), h: Math.floor(h * scale) };
+ };
+
+ Gallery.prototype._resizeImageSize = function() {
+ var i, $item, $items = this.$items, item, size;
+ this.contentWidth = this.$swiperWrapper && this.$swiperWrapper.width();
+ this.contentHeight = this.$swiperWrapper && this.$swiperWrapper.height();
+ if ($items.length < 1) { return; }
+ for (i = 0; i < $items.length; i++) {
+ item = this.items[i], $item = $items[i];
+ size = this._calculateImageSize(item.w, item.h);
+ item.width = size.w; item.height = size.h;
+ $item && $item.find('img').css({ width: size.w, height: size.h });
+ }
+ };
+ Gallery.prototype._handleChangeEnd = function(index, $dom, preIndex, $preDom) {
+ this.curIndex = index;
+ this.lastZoomRect = null; this.lastZoomRect = null;
+ this.lastTranslate = this.translate = { x: 0, y:0 };
+ this.lastZoom = this.preZoom = this.zoom = 1;
+ this.$activeItem = $dom.find('.gallery-item__content');
+ setState($preDom.find('.gallery-item__content'), this.zoom, this.translate);
+ };
+
+ Gallery.prototype.refresh = function() {
+ this.swiper && this.swiper.refresh();
+ this._resizeImageSize();
+ };
+ Gallery.prototype.setOptions = function(options) {
+ this.disabled = options.disabled;
+ this.swiper && this.swiper.setOptions(options);
+ };
+ window.Gallery = Gallery;
+ });
+})(); \ No newline at end of file
diff --git a/_includes/scripts/lib/lazyload.js b/_includes/scripts/lib/lazyload.js
new file mode 100644
index 0000000..9911535
--- /dev/null
+++ b/_includes/scripts/lib/lazyload.js
@@ -0,0 +1,143 @@
+(function() {
+ var Set = (function() {
+ var add = function(item) {
+ var i, data = this._data;
+ for (i = 0; i < data.length; i++) {
+ if (data[i] === item) {
+ return;
+ }
+ }
+ this.size ++;
+ data.push(item);
+ return data;
+ };
+
+ var Set = function(data) {
+ this.size = 0;
+ this._data = [];
+ var i;
+ if (data.length > 0) {
+ for (i = 0; i < data.length; i++) {
+ add.call(this, data[i]);
+ }
+ }
+ };
+ Set.prototype.add = add;
+ Set.prototype.get = function(index) { return this._data[index]; };
+ Set.prototype.has = function(item) {
+ var i, data = this._data;
+ for (i = 0; i < data.length; i++) {
+ if (this.get(i) === item) {
+ return true;
+ }
+ }
+ return false;
+ };
+ Set.prototype.is = function(map) {
+ if (map._data.length !== this._data.length) { return false; }
+ var i, j, flag, tData = this._data, mData = map._data;
+ for (i = 0; i < tData.length; i++) {
+ for (flag = false, j = 0; j < mData.length; j++) {
+ if (tData[i] === mData[j]) {
+ flag = true;
+ break;
+ }
+ }
+ if (!flag) { return false; }
+ }
+ return true;
+ };
+ Set.prototype.values = function() {
+ return this._data;
+ };
+ return Set;
+ })();
+
+ window.Lazyload = (function(doc) {
+ var queue = {js: [], css: []}, sources = {js: {}, css: {}}, context = this;
+ var createNode = function(name, attrs) {
+ var node = doc.createElement(name), attr;
+ for (attr in attrs) {
+ if (attrs.hasOwnProperty(attr)) {
+ node.setAttribute(attr, attrs[attr]);
+ }
+ }
+ return node;
+ };
+ var end = function(type, url) {
+ var s, q, qi, cbs, i, j, cur, val, flag;
+ if (type === 'js' || type ==='css') {
+ s = sources[type], q = queue[type];
+ s[url] = true;
+ for (i = 0; i < q.length; i++) {
+ cur = q[i];
+ if (cur.urls.has(url)) {
+ qi = cur, val = qi.urls.values();
+ qi && (cbs = qi.callbacks);
+ for (flag = true, j = 0; j < val.length; j++) {
+ cur = val[j];
+ if (!s[cur]) {
+ flag = false;
+ }
+ }
+ if (flag && cbs && cbs.length > 0) {
+ for (j = 0; j < cbs.length; j++) {
+ cbs[j].call(context);
+ }
+ qi.load = true;
+ }
+ }
+ }
+ }
+ };
+ var load = function(type, urls, callback) {
+ var s, q, qi, node, i, cur,
+ _urls = typeof urls === 'string' ? new Set([urls]) : new Set(urls), val, url;
+ if (type === 'js' || type ==='css') {
+ s = sources[type], q = queue[type];
+ for (i = 0; i < q.length; i++) {
+ cur = q[i];
+ if (_urls.is(cur.urls)) {
+ qi = cur;
+ break;
+ }
+ }
+ val = _urls.values();
+ if (qi) {
+ callback && (qi.load || qi.callbacks.push(callback));
+ callback && (qi.load && callback());
+ } else {
+ q.push({
+ urls: _urls,
+ callbacks: callback ? [callback] : [],
+ load: false
+ });
+ for (i = 0; i < val.length; i++) {
+ node = null, url = val[i];
+ if (s[url] === undefined) {
+ (type === 'js' ) && (node = createNode('script', { src: url }));
+ (type === 'css') && (node = createNode('link', { rel: 'stylesheet', href: url }));
+ if (node) {
+ node.onload = (function(type, url) {
+ return function() {
+ end(type, url);
+ };
+ })(type, url);
+ (doc.head || doc.body).appendChild(node);
+ s[url] = false;
+ }
+ }
+ }
+ }
+ }
+ };
+ return {
+ js: function(url, callback) {
+ load('js', url, callback);
+ },
+ css: function(url, callback) {
+ load('css', url, callback);
+ }
+ };
+ })(this.document);
+})();
diff --git a/_includes/scripts/lib/modal.js b/_includes/scripts/lib/modal.js
new file mode 100644
index 0000000..cb5d188
--- /dev/null
+++ b/_includes/scripts/lib/modal.js
@@ -0,0 +1,64 @@
+(function() {
+ var SOURCES = window.TEXT_VARIABLES.sources;
+ window.Lazyload.js(SOURCES.jquery, function() {
+ var $body = $('body'), $window = $(window);
+ var $pageRoot = $('.js-page-root'), $pageMain = $('.js-page-main');
+ var activeCount = 0;
+ function modal(options) {
+ var $root = this, visible, onChange, hideWhenWindowScroll = false;
+ var scrollTop;
+ function setOptions(options) {
+ var _options = options || {};
+ visible = _options.initialVisible === undefined ? false : show;
+ onChange = _options.onChange;
+ hideWhenWindowScroll = _options.hideWhenWindowScroll;
+ }
+ function init() {
+ setState(visible);
+ }
+ function setState(isShow) {
+ if (isShow === visible) {
+ return;
+ }
+ visible = isShow;
+ if (visible) {
+ activeCount++;
+ scrollTop = $(window).scrollTop() || $pageMain.scrollTop();
+ $root.addClass('modal--show');
+ $pageMain.scrollTop(scrollTop);
+ activeCount === 1 && ($pageRoot.addClass('show-modal'), $body.addClass('of-hidden'));
+ hideWhenWindowScroll && window.hasEvent('touchstart') && $window.on('scroll', hide);
+ $window.on('keyup', handleKeyup);
+ } else {
+ activeCount > 0 && activeCount--;
+ $root.removeClass('modal--show');
+ $window.scrollTop(scrollTop);
+ activeCount === 0 && ($pageRoot.removeClass('show-modal'), $body.removeClass('of-hidden'));
+ hideWhenWindowScroll && window.hasEvent('touchstart') && $window.off('scroll', hide);
+ $window.off('keyup', handleKeyup);
+ }
+ onChange && onChange(visible);
+ }
+ function show() {
+ setState(true);
+ }
+ function hide() {
+ setState(false);
+ }
+ function handleKeyup(e) {
+ // Char Code: 27 ESC
+ if (e.which === 27) {
+ hide();
+ }
+ }
+ setOptions(options);
+ init();
+ return {
+ show: show,
+ hide: hide,
+ $el: $root
+ };
+ }
+ $.fn.modal = modal;
+ });
+})();
diff --git a/_includes/scripts/lib/scroll-to.js b/_includes/scripts/lib/scroll-to.js
new file mode 100644
index 0000000..e5a0ea2
--- /dev/null
+++ b/_includes/scripts/lib/scroll-to.js
@@ -0,0 +1,13 @@
+(function() {
+ var SOURCES = window.TEXT_VARIABLES.sources;
+ window.Lazyload.js(SOURCES.jquery, function() {
+ function scrollToAnchor(anchor, duration, callback) {
+ var $root = this;
+ $root.animate({ scrollTop: $(anchor).position().top }, duration, function() {
+ window.history.replaceState(null, '', window.location.href.split('#')[0] + anchor);
+ callback && callback();
+ });
+ }
+ $.fn.scrollToAnchor = scrollToAnchor;
+ });
+})();
diff --git a/_includes/scripts/lib/swiper.js b/_includes/scripts/lib/swiper.js
new file mode 100644
index 0000000..3d06419
--- /dev/null
+++ b/_includes/scripts/lib/swiper.js
@@ -0,0 +1,203 @@
+(function() {
+ var SOURCES = window.TEXT_VARIABLES.sources;
+ window.Lazyload.js(SOURCES.jquery, function() {
+ function swiper(options) {
+ var $window = $(window), $root = this, $swiperWrapper, $swiperSlides, $swiperButtonPrev, $swiperButtonNext,
+ initialSlide, animation, onChange, onChangeEnd,
+ rootWidth, count, preIndex, curIndex, translateX, CRITICAL_ANGLE = Math.PI / 3;
+
+ function setOptions(options) {
+ var _options = options || {};
+ initialSlide = _options.initialSlide || 0;
+ animation = _options.animation === undefined && true;
+ onChange = onChange || _options.onChange;
+ onChangeEnd = onChangeEnd || _options.onChangeEnd;
+ }
+
+ function init() {
+ $swiperWrapper = $root.find('.swiper__wrapper');
+ $swiperSlides = $root.find('.swiper__slide');
+ $swiperButtonPrev = $root.find('.swiper__button--prev');
+ $swiperButtonNext = $root.find('.swiper__button--next');
+ animation && $swiperWrapper.addClass('swiper__wrapper--animation');
+ calc(true);
+ }
+
+ function preCalc() {
+ rootWidth = $root.width();
+ count = $swiperWrapper.children('.swiper__slide').length;
+ if (count < 2) {
+ $swiperButtonPrev.addClass('d-none');
+ $swiperButtonNext.addClass('d-none');
+ }
+ curIndex = initialSlide || 0;
+ translateX = getTranslateXFromCurIndex();
+ }
+
+ var calc = (function() {
+ var preAnimation, $swiperSlide, $preSwiperSlide;
+ return function (needPreCalc, params) {
+ needPreCalc && preCalc();
+ var _animation = (params && params.animation !== undefined) ? params.animation : animation;
+ if (preAnimation === undefined || preAnimation !== _animation) {
+ preAnimation = _animation ? $swiperWrapper.addClass('swiper__wrapper--animation') :
+ $swiperWrapper.removeClass('swiper__wrapper--animation');
+ }
+ if (preIndex !== curIndex) {
+ ($preSwiperSlide = $swiperSlides.eq(preIndex)).removeClass('active');
+ ($swiperSlide = $swiperSlides.eq(curIndex)).addClass('active');
+ onChange && onChange(curIndex, $swiperSlides.eq(curIndex), $swiperSlide, $preSwiperSlide);
+ if (onChangeEnd) {
+ if (_animation) {
+ setTimeout(function() {
+ onChangeEnd(curIndex, $swiperSlides.eq(curIndex), $swiperSlide, $preSwiperSlide);
+ }, 400);
+ } else {
+ onChangeEnd(curIndex, $swiperSlides.eq(curIndex), $swiperSlide, $preSwiperSlide);
+ }
+ }
+ preIndex = curIndex;
+ }
+ $swiperWrapper.css('transform', 'translate(' + translateX + 'px, 0)');
+ if (count > 1) {
+ if (curIndex <= 0) {
+ $swiperButtonPrev.addClass('disabled');
+ } else {
+ $swiperButtonPrev.removeClass('disabled');
+ }
+ if (curIndex >= count - 1) {
+ $swiperButtonNext.addClass('disabled');
+ } else {
+ $swiperButtonNext.removeClass('disabled');
+ }
+ }
+ };
+ })();
+
+ function getTranslateXFromCurIndex() {
+ return curIndex <= 0 ? 0 : - rootWidth * curIndex;
+ }
+
+ function moveToIndex(index ,params) {
+ preIndex = curIndex;
+ curIndex = index;
+ translateX = getTranslateXFromCurIndex();
+ calc(false, params);
+ }
+
+ function move(type) {
+ var nextIndex = curIndex, unstableTranslateX;
+ if (type === 'prev') {
+ nextIndex > 0 && nextIndex--;
+ } else if (type === 'next') {
+ nextIndex < count - 1 && nextIndex++;
+ }
+ if (type === 'cur') {
+ moveToIndex(curIndex, { animation: true });
+ return;
+ }
+ unstableTranslateX = translateX % rootWidth !== 0;
+ if (nextIndex !== curIndex || unstableTranslateX) {
+ unstableTranslateX ? moveToIndex(nextIndex, { animation: true }) : moveToIndex(nextIndex);
+ }
+ }
+
+ setOptions(options);
+ init();
+ preIndex = curIndex;
+
+ $swiperButtonPrev.on('click', function(e) {
+ e.stopPropagation();
+ move('prev');
+ });
+ $swiperButtonNext.on('click', function(e) {
+ e.stopPropagation();
+ move('next');
+ });
+ $window.on('resize', function() {
+ calc(true, { animation: false });
+ });
+
+ (function() {
+ var pageX, pageY, velocityX, preTranslateX = translateX, timeStamp, touching;
+ function handleTouchstart(e) {
+ var point = e.touches ? e.touches[0] : e;
+ pageX = point.pageX;
+ pageY = point.pageY;
+ velocityX = 0;
+ preTranslateX = translateX;
+ }
+ function handleTouchmove(e) {
+ if (e.touches && e.touches.length > 1) {
+ return;
+ }
+ var point = e.touches ? e.touches[0] : e;
+ var deltaX = point.pageX - pageX;
+ var deltaY = point.pageY - pageY;
+ velocityX = deltaX / (e.timeStamp - timeStamp);
+ timeStamp = e.timeStamp;
+ if (e.cancelable && Math.abs(Math.atan(deltaY / deltaX)) < CRITICAL_ANGLE) {
+ touching = true;
+ translateX += deltaX;
+ calc(false, { animation: false });
+ }
+ pageX = point.pageX;
+ pageY = point.pageY;
+ }
+ function handleTouchend() {
+ touching = false;
+ var deltaX = translateX - preTranslateX;
+ var distance = deltaX + velocityX * rootWidth;
+ if (Math.abs(distance) > rootWidth / 2) {
+ distance > 0 ? move('prev') : move('next');
+ } else {
+ move('cur');
+ }
+ }
+ $swiperWrapper.on('touchstart', handleTouchstart);
+ $swiperWrapper.on('touchmove', handleTouchmove);
+ $swiperWrapper.on('touchend', handleTouchend);
+ $swiperWrapper.on('touchcancel', handleTouchend);
+
+ (function() {
+ var pressing = false, moved = false;
+ $swiperWrapper.on('mousedown', function(e) {
+ pressing = true; handleTouchstart(e);
+ });
+ $swiperWrapper.on('mousemove', function(e) {
+ pressing && (e.preventDefault(), moved = true, handleTouchmove(e));
+ });
+ $swiperWrapper.on('mouseup', function(e) {
+ pressing && (pressing = false, handleTouchend(e));
+ });
+ $swiperWrapper.on('mouseleave', function(e) {
+ pressing && (pressing = false, handleTouchend(e));
+ });
+ $swiperWrapper.on('click', function(e) {
+ moved && (e.stopPropagation(), moved = false);
+ });
+ })();
+
+ $root.on('touchmove', function(e) {
+ if (e.cancelable & touching) {
+ e.preventDefault();
+ }
+ });
+ })();
+
+ return {
+ setOptions: setOptions,
+ previous: function(){
+ move('prev');
+ },
+ next: function(){
+ move('next');
+ },
+ refresh: function() {
+ calc(true, { animation: false });
+ }
+ };
+ }
+ $.fn.swiper = swiper;
+ });
+})();
diff --git a/_includes/scripts/lib/throttle.js b/_includes/scripts/lib/throttle.js
new file mode 100644
index 0000000..2add23c
--- /dev/null
+++ b/_includes/scripts/lib/throttle.js
@@ -0,0 +1,28 @@
+(function() {
+ window.throttle = function(func, wait) {
+ var args, result, thisArg, timeoutId, lastCalled = 0;
+
+ function trailingCall() {
+ lastCalled = new Date;
+ timeoutId = null;
+ result = func.apply(thisArg, args);
+ }
+ return function() {
+ var now = new Date,
+ remaining = wait - (now - lastCalled);
+
+ args = arguments;
+ thisArg = this;
+
+ if (remaining <= 0) {
+ clearTimeout(timeoutId);
+ timeoutId = null;
+ lastCalled = now;
+ result = func.apply(thisArg, args);
+ } else if (!timeoutId) {
+ timeoutId = setTimeout(trailingCall, remaining);
+ }
+ return result;
+ };
+ };
+})();
diff --git a/_includes/scripts/lib/toc.js b/_includes/scripts/lib/toc.js
new file mode 100644
index 0000000..fb43857
--- /dev/null
+++ b/_includes/scripts/lib/toc.js
@@ -0,0 +1,107 @@
+(function() {
+ var SOURCES = window.TEXT_VARIABLES.sources;
+ window.Lazyload.js(SOURCES.jquery, function() {
+ function toc(options) {
+ var $root = this, $window = $(window), $scrollTarget, $scroller, $tocUl = $('<ul class="toc toc--ellipsis"></ul>'), $tocLi, $headings, $activeLast, $activeCur,
+ selectors = 'h1,h2,h3', container = 'body', scrollTarget = window, scroller = 'html, body', disabled = false,
+ headingsPos, scrolling = false, hasRendered = false, hasInit = false;
+
+ function setOptions(options) {
+ var _options = options || {};
+ _options.selectors && (selectors = _options.selectors);
+ _options.container && (container = _options.container);
+ _options.scrollTarget && (scrollTarget = _options.scrollTarget);
+ _options.scroller && (scroller = _options.scroller);
+ _options.disabled !== undefined && (disabled = _options.disabled);
+ $headings = $(container).find(selectors).filter('[id]');
+ $scrollTarget = $(scrollTarget);
+ $scroller = $(scroller);
+ }
+ function calc() {
+ headingsPos = [];
+ $headings.each(function() {
+ headingsPos.push(Math.floor($(this).position().top));
+ });
+ }
+ function setState(element, disabled) {
+ var scrollTop = $scrollTarget.scrollTop(), i;
+ if (disabled || !headingsPos || headingsPos.length < 1) { return; }
+ if (element) {
+ $activeCur = element;
+ } else {
+ for (i = 0; i < headingsPos.length; i++) {
+ if (scrollTop >= headingsPos[i]) {
+ $activeCur = $tocLi.eq(i);
+ } else {
+ $activeCur || ($activeCur = $tocLi.eq(i));
+ break;
+ }
+ }
+ }
+ $activeLast && $activeLast.removeClass('active');
+ ($activeLast = $activeCur).addClass('active');
+ }
+ function render() {
+ if(!hasRendered) {
+ $root.append($tocUl);
+ $headings.each(function() {
+ var $this = $(this);
+ $tocUl.append($('<li></li>').addClass('toc-' + $this.prop('tagName').toLowerCase())
+ .append($('<a></a>').text($this.text()).attr('href', '#' + $this.prop('id'))));
+ });
+ $tocLi = $tocUl.children('li');
+ $tocUl.on('click', 'a', function(e) {
+ e.preventDefault();
+ var $this = $(this);
+ scrolling = true;
+ setState($this.parent());
+ $scroller.scrollToAnchor($this.attr('href'), 400, function() {
+ scrolling = false;
+ });
+ });
+ }
+ hasRendered = true;
+ }
+ function init() {
+ var interval, timeout;
+ if(!hasInit) {
+ render(); calc(); setState(null, scrolling);
+ // run calc every 100 millisecond
+ interval = setInterval(function() {
+ calc();
+ }, 100);
+ timeout = setTimeout(function() {
+ clearInterval(interval);
+ }, 45000);
+ window.pageLoad.then(function() {
+ setTimeout(function() {
+ clearInterval(interval);
+ clearTimeout(timeout);
+ }, 3000);
+ });
+ $scrollTarget.on('scroll', function() {
+ disabled || setState(null, scrolling);
+ });
+ $window.on('resize', window.throttle(function() {
+ if (!disabled) {
+ render(); calc(); setState(null, scrolling);
+ }
+ }, 100));
+ }
+ hasInit = true;
+ }
+
+ setOptions(options);
+ if (!disabled) {
+ init();
+ }
+ $window.on('resize', window.throttle(function() {
+ init();
+ }, 200));
+ return {
+ setOptions: setOptions
+ };
+ }
+ $.fn.toc = toc;
+ });
+})();