diff options
Diffstat (limited to 'theme/javascript')
26 files changed, 584 insertions, 783 deletions
diff --git a/theme/javascript/core/events.js b/theme/javascript/core/events.js deleted file mode 100644 index 855755f..0000000 --- a/theme/javascript/core/events.js +++ /dev/null @@ -1,7 +0,0 @@ -define([ - "jQuery" -], function($) { - var events = $({}); - - return events; -});
\ No newline at end of file diff --git a/theme/javascript/core/font-settings.js b/theme/javascript/core/font-settings.js deleted file mode 100644 index 63177ee..0000000 --- a/theme/javascript/core/font-settings.js +++ /dev/null @@ -1,103 +0,0 @@ -define([ - "jQuery", - "utils/storage" -], function($, storage) { - var fontState; - - var THEMES = { - "white": 0, - "sepia": 1, - "night": 2 - }; - - var FAMILY = { - "serif": 0, - "sans": 1 - }; - - var enlargeFontSize = function(e){ - if (fontState.size < 4){ - fontState.size++; - fontState.save(); - } - }; - - var reduceFontSize = function(e){ - if (fontState.size > 0){ - fontState.size--; - fontState.save(); - } - }; - - var changeFontFamily = function(){ - var index = $(this).data("font"); - - fontState.family = index; - fontState.save(); - }; - - var changeColorTheme = function(){ - var $book = $(".book"); - var index = $(this).data("theme"); - - if (fontState.theme !== 0) - $book.removeClass("color-theme-"+fontState.theme); - - fontState.theme = index; - if (fontState.theme !== 0) - $book.addClass("color-theme-"+fontState.theme); - - fontState.save(); - }; - - var update = function() { - var $book = $(".book"); - - $(".font-settings .font-family-list li").removeClass("active"); - $(".font-settings .font-family-list li:nth-child("+(fontState.family+1)+")").addClass("active"); - - $book[0].className = $book[0].className.replace(/\bfont-\S+/g, ''); - $book.addClass("font-size-"+fontState.size); - $book.addClass("font-family-"+fontState.family); - - if(fontState.theme !== 0) { - $book[0].className = $book[0].className.replace(/\bcolor-theme-\S+/g, ''); - $book.addClass("color-theme-"+fontState.theme); - } - }; - - var init = function(config) { - var $toggle, $bookBody, $dropdown, $book; - - //Find DOM elements. - $book = $(".book"); - $toggle = $(".book-header .toggle-font-settings"); - $dropdown = $("#font-settings-wrapper .dropdown-menu"); - $bookBody = $(".book-body"); - - // Instantiate font state object - fontState = storage.get("fontState", { - size: config.size || 2, - family: FAMILY[config.family || "sans"], - theme: THEMES[config.theme || "white"] - }); - fontState.save = function(){ - storage.set("fontState",fontState); - update(); - }; - - update(); - - //Add event listeners - $(document).on('click', "#enlarge-font-size", enlargeFontSize); - $(document).on('click', "#reduce-font-size", reduceFontSize); - - $(document).on('click', "#font-settings-wrapper .font-family-list .button", changeFontFamily); - $(document).on('click', "#font-settings-wrapper .color-theme-list .button", changeColorTheme); - }; - - return { - init: init, - update: update - } -});
\ No newline at end of file diff --git a/theme/javascript/core/keyboard.js b/theme/javascript/core/keyboard.js deleted file mode 100755 index 22fe953..0000000 --- a/theme/javascript/core/keyboard.js +++ /dev/null @@ -1,38 +0,0 @@ -define([ - "jQuery", - "Mousetrap", - "core/navigation", - "core/sidebar", - "core/search" -], function($, Mousetrap, navigation, sidebar, search){ - // Bind keyboard shortcuts - var init = function() { - // Next - Mousetrap.bind(['right'], function(e) { - navigation.goNext(); - return false; - }); - - // Prev - Mousetrap.bind(['left'], function(e) { - navigation.goPrev(); - return false; - }); - - // Toggle Summary - Mousetrap.bind(['s'], function(e) { - sidebar.toggle(); - return false; - }); - - // Toggle Search - Mousetrap.bind(['f'], function(e) { - search.toggle(); - return false; - }); - }; - - return { - init: init - }; -});
\ No newline at end of file diff --git a/theme/javascript/core/loading.js b/theme/javascript/core/loading.js deleted file mode 100644 index 1ddb213..0000000 --- a/theme/javascript/core/loading.js +++ /dev/null @@ -1,16 +0,0 @@ -define([ - "jQuery" -], function($) { - var showLoading = function(p) { - $(".book").addClass("is-loading"); - p.always(function() { - $(".book").removeClass("is-loading"); - }); - - return p; - }; - - return { - show: showLoading - }; -});
\ No newline at end of file diff --git a/theme/javascript/core/navigation.js b/theme/javascript/core/navigation.js deleted file mode 100755 index c1766ab..0000000 --- a/theme/javascript/core/navigation.js +++ /dev/null @@ -1,174 +0,0 @@ -define([ - "jQuery", - "utils/url", - "core/events", - "core/state", - "core/progress", - "core/loading", - "core/search" -], function($, URL, events, state, progress, loading, search) { - var prev, next; - - var usePushState = (typeof history.pushState !== "undefined"); - - var handleNavigation = function(relativeUrl, push) { - var url = URL.join(window.location.pathname, relativeUrl); - console.log("navigate to ", url, "baseurl="+relativeUrl, "current="+window.location.pathname); - - if (!usePushState) { - // Refresh the page to the new URL if pushState not supported - location.href = relativeUrl; - return - } - - return loading.show($.get(url) - .done(function (html) { - // Push url to history - if (push) history.pushState({ path: url }, null, url); - - // 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")); - // recover search keyword - search.recover(); - preparePage(); - }) - .fail(function (e) { - location.href = relativeUrl; - })); - }; - - var updateNavigationPosition = function() { - 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'); - }; - - var preparePage = function() { - var $bookBody = $(".book-body"); - var $bookInner = $bookBody.find(".body-inner"); - var $pageWrapper = $bookInner.find(".page-wrapper"); - - // Show progress - progress.show(); - - // Update navigation position - updateNavigationPosition(); - - // Focus on content - $pageWrapper.focus(); - - // Reset scroll - $bookInner.scrollTop(0); - $bookBody.scrollTop(0); - - // Notify - events.trigger("page.change"); - }; - - var isLeftClickEvent = function (e) { - return e.button === 0; - }; - - var isModifiedEvent = function (e) { - return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey); - }; - - var handlePagination = function (e) { - if (isModifiedEvent(e) || !isLeftClickEvent(e)) { - return; - } - - e.stopPropagation(); - e.preventDefault(); - - var url = $(this).attr('href'); - if (url) handleNavigation(url, true); - }; - - var goNext = function() { - var url = $(".navigation-next").attr("href"); - if (url) handleNavigation(url, true); - }; - - var goPrev = function() { - var url = $(".navigation-prev").attr("href"); - if (url) handleNavigation(url, true); - }; - - - - var init = function() { - // 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(); - }; - - return { - init: init, - goNext: goNext, - goPrev: goPrev - }; -}); - diff --git a/theme/javascript/core/progress.js b/theme/javascript/core/progress.js deleted file mode 100755 index a409a11..0000000 --- a/theme/javascript/core/progress.js +++ /dev/null @@ -1,73 +0,0 @@ -define([ - "lodash", - "jQuery", - "utils/storage", - "core/state" -], function(_, $, storage, state) { - // Get current level - var getCurrentLevel = function() { - return state.level; - }; - - // Return all levels - var getLevels = function () { - var levels = $(".book-summary li[data-level]"); - - return _.map(levels, function(level) { - return $(level).data("level").toString(); - }); - }; - - // Return a map chapter -> number (timestamp) - var getProgress = function () { - // Current level - var progress = storage.get("progress", {}); - - // Levels - var levels = getLevels(); - - _.each(levels, function(level) { - progress[level] = progress[level] || 0; - }); - - return progress; - }; - - // Change value of progress for a level - var markProgress = function (level, state) { - var progress = getProgress(); - - if (state == null) { - state = true; - } - - progress[level] = state - ? Date.now() - : 0; - - storage.set("progress", progress); - }; - - // Show progress - var showProgress = function () { - var progress = getProgress(); - var $summary = $(".book-summary"); - - _.each(progress, function (value, level) { - $summary.find("li[data-level='"+level+"']").toggleClass("done", value > 0); - }); - - // Mark current progress if we have not already - if (!progress[getCurrentLevel()]) { - markProgress(getCurrentLevel(), true); - } - }; - - return { - 'current': getCurrentLevel, - 'levels': getLevels, - 'get': getProgress, - 'mark': markProgress, - 'show': showProgress - }; -});
\ No newline at end of file diff --git a/theme/javascript/core/search.js b/theme/javascript/core/search.js deleted file mode 100755 index 4cbc3ed..0000000 --- a/theme/javascript/core/search.js +++ /dev/null @@ -1,114 +0,0 @@ -define([ - "jQuery", - "lodash", - "lunr", - "utils/storage", - "core/state", - "core/sidebar" -], function($, _, lunr, storage, state, sidebar) { - var index = null; - - // Use a specific idnex - var useIndex = function(data) { - index = lunr.Index.load(data); - }; - - // Load complete index - var loadIndex = function() { - $.getJSON(state.basePath+"/search_index.json") - .then(useIndex); - }; - - // Search for a term - var search = function(q) { - if (!index) return; - var results = _.chain(index.search(q)) - .map(function(result) { - var parts = result.ref.split("#") - return { - path: parts[0], - hash: parts[1] - } - }) - .value(); - - return results; - }; - - // Toggle search bar - var toggleSearch = function(_state) { - if (state != null && isSearchOpen() == _state) return; - - var $searchInput = $(".book-search input"); - state.$book.toggleClass("with-search", _state); - - // If search bar is open: focus input - if (isSearchOpen()) { - sidebar.toggle(true); - $searchInput.focus(); - } else { - $searchInput.blur(); - $searchInput.val(""); - sidebar.filter(null); - } - }; - - // Return true if search bar is open - var isSearchOpen = function() { - return state.$book.hasClass("with-search"); - }; - - - var init = function() { - loadIndex(); - - // Toggle search - $(document).on("click", ".book-header .toggle-search", function(e) { - e.preventDefault(); - toggleSearch(); - }); - - - // Type in search bar - $(document).on("keyup", ".book-search input", function(e) { - var key = (e.keyCode ? e.keyCode : e.which); - var q = $(this).val(); - - if (key == 27) { - e.preventDefault(); - toggleSearch(false); - return; - } - if (q.length == 0) { - sidebar.filter(null); - storage.remove("keyword"); - } else { - var results = search(q); - sidebar.filter( - _.pluck(results, "path") - ); - storage.set("keyword", q); - } - }) - - }; - - // filter sidebar menu with current search keyword - var recoverSearch = function() { - var keyword = storage.get("keyword", ""); - if(keyword.length > 0) { - if(!isSearchOpen()){ - toggleSearch(); - } - sidebar.filter(_.pluck(search(keyword), "path")); - } - $(".book-search input").val(keyword); - }; - - return { - init: init, - search: search, - toggle: toggleSearch, - recover:recoverSearch - }; -}); diff --git a/theme/javascript/core/sidebar.js b/theme/javascript/core/sidebar.js deleted file mode 100755 index 828dc73..0000000 --- a/theme/javascript/core/sidebar.js +++ /dev/null @@ -1,56 +0,0 @@ -define([ - "jQuery", - "lodash", - "utils/storage", - "utils/platform", - "core/state" -], function($, _, storage, platform, state) { - // Toggle sidebar with or withour animation - var toggleSidebar = function(_state, animation) { - if (state != null && isOpen() == _state) return; - if (animation == null) animation = true; - - state.$book.toggleClass("without-animation", !animation); - state.$book.toggleClass("with-summary", _state); - - storage.set("sidebar", isOpen()); - }; - - // Return true if sidebar is open - var isOpen = function() { - return state.$book.hasClass("with-summary"); - }; - - // Prepare sidebar: state and toggle button - var init = function() { - // Toggle summary - $(document).on("click", ".book-header .toggle-summary", function(e) { - e.preventDefault(); - toggleSidebar(); - }); - - // Init last state if not mobile - if (!platform.isMobile) { - toggleSidebar(storage.get("sidebar", true), false); - } - }; - - // Filter summary with a list of path - var filterSummary = function(paths) { - var $summary = $(".book-summary"); - - $summary.find("li").each(function() { - var path = $(this).data("path"); - var st = paths == null || _.contains(paths, path); - - $(this).toggle(st); - if (st) $(this).parents("li").show(); - }); - }; - - return { - init: init, - toggle: toggleSidebar, - filter: filterSummary - } -});
\ No newline at end of file diff --git a/theme/javascript/core/state.js b/theme/javascript/core/state.js deleted file mode 100755 index de5c65c..0000000 --- a/theme/javascript/core/state.js +++ /dev/null @@ -1,18 +0,0 @@ -define([ - "jQuery" -], function() { - var state = {}; - - state.update = function(dom) { - var $book = $(dom.find(".book")); - - state.$book = $book; - state.level = $book.data("level"); - state.basePath = $book.data("basepath"); - state.revision = $book.data("revision"); - }; - - state.update($); - - return state; -});
\ No newline at end of file diff --git a/theme/javascript/dropdown.js b/theme/javascript/dropdown.js new file mode 100644 index 0000000..d6fc548 --- /dev/null +++ b/theme/javascript/dropdown.js @@ -0,0 +1,25 @@ +var $ = require('jquery'); + +function toggleDropdown(e) { + var $dropdown = $(e.currentTarget).parent().find('.dropdown-menu'); + + $dropdown.toggleClass('open'); + e.stopPropagation(); + e.preventDefault(); +} + +function closeDropdown(e) { + $('.dropdown-menu').removeClass('open'); +} + +// Bind all dropdown +function init() { + $(document).on('click', '.toggle-dropdown', toggleDropdown); + $(document).on('click', '.dropdown-menu', function(e){ e.stopPropagation(); }); + $(document).on('click', closeDropdown); +} + +module.exports = { + init: init +}; + diff --git a/theme/javascript/events.js b/theme/javascript/events.js new file mode 100644 index 0000000..9b9a730 --- /dev/null +++ b/theme/javascript/events.js @@ -0,0 +1,4 @@ +var $ = require('jquery'); + +module.exports = $({}); + diff --git a/theme/javascript/gitbook.js b/theme/javascript/gitbook.js deleted file mode 100755 index 495afac..0000000 --- a/theme/javascript/gitbook.js +++ /dev/null @@ -1,49 +0,0 @@ -define([ - "jQuery", - "utils/storage", - "utils/sharing", - "utils/dropdown", - - "core/events", - "core/font-settings", - "core/state", - "core/keyboard", - "core/navigation", - "core/progress", - "core/sidebar", - "core/search" -], function($, storage, sharing, dropdown, events, fontSettings, state, keyboard, navigation, progress, sidebar, search){ - var start = function(config) { - var $book; - $book = state.$book; - - // Init sidebar - sidebar.init(); - - // Load search - search.init(); - - // Init keyboard - keyboard.init(); - - // Bind sharing button - sharing.init(); - - // Bind dropdown - dropdown.init(); - - // Init navigation - navigation.init(); - - //Init font settings - fontSettings.init(config.fontSettings || {}); - - events.trigger("start", config); - } - - return { - start: start, - events: events, - state: state - }; -}); diff --git a/theme/javascript/index.js b/theme/javascript/index.js new file mode 100755 index 0000000..6e601c6 --- /dev/null +++ b/theme/javascript/index.js @@ -0,0 +1,81 @@ +var $ = require('jquery'); +var _ = require('lodash'); + +var storage = require('./storage'); +var dropdown = require('./dropdown'); +var events = require('./events'); +var state = require('./state'); +var keyboard = require('./keyboard'); +var navigation = require('./navigation'); +var sidebar = require('./sidebar'); +var toolbar = require('./toolbar'); + + +function start(config) { + // Init sidebar + sidebar.init(); + + // Init keyboard + keyboard.init(); + + // Bind dropdown + dropdown.init(); + + // Init navigation + navigation.init(); + + + // Add action to toggle sidebar + toolbar.createButton({ + icon: 'fa fa-align-justify', + onClick: function(e) { + e.preventDefault(); + sidebar.toggle(); + } + }); + + events.trigger('start', config); +} + +// Export APIs for plugins +var gitbook = { + start: start, + events: events, + state: state, + + // UI sections + toolbar: toolbar, + sidebar: sidebar, + + // Read/Write the localstorage + storage: storage, + + // Create keyboard shortcuts + keyboard: keyboard +}; + + +// Modules mapping for plugins +var MODULES = { + 'gitbook': gitbook, + 'jQuery': $, + 'lodash': _ +}; + +window.gitbook = gitbook; +window.$ = $; +window.jQuery = $; +window.require = function(mods, fn) { + mods = _.map(mods, function(mod) { + if (!MODULES[mod]) { + throw new Error('GitBook module '+mod+' doesn\'t exist'); + } + + return MODULES[mod]; + }); + + fn.apply(null, mods); +}; + +module.exports = {}; + diff --git a/theme/javascript/keyboard.js b/theme/javascript/keyboard.js new file mode 100644 index 0000000..ab0cef6 --- /dev/null +++ b/theme/javascript/keyboard.js @@ -0,0 +1,36 @@ +var Mousetrap = require('mousetrap'); + +var navigation = require('./navigation'); +var sidebar = require('./sidebar'); + +// Bind a keyboard shortcuts +function bindShortcut(keys, fn) { + Mousetrap.bind(keys, function(e) { + fn(); + return false; + }); +} + + +// Bind keyboard shortcuts +function init() { + // Next + bindShortcut(['right'], function(e) { + navigation.goNext(); + }); + + // Prev + bindShortcut(['left'], function(e) { + navigation.goPrev(); + }); + + // Toggle Summary + bindShortcut(['s'], function(e) { + sidebar.toggle(); + }); +} + +module.exports = { + init: init, + bind: bindShortcut +}; diff --git a/theme/javascript/loading.js b/theme/javascript/loading.js new file mode 100644 index 0000000..797b487 --- /dev/null +++ b/theme/javascript/loading.js @@ -0,0 +1,14 @@ +var state = require('./state'); + +function showLoading(p) { + state.$book.addClass('is-loading'); + p.always(function() { + state.$book.removeClass('is-loading'); + }); + + return p; +} + +module.exports = { + show: showLoading +}; 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 +}; diff --git a/theme/javascript/platform.js b/theme/javascript/platform.js new file mode 100644 index 0000000..9721fb7 --- /dev/null +++ b/theme/javascript/platform.js @@ -0,0 +1,3 @@ +module.exports = { + isMobile: /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) +}; diff --git a/theme/javascript/sidebar.js b/theme/javascript/sidebar.js new file mode 100644 index 0000000..d381822 --- /dev/null +++ b/theme/javascript/sidebar.js @@ -0,0 +1,51 @@ +var $ = require('jquery'); +var _ = require('lodash'); + +var storage = require('./storage'); +var platform = require('./platform'); +var state = require('./state'); + + +// Toggle sidebar with or withour animation +function toggleSidebar(_state, animation) { + if (state != null && isOpen() == _state) return; + if (animation == null) animation = true; + + state.$book.toggleClass('without-animation', !animation); + state.$book.toggleClass('with-summary', _state); + + storage.set('sidebar', isOpen()); +} + +// Return true if sidebar is open +function isOpen() { + return state.$book.hasClass('with-summary'); +} + +// Prepare sidebar: state and toggle button +function init() { + // Init last state if not mobile + if (!platform.isMobile) { + toggleSidebar(storage.get('sidebar', true), false); + } +} + +// Filter summary with a list of path +function filterSummary(paths) { + var $summary = $('.book-summary'); + + $summary.find('li').each(function() { + var path = $(this).data('path'); + var st = paths == null || _.contains(paths, path); + + $(this).toggle(st); + if (st) $(this).parents('li').show(); + }); +} + +module.exports = { + init: init, + isOpen: isOpen, + toggle: toggleSidebar, + filter: filterSummary +}; diff --git a/theme/javascript/state.js b/theme/javascript/state.js new file mode 100644 index 0000000..52b9ab3 --- /dev/null +++ b/theme/javascript/state.js @@ -0,0 +1,16 @@ +var $ = require('jquery'); + +var state = {}; + +state.update = function(dom) { + var $book = $(dom.find(".book")); + + state.$book = $book; + state.level = $book.data("level"); + state.basePath = $book.data("basepath"); + state.revision = $book.data("revision"); +}; + +state.update($); + +module.exports = state; diff --git a/theme/javascript/storage.js b/theme/javascript/storage.js new file mode 100644 index 0000000..7a7643c --- /dev/null +++ b/theme/javascript/storage.js @@ -0,0 +1,37 @@ +var baseKey = ''; + +/* + * Simple module for storing data in the browser's local storage + */ +module.exports = { + setBaseKey: function(key) { + baseKey = key; + }, + + // Write something in localstorage + set: function(key, value) { + key = baseKey+':'+key; + + try { + localStorage[key] = JSON.stringify(value); + } catch(e) {} + }, + + // Read a value from localstorage + get: function(key, def) { + key = baseKey+':'+key; + if (localStorage[key] === undefined) return def; + try { + var v = JSON.parse(localStorage[key]); + return v == null ? def : v;; + } catch(err) { + return localStorage[key] || def; + } + }, + + // Remove a key from localstorage + remove: function(key) { + key = baseKey+':'+key; + localStorage.removeItem(key); + } +}; diff --git a/theme/javascript/toolbar.js b/theme/javascript/toolbar.js new file mode 100644 index 0000000..b987c88 --- /dev/null +++ b/theme/javascript/toolbar.js @@ -0,0 +1,157 @@ +var $ = require('jquery'); +var _ = require('lodash'); + +var events = require('./events'); + +// List of created buttons +var buttons = []; + + +// Default click handler +function defaultOnClick(e) { + e.preventDefault(); +} + +// Create a dropdown menu +function createDropdownMenu(dropdown) { + var $menu = $('<div>', { + 'class': 'dropdown-menu', + 'html': '<div class="dropdown-caret"><span class="caret-outer"></span><span class="caret-inner"></span></div>' + }); + + if (_.isString(dropdown)) { + $menu.append(dropdown); + } else { + var groups = _.map(dropdown, function(group) { + if (_.isArray(group)) return group; + else return [group]; + }); + + // Create buttons groups + _.each(groups, function(group) { + var $group = $('<div>', { + 'class': 'buttons' + }); + var sizeClass = 'size-'+group.length; + + // Append buttons + _.each(group, function(btn) { + btn = _.defaults(btn || {}, { + text: '', + className: '', + onClick: defaultOnClick + }); + + var $btn = $('<button>', { + 'class': 'button '+sizeClass+' '+btn.className, + 'text': btn.text + }); + $btn.click(btn.onClick); + + $group.append($btn); + }); + + + $menu.append($group); + }); + + } + + + return $menu; +} + +// Create a new button in the toolbar +function createButton(opts) { + opts = _.defaults(opts || {}, { + // Aria label for the button + label: '', + + // Icon to show + icon: '', + + // Inner text + text: '', + + // Right or left position + position: 'left', + + // Other class name to add to the button + className: '', + + // Triggered when user click on the button + onClick: defaultOnClick, + + // Button is a dropdown + dropdown: null + }); + + buttons.push(opts); + updateButton(opts); +} + +// Update a button +function updateButton(opts) { + var $toolbar = $('.book-header'); + var $title = $toolbar.find('h1'); + + // Build class name + var positionClass = 'pull-'+opts.position; + + // Create button + var $btn = $('<a>', { + 'class': 'btn', + 'text': opts.text, + 'aria-label': opts.label, + 'href': '#' + }); + + // Bind click + $btn.click(opts.onClick); + + // Prepend icon + if (opts.icon) { + $('<i>', { + 'class': opts.icon + }).prependTo($btn); + } + + // Prepare dropdown + if (opts.dropdown) { + var $container = $('<div>', { + 'class': 'dropdown '+positionClass+' '+opts.className + }); + + // Add button to container + $btn.addClass('toggle-dropdown'); + $container.append($btn); + + // Create inner menu + var $menu = createDropdownMenu(opts.dropdown); + + // Menu position + $menu.addClass('dropdown-'+(opts.position == 'right'? 'left' : 'right')); + + $container.append($menu); + + $container.insertBefore($title); + } else { + $btn.addClass(positionClass); + $btn.addClass(opts.className); + $btn.insertBefore($title); + } +} + +// Update all buttons +function updateAllButtons() { + _.each(buttons, updateButton); +} + +// When page changed, reset buttons +events.bind('page.change', function() { + updateAllButtons(); +}); + +module.exports = { + createButton: createButton +}; diff --git a/theme/javascript/utils/dropdown.js b/theme/javascript/utils/dropdown.js deleted file mode 100644 index fe4e1f4..0000000 --- a/theme/javascript/utils/dropdown.js +++ /dev/null @@ -1,27 +0,0 @@ -define([ - "jQuery" -], function($) { - - var toggleDropdown = function(e) { - var $dropdown = $(e.currentTarget).parent().find(".dropdown-menu"); - - $dropdown.toggleClass("open"); - e.stopPropagation(); - e.preventDefault(); - }; - - var closeDropdown = function(e) { - $(".dropdown-menu").removeClass("open"); - }; - - // Bind all dropdown - var init = function() { - $(document).on('click', ".toggle-dropdown", toggleDropdown); - $(document).on('click', ".dropdown-menu", function(e){ e.stopPropagation(); }); - $(document).on("click", closeDropdown); - }; - - return { - init: init - }; -}); diff --git a/theme/javascript/utils/platform.js b/theme/javascript/utils/platform.js deleted file mode 100755 index ad5f3b4..0000000 --- a/theme/javascript/utils/platform.js +++ /dev/null @@ -1,5 +0,0 @@ -define([], function() { - return { - isMobile: /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) - }; -});
\ No newline at end of file diff --git a/theme/javascript/utils/sharing.js b/theme/javascript/utils/sharing.js deleted file mode 100755 index a0cfb59..0000000 --- a/theme/javascript/utils/sharing.js +++ /dev/null @@ -1,39 +0,0 @@ -define([ - "jQuery" -], function($) { - var types = { - "twitter": function($el) { - window.open("http://twitter.com/home?status="+encodeURIComponent($("title").text()+" "+location.href)) - }, - "facebook": function($el) { - window.open("http://www.facebook.com/sharer/sharer.php?s=100&p[url]="+encodeURIComponent(location.href)) - }, - "google-plus": function($el) { - window.open("https://plus.google.com/share?url="+encodeURIComponent(location.href)) - }, - "weibo": function($el) { - window.open("http://service.weibo.com/share/share.php?content=utf-8&url="+encodeURIComponent(location.href)+"&title="+encodeURIComponent($("title").text())) - }, - "instapaper": function($el) { - window.open("http://www.instapaper.com/text?u="+encodeURIComponent(location.href)); - }, - "vk": function($el) { - window.open("http://vkontakte.ru/share.php?url="+encodeURIComponent(location.href)); - } - }; - - - // Bind all sharing button - var init = function() { - $(document).on("click", "a[data-sharing],button[data-sharing]", function(e) { - if (e) e.preventDefault(); - var type = $(this).data("sharing"); - - types[type]($(this)); - }) - }; - - return { - init: init - }; -}); diff --git a/theme/javascript/utils/storage.js b/theme/javascript/utils/storage.js deleted file mode 100755 index 57f5878..0000000 --- a/theme/javascript/utils/storage.js +++ /dev/null @@ -1,31 +0,0 @@ -define(function(){ - var baseKey = ""; - - /* - * Simple module for storing data in the browser's local storage - */ - return { - setBaseKey: function(key) { - baseKey = key; - }, - set: function(key, value) { - key = baseKey+":"+key; - localStorage[key] = JSON.stringify(value); - }, - get: function(key, def) { - key = baseKey+":"+key; - if (localStorage[key] === undefined) return def; - try { - var v = JSON.parse(localStorage[key]); - return v == null ? def : v;; - } catch(err) { - console.error(err); - return localStorage[key] || def; - } - }, - remove: function(key) { - key = baseKey+":"+key; - localStorage.removeItem(key); - } - }; -});
\ No newline at end of file diff --git a/theme/javascript/utils/url.js b/theme/javascript/utils/url.js deleted file mode 100644 index 0254299..0000000 --- a/theme/javascript/utils/url.js +++ /dev/null @@ -1,33 +0,0 @@ -define([ - "URIjs/URI" -], function(URI) { - // Joins path segments. Preserves initial "/" and resolves ".." and "." - // Does not support using ".." to go above/outside the root. - // This means that join("foo", "../../bar") will not resolve to "../bar" - function join(baseUrl, url) { - var theUrl = new URI(url); - if (theUrl.is("relative")) { - theUrl = theUrl.absoluteTo(baseUrl); - } - return theUrl.toString(); - } - - // A simple function to get the dirname of a path - // Trailing slashes are ignored. Leading slash is preserved. - function dirname(path) { - return join(path, ".."); - } - - // test if a path or url is absolute - function isAbsolute(path) { - if (!path) return false; - - return (path[0] == "/" || path.indexOf("http://") == 0 || path.indexOf("https://") == 0); - } - - return { - dirname: dirname, - join: join, - isAbsolute: isAbsolute - }; -})
\ No newline at end of file |