summaryrefslogtreecommitdiffstats
path: root/theme/javascript/navigation.js
diff options
context:
space:
mode:
Diffstat (limited to 'theme/javascript/navigation.js')
-rw-r--r--theme/javascript/navigation.js160
1 files changed, 160 insertions, 0 deletions
diff --git a/theme/javascript/navigation.js b/theme/javascript/navigation.js
new file mode 100644
index 0000000..8cc420e
--- /dev/null
+++ b/theme/javascript/navigation.js
@@ -0,0 +1,160 @@
+var $ = require('jquery');
+var url = require('url');
+
+var events = require('./events');
+var state = require('./state');
+var loading = require('./loading');
+
+
+var usePushState = (typeof history.pushState !== 'undefined');
+
+function handleNavigation(relativeUrl, push) {
+ var uri = url.resolve(window.location.pathname, relativeUrl);
+
+ if (!usePushState) {
+ // Refresh the page to the new URL if pushState not supported
+ location.href = relativeUrl;
+ return;
+ }
+
+ return loading.show($.get(uri)
+ .done(function (html) {
+ // Push url to history
+ if (push) history.pushState({ path: uri }, null, uri);
+
+ // Replace html content
+ html = html.replace( /<(\/?)(html|head|body)([^>]*)>/ig, function(a,b,c,d){
+ return '<' + b + 'div' + ( b ? '' : ' data-element="' + c + '"' ) + d + '>';
+ });
+
+ var $page = $(html);
+ var $pageHead = $page.find('[data-element=head]');
+ var $pageBody = $page.find('.book');
+
+ // Merge heads
+ // !! Warning !!: we only update necessary portions to avoid strange behavior (page flickering etc ...)
+
+ // Update title
+ document.title = $pageHead.find('title').text();
+
+ // Reference to $('head');
+ var $head = $('head');
+
+ // Update next & prev <link> tags
+ // Remove old
+ $head.find('link[rel=prev]').remove();
+ $head.find('link[rel=next]').remove();
+
+ // Add new next * prev <link> tags
+ $head.append($pageHead.find('link[rel=prev]'));
+ $head.append($pageHead.find('link[rel=next]'));
+
+ // Merge body
+ var bodyClass = $('.book').attr('class');
+ var scrollPosition = $('.book-summary .summary').scrollTop();
+ $pageBody.toggleClass('with-summary', $('.book').hasClass('with-summary'));
+
+ $('.book').replaceWith($pageBody);
+ $('.book').attr('class', bodyClass);
+ $('.book-summary .summary').scrollTop(scrollPosition);
+
+ // Update state
+ state.update($('html'));
+ preparePage();
+ })
+ .fail(function (e) {
+ location.href = relativeUrl;
+ }));
+}
+
+function updateNavigationPosition() {
+ var bodyInnerWidth, pageWrapperWidth;
+
+ bodyInnerWidth = parseInt($('.body-inner').css('width'), 10);
+ pageWrapperWidth = parseInt($('.page-wrapper').css('width'), 10);
+ $('.navigation-next').css('margin-right', (bodyInnerWidth - pageWrapperWidth) + 'px');
+}
+
+function preparePage() {
+ var $bookBody = $('.book-body');
+ var $bookInner = $bookBody.find('.body-inner');
+ var $pageWrapper = $bookInner.find('.page-wrapper');
+
+ // Update navigation position
+ updateNavigationPosition();
+
+ // Focus on content
+ $pageWrapper.focus();
+
+ // Reset scroll
+ $bookInner.scrollTop(0);
+ $bookBody.scrollTop(0);
+
+ // Notify
+ events.trigger('page.change');
+}
+
+function isLeftClickEvent(e) {
+ return e.button === 0;
+}
+
+function isModifiedEvent(e) {
+ return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);
+}
+
+function handlePagination(e) {
+ if (isModifiedEvent(e) || !isLeftClickEvent(e)) {
+ return;
+ }
+
+ e.stopPropagation();
+ e.preventDefault();
+
+ var url = $(this).attr('href');
+ if (url) handleNavigation(url, true);
+}
+
+function goNext() {
+ var url = $('.navigation-next').attr('href');
+ if (url) handleNavigation(url, true);
+}
+
+function goPrev() {
+ var url = $('.navigation-prev').attr('href');
+ if (url) handleNavigation(url, true);
+}
+
+
+function init() {
+ // Prevent cache so that using the back button works
+ // See: http://stackoverflow.com/a/15805399/983070
+ $.ajaxSetup({
+ cache: false
+ });
+
+ // Recreate first page when the page loads.
+ history.replaceState({ path: window.location.href }, '');
+
+ // Back Button Hijacking :(
+ window.onpopstate = function (event) {
+ if (event.state === null) {
+ return;
+ }
+ return handleNavigation(event.state.path, false);
+ };
+
+ $(document).on('click', '.navigation-prev', handlePagination);
+ $(document).on('click', '.navigation-next', handlePagination);
+ $(document).on('click', '.summary [data-path] a', handlePagination);
+
+ $(window).resize(updateNavigationPosition);
+
+ // Prepare current page
+ preparePage();
+}
+
+module.exports = {
+ init: init,
+ goNext: goNext,
+ goPrev: goPrev
+};