initial
This commit is contained in:
168
themes/next/source/js/affix.js
Normal file
168
themes/next/source/js/affix.js
Normal file
@ -0,0 +1,168 @@
|
||||
/* ========================================================================
|
||||
* Bootstrap: affix.js v3.3.5
|
||||
* http://getbootstrap.com/javascript/#affix
|
||||
* ========================================================================
|
||||
* Copyright 2011-2015 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
* ======================================================================== */
|
||||
|
||||
/**
|
||||
* Customized by Ivan.Nginx
|
||||
*
|
||||
* - Refactored with eslint-config-theme-next style.
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
'use strict';
|
||||
|
||||
// AFFIX CLASS DEFINITION
|
||||
// ======================
|
||||
|
||||
var Affix = function(element, options) {
|
||||
this.options = $.extend({}, Affix.DEFAULTS, options);
|
||||
|
||||
this.$target = $(this.options.target)
|
||||
.on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
|
||||
.on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this));
|
||||
|
||||
this.$element = $(element);
|
||||
this.affixed = null;
|
||||
this.unpin = null;
|
||||
this.pinnedOffset = null;
|
||||
|
||||
this.checkPosition();
|
||||
};
|
||||
|
||||
Affix.VERSION = '3.3.5';
|
||||
|
||||
Affix.RESET = 'affix affix-top affix-bottom';
|
||||
|
||||
Affix.DEFAULTS = {
|
||||
offset: 0,
|
||||
target: window
|
||||
};
|
||||
|
||||
Affix.prototype.getState = function(scrollHeight, height, offsetTop, offsetBottom) {
|
||||
var scrollTop = this.$target.scrollTop();
|
||||
var position = this.$element.offset();
|
||||
var targetHeight = this.$target.height();
|
||||
|
||||
if (offsetTop != null && this.affixed === 'top') return scrollTop < offsetTop ? 'top' : false;
|
||||
|
||||
if (this.affixed === 'bottom') {
|
||||
if (offsetTop != null) return scrollTop + this.unpin <= position.top ? false : 'bottom';
|
||||
return scrollTop + targetHeight <= scrollHeight - offsetBottom ? false : 'bottom';
|
||||
}
|
||||
|
||||
var initializing = this.affixed == null;
|
||||
var colliderTop = initializing ? scrollTop : position.top;
|
||||
var colliderHeight = initializing ? targetHeight : height;
|
||||
|
||||
if (offsetTop != null && scrollTop <= offsetTop) return 'top';
|
||||
if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom';
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
Affix.prototype.getPinnedOffset = function() {
|
||||
if (this.pinnedOffset) return this.pinnedOffset;
|
||||
this.$element.removeClass(Affix.RESET).addClass('affix');
|
||||
var scrollTop = this.$target.scrollTop();
|
||||
var position = this.$element.offset();
|
||||
return (this.pinnedOffset = position.top - scrollTop);
|
||||
};
|
||||
|
||||
Affix.prototype.checkPositionWithEventLoop = function() {
|
||||
setTimeout($.proxy(this.checkPosition, this), 1);
|
||||
};
|
||||
|
||||
Affix.prototype.checkPosition = function() {
|
||||
if (!this.$element.is(':visible')) return;
|
||||
|
||||
var height = this.$element.height();
|
||||
var offset = this.options.offset;
|
||||
var offsetTop = offset.top;
|
||||
var offsetBottom = offset.bottom;
|
||||
var scrollHeight = Math.max($(document).height(), $(document.body).height());
|
||||
|
||||
/* eslint-disable */
|
||||
if (typeof offset !== 'object') offsetBottom = offsetTop = offset;
|
||||
if (typeof offsetTop === 'function') offsetTop = offset.top(this.$element);
|
||||
if (typeof offsetBottom === 'function') offsetBottom = offset.bottom(this.$element);
|
||||
/* eslint-enable */
|
||||
|
||||
var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom);
|
||||
|
||||
if (this.affixed !== affix) {
|
||||
if (this.unpin != null) this.$element.css('top', '');
|
||||
|
||||
var affixType = 'affix' + (affix ? '-' + affix : '');
|
||||
var e = new $.Event(affixType + '.bs.affix');
|
||||
|
||||
this.$element.trigger(e);
|
||||
|
||||
if (e.isDefaultPrevented()) return;
|
||||
|
||||
this.affixed = affix;
|
||||
this.unpin = affix === 'bottom' ? this.getPinnedOffset() : null;
|
||||
|
||||
this.$element
|
||||
.removeClass(Affix.RESET)
|
||||
.addClass(affixType)
|
||||
.trigger(affixType.replace('affix', 'affixed') + '.bs.affix');
|
||||
}
|
||||
|
||||
if (affix === 'bottom') {
|
||||
this.$element.offset({
|
||||
top: scrollHeight - height - offsetBottom
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// AFFIX PLUGIN DEFINITION
|
||||
// =======================
|
||||
|
||||
function Plugin(option) {
|
||||
return this.each(function() {
|
||||
var $this = $(this);
|
||||
var data = $this.data('bs.affix');
|
||||
var options = typeof option === 'object' && option;
|
||||
|
||||
if (!data) $this.data('bs.affix', data = new Affix(this, options));
|
||||
if (typeof option === 'string') data[option]();
|
||||
});
|
||||
}
|
||||
|
||||
var old = $.fn.affix;
|
||||
|
||||
$.fn.affix = Plugin;
|
||||
$.fn.affix.Constructor = Affix;
|
||||
|
||||
// AFFIX NO CONFLICT
|
||||
// =================
|
||||
|
||||
$.fn.affix.noConflict = function() {
|
||||
$.fn.affix = old;
|
||||
return this;
|
||||
};
|
||||
|
||||
// AFFIX DATA-API
|
||||
// ==============
|
||||
|
||||
$(window).on('load', function() {
|
||||
$('[data-spy="affix"]').each(function() {
|
||||
var $spy = $(this);
|
||||
var data = $spy.data();
|
||||
|
||||
data.offset = data.offset || {};
|
||||
|
||||
/* eslint-disable */
|
||||
if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom;
|
||||
if (data.offsetTop != null) data.offset.top = data.offsetTop;
|
||||
/* eslint-enable */
|
||||
|
||||
Plugin.call($spy, data);
|
||||
});
|
||||
});
|
||||
|
||||
}(jQuery));
|
114
themes/next/source/js/algolia-search.js
Normal file
114
themes/next/source/js/algolia-search.js
Normal file
@ -0,0 +1,114 @@
|
||||
/* global instantsearch, CONFIG */
|
||||
|
||||
$(document).ready(function() {
|
||||
var algoliaSettings = CONFIG.algolia;
|
||||
var isAlgoliaSettingsValid = algoliaSettings.applicationID
|
||||
&& algoliaSettings.apiKey
|
||||
&& algoliaSettings.indexName;
|
||||
|
||||
if (!isAlgoliaSettingsValid) {
|
||||
window.console.error('Algolia Settings are invalid.');
|
||||
return;
|
||||
}
|
||||
|
||||
var search = instantsearch({
|
||||
appId : algoliaSettings.applicationID,
|
||||
apiKey : algoliaSettings.apiKey,
|
||||
indexName : algoliaSettings.indexName,
|
||||
searchFunction: function(helper) {
|
||||
var searchInput = $('#algolia-search-input').find('input');
|
||||
|
||||
if (searchInput.val()) {
|
||||
helper.search();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Registering Widgets
|
||||
[
|
||||
instantsearch.widgets.searchBox({
|
||||
container : '#algolia-search-input',
|
||||
placeholder: algoliaSettings.labels.input_placeholder
|
||||
}),
|
||||
|
||||
instantsearch.widgets.hits({
|
||||
container : '#algolia-hits',
|
||||
hitsPerPage: algoliaSettings.hits.per_page || 10,
|
||||
templates : {
|
||||
item: function(data) {
|
||||
var link = data.permalink ? data.permalink : CONFIG.root + data.path;
|
||||
return (
|
||||
'<a href="' + link + '" class="algolia-hit-item-link">'
|
||||
+ data._highlightResult.title.value
|
||||
+ '</a>'
|
||||
);
|
||||
},
|
||||
empty: function(data) {
|
||||
return (
|
||||
'<div id="algolia-hits-empty">'
|
||||
+ algoliaSettings.labels.hits_empty.replace(/\$\{query}/, data.query)
|
||||
+ '</div>'
|
||||
);
|
||||
}
|
||||
},
|
||||
cssClasses: {
|
||||
item: 'algolia-hit-item'
|
||||
}
|
||||
}),
|
||||
|
||||
instantsearch.widgets.stats({
|
||||
container: '#algolia-stats',
|
||||
templates: {
|
||||
body: function(data) {
|
||||
var stats = algoliaSettings.labels.hits_stats
|
||||
.replace(/\$\{hits}/, data.nbHits)
|
||||
.replace(/\$\{time}/, data.processingTimeMS);
|
||||
return (
|
||||
stats
|
||||
+ '<span class="algolia-powered">'
|
||||
+ ' <img src="' + CONFIG.root + 'images/algolia_logo.svg" alt="Algolia" />'
|
||||
+ '</span>'
|
||||
+ '<hr />'
|
||||
);
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
instantsearch.widgets.pagination({
|
||||
container : '#algolia-pagination',
|
||||
scrollTo : false,
|
||||
showFirstLast: false,
|
||||
labels : {
|
||||
first : '<i class="fa fa-angle-double-left"></i>',
|
||||
last : '<i class="fa fa-angle-double-right"></i>',
|
||||
previous: '<i class="fa fa-angle-left"></i>',
|
||||
next : '<i class="fa fa-angle-right"></i>'
|
||||
},
|
||||
cssClasses: {
|
||||
root : 'pagination',
|
||||
item : 'pagination-item',
|
||||
link : 'page-number',
|
||||
active : 'current',
|
||||
disabled: 'disabled-item'
|
||||
}
|
||||
})
|
||||
].forEach(search.addWidget, search);
|
||||
|
||||
search.start();
|
||||
|
||||
$('.popup-trigger').on('click', function(e) {
|
||||
e.stopPropagation();
|
||||
$('body')
|
||||
.append('<div class="search-popup-overlay algolia-pop-overlay"></div>')
|
||||
.css('overflow', 'hidden');
|
||||
$('.popup').toggle();
|
||||
$('#algolia-search-input').find('input').focus();
|
||||
});
|
||||
|
||||
$('.popup-btn-close').click(function() {
|
||||
$('.popup').hide();
|
||||
$('.algolia-pop-overlay').remove();
|
||||
$('body').css('overflow', '');
|
||||
});
|
||||
|
||||
});
|
14
themes/next/source/js/exturl.js
Normal file
14
themes/next/source/js/exturl.js
Normal file
@ -0,0 +1,14 @@
|
||||
$(document).ready(function() {
|
||||
|
||||
// Create Base64 Object
|
||||
/* eslint-disable */
|
||||
var Base64={_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(e){var t="";var n,r,i,s,o,u,a;var f=0;e=Base64._utf8_encode(e);while(f<e.length){n=e.charCodeAt(f++);r=e.charCodeAt(f++);i=e.charCodeAt(f++);s=n>>2;o=(n&3)<<4|r>>4;u=(r&15)<<2|i>>6;a=i&63;if(isNaN(r)){u=a=64}else if(isNaN(i)){a=64}t=t+this._keyStr.charAt(s)+this._keyStr.charAt(o)+this._keyStr.charAt(u)+this._keyStr.charAt(a)}return t},decode:function(e){var t="";var n,r,i;var s,o,u,a;var f=0;e=e.replace(/[^A-Za-z0-9+/=]/g,"");while(f<e.length){s=this._keyStr.indexOf(e.charAt(f++));o=this._keyStr.indexOf(e.charAt(f++));u=this._keyStr.indexOf(e.charAt(f++));a=this._keyStr.indexOf(e.charAt(f++));n=s<<2|o>>4;r=(o&15)<<4|u>>2;i=(u&3)<<6|a;t=t+String.fromCharCode(n);if(u!=64){t=t+String.fromCharCode(r)}if(a!=64){t=t+String.fromCharCode(i)}}t=Base64._utf8_decode(t);return t},_utf8_encode:function(e){e=e.replace(/rn/g,"n");var t="";for(var n=0;n<e.length;n++){var r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r)}else if(r>127&&r<2048){t+=String.fromCharCode(r>>6|192);t+=String.fromCharCode(r&63|128)}else{t+=String.fromCharCode(r>>12|224);t+=String.fromCharCode(r>>6&63|128);t+=String.fromCharCode(r&63|128)}}return t},_utf8_decode:function(e){var t="";var n=0;var r=c1=c2=0;while(n<e.length){r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r);n++}else if(r>191&&r<224){c2=e.charCodeAt(n+1);t+=String.fromCharCode((r&31)<<6|c2&63);n+=2}else{c2=e.charCodeAt(n+1);c3=e.charCodeAt(n+2);t+=String.fromCharCode((r&15)<<12|(c2&63)<<6|c3&63);n+=3}}return t}};
|
||||
|
||||
$('.exturl').on('click', function() {
|
||||
var $exturl = $(this).attr('data-url');
|
||||
var $decurl = Base64.decode($exturl);
|
||||
window.open($decurl, '_blank');
|
||||
return false;
|
||||
});
|
||||
|
||||
});
|
166
themes/next/source/js/js.cookie.js
Normal file
166
themes/next/source/js/js.cookie.js
Normal file
@ -0,0 +1,166 @@
|
||||
/*!
|
||||
* JavaScript Cookie v2.1.4
|
||||
* https://github.com/js-cookie/js-cookie
|
||||
*
|
||||
* Copyright 2006, 2015 Klaus Hartl & Fagner Brack
|
||||
* Released under the MIT license
|
||||
*/
|
||||
|
||||
;(function (factory) {
|
||||
var registeredInModuleLoader = false;
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
define(factory);
|
||||
registeredInModuleLoader = true;
|
||||
}
|
||||
if (typeof exports === 'object') {
|
||||
module.exports = factory();
|
||||
registeredInModuleLoader = true;
|
||||
}
|
||||
if (!registeredInModuleLoader) {
|
||||
var OldCookies = window.Cookies;
|
||||
var api = window.Cookies = factory();
|
||||
api.noConflict = function () {
|
||||
window.Cookies = OldCookies;
|
||||
return api;
|
||||
};
|
||||
}
|
||||
}(function () {
|
||||
function extend () {
|
||||
var i = 0;
|
||||
var result = {};
|
||||
for (; i < arguments.length; i++) {
|
||||
var attributes = arguments[ i ];
|
||||
for (var key in attributes) {
|
||||
result[key] = attributes[key];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function init (converter) {
|
||||
function api (key, value, attributes) {
|
||||
var result;
|
||||
if (typeof document === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Write
|
||||
|
||||
if (arguments.length > 1) {
|
||||
attributes = extend({
|
||||
path: '/'
|
||||
}, api.defaults, attributes);
|
||||
|
||||
if (typeof attributes.expires === 'number') {
|
||||
var expires = new Date();
|
||||
expires.setMilliseconds(expires.getMilliseconds() + attributes.expires * 864e+5);
|
||||
attributes.expires = expires;
|
||||
}
|
||||
|
||||
// We're using "expires" because "max-age" is not supported by IE
|
||||
attributes.expires = attributes.expires ? attributes.expires.toUTCString() : '';
|
||||
|
||||
try {
|
||||
result = JSON.stringify(value);
|
||||
if (/^[\{\[]/.test(result)) {
|
||||
value = result;
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
if (!converter.write) {
|
||||
value = encodeURIComponent(String(value))
|
||||
.replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent);
|
||||
} else {
|
||||
value = converter.write(value, key);
|
||||
}
|
||||
|
||||
key = encodeURIComponent(String(key));
|
||||
key = key.replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent);
|
||||
key = key.replace(/[\(\)]/g, escape);
|
||||
|
||||
var stringifiedAttributes = '';
|
||||
|
||||
for (var attributeName in attributes) {
|
||||
if (!attributes[attributeName]) {
|
||||
continue;
|
||||
}
|
||||
stringifiedAttributes += '; ' + attributeName;
|
||||
if (attributes[attributeName] === true) {
|
||||
continue;
|
||||
}
|
||||
stringifiedAttributes += '=' + attributes[attributeName];
|
||||
}
|
||||
return (document.cookie = key + '=' + value + stringifiedAttributes);
|
||||
}
|
||||
|
||||
// Read
|
||||
|
||||
if (!key) {
|
||||
result = {};
|
||||
}
|
||||
|
||||
// To prevent the for loop in the first place assign an empty array
|
||||
// in case there are no cookies at all. Also prevents odd result when
|
||||
// calling "get()"
|
||||
var cookies = document.cookie ? document.cookie.split('; ') : [];
|
||||
var rdecode = /(%[0-9A-Z]{2})+/g;
|
||||
var i = 0;
|
||||
|
||||
for (; i < cookies.length; i++) {
|
||||
var parts = cookies[i].split('=');
|
||||
var cookie = parts.slice(1).join('=');
|
||||
|
||||
if (cookie.charAt(0) === '"') {
|
||||
cookie = cookie.slice(1, -1);
|
||||
}
|
||||
|
||||
try {
|
||||
var name = parts[0].replace(rdecode, decodeURIComponent);
|
||||
cookie = converter.read ?
|
||||
converter.read(cookie, name) : converter(cookie, name) ||
|
||||
cookie.replace(rdecode, decodeURIComponent);
|
||||
|
||||
if (this.json) {
|
||||
try {
|
||||
cookie = JSON.parse(cookie);
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
if (key === name) {
|
||||
result = cookie;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!key) {
|
||||
result[name] = cookie;
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
api.set = api;
|
||||
api.get = function (key) {
|
||||
return api.call(api, key);
|
||||
};
|
||||
api.getJSON = function () {
|
||||
return api.apply({
|
||||
json: true
|
||||
}, [].slice.call(arguments));
|
||||
};
|
||||
api.defaults = {};
|
||||
|
||||
api.remove = function (key, attributes) {
|
||||
api(key, '', extend(attributes, {
|
||||
expires: -1
|
||||
}));
|
||||
};
|
||||
|
||||
api.withConverter = init;
|
||||
|
||||
return api;
|
||||
}
|
||||
|
||||
return init(function () {});
|
||||
}));
|
372
themes/next/source/js/motion.js
Normal file
372
themes/next/source/js/motion.js
Normal file
@ -0,0 +1,372 @@
|
||||
/* global NexT, CONFIG */
|
||||
|
||||
$(document).ready(function() {
|
||||
NexT.motion = {};
|
||||
|
||||
var sidebarToggleLines = {
|
||||
lines: [],
|
||||
push : function(line) {
|
||||
this.lines.push(line);
|
||||
},
|
||||
init: function() {
|
||||
this.lines.forEach(function(line) {
|
||||
line.init();
|
||||
});
|
||||
},
|
||||
arrow: function() {
|
||||
this.lines.forEach(function(line) {
|
||||
line.arrow();
|
||||
});
|
||||
},
|
||||
close: function() {
|
||||
this.lines.forEach(function(line) {
|
||||
line.close();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function SidebarToggleLine(settings) {
|
||||
this.el = $(settings.el);
|
||||
this.status = $.extend({}, {
|
||||
init: {
|
||||
width : '100%',
|
||||
opacity: 1,
|
||||
left : 0,
|
||||
rotateZ: 0,
|
||||
top : 0
|
||||
}
|
||||
}, settings.status);
|
||||
}
|
||||
|
||||
SidebarToggleLine.prototype.init = function() {
|
||||
this.transform('init');
|
||||
};
|
||||
SidebarToggleLine.prototype.arrow = function() {
|
||||
this.transform('arrow');
|
||||
};
|
||||
SidebarToggleLine.prototype.close = function() {
|
||||
this.transform('close');
|
||||
};
|
||||
SidebarToggleLine.prototype.transform = function(status) {
|
||||
this.el.velocity('stop').velocity(this.status[status]);
|
||||
};
|
||||
|
||||
var sidebarToggleLine1st = new SidebarToggleLine({
|
||||
el : '.sidebar-toggle-line-first',
|
||||
status: {
|
||||
arrow: {width: '50%', rotateZ: '-45deg', top: '2px'},
|
||||
close: {width: '100%', rotateZ: '-45deg', top: '5px'}
|
||||
}
|
||||
});
|
||||
var sidebarToggleLine2nd = new SidebarToggleLine({
|
||||
el : '.sidebar-toggle-line-middle',
|
||||
status: {
|
||||
arrow: {width: '90%'},
|
||||
close: {opacity: 0}
|
||||
}
|
||||
});
|
||||
var sidebarToggleLine3rd = new SidebarToggleLine({
|
||||
el : '.sidebar-toggle-line-last',
|
||||
status: {
|
||||
arrow: {width: '50%', rotateZ: '45deg', top: '-2px'},
|
||||
close: {width: '100%', rotateZ: '45deg', top: '-5px'}
|
||||
}
|
||||
});
|
||||
|
||||
sidebarToggleLines.push(sidebarToggleLine1st);
|
||||
sidebarToggleLines.push(sidebarToggleLine2nd);
|
||||
sidebarToggleLines.push(sidebarToggleLine3rd);
|
||||
|
||||
var SIDEBAR_WIDTH = CONFIG.sidebar.width ? CONFIG.sidebar.width : '320px';
|
||||
var SIDEBAR_DISPLAY_DURATION = 200;
|
||||
var xPos, yPos;
|
||||
|
||||
var sidebarToggleMotion = {
|
||||
toggleEl : $('.sidebar-toggle'),
|
||||
dimmerEl : $('#sidebar-dimmer'),
|
||||
sidebarEl : $('.sidebar'),
|
||||
isSidebarVisible: false,
|
||||
init : function() {
|
||||
this.toggleEl.on('click', this.clickHandler.bind(this));
|
||||
this.dimmerEl.on('click', this.clickHandler.bind(this));
|
||||
this.toggleEl.on('mouseenter', this.mouseEnterHandler.bind(this));
|
||||
this.toggleEl.on('mouseleave', this.mouseLeaveHandler.bind(this));
|
||||
this.sidebarEl.on('touchstart', this.touchstartHandler.bind(this));
|
||||
this.sidebarEl.on('touchend', this.touchendHandler.bind(this));
|
||||
this.sidebarEl.on('touchmove', function(e) { e.preventDefault(); });
|
||||
|
||||
$(document)
|
||||
.on('sidebar.isShowing', function() {
|
||||
NexT.utils.isDesktop() && $('body').velocity('stop').velocity(
|
||||
{paddingRight: SIDEBAR_WIDTH},
|
||||
SIDEBAR_DISPLAY_DURATION
|
||||
);
|
||||
})
|
||||
.on('sidebar.isHiding', function() {
|
||||
});
|
||||
},
|
||||
clickHandler: function() {
|
||||
this.isSidebarVisible ? this.hideSidebar() : this.showSidebar();
|
||||
this.isSidebarVisible = !this.isSidebarVisible;
|
||||
},
|
||||
mouseEnterHandler: function() {
|
||||
if (this.isSidebarVisible) {
|
||||
return;
|
||||
}
|
||||
sidebarToggleLines.arrow();
|
||||
},
|
||||
mouseLeaveHandler: function() {
|
||||
if (this.isSidebarVisible) {
|
||||
return;
|
||||
}
|
||||
sidebarToggleLines.init();
|
||||
},
|
||||
touchstartHandler: function(e) {
|
||||
xPos = e.originalEvent.touches[0].clientX;
|
||||
yPos = e.originalEvent.touches[0].clientY;
|
||||
},
|
||||
touchendHandler: function(e) {
|
||||
var _xPos = e.originalEvent.changedTouches[0].clientX;
|
||||
var _yPos = e.originalEvent.changedTouches[0].clientY;
|
||||
if (_xPos - xPos > 30 && Math.abs(_yPos - yPos) < 20) {
|
||||
this.clickHandler();
|
||||
}
|
||||
},
|
||||
showSidebar: function() {
|
||||
var self = this;
|
||||
|
||||
sidebarToggleLines.close();
|
||||
|
||||
this.sidebarEl.velocity('stop').velocity({
|
||||
width: SIDEBAR_WIDTH
|
||||
}, {
|
||||
display : 'block',
|
||||
duration: SIDEBAR_DISPLAY_DURATION,
|
||||
begin : function() {
|
||||
$('.sidebar .motion-element').not('.site-state').velocity(
|
||||
'transition.slideRightIn', {
|
||||
stagger : 50,
|
||||
drag : true,
|
||||
complete: function() {
|
||||
self.sidebarEl.trigger('sidebar.motion.complete');
|
||||
}
|
||||
}
|
||||
);
|
||||
$('.site-state').velocity(
|
||||
'transition.slideRightIn', {
|
||||
stagger : 50,
|
||||
drag : true,
|
||||
display : 'flex'
|
||||
}
|
||||
);
|
||||
},
|
||||
complete: function() {
|
||||
self.sidebarEl.addClass('sidebar-active');
|
||||
self.sidebarEl.trigger('sidebar.didShow');
|
||||
}
|
||||
});
|
||||
|
||||
this.sidebarEl.trigger('sidebar.isShowing');
|
||||
},
|
||||
hideSidebar: function() {
|
||||
NexT.utils.isDesktop() && $('body').velocity('stop').velocity({paddingRight: 0});
|
||||
this.sidebarEl.find('.motion-element').velocity('stop').css('display', 'none');
|
||||
this.sidebarEl.velocity('stop').velocity({width: 0}, {display: 'none'});
|
||||
|
||||
sidebarToggleLines.init();
|
||||
|
||||
this.sidebarEl.removeClass('sidebar-active');
|
||||
this.sidebarEl.trigger('sidebar.isHiding');
|
||||
|
||||
// Prevent adding TOC to Overview if Overview was selected when close & open sidebar.
|
||||
if ($('.post-toc-wrap')) {
|
||||
if ($('.site-overview-wrap').css('display') === 'block') {
|
||||
$('.post-toc-wrap').removeClass('motion-element');
|
||||
} else {
|
||||
$('.post-toc-wrap').addClass('motion-element');
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
sidebarToggleMotion.init();
|
||||
|
||||
NexT.motion.integrator = {
|
||||
queue : [],
|
||||
cursor: -1,
|
||||
add : function(fn) {
|
||||
this.queue.push(fn);
|
||||
return this;
|
||||
},
|
||||
next: function() {
|
||||
this.cursor++;
|
||||
var fn = this.queue[this.cursor];
|
||||
$.isFunction(fn) && fn(NexT.motion.integrator);
|
||||
},
|
||||
bootstrap: function() {
|
||||
this.next();
|
||||
}
|
||||
};
|
||||
|
||||
NexT.motion.middleWares = {
|
||||
logo: function(integrator) {
|
||||
var sequence = [];
|
||||
var $brand = $('.brand');
|
||||
var $image = $('.custom-logo-image');
|
||||
var $title = $('.site-title');
|
||||
var $subtitle = $('.site-subtitle');
|
||||
var $logoLineTop = $('.logo-line-before i');
|
||||
var $logoLineBottom = $('.logo-line-after i');
|
||||
|
||||
$brand.length > 0 && sequence.push({
|
||||
e: $brand,
|
||||
p: {opacity: 1},
|
||||
o: {duration: 200}
|
||||
});
|
||||
|
||||
/**
|
||||
* Check if $elements exist.
|
||||
* @param {jQuery|Array} $elements
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasElement($elements) {
|
||||
$elements = Array.isArray($elements) ? $elements : [$elements];
|
||||
return $elements.every(function($element) {
|
||||
return $element.length > 0;
|
||||
});
|
||||
}
|
||||
|
||||
function getMistLineSettings(element, translateX) {
|
||||
return {
|
||||
e: $(element),
|
||||
p: {translateX: translateX},
|
||||
o: {
|
||||
duration : 500,
|
||||
sequenceQueue: false
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function pushImageToSequence() {
|
||||
sequence.push({
|
||||
e: $image,
|
||||
p: {opacity: 1, top: 0},
|
||||
o: {duration: 200}
|
||||
});
|
||||
}
|
||||
|
||||
NexT.utils.isMist() && hasElement([$logoLineTop, $logoLineBottom])
|
||||
&& sequence.push(
|
||||
getMistLineSettings($logoLineTop, '100%'),
|
||||
getMistLineSettings($logoLineBottom, '-100%')
|
||||
);
|
||||
|
||||
NexT.utils.isMuse() && hasElement($image) && pushImageToSequence();
|
||||
|
||||
hasElement($title) && sequence.push({
|
||||
e: $title,
|
||||
p: {opacity: 1, top: 0},
|
||||
o: {duration: 200}
|
||||
});
|
||||
|
||||
hasElement($subtitle) && sequence.push({
|
||||
e: $subtitle,
|
||||
p: {opacity: 1, top: 0},
|
||||
o: {duration: 200}
|
||||
});
|
||||
|
||||
(NexT.utils.isPisces() || NexT.utils.isGemini()) && hasElement($image) && pushImageToSequence();
|
||||
|
||||
if (CONFIG.motion.async) {
|
||||
integrator.next();
|
||||
}
|
||||
|
||||
if (sequence.length > 0) {
|
||||
sequence[sequence.length - 1].o.complete = function() {
|
||||
integrator.next();
|
||||
};
|
||||
/* eslint-disable */
|
||||
$.Velocity.RunSequence(sequence);
|
||||
/* eslint-enable */
|
||||
} else {
|
||||
integrator.next();
|
||||
}
|
||||
},
|
||||
|
||||
menu: function(integrator) {
|
||||
|
||||
if (CONFIG.motion.async) {
|
||||
integrator.next();
|
||||
}
|
||||
|
||||
$('.menu-item').velocity('transition.slideDownIn', {
|
||||
display : null,
|
||||
duration: 200,
|
||||
complete: function() {
|
||||
integrator.next();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
postList: function(integrator) {
|
||||
|
||||
//var $post = $('.post');
|
||||
var $postBlock = $('.post-block, .pagination, .comments');
|
||||
var $postBlockTransition = CONFIG.motion.transition.post_block;
|
||||
var $postHeader = $('.post-header');
|
||||
var $postHeaderTransition = CONFIG.motion.transition.post_header;
|
||||
var $postBody = $('.post-body');
|
||||
var $postBodyTransition = CONFIG.motion.transition.post_body;
|
||||
var $collHeader = $('.collection-title, .archive-year');
|
||||
var $collHeaderTransition = CONFIG.motion.transition.coll_header;
|
||||
var $sidebarAffix = $('.sidebar-inner');
|
||||
var $sidebarAffixTransition = CONFIG.motion.transition.sidebar;
|
||||
var hasPost = $postBlock.length > 0;
|
||||
|
||||
function postMotion() {
|
||||
var postMotionOptions = window.postMotionOptions || {
|
||||
stagger: 100,
|
||||
drag : true
|
||||
};
|
||||
postMotionOptions.complete = function() {
|
||||
// After motion complete need to remove transform from sidebar to let affix work on Pisces | Gemini.
|
||||
if (CONFIG.motion.transition.sidebar && (NexT.utils.isPisces() || NexT.utils.isGemini())) {
|
||||
$sidebarAffix.css({ 'transform': 'initial' });
|
||||
}
|
||||
integrator.next();
|
||||
};
|
||||
|
||||
//$post.velocity('transition.slideDownIn', postMotionOptions);
|
||||
if (CONFIG.motion.transition.post_block) {
|
||||
$postBlock.velocity('transition.' + $postBlockTransition, postMotionOptions);
|
||||
}
|
||||
if (CONFIG.motion.transition.post_header) {
|
||||
$postHeader.velocity('transition.' + $postHeaderTransition, postMotionOptions);
|
||||
}
|
||||
if (CONFIG.motion.transition.post_body) {
|
||||
$postBody.velocity('transition.' + $postBodyTransition, postMotionOptions);
|
||||
}
|
||||
if (CONFIG.motion.transition.coll_header) {
|
||||
$collHeader.velocity('transition.' + $collHeaderTransition, postMotionOptions);
|
||||
}
|
||||
// Only for Pisces | Gemini.
|
||||
if (CONFIG.motion.transition.sidebar && (NexT.utils.isPisces() || NexT.utils.isGemini())) {
|
||||
$sidebarAffix.velocity('transition.' + $sidebarAffixTransition, postMotionOptions);
|
||||
}
|
||||
}
|
||||
|
||||
hasPost ? postMotion() : integrator.next();
|
||||
|
||||
if (CONFIG.motion.async) {
|
||||
integrator.next();
|
||||
}
|
||||
},
|
||||
|
||||
sidebar: function(integrator) {
|
||||
if (CONFIG.sidebar.display === 'always') {
|
||||
NexT.utils.displaySidebar();
|
||||
}
|
||||
integrator.next();
|
||||
}
|
||||
};
|
||||
|
||||
});
|
53
themes/next/source/js/next-boot.js
Normal file
53
themes/next/source/js/next-boot.js
Normal file
@ -0,0 +1,53 @@
|
||||
/* global NexT, CONFIG */
|
||||
|
||||
$(document).ready(function() {
|
||||
|
||||
$(document).trigger('bootstrap:before');
|
||||
|
||||
/**
|
||||
* Register JS handlers by condition option.
|
||||
* Need to add config option in Front-End at 'layout/_partials/head.swig' file.
|
||||
*/
|
||||
CONFIG.fastclick && NexT.utils.isMobile() && window.FastClick.attach(document.body);
|
||||
CONFIG.lazyload && NexT.utils.lazyLoadPostsImages();
|
||||
|
||||
NexT.utils.registerESCKeyEvent();
|
||||
|
||||
CONFIG.back2top && NexT.utils.registerBackToTop();
|
||||
|
||||
// Mobile top menu bar.
|
||||
$('.site-nav-toggle button').on('click', function() {
|
||||
var $siteNav = $('.site-nav');
|
||||
var ON_CLASS_NAME = 'site-nav-on';
|
||||
var isSiteNavOn = $siteNav.hasClass(ON_CLASS_NAME);
|
||||
var animateAction = isSiteNavOn ? 'slideUp' : 'slideDown';
|
||||
var animateCallback = isSiteNavOn ? 'removeClass' : 'addClass';
|
||||
|
||||
$siteNav.stop()[animateAction]('fast', function() {
|
||||
$siteNav[animateCallback](ON_CLASS_NAME);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Register JS handlers by condition option.
|
||||
* Need to add config option in Front-End at 'layout/_partials/head.swig' file.
|
||||
*/
|
||||
CONFIG.fancybox && NexT.utils.wrapImageWithFancyBox();
|
||||
CONFIG.tabs && NexT.utils.registerTabsTag();
|
||||
|
||||
NexT.utils.embeddedVideoTransformer();
|
||||
|
||||
// Define Motion Sequence.
|
||||
NexT.motion.integrator
|
||||
.add(NexT.motion.middleWares.logo)
|
||||
.add(NexT.motion.middleWares.menu)
|
||||
.add(NexT.motion.middleWares.postList)
|
||||
.add(NexT.motion.middleWares.sidebar);
|
||||
|
||||
$(document).trigger('motion:before');
|
||||
|
||||
// Bootstrap Motion.
|
||||
CONFIG.motion.enable && NexT.motion.integrator.bootstrap();
|
||||
|
||||
$(document).trigger('bootstrap:after');
|
||||
});
|
104
themes/next/source/js/post-details.js
Normal file
104
themes/next/source/js/post-details.js
Normal file
@ -0,0 +1,104 @@
|
||||
/* global NexT, CONFIG */
|
||||
|
||||
$(document).ready(function() {
|
||||
|
||||
function initScrollSpy() {
|
||||
var tocSelector = '.post-toc';
|
||||
var $tocElement = $(tocSelector);
|
||||
var activeCurrentSelector = '.active-current';
|
||||
|
||||
function removeCurrentActiveClass() {
|
||||
$(tocSelector + ' ' + activeCurrentSelector)
|
||||
.removeClass(activeCurrentSelector.substring(1));
|
||||
}
|
||||
|
||||
$tocElement
|
||||
.on('activate.bs.scrollspy', function() {
|
||||
var $currentActiveElement = $(tocSelector + ' .active').last();
|
||||
|
||||
removeCurrentActiveClass();
|
||||
$currentActiveElement.addClass('active-current');
|
||||
|
||||
// Scrolling to center active TOC element if TOC content is taller then viewport.
|
||||
$tocElement.scrollTop($currentActiveElement.offset().top - $tocElement.offset().top + $tocElement.scrollTop() - ($tocElement.height() / 2));
|
||||
})
|
||||
.on('clear.bs.scrollspy', removeCurrentActiveClass);
|
||||
|
||||
$('body').scrollspy({ target: tocSelector });
|
||||
}
|
||||
|
||||
initScrollSpy();
|
||||
});
|
||||
|
||||
$(document).ready(function() {
|
||||
var html = $('html');
|
||||
var TAB_ANIMATE_DURATION = 200;
|
||||
var hasVelocity = $.isFunction(html.velocity);
|
||||
|
||||
$('.sidebar-nav li').on('click', function() {
|
||||
var item = $(this);
|
||||
var activeTabClassName = 'sidebar-nav-active';
|
||||
var activePanelClassName = 'sidebar-panel-active';
|
||||
if (item.hasClass(activeTabClassName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var currentTarget = $('.' + activePanelClassName);
|
||||
var target = $('.' + item.data('target'));
|
||||
|
||||
hasVelocity
|
||||
? currentTarget.velocity('transition.slideUpOut', TAB_ANIMATE_DURATION, function() {
|
||||
target
|
||||
.velocity('stop')
|
||||
.velocity('transition.slideDownIn', TAB_ANIMATE_DURATION)
|
||||
.addClass(activePanelClassName);
|
||||
})
|
||||
: currentTarget.animate({ opacity: 0 }, TAB_ANIMATE_DURATION, function() {
|
||||
currentTarget.hide();
|
||||
target
|
||||
.stop()
|
||||
.css({'opacity': 0, 'display': 'block'})
|
||||
.animate({ opacity: 1 }, TAB_ANIMATE_DURATION, function() {
|
||||
currentTarget.removeClass(activePanelClassName);
|
||||
target.addClass(activePanelClassName);
|
||||
});
|
||||
});
|
||||
|
||||
item.siblings().removeClass(activeTabClassName);
|
||||
item.addClass(activeTabClassName);
|
||||
});
|
||||
|
||||
// TOC item animation navigate & prevent #item selector in adress bar.
|
||||
$('.post-toc a').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
var targetSelector = NexT.utils.escapeSelector(this.getAttribute('href'));
|
||||
var offset = $(targetSelector).offset().top;
|
||||
|
||||
hasVelocity
|
||||
? html.velocity('stop').velocity('scroll', {
|
||||
offset : offset + 'px',
|
||||
mobileHA: false
|
||||
})
|
||||
: $('html, body').stop().animate({
|
||||
scrollTop: offset
|
||||
}, 500);
|
||||
});
|
||||
|
||||
// Expand sidebar on post detail page by default, when post has a toc.
|
||||
var $tocContent = $('.post-toc-content');
|
||||
var display = CONFIG.page.sidebar;
|
||||
if (typeof display !== 'boolean') {
|
||||
// There's no definition sidebar in the page front-matter
|
||||
var isSidebarCouldDisplay = CONFIG.sidebar.display === 'post'
|
||||
|| CONFIG.sidebar.display === 'always';
|
||||
var hasTOC = $tocContent.length > 0 && $tocContent.html().trim().length > 0;
|
||||
display = isSidebarCouldDisplay && hasTOC;
|
||||
}
|
||||
if (display) {
|
||||
CONFIG.motion.enable
|
||||
? NexT.motion.middleWares.sidebar = function() {
|
||||
NexT.utils.displaySidebar();
|
||||
}
|
||||
: NexT.utils.displaySidebar();
|
||||
}
|
||||
});
|
9
themes/next/source/js/schemes/muse.js
Normal file
9
themes/next/source/js/schemes/muse.js
Normal file
@ -0,0 +1,9 @@
|
||||
$(document).ready(function() {
|
||||
function updateFooterPosition() {
|
||||
var containerHeight = $('#footer').attr('position') ? $('.container').height() + $('#footer').outerHeight(true) : $('.container').height();
|
||||
if (containerHeight < window.innerHeight) $('#footer').css({ 'position': 'fixed', 'bottom': 0, 'left': 0, 'right': 0 }).attr('position', 'fixed');
|
||||
else $('#footer').removeAttr('style position');
|
||||
}
|
||||
updateFooterPosition();
|
||||
$(window).on('resize scroll', updateFooterPosition);
|
||||
});
|
57
themes/next/source/js/schemes/pisces.js
Normal file
57
themes/next/source/js/schemes/pisces.js
Normal file
@ -0,0 +1,57 @@
|
||||
/* global NexT, CONFIG */
|
||||
|
||||
$(document).ready(function() {
|
||||
|
||||
var sidebarInner = $('.sidebar-inner');
|
||||
var sidebarOffset = CONFIG.sidebar.offset || 12;
|
||||
|
||||
function getHeaderOffset() {
|
||||
return $('.header-inner').height() + sidebarOffset;
|
||||
}
|
||||
|
||||
function getFooterOffset() {
|
||||
var footer = $('#footer');
|
||||
var footerInner = $('.footer-inner');
|
||||
var footerMargin = footer.outerHeight() - footerInner.outerHeight();
|
||||
var footerOffset = footer.outerHeight() + footerMargin;
|
||||
return footerOffset;
|
||||
}
|
||||
|
||||
function initAffix() {
|
||||
var headerOffset = getHeaderOffset();
|
||||
var footerOffset = getFooterOffset();
|
||||
var sidebarHeight = $('#sidebar').height() + NexT.utils.getSidebarb2tHeight();
|
||||
var contentHeight = $('#content').height();
|
||||
|
||||
// Not affix if sidebar taller than content (to prevent bottom jumping).
|
||||
if (headerOffset + sidebarHeight < contentHeight) {
|
||||
sidebarInner.affix({
|
||||
offset: {
|
||||
top : headerOffset - sidebarOffset,
|
||||
bottom: footerOffset
|
||||
}
|
||||
});
|
||||
sidebarInner.affix('checkPosition');
|
||||
}
|
||||
|
||||
$('#sidebar').css({ 'margin-top': headerOffset, 'margin-left': 'auto' });
|
||||
}
|
||||
|
||||
function recalculateAffixPosition() {
|
||||
$(window).off('.affix');
|
||||
sidebarInner.removeData('bs.affix').removeClass('affix affix-top affix-bottom');
|
||||
initAffix();
|
||||
}
|
||||
|
||||
function resizeListener() {
|
||||
var mql = window.matchMedia('(min-width: 992px)');
|
||||
mql.addListener(function(e) {
|
||||
if (e.matches) {
|
||||
recalculateAffixPosition();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
initAffix();
|
||||
resizeListener();
|
||||
});
|
25
themes/next/source/js/scroll-cookie.js
Normal file
25
themes/next/source/js/scroll-cookie.js
Normal file
@ -0,0 +1,25 @@
|
||||
$(document).ready(function() {
|
||||
|
||||
/* global Cookies */
|
||||
|
||||
// Set relative link path (without domain)
|
||||
var rpath = window.location.href.replace(window.location.origin, '');
|
||||
|
||||
// Write position in cookie
|
||||
var timeout;
|
||||
$(window).on('scroll', function() {
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(function() {
|
||||
Cookies.set('scroll-cookie', $(window).scrollTop() + '|' + rpath, { expires: 365, path: '' });
|
||||
}, 250);
|
||||
});
|
||||
|
||||
// Read position from cookie
|
||||
if (Cookies.get('scroll-cookie') !== undefined) {
|
||||
var cvalues = Cookies.get('scroll-cookie').split('|');
|
||||
if (cvalues[1] === rpath) {
|
||||
$(window).scrollTop(cvalues[0]);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
179
themes/next/source/js/scrollspy.js
Normal file
179
themes/next/source/js/scrollspy.js
Normal file
@ -0,0 +1,179 @@
|
||||
/* ========================================================================
|
||||
* Bootstrap: scrollspy.js v3.3.2
|
||||
* http://getbootstrap.com/javascript/#scrollspy
|
||||
* ========================================================================
|
||||
* Copyright 2011-2015 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
* ======================================================================== */
|
||||
|
||||
/**
|
||||
* Customized by iissnan & Ivan.Nginx
|
||||
*
|
||||
* - Add a `clear.bs.scrollspy` event.
|
||||
* - Esacpe targets selector.
|
||||
* - Refactored with eslint-config-theme-next style.
|
||||
*/
|
||||
|
||||
/* global NexT */
|
||||
|
||||
(function($) {
|
||||
'use strict';
|
||||
|
||||
// SCROLLSPY CLASS DEFINITION
|
||||
// ==========================
|
||||
function ScrollSpy(element, options) {
|
||||
this.$body = $(document.body);
|
||||
this.$scrollElement = $(element).is(document.body) ? $(window) : $(element);
|
||||
this.options = $.extend({}, ScrollSpy.DEFAULTS, options);
|
||||
this.selector = (this.options.target || '') + ' .nav li > a';
|
||||
this.offsets = [];
|
||||
this.targets = [];
|
||||
this.activeTarget = null;
|
||||
this.scrollHeight = 0;
|
||||
|
||||
this.$scrollElement.on('scroll.bs.scrollspy', $.proxy(this.process, this));
|
||||
this.refresh();
|
||||
this.process();
|
||||
}
|
||||
|
||||
ScrollSpy.VERSION = '3.3.2';
|
||||
|
||||
ScrollSpy.DEFAULTS = {
|
||||
offset: 10
|
||||
};
|
||||
|
||||
ScrollSpy.prototype.getScrollHeight = function() {
|
||||
return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight);
|
||||
};
|
||||
|
||||
ScrollSpy.prototype.refresh = function() {
|
||||
var that = this;
|
||||
var offsetMethod = 'offset';
|
||||
var offsetBase = 0;
|
||||
|
||||
this.offsets = [];
|
||||
this.targets = [];
|
||||
this.scrollHeight = this.getScrollHeight();
|
||||
|
||||
if (!$.isWindow(this.$scrollElement[0])) {
|
||||
offsetMethod = 'position';
|
||||
offsetBase = this.$scrollElement.scrollTop();
|
||||
}
|
||||
|
||||
this.$body
|
||||
.find(this.selector)
|
||||
.map(function() {
|
||||
var $el = $(this);
|
||||
var href = $el.data('target') || $el.attr('href');
|
||||
var $href = /^#./.test(href) && $(NexT.utils.escapeSelector(href)); // Need to escape selector.
|
||||
|
||||
return ($href
|
||||
&& $href.length
|
||||
&& $href.is(':visible')
|
||||
&& [[$href[offsetMethod]().top + offsetBase, href]]) || null;
|
||||
})
|
||||
.sort(function(a, b) {
|
||||
return a[0] - b[0];
|
||||
})
|
||||
.each(function() {
|
||||
that.offsets.push(this[0]);
|
||||
that.targets.push(this[1]);
|
||||
});
|
||||
|
||||
|
||||
};
|
||||
|
||||
ScrollSpy.prototype.process = function() {
|
||||
var scrollTop = this.$scrollElement.scrollTop() + this.options.offset;
|
||||
var scrollHeight = this.getScrollHeight();
|
||||
var maxScroll = this.options.offset + scrollHeight - this.$scrollElement.height();
|
||||
var offsets = this.offsets;
|
||||
var targets = this.targets;
|
||||
var activeTarget = this.activeTarget;
|
||||
var i;
|
||||
|
||||
if (this.scrollHeight !== scrollHeight) {
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
if (scrollTop >= maxScroll) {
|
||||
return activeTarget !== (i = targets[targets.length - 1]) && this.activate(i);
|
||||
}
|
||||
|
||||
if (activeTarget && scrollTop < offsets[0]) {
|
||||
$(this.selector).trigger('clear.bs.scrollspy'); // Add a custom event.
|
||||
this.activeTarget = null;
|
||||
return this.clear();
|
||||
}
|
||||
|
||||
for (i = offsets.length; i--;) {
|
||||
activeTarget !== targets[i]
|
||||
&& scrollTop >= offsets[i]
|
||||
&& (!offsets[i + 1] || scrollTop <= offsets[i + 1])
|
||||
&& this.activate(targets[i]);
|
||||
}
|
||||
};
|
||||
|
||||
ScrollSpy.prototype.activate = function(target) {
|
||||
this.activeTarget = target;
|
||||
|
||||
this.clear();
|
||||
|
||||
var selector = this.selector
|
||||
+ '[data-target="' + target + '"],'
|
||||
+ this.selector + '[href="' + target + '"]';
|
||||
|
||||
var active = $(selector)
|
||||
.parents('li')
|
||||
.addClass('active');
|
||||
|
||||
if (active.parent('.dropdown-menu').length) {
|
||||
active = active
|
||||
.closest('li.dropdown')
|
||||
.addClass('active');
|
||||
}
|
||||
|
||||
active.trigger('activate.bs.scrollspy');
|
||||
};
|
||||
|
||||
ScrollSpy.prototype.clear = function() {
|
||||
$(this.selector)
|
||||
.parentsUntil(this.options.target, '.active')
|
||||
.removeClass('active');
|
||||
};
|
||||
|
||||
// SCROLLSPY PLUGIN DEFINITION
|
||||
// ===========================
|
||||
function Plugin(option) {
|
||||
return this.each(function() {
|
||||
var $this = $(this);
|
||||
var data = $this.data('bs.scrollspy');
|
||||
var options = typeof option === 'object' && option;
|
||||
|
||||
if (!data) $this.data('bs.scrollspy', data = new ScrollSpy(this, options));
|
||||
if (typeof option === 'string') data[option]();
|
||||
});
|
||||
}
|
||||
|
||||
var old = $.fn.scrollspy;
|
||||
|
||||
$.fn.scrollspy = Plugin;
|
||||
$.fn.scrollspy.Constructor = ScrollSpy;
|
||||
|
||||
// SCROLLSPY NO CONFLICT
|
||||
// =====================
|
||||
$.fn.scrollspy.noConflict = function() {
|
||||
$.fn.scrollspy = old;
|
||||
return this;
|
||||
};
|
||||
|
||||
// SCROLLSPY DATA-API
|
||||
// ==================
|
||||
$(window).on('load.bs.scrollspy.data-api', function() {
|
||||
$('[data-spy="scroll"]').each(function() {
|
||||
var $spy = $(this);
|
||||
Plugin.call($spy, $spy.data());
|
||||
});
|
||||
});
|
||||
|
||||
}(jQuery));
|
340
themes/next/source/js/utils.js
Normal file
340
themes/next/source/js/utils.js
Normal file
@ -0,0 +1,340 @@
|
||||
/* global NexT, CONFIG */
|
||||
|
||||
NexT.utils = NexT.$u = {
|
||||
|
||||
/**
|
||||
* Wrap images with fancybox support.
|
||||
*/
|
||||
wrapImageWithFancyBox: function() {
|
||||
$('.content img')
|
||||
.not(':hidden')
|
||||
.each(function() {
|
||||
var $image = $(this);
|
||||
var imageTitle = $image.attr('title') || $image.attr('alt');
|
||||
var $imageWrapLink = $image.parent('a');
|
||||
|
||||
if ($imageWrapLink.length < 1) {
|
||||
var imageLink = $image.attr('data-original') || $image.attr('src');
|
||||
$imageWrapLink = $image.wrap('<a class="fancybox fancybox.image" href="' + imageLink + '" itemscope itemtype="http://schema.org/ImageObject" itemprop="url"></a>').parent('a');
|
||||
if ($image.is('.post-gallery img')) {
|
||||
$imageWrapLink.addClass('post-gallery-img');
|
||||
$imageWrapLink.attr('data-fancybox', 'gallery').attr('rel', 'gallery');
|
||||
}
|
||||
else if ($image.is('.group-picture img')) {
|
||||
$imageWrapLink.attr('data-fancybox', 'group').attr('rel', 'group');
|
||||
}
|
||||
else {
|
||||
$imageWrapLink.attr('data-fancybox', 'default').attr('rel', 'default');
|
||||
}
|
||||
}
|
||||
|
||||
if (imageTitle) {
|
||||
$imageWrapLink.append('<p class="image-caption">' + imageTitle + '</p>');
|
||||
// Make sure img title tag will show correctly in fancybox
|
||||
$imageWrapLink.attr('title', imageTitle).attr('data-caption', imageTitle);
|
||||
}
|
||||
});
|
||||
|
||||
$('.fancybox').fancybox({
|
||||
loop: true,
|
||||
helpers: {
|
||||
overlay: {
|
||||
locked: false
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
lazyLoadPostsImages: function() {
|
||||
$('#posts').find('img').lazyload({
|
||||
//placeholder: '/images/loading.gif',
|
||||
effect : 'fadeIn',
|
||||
threshold: 0
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Tabs tag listener (without twitter bootstrap).
|
||||
*/
|
||||
registerTabsTag: function() {
|
||||
var tNav = '.tabs ul.nav-tabs ';
|
||||
|
||||
// Binding `nav-tabs` & `tab-content` by real time permalink changing.
|
||||
$(function() {
|
||||
$(window).bind('hashchange', function() {
|
||||
var tHash = location.hash;
|
||||
if (tHash !== '' && !tHash.match(/%\S{2}/)) {
|
||||
$(tNav + 'li:has(a[href="' + tHash + '"])').addClass('active').siblings().removeClass('active');
|
||||
$(tHash).addClass('active').siblings().removeClass('active');
|
||||
}
|
||||
}).trigger('hashchange');
|
||||
});
|
||||
|
||||
$(tNav + '.tab').on('click', function(href) {
|
||||
href.preventDefault();
|
||||
// Prevent selected tab to select again.
|
||||
if (!$(this).hasClass('active')) {
|
||||
|
||||
// Add & Remove active class on `nav-tabs` & `tab-content`.
|
||||
$(this).addClass('active').siblings().removeClass('active');
|
||||
var tActive = $(this).find('a').attr('href');
|
||||
$(tActive).addClass('active').siblings().removeClass('active');
|
||||
|
||||
// Clear location hash in browser if #permalink exists.
|
||||
if (location.hash !== '') {
|
||||
history.pushState('', document.title, window.location.pathname + window.location.search);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
registerESCKeyEvent: function() {
|
||||
$(document).on('keyup', function(event) {
|
||||
var shouldDismissSearchPopup = event.which === 27
|
||||
&& $('.search-popup').is(':visible');
|
||||
if (shouldDismissSearchPopup) {
|
||||
$('.search-popup').hide();
|
||||
$('.search-popup-overlay').remove();
|
||||
$('body').css('overflow', '');
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
registerBackToTop: function() {
|
||||
var THRESHOLD = 50;
|
||||
var $top = $('.back-to-top');
|
||||
|
||||
function initBackToTop() {
|
||||
$top.toggleClass('back-to-top-on', window.pageYOffset > THRESHOLD);
|
||||
|
||||
var scrollTop = $(window).scrollTop();
|
||||
var contentVisibilityHeight = NexT.utils.getContentVisibilityHeight();
|
||||
var scrollPercent = scrollTop / contentVisibilityHeight;
|
||||
var scrollPercentRounded = Math.round(scrollPercent * 100);
|
||||
var scrollPercentMaxed = scrollPercentRounded > 100 ? 100 : scrollPercentRounded;
|
||||
$('#scrollpercent>span').html(scrollPercentMaxed);
|
||||
}
|
||||
|
||||
// For init back to top in sidebar if page was scrolled after page refresh.
|
||||
$(window).on('load', function() {
|
||||
initBackToTop();
|
||||
});
|
||||
|
||||
$(window).on('scroll', function() {
|
||||
initBackToTop();
|
||||
});
|
||||
|
||||
$top.on('click', function() {
|
||||
$.isFunction($('html').velocity) ? $('body').velocity('scroll') : $('html, body').animate({ scrollTop: 0 });
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Transform embedded video to support responsive layout.
|
||||
* @see http://toddmotto.com/fluid-and-responsive-youtube-and-vimeo-videos-with-fluidvids-js/
|
||||
*/
|
||||
embeddedVideoTransformer: function() {
|
||||
var $iframes = $('iframe');
|
||||
|
||||
// Supported Players. Extend this if you need more players.
|
||||
var SUPPORTED_PLAYERS = [
|
||||
'www.youtube.com',
|
||||
'player.vimeo.com',
|
||||
'player.youku.com',
|
||||
'music.163.com',
|
||||
'www.tudou.com'
|
||||
];
|
||||
var pattern = new RegExp(SUPPORTED_PLAYERS.join('|'));
|
||||
|
||||
function getDimension($element) {
|
||||
return {
|
||||
width : $element.width(),
|
||||
height: $element.height()
|
||||
};
|
||||
}
|
||||
|
||||
function getAspectRadio(width, height) {
|
||||
return height / width * 100;
|
||||
}
|
||||
|
||||
$iframes.each(function() {
|
||||
var iframe = this;
|
||||
var $iframe = $(this);
|
||||
var oldDimension = getDimension($iframe);
|
||||
var newDimension;
|
||||
|
||||
if (this.src.search(pattern) > 0) {
|
||||
|
||||
// Calculate the video ratio based on the iframe's w/h dimensions
|
||||
var videoRatio = getAspectRadio(oldDimension.width, oldDimension.height);
|
||||
|
||||
// Replace the iframe's dimensions and position the iframe absolute
|
||||
// This is the trick to emulate the video ratio
|
||||
$iframe.width('100%').height('100%')
|
||||
.css({
|
||||
position: 'absolute',
|
||||
top : '0',
|
||||
left : '0'
|
||||
});
|
||||
|
||||
// Wrap the iframe in a new <div> which uses a dynamically fetched padding-top property
|
||||
// based on the video's w/h dimensions
|
||||
var wrap = document.createElement('div');
|
||||
wrap.className = 'fluid-vids';
|
||||
wrap.style.position = 'relative';
|
||||
wrap.style.marginBottom = '20px';
|
||||
wrap.style.width = '100%';
|
||||
wrap.style.paddingTop = videoRatio + '%';
|
||||
// Fix for appear inside tabs tag.
|
||||
(wrap.style.paddingTop === '') && (wrap.style.paddingTop = '50%');
|
||||
|
||||
// Add the iframe inside our newly created <div>
|
||||
var iframeParent = iframe.parentNode;
|
||||
iframeParent.insertBefore(wrap, iframe);
|
||||
wrap.appendChild(iframe);
|
||||
|
||||
// Additional adjustments for 163 Music
|
||||
if (this.src.search('music.163.com') > 0) {
|
||||
newDimension = getDimension($iframe);
|
||||
var shouldRecalculateAspect = newDimension.width > oldDimension.width
|
||||
|| newDimension.height < oldDimension.height;
|
||||
|
||||
// 163 Music Player has a fixed height, so we need to reset the aspect radio
|
||||
if (shouldRecalculateAspect) {
|
||||
wrap.style.paddingTop = getAspectRadio(newDimension.width, oldDimension.height) + '%';
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
hasMobileUA: function() {
|
||||
var nav = window.navigator;
|
||||
var ua = nav.userAgent;
|
||||
var pa = /iPad|iPhone|Android|Opera Mini|BlackBerry|webOS|UCWEB|Blazer|PSP|IEMobile|Symbian/g;
|
||||
|
||||
return pa.test(ua);
|
||||
},
|
||||
|
||||
isTablet: function() {
|
||||
return window.screen.width < 992 && window.screen.width > 767 && this.hasMobileUA();
|
||||
},
|
||||
|
||||
isMobile: function() {
|
||||
return window.screen.width < 767 && this.hasMobileUA();
|
||||
},
|
||||
|
||||
isDesktop: function() {
|
||||
return !this.isTablet() && !this.isMobile();
|
||||
},
|
||||
|
||||
/**
|
||||
* Escape meta symbols in jQuery selectors.
|
||||
*
|
||||
* @param selector
|
||||
* @returns {string|void|XML|*}
|
||||
*/
|
||||
escapeSelector: function(selector) {
|
||||
return selector.replace(/[!"$%&'()*+,./:;<=>?@[\\\]^`{|}~]/g, '\\$&');
|
||||
},
|
||||
|
||||
displaySidebar: function() {
|
||||
if (!this.isDesktop() || this.isPisces() || this.isGemini()) {
|
||||
return;
|
||||
}
|
||||
$('.sidebar-toggle').trigger('click');
|
||||
},
|
||||
|
||||
isMuse: function() {
|
||||
return CONFIG.scheme === 'Muse';
|
||||
},
|
||||
|
||||
isMist: function() {
|
||||
return CONFIG.scheme === 'Mist';
|
||||
},
|
||||
|
||||
isPisces: function() {
|
||||
return CONFIG.scheme === 'Pisces';
|
||||
},
|
||||
|
||||
isGemini: function() {
|
||||
return CONFIG.scheme === 'Gemini';
|
||||
},
|
||||
|
||||
getScrollbarWidth: function() {
|
||||
var $div = $('<div />').addClass('scrollbar-measure').prependTo('body');
|
||||
var div = $div[0];
|
||||
var scrollbarWidth = div.offsetWidth - div.clientWidth;
|
||||
$div.remove();
|
||||
|
||||
return scrollbarWidth;
|
||||
},
|
||||
|
||||
getContentVisibilityHeight: function() {
|
||||
var docHeight = $('.container').height();
|
||||
var winHeight = $(window).height();
|
||||
var contentVisibilityHeight = docHeight > winHeight ? docHeight - winHeight : $(document).height() - winHeight;
|
||||
return contentVisibilityHeight;
|
||||
},
|
||||
|
||||
getSidebarb2tHeight: function() {
|
||||
var sidebarb2tHeight = (CONFIG.back2top && CONFIG.back2top_sidebar) ? $('.back-to-top').height() : 0;
|
||||
return sidebarb2tHeight;
|
||||
},
|
||||
|
||||
getSidebarSchemePadding: function() {
|
||||
var sidebarNavHeight = $('.sidebar-nav').css('display') === 'block' ? $('.sidebar-nav').outerHeight(true) : 0;
|
||||
var sidebarInner = $('.sidebar-inner');
|
||||
var sidebarPadding = sidebarInner.innerWidth() - sidebarInner.width();
|
||||
var sidebarOffset = CONFIG.sidebar.offset ? CONFIG.sidebar.offset : 12;
|
||||
var sidebarSchemePadding = this.isPisces() || this.isGemini()
|
||||
? (sidebarPadding * 2) + sidebarNavHeight + sidebarOffset + this.getSidebarb2tHeight()
|
||||
: (sidebarPadding * 2) + (sidebarNavHeight / 2);
|
||||
return sidebarSchemePadding;
|
||||
}
|
||||
};
|
||||
|
||||
$(document).ready(function() {
|
||||
|
||||
function wrapTable() {
|
||||
$('table').not('.gist table').wrap('<div class="table-container"></div>');
|
||||
}
|
||||
|
||||
/**
|
||||
* Init Sidebar & TOC inner dimensions on all pages and for all schemes.
|
||||
* Need for Sidebar/TOC inner scrolling if content taller then viewport.
|
||||
*/
|
||||
function updateSidebarHeight(height) {
|
||||
height = height || 'auto';
|
||||
$('.site-overview, .post-toc').css('max-height', height);
|
||||
}
|
||||
|
||||
function initSidebarDimension() {
|
||||
var updateSidebarHeightTimer;
|
||||
|
||||
$(window).on('resize', function() {
|
||||
updateSidebarHeightTimer && clearTimeout(updateSidebarHeightTimer);
|
||||
|
||||
updateSidebarHeightTimer = setTimeout(function() {
|
||||
var sidebarWrapperHeight = document.body.clientHeight - NexT.utils.getSidebarSchemePadding();
|
||||
|
||||
updateSidebarHeight(sidebarWrapperHeight);
|
||||
}, 0);
|
||||
});
|
||||
|
||||
// Initialize Sidebar & TOC Width.
|
||||
var scrollbarWidth = NexT.utils.getScrollbarWidth();
|
||||
if ($('.site-overview-wrap').height() > (document.body.clientHeight - NexT.utils.getSidebarSchemePadding())) {
|
||||
$('.site-overview').css('width', 'calc(100% + ' + scrollbarWidth + 'px)');
|
||||
}
|
||||
if ($('.post-toc-wrap').height() > (document.body.clientHeight - NexT.utils.getSidebarSchemePadding())) {
|
||||
$('.post-toc').css('width', 'calc(100% + ' + scrollbarWidth + 'px)');
|
||||
}
|
||||
|
||||
// Initialize Sidebar & TOC Height.
|
||||
updateSidebarHeight(document.body.clientHeight - NexT.utils.getSidebarSchemePadding());
|
||||
}
|
||||
initSidebarDimension();
|
||||
wrapTable();
|
||||
});
|
Reference in New Issue
Block a user