/* global NexT: true */ NexT.utils = NexT.$u = { /** * Wrap images with fancybox support. */ wrapImageWithFancyBox: function () { $('.content img') .not('[hidden]') .not('.group-picture img, .post-gallery img') .each(function () { var $image = $(this); var imageTitle = $image.attr('title'); var $imageWrapLink = $image.parent('a'); if ($imageWrapLink.size() < 1) { var imageLink = ($image.attr('data-original')) ? this.getAttribute('data-original') : this.getAttribute('src'); $imageWrapLink = $image.wrap('').parent('a'); } $imageWrapLink.addClass('fancybox fancybox.image'); $imageWrapLink.attr('rel', 'group'); if (imageTitle) { $imageWrapLink.append('

' + imageTitle + '

'); //make sure img title tag will show correctly in fancybox $imageWrapLink.attr('title', imageTitle); } }); $('.fancybox').fancybox({ 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 !== '') { $(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'); $(window).on('scroll', function () { $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); }); $top.on('click', function () { $('body').velocity('scroll'); }); }, /** * 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('|') ); $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
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
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) + '%'; } } } }); function getDimension($element) { return { width: $element.width(), height: $element.height() }; } function getAspectRadio(width, height) { return height / width * 100; } }, /** * Add `menu-item-active` class name to menu item * via comparing location.path with menu item's href. */ addActiveClassToMenuItem: function () { var path = window.location.pathname; path = path === '/' ? path : path.substring(0, path.length - 1); $('.menu-item a[href^="' + path + '"]:first').parent().addClass('menu-item-active'); }, 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'); }, isMist: function () { return CONFIG.scheme === 'Mist'; }, isPisces: function () { return CONFIG.scheme === 'Pisces'; }, isGemini: function () { return CONFIG.scheme === 'Gemini'; }, getScrollbarWidth: function () { var $div = $('
').addClass('scrollbar-measure').prependTo('body'); var div = $div[0]; var scrollbarWidth = div.offsetWidth - div.clientWidth; $div.remove(); return scrollbarWidth; }, getContentVisibilityHeight: function () { var docHeight = $('#content').height(), winHeight = $(window).height(), contentVisibilityHeight = (docHeight > winHeight) ? (docHeight - winHeight) : ($(document).height() - winHeight); return contentVisibilityHeight; }, getSidebarb2tHeight: function () { //var sidebarb2tHeight = (CONFIG.sidebar.b2t) ? document.getElementsByClassName('back-to-top')[0].clientHeight : 0; var sidebarb2tHeight = (CONFIG.sidebar.b2t) ? $('.back-to-top').height() : 0; //var sidebarb2tHeight = (CONFIG.sidebar.b2t) ? 24 : 0; return sidebarb2tHeight; }, getSidebarSchemePadding: function () { var sidebarNavHeight = ($('.sidebar-nav').css('display') == 'block') ? $('.sidebar-nav').outerHeight(true) : 0, sidebarInner = $('.sidebar-inner'), sidebarPadding = sidebarInner.innerWidth() - sidebarInner.width(), sidebarSchemePadding = this.isPisces() || this.isGemini() ? ((sidebarPadding * 2) + sidebarNavHeight + (CONFIG.sidebar.offset * 2) + this.getSidebarb2tHeight()) : ((sidebarPadding * 2) + (sidebarNavHeight / 2)); return sidebarSchemePadding; } /** * Affix behaviour for Sidebar. * * @returns {Boolean} */ // needAffix: function () { // return this.isPisces() || this.isGemini(); // } }; $(document).ready(function () { initSidebarDimension(); /** * Init Sidebar & TOC inner dimensions on all pages and for all schemes. * Need for Sidebar/TOC inner scrolling if content taller then viewport. */ 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()); } function updateSidebarHeight (height) { height = height || 'auto'; $('.site-overview, .post-toc').css('max-height', height); } });