HandyControl/doc/themes/next/source/js/utils.js
2019-04-10 22:28:09 +08:00

341 lines
11 KiB
JavaScript

/* 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('figure 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();
});