diff options
Diffstat (limited to '_includes/scripts')
-rw-r--r-- | _includes/scripts/archieve.js | 135 | ||||
-rw-r--r-- | _includes/scripts/article.js | 24 | ||||
-rw-r--r-- | _includes/scripts/aside/affix.js | 26 | ||||
-rw-r--r-- | _includes/scripts/aside/toc.js | 35 | ||||
-rw-r--r-- | _includes/scripts/common.js | 7 | ||||
-rw-r--r-- | _includes/scripts/components/lightbox.js | 49 | ||||
-rw-r--r-- | _includes/scripts/components/search.js | 86 | ||||
-rw-r--r-- | _includes/scripts/components/sidebar.js | 30 | ||||
-rw-r--r-- | _includes/scripts/home.js | 3 | ||||
-rw-r--r-- | _includes/scripts/lib/affix.js | 111 | ||||
-rw-r--r-- | _includes/scripts/lib/gallery.js | 192 | ||||
-rw-r--r-- | _includes/scripts/lib/lazyload.js | 143 | ||||
-rw-r--r-- | _includes/scripts/lib/modal.js | 64 | ||||
-rw-r--r-- | _includes/scripts/lib/scroll-to.js | 13 | ||||
-rw-r--r-- | _includes/scripts/lib/swiper.js | 203 | ||||
-rw-r--r-- | _includes/scripts/lib/throttle.js | 28 | ||||
-rw-r--r-- | _includes/scripts/lib/toc.js | 107 | ||||
-rw-r--r-- | _includes/scripts/page.js | 3 | ||||
-rw-r--r-- | _includes/scripts/utils/imagesLoad.js | 28 | ||||
-rw-r--r-- | _includes/scripts/utils/utils.js | 39 | ||||
-rw-r--r-- | _includes/scripts/variables.html | 35 |
21 files changed, 1361 insertions, 0 deletions
diff --git a/_includes/scripts/archieve.js b/_includes/scripts/archieve.js new file mode 100644 index 0000000..96549b5 --- /dev/null +++ b/_includes/scripts/archieve.js @@ -0,0 +1,135 @@ +(function() { + var SOURCES = window.TEXT_VARIABLES.sources; + function queryString() { + // This function is anonymous, is executed immediately and + // the return value is assigned to QueryString! + var i = 0, queryObj = {}, pair; + var queryStr = window.location.search.substring(1); + var queryArr = queryStr.split('&'); + for (i = 0; i < queryArr.length; i++) { + pair = queryArr[i].split('='); + // If first entry with this name + if (typeof queryObj[pair[0]] === 'undefined') { + queryObj[pair[0]] = pair[1]; + // If second entry with this name + } else if (typeof queryObj[pair[0]] === 'string') { + queryObj[pair[0]] = [queryObj[pair[0]], pair[1]]; + // If third or later entry with this name + } else { + queryObj[pair[0]].push(pair[1]); + } + } + return queryObj; + } + + var setUrlQuery = (function() { + var baseUrl = window.location.href.split('?')[0]; + return function(query) { + if (typeof query === 'string') { + window.history.replaceState(null, '', baseUrl + query); + } else { + window.history.replaceState(null, '', baseUrl); + } + }; + })(); + + window.Lazyload.js(SOURCES.jquery, function() { + var $tags = $('.js-tags'); + var $articleTags = $tags.find('button'); + var $tagShowAll = $tags.find('.tag-button--all'); + var $result = $('.js-result'); + var $sections = $result.find('section'); + var sectionArticles = []; + var $lastFocusButton = null; + var sectionTopArticleIndex = []; + var hasInit = false; + + $sections.each(function() { + sectionArticles.push($(this).find('.item')); + }); + + function init() { + var i, index = 0; + for (i = 0; i < $sections.length; i++) { + sectionTopArticleIndex.push(index); + index += $sections.eq(i).find('.item').length; + } + sectionTopArticleIndex.push(index); + } + + function searchButtonsByTag(_tag/*raw tag*/) { + if (!_tag) { + return $tagShowAll; + } + var _buttons = $articleTags.filter('[data-encode="' + _tag + '"]'); + if (_buttons.length === 0) { + return $tagShowAll; + } + return _buttons; + } + function buttonFocus(target) { + if (target) { + target.addClass('focus'); + $lastFocusButton && !$lastFocusButton.is(target) && $lastFocusButton.removeClass('focus'); + $lastFocusButton = target; + } + } + + function tagSelect (tag/*raw tag*/, target) { + var result = {}, $articles; + var i, j, k, _tag; + + for (i = 0; i < sectionArticles.length; i++) { + $articles = sectionArticles[i]; + for (j = 0; j < $articles.length; j++) { + if (tag === '' || tag === undefined) { + result[i] || (result[i] = {}); + result[i][j] = true; + } else { + var tags = $articles.eq(j).data('tags').split(','); + for (k = 0; k < tags.length; k++) { + if (tags[k] === tag) { + result[i] || (result[i] = {}); + result[i][j] = true; break; + } + } + } + } + } + + for (i = 0; i < sectionArticles.length; i++) { + result[i] && $sections.eq(i).removeClass('d-none'); + result[i] || $sections.eq(i).addClass('d-none'); + for (j = 0; j < sectionArticles[i].length; j++) { + if (result[i] && result[i][j]) { + sectionArticles[i].eq(j).removeClass('d-none'); + } else { + sectionArticles[i].eq(j).addClass('d-none'); + } + } + } + + hasInit || ($result.removeClass('d-none'), hasInit = true); + + + if (target) { + buttonFocus(target); + _tag = target.attr('data-encode'); + if (_tag === '' || typeof _tag !== 'string') { + setUrlQuery(); + } else { + setUrlQuery('?tag=' + _tag); + } + } else { + buttonFocus(searchButtonsByTag(tag)); + } + } + + var query = queryString(), _tag = query.tag; + init(); tagSelect(_tag); + $tags.on('click', 'button', function() { + tagSelect($(this).data('encode'), $(this)); + }); + + }); +})(); diff --git a/_includes/scripts/article.js b/_includes/scripts/article.js new file mode 100644 index 0000000..9b18ef5 --- /dev/null +++ b/_includes/scripts/article.js @@ -0,0 +1,24 @@ +(function() { + var SOURCES = window.TEXT_VARIABLES.sources; + window.Lazyload.js(SOURCES.jquery, function() { + $(function() { + var $this ,$scroll; + var $articleContent = $('.js-article-content'); + var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar'); + var scroll = hasSidebar ? '.js-page-main' : 'html, body'; + $scroll = $(scroll); + + $articleContent.find('.highlight').each(function() { + $this = $(this); + $this.attr('data-lang', $this.find('code').attr('data-lang')); + }); + $articleContent.find('h1[id], h2[id], h3[id], h4[id], h5[id], h6[id]').each(function() { + $this = $(this); + $this.append($('<a class="anchor d-print-none" aria-hidden="true"></a>').html('<i class="fas fa-anchor"></i>')); + }); + $articleContent.on('click', '.anchor', function() { + $scroll.scrollToAnchor('#' + $(this).parent().attr('id'), 400); + }); + }); + }); +})(); diff --git a/_includes/scripts/aside/affix.js b/_includes/scripts/aside/affix.js new file mode 100644 index 0000000..1db3b8e --- /dev/null +++ b/_includes/scripts/aside/affix.js @@ -0,0 +1,26 @@ +(function() { + var SOURCES = window.TEXT_VARIABLES.sources; + window.Lazyload.js(SOURCES.jquery, function() { + var $window = $(window), $pageFooter = $('.js-page-footer'); + var $pageAside = $('.js-page-aside'); + var affix; + var tocDisabled = false; + var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar'); + + affix = $pageAside.affix({ + offsetBottom: $pageFooter.outerHeight(), + scrollTarget: hasSidebar ? '.js-page-main' : null, + scroller: hasSidebar ? '.js-page-main' : null, + scroll: hasSidebar ? $('.js-page-main').children() : null, + disabled: tocDisabled + }); + + $window.on('resize', window.throttle(function() { + affix && affix.setOptions({ + disabled: tocDisabled + }); + }, 100)); + + window.pageAsideAffix = affix; + }); +})(); diff --git a/_includes/scripts/aside/toc.js b/_includes/scripts/aside/toc.js new file mode 100644 index 0000000..a19ea95 --- /dev/null +++ b/_includes/scripts/aside/toc.js @@ -0,0 +1,35 @@ +(function() { + var SOURCES = window.TEXT_VARIABLES.sources; + var TOC_SELECTOR = window.TEXT_VARIABLES.site.toc.selectors; + window.Lazyload.js(SOURCES.jquery, function() { + var $window = $(window); + var $articleContent = $('.js-article-content'); + var $tocRoot = $('.js-toc-root'), $col2 = $('.js-col-aside'); + var toc; + var tocDisabled = false; + var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar'); + var hasToc = $articleContent.find(TOC_SELECTOR).length > 0; + + function disabled() { + return $col2.css('display') === 'none' || !hasToc; + } + + tocDisabled = disabled(); + + toc = $tocRoot.toc({ + selectors: TOC_SELECTOR, + container: $articleContent, + scrollTarget: hasSidebar ? '.js-page-main' : null, + scroller: hasSidebar ? '.js-page-main' : null, + disabled: tocDisabled + }); + + $window.on('resize', window.throttle(function() { + tocDisabled = disabled(); + toc && toc.setOptions({ + disabled: tocDisabled + }); + }, 100)); + + }); +})(); diff --git a/_includes/scripts/common.js b/_includes/scripts/common.js new file mode 100644 index 0000000..09400a2 --- /dev/null +++ b/_includes/scripts/common.js @@ -0,0 +1,7 @@ +(function () { + var $root = document.getElementsByClassName('root')[0]; + if (window.hasEvent('touchstart')) { + $root.dataset.isTouch = true; + document.addEventListener('touchstart', function(){}, false); + } +})(); diff --git a/_includes/scripts/components/lightbox.js b/_includes/scripts/components/lightbox.js new file mode 100644 index 0000000..51689c2 --- /dev/null +++ b/_includes/scripts/components/lightbox.js @@ -0,0 +1,49 @@ +{%- include scripts/utils/imagesLoad.js -%} +(function () { + var SOURCES = window.TEXT_VARIABLES.sources; + window.Lazyload.js(SOURCES.jquery, function() { + var $pageGalleryModal = $('.js-page-gallery-modal'); + var $images = $('.page__content').find('img:not(.lightbox-ignore)'); + window.imagesLoad($images).then(function() { + /* global Gallery */ + var pageGalleryModal = $pageGalleryModal.modal({ onChange: handleModalChange }); + var gallery = null; + var modalVisible = false; + var i, items = [], image, item; + if($images && $images.length > 0) { + for (i = 0; i < $images.length; i++) { + image = $images.eq(i); + if (image.get(0).naturalWidth > 800) { + items.push({ src: image.attr('src'), w: image.get(0).naturalWidth, h: image.get(0).naturalHeight, $el: image}); + } + } + } + + if(items.length > 0) { + gallery = new Gallery('.gallery', items); + gallery.setOptions({ disabled: !modalVisible }); + gallery.init(); + for (i = 0; i < items.length; i++) { + item = items[i]; + item.$el && (item.$el.addClass('popup-image'), item.$el.on('click', (function() { + var index = i; + return function() { + pageGalleryModal.show(); + gallery.setOptions({ initialSlide: index }); + gallery.refresh(true, { animation: false }); + }; + })())); + } + } + + function handleModalChange(visible) { + modalVisible = visible; + gallery && gallery.setOptions({ disabled: !modalVisible }); + } + + $pageGalleryModal.on('click', function() { + pageGalleryModal.hide(); + }); + }); + }); +})(); diff --git a/_includes/scripts/components/search.js b/_includes/scripts/components/search.js new file mode 100644 index 0000000..e1c8c27 --- /dev/null +++ b/_includes/scripts/components/search.js @@ -0,0 +1,86 @@ + +(function () { + var SOURCES = window.TEXT_VARIABLES.sources; + window.Lazyload.js(SOURCES.jquery, function() { + // search panel + var search = (window.search || (window.search = {})); + var useDefaultSearchBox = window.useDefaultSearchBox === undefined ? + true : window.useDefaultSearchBox ; + + var $searchModal = $('.js-page-search-modal'); + var $searchToggle = $('.js-search-toggle'); + var searchModal = $searchModal.modal({ onChange: handleModalChange, hideWhenWindowScroll: true }); + var modalVisible = false; + search.searchModal = searchModal; + + var $searchBox = null; + var $searchInput = null; + var $searchClear = null; + + function getModalVisible() { + return modalVisible; + } + search.getModalVisible = getModalVisible; + + function handleModalChange(visible) { + modalVisible = visible; + if (visible) { + search.onShow && search.onShow(); + useDefaultSearchBox && $searchInput[0] && $searchInput[0].focus(); + } else { + search.onShow && search.onHide(); + useDefaultSearchBox && $searchInput[0] && $searchInput[0].blur(); + setTimeout(function() { + useDefaultSearchBox && ($searchInput.val(''), $searchBox.removeClass('not-empty')); + search.clear && search.clear(); + window.pageAsideAffix && window.pageAsideAffix.refresh(); + }, 400); + } + } + + $searchToggle.on('click', function() { + modalVisible ? searchModal.hide() : searchModal.show(); + }); + // Char Code: 83 S, 191 / + $(window).on('keyup', function(e) { + if (!modalVisible && !window.isFormElement(e.target || e.srcElement) && (e.which === 83 || e.which === 191)) { + modalVisible || searchModal.show(); + } + }); + + if (useDefaultSearchBox) { + $searchBox = $('.js-search-box'); + $searchInput = $searchBox.children('input'); + $searchClear = $searchBox.children('.js-icon-clear'); + search.getSearchInput = function() { + return $searchInput.get(0); + }; + search.getVal = function() { + return $searchInput.val(); + }; + search.setVal = function(val) { + $searchInput.val(val); + }; + + $searchInput.on('focus', function() { + $(this).addClass('focus'); + }); + $searchInput.on('blur', function() { + $(this).removeClass('focus'); + }); + $searchInput.on('input', window.throttle(function() { + var val = $(this).val(); + if (val === '' || typeof val !== 'string') { + search.clear && search.clear(); + } else { + $searchBox.addClass('not-empty'); + search.onInputNotEmpty && search.onInputNotEmpty(val); + } + }, 400)); + $searchClear.on('click', function() { + $searchInput.val(''); $searchBox.removeClass('not-empty'); + search.clear && search.clear(); + }); + } + }); +})(); diff --git a/_includes/scripts/components/sidebar.js b/_includes/scripts/components/sidebar.js new file mode 100644 index 0000000..92c5591 --- /dev/null +++ b/_includes/scripts/components/sidebar.js @@ -0,0 +1,30 @@ +(function() { + var SOURCES = window.TEXT_VARIABLES.sources; + + window.Lazyload.js(SOURCES.jquery, function() { + var $pageMask = $('.js-page-mask'); + var $pageRoot = $('.js-page-root'); + var $sidebarShow = $('.js-sidebar-show'); + var $sidebarHide = $('.js-sidebar-hide'); + + function freeze(e) { + if (e.target === $pageMask[0]) { + e.preventDefault(); + } + } + function stopBodyScrolling(bool) { + if (bool === true) { + window.addEventListener('touchmove', freeze, { passive: false }); + } else { + window.removeEventListener('touchmove', freeze, { passive: false }); + } + } + + $sidebarShow.on('click', function() { + stopBodyScrolling(true); $pageRoot.addClass('show-sidebar'); + }); + $sidebarHide.on('click', function() { + stopBodyScrolling(false); $pageRoot.removeClass('show-sidebar'); + }); + }); +})(); diff --git a/_includes/scripts/home.js b/_includes/scripts/home.js new file mode 100644 index 0000000..91d05b9 --- /dev/null +++ b/_includes/scripts/home.js @@ -0,0 +1,3 @@ +/*(function () { + +})();*/ 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; + }); +})(); diff --git a/_includes/scripts/page.js b/_includes/scripts/page.js new file mode 100644 index 0000000..91d05b9 --- /dev/null +++ b/_includes/scripts/page.js @@ -0,0 +1,3 @@ +/*(function () { + +})();*/ diff --git a/_includes/scripts/utils/imagesLoad.js b/_includes/scripts/utils/imagesLoad.js new file mode 100644 index 0000000..63a6bdf --- /dev/null +++ b/_includes/scripts/utils/imagesLoad.js @@ -0,0 +1,28 @@ +(function() { + window.imagesLoad = function(images) { + images = images || document.getElementsByTagName('img'); + var imagesCount = images.length, loadedCount = 0, image; + var i, j, loaded = false, cbs = []; + imagesCount < 1 && (loaded = true); + for (i = 0; i < imagesCount; i++) { + image = images[i]; + image.complete ? handleImageLoad() : image.addEventListener('load', handleImageLoad); + } + function handleImageLoad() { + loadedCount++; + if (loadedCount === imagesCount) { + loaded = true; + if (cbs.length > 0) { + for (j = 0; j < cbs.length; j++) { + cbs[j](); + } + } + } + } + return { + then: function(cb) { + cb && (loaded ? cb() : (cbs.push(cb))); + } + }; + }; +})(); diff --git a/_includes/scripts/utils/utils.js b/_includes/scripts/utils/utils.js new file mode 100644 index 0000000..e7bce45 --- /dev/null +++ b/_includes/scripts/utils/utils.js @@ -0,0 +1,39 @@ +(function() { + window.isArray = function(val) { + return Object.prototype.toString.call(val) === '[object Array]'; + }; + window.isString = function(val) { + return typeof val === 'string'; + }; + + window.hasEvent = function(event) { + return 'on'.concat(event) in window.document; + }; + + window.isOverallScroller = function(node) { + return node === document.documentElement || node === document.body || node === window; + }; + + window.isFormElement = function(node) { + var tagName = node.tagName; + return tagName === 'INPUT' || tagName === 'SELECT' || tagName === 'TEXTAREA'; + }; + + window.pageLoad = (function () { + var loaded = false, cbs = []; + window.addEventListener('load', function () { + var i; + loaded = true; + if (cbs.length > 0) { + for (i = 0; i < cbs.length; i++) { + cbs[i](); + } + } + }); + return { + then: function(cb) { + cb && (loaded ? cb() : (cbs.push(cb))); + } + }; + })(); +})(); diff --git a/_includes/scripts/variables.html b/_includes/scripts/variables.html new file mode 100644 index 0000000..5bd1770 --- /dev/null +++ b/_includes/scripts/variables.html @@ -0,0 +1,35 @@ +{%- include snippets/get-sources.html -%} +{%- assign _sources = __return -%} + +{%- include snippets/get-nav-url.html path="/assets/search.js" -%} +{%- assign _paths_search_js = __return -%} + +<script> + (function() { + var TEXT_VARIABLES = { + version: '2.2.6', + sources: { + font_awesome: '{{ _sources.font_awesome }}', + jquery: '{{ _sources.jquery }}', + leancloud_js_sdk: '{{ _sources.leancloud_js_sdk }}', + chart: '{{ _sources.chart }}', + gitalk: { + js: '{{ _sources.gitalk.js }}', + css: '{{ _sources.gitalk.css }}' + }, + valine: '{{ _sources.valine }}', + mathjax: '{{ _sources.mathjax }}', + mermaid: '{{ _sources.mermaid }}' + }, + site: { + toc: { + selectors: '{{ site.toc.selectors | default: site.data.variables.default.toc.selectors }}' + } + }, + paths: { + search_js: '{{ _paths_search_js }}' + } + }; + window.TEXT_VARIABLES = TEXT_VARIABLES; + })(); +</script> |