blob: bd90080f79be210cc4c729bb49d639d90177e32f [file] [log] [blame]
Hao Zhuc1450882018-10-03 17:56:26 -04001gitbook.require(["gitbook", "lodash", "jQuery"], function(gitbook, _, $) {
2
3 var gs = gitbook.storage;
4
5 gitbook.events.bind("start", function(e, config) {
6
7 // add the Edit button (edit on Github)
8 var edit = config.edit;
9 if (edit && edit.link) gitbook.toolbar.createButton({
10 icon: 'fa fa-edit',
11 label: edit.text || 'Edit',
12 position: 'left',
13 onClick: function(e) {
14 e.preventDefault();
15 window.open(edit.link);
16 }
17 });
18
19 var down = config.download;
20 var normalizeDownload = function() {
21 if (!down || !(down instanceof Array) || down.length === 0) return;
22 if (down[0] instanceof Array) return down;
23 return $.map(down, function(file, i) {
24 return [[file, file.replace(/.*[.]/g, '').toUpperCase()]];
25 });
26 };
27 down = normalizeDownload(down);
28 if (down) if (down.length === 1 && /[.]pdf$/.test(down[0][0])) {
29 gitbook.toolbar.createButton({
30 icon: 'fa fa-file-pdf-o',
31 label: down[0][1],
32 position: 'left',
33 onClick: function(e) {
34 e.preventDefault();
35 window.open(down[0][0]);
36 }
37 });
38 } else {
39 gitbook.toolbar.createButton({
40 icon: 'fa fa-download',
41 label: 'Download',
42 position: 'left',
43 dropdown: $.map(down, function(item, i) {
44 return {
45 text: item[1],
46 onClick: function(e) {
47 e.preventDefault();
48 window.open(item[0]);
49 }
50 };
51 })
52 });
53 }
54
55 // highlight the current section in TOC
56 var href = window.location.pathname;
57 href = href.substr(href.lastIndexOf('/') + 1);
58 if (href === '') href = 'index.html';
59 var li = $('a[href^="' + href + location.hash + '"]').parent('li.chapter').first();
60 var summary = $('ul.summary'), chaps = summary.find('li.chapter');
61 if (li.length === 0) li = chaps.first();
62 li.addClass('active');
63 chaps.on('click', function(e) {
64 chaps.removeClass('active');
65 $(this).addClass('active');
66 gs.set('tocScrollTop', summary.scrollTop());
67 });
68
69 var toc = config.toc;
70 // collapse TOC items that are not for the current chapter
71 if (toc && toc.collapse) (function() {
72 var type = toc.collapse;
73 if (type === 'none') return;
74 if (type !== 'section' && type !== 'subsection') return;
75 // sections under chapters
76 var toc_sub = summary.children('li[data-level]').children('ul');
77 if (type === 'section') {
78 toc_sub.hide()
79 .parent().has(li).children('ul').show();
80 } else {
81 toc_sub.children('li').children('ul').hide()
82 .parent().has(li).children('ul').show();
83 }
84 li.children('ul').show();
85 var toc_sub2 = toc_sub.children('li');
86 if (type === 'section') toc_sub2.children('ul').hide();
87 summary.children('li[data-level]').find('a')
88 .on('click.bookdown', function(e) {
89 if (href === $(this).attr('href').replace(/#.*/, ''))
90 $(this).parent('li').children('ul').toggle();
91 });
92 })();
93
94 // add tooltips to the <a>'s that are truncated
95 $('a').each(function(i, el) {
96 if (el.offsetWidth >= el.scrollWidth) return;
97 if (typeof el.title === 'undefined') return;
98 el.title = el.text;
99 });
100
101 // restore TOC scroll position
102 var pos = gs.get('tocScrollTop');
103 if (typeof pos !== 'undefined') summary.scrollTop(pos);
104
105 // highlight the TOC item that has same text as the heading in view as scrolling
106 if (toc && toc.scroll_highlight !== false) (function() {
107 // scroll the current TOC item into viewport
108 var ht = $(window).height(), rect = li[0].getBoundingClientRect();
109 if (rect.top >= ht || rect.top <= 0 || rect.bottom <= 0) {
110 summary.scrollTop(li[0].offsetTop);
111 }
112 // current chapter TOC items
113 var items = $('a[href^="' + href + '"]').parent('li.chapter'),
114 m = items.length;
115 if (m === 0) {
116 items = summary.find('li.chapter');
117 m = items.length;
118 }
119 if (m === 0) return;
120 // all section titles on current page
121 var hs = bookInner.find('.page-inner').find('h1,h2,h3'), n = hs.length,
122 ts = hs.map(function(i, el) { return $(el).text(); });
123 if (n === 0) return;
124 var scrollHandler = function(e) {
125 var ht = $(window).height();
126 clearTimeout($.data(this, 'scrollTimer'));
127 $.data(this, 'scrollTimer', setTimeout(function() {
128 // find the first visible title in the viewport
129 for (var i = 0; i < n; i++) {
130 var rect = hs[i].getBoundingClientRect();
131 if (rect.top >= 0 && rect.bottom <= ht) break;
132 }
133 if (i === n) return;
134 items.removeClass('active');
135 for (var j = 0; j < m; j++) {
136 if (items.eq(j).children('a').first().text() === ts[i]) break;
137 }
138 if (j === m) j = 0; // highlight the chapter title
139 // search bottom-up for a visible TOC item to highlight; if an item is
140 // hidden, we check if its parent is visible, and so on
141 while (j > 0 && items.eq(j).is(':hidden')) j--;
142 items.eq(j).addClass('active');
143 }, 250));
144 };
145 bookInner.on('scroll.bookdown', scrollHandler);
146 bookBody.on('scroll.bookdown', scrollHandler);
147 })();
148
149 // do not refresh the page if the TOC item points to the current page
150 $('a[href="' + href + '"]').parent('li.chapter').children('a')
151 .on('click', function(e) {
152 bookInner.scrollTop(0);
153 bookBody.scrollTop(0);
154 return false;
155 });
156
157 var toolbar = config.toolbar;
158 if (!toolbar || toolbar.position !== 'static') {
159 var bookHeader = $('.book-header');
160 bookBody.addClass('fixed');
161 bookHeader.addClass('fixed')
162 .css('background-color', bookBody.css('background-color'))
163 .on('click.bookdown', function(e) {
164 // the theme may have changed after user clicks the theme button
165 bookHeader.css('background-color', bookBody.css('background-color'));
166 });
167 }
168
169 });
170
171 gitbook.events.bind("page.change", function(e) {
172 // store TOC scroll position
173 var summary = $('ul.summary');
174 gs.set('tocScrollTop', summary.scrollTop());
175 });
176
177 var bookBody = $('.book-body'), bookInner = bookBody.find('.body-inner');
178 var chapterTitle = function() {
179 return bookInner.find('.page-inner').find('h1,h2').first().text();
180 };
181 var bookTitle = function() {
182 return bookInner.find('.book-header > h1').first().text();
183 };
184 var saveScrollPos = function(e) {
185 // save scroll position before page is reloaded
186 gs.set('bodyScrollTop', {
187 body: bookBody.scrollTop(),
188 inner: bookInner.scrollTop(),
189 focused: document.hasFocus(),
190 title: chapterTitle()
191 });
192 };
193 $(document).on('servr:reload', saveScrollPos);
194
195 // check if the page is loaded in an iframe (e.g. the RStudio preview window)
196 var inIFrame = function() {
197 var inIframe = true;
198 try { inIframe = window.self !== window.top; } catch (e) {}
199 return inIframe;
200 };
201 $(window).on('blur unload', function(e) {
202 if (inIFrame()) saveScrollPos(e);
203 gs.set('bookTitle', bookTitle());
204 });
205
206 $(function(e) {
207 if (gs.get('bookTitle', '') !== bookTitle()) localStorage.clear();
208 var pos = gs.get('bodyScrollTop');
209 if (pos) {
210 if (pos.title === chapterTitle()) {
211 if (pos.body !== 0) bookBody.scrollTop(pos.body);
212 if (pos.inner !== 0) bookInner.scrollTop(pos.inner);
213 }
214 if (pos.focused) bookInner.find('.page-wrapper').focus();
215 }
216 // clear book body scroll position
217 gs.remove('bodyScrollTop');
218 });
219
220});