1 /*
2 主站,子频道,定向站点共用
3 */
4 (function() {
5
6 scrollToAnchor();
7
8 toggleSearchForm();
9
10 scrollTop();
11
12 initScrollBar();
13
14 // 文档图片放大查看
15 imgZoom();
16
17 renderCodeBox();
18
19 dropdownClick();
20
21 fixAside();
22
23 // 侧边栏固定
24 function fixAside() {
25 if (SITE_SLUG === 'open') {
26 var headerHeight = $('.header').outerHeight() + $('.search-wrapper').outerHeight() + 32;
27 var offsetTop = $('.dropdown-menu-selector').height() || 0;
28 affixSidebar(headerHeight, offsetTop);
29 affix($('.breadcrumb'), headerHeight, 0);
30 } else {
31 var headerHeight = $('.header').outerHeight();
32 var offsetTop = 86;
33 affixSidebar(headerHeight, offsetTop);
34 }
35 }
36
37 // 页面加载时的锚点定位
38 function initScrollBar() {
39 $(window).on('load', function() {
40 var hash = decodeURIComponent(window.location.hash);
41 if (!hash) return;
42
43 // 兼容 toc 旧版本中的链接错误
44 if (hash.substr(0, 2) === '##') {
45 hash = hash.substr(1);
46 }
47
48 if (hash !== '#' && $(hash).length) {
49 var top = $(hash).offset().top - $('.breadcrumb').outerHeight();
50
51 // 子站点需要计算头部高度
52 if (SITE_SLUG !== 'open') {
53 top -= $('.page-title').outerHeight();
54 }
55 setTimeout(function() {
56 $(window).scrollTop(top);
57 }, 0);
58 }
59 });
60 }
61
62 function affix($el, headerHeight, offsetTop) {
63 $(window).on('load scroll resize', function () {
64 if (!$el.length) return;
65
66 var scrollTop = window.scrollY || window.pageYOffset;
67 if (scrollTop > headerHeight) {
68 $el.css({
69 position: 'fixed',
70 top: offsetTop,
71 left: $el.offset().left,
72 right: $('body').width() - $el.offset().left - $el.width(),
73 })
74 } else {
75 $el.removeAttr('style')
76 }
77 });
78 }
79
80 function affixSidebar(headerHeight, offsetTop) {
81 var footerHeight = $('.body-footer').outerHeight();
82 var $sidebar = $('.sidebar-wrapper');
83 var $breadcrumb = $('.breadcrumb');
84
85 $(window).on('load scroll resize', function () {
86 var scrollTop = window.scrollY || window.pageYOffset;
87
88 // sidebar fixed 时跟底部保持的距离
89 var offsetBottom = document.body.scrollHeight - scrollTop - window.innerHeight - 32;
90
91 var bottom = 0;
92 if (offsetBottom < footerHeight) {
93 bottom = footerHeight - offsetBottom;
94 }
95
96 $sidebar.find('.sidebar').css({
97 'height': window.innerHeight - bottom - offsetTop,
98 });
99
100 // sidebar fixed
101 if (scrollTop > headerHeight) {
102 $sidebar.addClass('fixed');
103 } else {
104 $sidebar.removeClass('fixed');
105 }
106 });
107 }
108
109
110 function dropdownClick() {
111 // dropdown trigger: click
112 $('body').on('click', '.dropdown .dropdown-trigger', function() {
113 var $dropdown = $(this).parent('.dropdown');
114 $dropdown.toggleClass('open');
115
116 if ($dropdown.hasClass('open') && $dropdown.hasClass('dropdown-menu-selector')) {
117 var $menu = $('#main-menu');
118 var $active = $menu.find('.menu-item .active');
119 if ($active.length) {
120 var top = $menu.scrollTop() + $active.position().top - 56;
121 if (top > 0) {
122 $menu.scrollTop(top);
123 }
124 }
125 }
126 });
127 $('html').on('click', function() {
128 $('.dropdown.open').removeClass('open');
129 });
130 $('html').on('click', '.dropdown', function(e) {
131 e.stopPropagation();
132 });
133 }
134
135 function renderCodeBox() {
136 // copy code
137 var $codeBox = $('<div class="code-box" />');
138 var codeTemplate = '<span class="btn-copy-code">点击复制</span>';
139 $('code.language-js, code.language-javascript, code.language-jsx').each(function(index, item) {
140 $(item).parent('pre').wrap($codeBox).before(codeTemplate);
141 })
142
143 var clipboard = new Clipboard('.btn-copy-code', {
144 text: function(trigger) {
145 return trigger.nextElementSibling.textContent;
146 }
147 });
148
149 var clipboardTimer = null;
150 clipboard.on('success', (e) => {
151 $(e.trigger).text('复制成功!');
152 if (clipboardTimer) {
153 clearTimeout(clipboardTimer);
154 }
155 clipboardTimer = setTimeout(() => {
156 $(e.trigger).text('点击复制');
157 }, 1500);
158 });
159 }
160
161 function imgZoom() {
162 var zoomDefaults = {
163 styles: {
164 zoomImage: {
165 cursor : 'zoom-out',
166 position : 'absolute',
167 transition : 'transform 300ms',
168 transform : 'translate3d(0, 0, 0) scale(1)',
169 transformOrigin : 'center center',
170 willChange : 'transform, top, left'
171 },
172 zoomContainer: {
173 position : 'fixed',
174 top : 0,
175 right : 0,
176 bottom : 0,
177 left : 0,
178 zIndex : 1024,
179 },
180 overlay: {
181 position : 'absolute',
182 top : 0,
183 right : 0,
184 bottom : 0,
185 left : 0,
186 backgroundColor : '#FFF',
187 opacity : 0,
188 transition : 'opacity 300ms',
189 },
190 btn: {
191 position : 'absolute',
192 bottom : 12,
193 right : 12,
194 padding : '4px 10px',
195 border : '1px solid #e9e9e9',
196 borderRadius : 2,
197 fontSize : 12,
198 color : '#999',
199 },
200 btnHover: {
201 color : '#666',
202 },
203 },
204 };
205 var zoomOriginImage = null;
206 var zoomTimer = null;
207 // zoom in
208 $('.markdown').on('click', 'img', function() {
209 zoomOriginImage = $(this).get(0);
210
211 var $wrap = $('<div />');
212 $wrap.css(zoomDefaults.styles.zoomContainer);
213
214 var $overlay = $('<div class="overlay" />');
215 $overlay.css(zoomDefaults.styles.overlay);
216
217 var $img = $(this).clone();
218 $img.css(getImageStyle(zoomOriginImage, false));
219
220 var $btn = $('<a target="_blank" />');
221 $btn.attr('href', $img.attr('src')).text('查看原图');
222 $btn.css(zoomDefaults.styles.btn);
223
224 $btn.hover(function() {
225 $(this).css(zoomDefaults.styles.btnHover);
226 }, function() {
227 $(this).css(zoomDefaults.styles.btn);
228 });
229
230 $wrap.append($overlay).append($img).append($btn);
231 $('#zoom-img').append($wrap);
232
233 // transition
234 $overlay.css({
235 opacity: 1,
236 });
237 $img.css(getImageStyle($img.get(0), true));
238 });
239
240 // zoom out
241 $('#zoom-img').on('click', function() {
242 var $zoom = $(this);
243 $zoom.find('img').css(getImageStyle(zoomOriginImage, false));
244 $zoom.find('.overlay').css({
245 opacity: 0
246 });
247
248 if (zoomTimer) {
249 clearTimeout(zoomTimer);
250 }
251 zoomTimer = setTimeout(function() {
252 $zoom.html('');
253 zoomOriginImage = null;
254 }, 150);
255 });
256
257 $(window).on('scroll', function() {
258 $('#zoom-img').html('');
259 zoomOriginImage = null;
260 });
261
262 $(window).on('resize', function() {
263 if ($('#zoom-img img').length) {
264 $('#zoom-img img').css(getImageStyle(zoomOriginImage, true));
265 }
266 });
267
268 function getImageStyle(image, isZoom) {
269 var imageOffset = image.getBoundingClientRect();
270 var top = imageOffset.top;
271 var left = imageOffset.left;
272 var width = image.width;
273 var height = image.height;
274
275 var style = {
276 top: top,
277 left: left,
278 width: width,
279 height: height
280 };
281
282 if (!isZoom) {
283 return Object.assign({}, zoomDefaults.styles.zoomImage, style);
284 }
285
286 // Get the the coords for center of the viewport
287 var viewportX = window.innerWidth / 2;
288 var viewportY = window.innerHeight / 2;
289
290 // Get the coords for center of the original image
291 var imageCenterX = imageOffset.left + image.width / 2;
292 var imageCenterY = imageOffset.top + image.height / 2;
293
294 // Get offset amounts for image coords to be centered on screen
295 var translateX = viewportX - imageCenterX;
296 var translateY = viewportY - imageCenterY;
297
298 // Figure out how much to scale the image so it doesn't overflow the screen
299 var scale = getScale(width, height);
300
301 var zoomStyle = {
302 transform: 'translate3d(' + translateX + 'px, ' + translateY + 'px, 0) scale(' + scale + ')',
303 }
304
305 return Object.assign({}, zoomDefaults.styles.zoomImage, style, zoomStyle);
306 }
307
308 function getScale(width, height) {
309 var totalMargin = 40;
310 var scaleX = window.innerWidth / (width + totalMargin);
311 var scaleY = window.innerHeight / (height + totalMargin);
312 return Math.min(scaleX, scaleY);
313 }
314 }
315
316 function scrollTop() {
317 // scroll top
318 $(window).on('load scroll', function() {
319 if ($(window).scrollTop() > 400) {
320 $('#scroll-top').addClass('visible');
321 } else {
322 $('#scroll-top').removeClass('visible');
323 }
324 })
325 $('#scroll-top').on('click', function(e) {
326 e.preventDefault();
327 $('html, body').animate({
328 scrollTop: 0
329 }, 150);
330 })
331 }
332
333 function scrollToAnchor(offsetTop) {
334 // anchor click scroll to element
335 var breadcrumbHeight = $('.breadcrumb').outerHeight();
336 var offsetTop = 0;
337 if (SITE_SLUG === 'open') {
338 offsetTop = breadcrumbHeight;
339 } else {
340 offsetTop = $('.page-title').outerHeight() + breadcrumbHeight;
341 }
342
343 // 锚点处理
344 $('.markdown').on('click', 'a', function(e) {
345 var href = $(this).attr('href');
346 if (/^#/.test(href)) {
347 e.preventDefault();
348 if ($(href).length) {
349 var top = $(href).offset().top - offsetTop;
350 $('html, body').scrollTop(top);
351 }
352 }
353 });
354 }
355
356 function toggleSearchForm() {
357 // header search
358 $('.header').on('click', '.btn-search', function(e) {
359 e.preventDefault();
360 $('.header .user-menu').addClass('search-open');
361 $('.header .search-form input').focus();
362 })
363 $('html').on('click', function(e) {
364 $('.header .user-menu.search-open').removeClass('search-open');
365 })
366 $('html').on('click', '.header .search-form', function(e) {
367 e.stopPropagation();
368 })
369 }
370 }());