Refactor js to exportable module

This commit is contained in:
Anthony Johnson 2015-09-09 00:17:10 -07:00
parent 60eb0af7fb
commit f0863fa0eb
5 changed files with 339 additions and 136 deletions

View File

@ -57,6 +57,29 @@ module.exports = function(grunt) {
} }
}, },
browserify: {
dev: {
options: {
external: ['jquery'],
alias: {
'sphinx-rtd-theme': './js/theme.js'
}
},
src: ['js/*.js'],
dest: 'sphinx_rtd_theme/static/js/theme.js'
},
build: {
options: {
external: ['jquery'],
alias: {
'sphinx-rtd-theme': './js/theme.js'
}
},
src: ['js/*.js'],
dest: 'sphinx_rtd_theme/static/js/theme.js'
}
},
exec: { exec: {
bower_update: { bower_update: {
cmd: 'bower update' cmd: 'bower update'
@ -81,6 +104,11 @@ module.exports = function(grunt) {
files: ['sphinx_rtd_theme/**/*', 'demo_docs/**/*.rst', 'demo_docs/**/*.py'], files: ['sphinx_rtd_theme/**/*', 'demo_docs/**/*.rst', 'demo_docs/**/*.py'],
tasks: ['clean:build','exec:build_sphinx'] tasks: ['clean:build','exec:build_sphinx']
}, },
/* JavaScript */
browserify: {
files: ['js/*.js'],
tasks: ['browserify:dev']
},
/* live-reload the demo_docs if sphinx re-builds */ /* live-reload the demo_docs if sphinx re-builds */
livereload: { livereload: {
files: ['demo_docs/build/**/*'], files: ['demo_docs/build/**/*'],
@ -97,9 +125,10 @@ module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-clean'); grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-copy'); grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-open'); grunt.loadNpmTasks('grunt-open');
grunt.loadNpmTasks('grunt-browserify');
grunt.registerTask('fonts', ['clean:fonts','copy:fonts']); grunt.registerTask('fonts', ['clean:fonts','copy:fonts']);
grunt.registerTask('default', ['exec:bower_update','clean:build','sass:dev','exec:build_sphinx','connect','open','watch']); grunt.registerTask('default', ['exec:bower_update','clean:build','sass:dev','browserify:dev','exec:build_sphinx','connect','open','watch']);
grunt.registerTask('build', ['exec:bower_update','clean:build','sass:build','exec:build_sphinx']); grunt.registerTask('build', ['exec:bower_update','clean:build','sass:build','browserify:build','exec:build_sphinx']);
} }

View File

@ -8,7 +8,7 @@
"description": "Sphinx theme for readthedocs.org.", "description": "Sphinx theme for readthedocs.org.",
"license": "MIT", "license": "MIT",
"main": [ "main": [
"dist/**" "js/theme.js"
], ],
"ignore": [ "ignore": [
"docs", "docs",

150
js/theme.js Normal file
View File

@ -0,0 +1,150 @@
var jQuery = (typeof(window) != 'undefined') ? window.jQuery : require('jquery');
// Sphinx theme nav state
function ThemeNav () {
var nav = {
navBar: null,
win: null,
winScroll: false,
winResize: false,
linkScroll: false,
winPosition: 0,
winHeight: null,
docHeight: null,
isRunning: null
};
nav.enable = function () {
var self = this;
jQuery(function ($) {
self.init($);
self.reset();
self.win.on('hashchange', self.reset);
// Set scroll monitor
self.win.on('scroll', function () {
if (!self.linkScroll) {
self.winScroll = true;
}
});
setInterval(function () { if (self.winScroll) self.onScroll(); }, 25);
// Set resize monitor
self.win.on('resize', function () {
self.winResize = true;
});
setInterval(function () { if (self.winResize) self.onResize(); }, 25);
self.onResize();
});
};
nav.init = function ($) {
var doc = $(document),
self = this;
this.navBar = $('div.wy-side-scroll:first');
this.win = $(window);
// Set up javascript UX bits
$(document)
// Shift nav in mobile when clicking the menu.
.on('click', "[data-toggle='wy-nav-top']", function() {
$("[data-toggle='wy-nav-shift']").toggleClass("shift");
$("[data-toggle='rst-versions']").toggleClass("shift");
})
// Nav menu link click operations
.on('click', ".wy-menu-vertical .current ul li a", function() {
var target = $(this);
// Close menu when you click a link.
$("[data-toggle='wy-nav-shift']").removeClass("shift");
$("[data-toggle='rst-versions']").toggleClass("shift");
// Handle dynamic display of l3 and l4 nav lists
self.toggleCurrent(target);
self.hashChange();
})
.on('click', "[data-toggle='rst-current-version']", function() {
$("[data-toggle='rst-versions']").toggleClass("shift-up");
})
// Make tables responsive
$("table.docutils:not(.field-list)")
.wrap("<div class='wy-table-responsive'></div>");
// Add expand links to all parents of nested ul
$('.wy-menu-vertical ul').not('.simple').siblings('a').each(function () {
var link = $(this);
expand = $('<span class="toctree-expand"></span>');
expand.on('click', function (ev) {
self.toggleCurrent(link);
ev.stopPropagation();
return false;
});
link.prepend(expand);
});
};
nav.reset = function () {
// Get anchor from URL and open up nested nav
var anchor = encodeURI(window.location.hash);
if (anchor) {
try {
var link = $('.wy-menu-vertical')
.find('[href="' + anchor + '"]');
$('.wy-menu-vertical li.toctree-l1 li.current')
.removeClass('current');
link.closest('li.toctree-l2').addClass('current');
link.closest('li.toctree-l3').addClass('current');
link.closest('li.toctree-l4').addClass('current');
}
catch (err) {
console.log("Error expanding nav for anchor", err);
}
}
};
nav.onScroll = function () {
this.winScroll = false;
var newWinPosition = this.win.scrollTop(),
winBottom = newWinPosition + this.winHeight,
navPosition = this.navBar.scrollTop(),
newNavPosition = navPosition + (newWinPosition - this.winPosition);
if (newWinPosition < 0 || winBottom > this.docHeight) {
return;
}
this.navBar.scrollTop(newNavPosition);
this.winPosition = newWinPosition;
};
nav.onResize = function () {
this.winResize = false;
this.winHeight = this.win.height();
this.docHeight = $(document).height();
};
nav.hashChange = function () {
this.linkScroll = true;
this.win.one('hashchange', function () {
this.linkScroll = false;
});
};
nav.toggleCurrent = function (elem) {
var parent_li = elem.closest('li');
parent_li.siblings('li.current').removeClass('current');
parent_li.siblings().find('li.current').removeClass('current');
parent_li.find('> ul li.current').removeClass('current');
parent_li.toggleClass('current');
}
return nav;
};
module.exports.ThemeNav = ThemeNav();
if (typeof(window) != 'undefined') {
window.SphinxRtdTheme = { StickyNav: module.exports.ThemeNav };
}

View File

@ -4,13 +4,15 @@
"private": true, "private": true,
"dependencies": {}, "dependencies": {},
"devDependencies": { "devDependencies": {
"browserify": "^11.0.0",
"connect-livereload": "~0.3.0",
"grunt": "~0.4.1", "grunt": "~0.4.1",
"grunt-browserify": "^3.8.0",
"grunt-contrib-clean": "0.5.0",
"grunt-contrib-connect": "0.5.0",
"grunt-contrib-copy": "0.5.0",
"grunt-contrib-sass": "~0.7.2", "grunt-contrib-sass": "~0.7.2",
"grunt-contrib-watch": "~0.4.3", "grunt-contrib-watch": "~0.4.3",
"grunt-contrib-connect": "0.5.0",
"grunt-contrib-clean": "0.5.0",
"grunt-contrib-copy": "0.5.0",
"connect-livereload": "~0.3.0",
"grunt-exec": "~0.4.2", "grunt-exec": "~0.4.2",
"grunt-open": "0.2.2", "grunt-open": "0.2.2",
"matchdep": "~0.1.2" "matchdep": "~0.1.2"

View File

@ -1,84 +1,94 @@
function toggleCurrent (elem) { require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({"sphinx-rtd-theme":[function(require,module,exports){
var parent_li = elem.closest('li'); var jQuery = (typeof(window) != 'undefined') ? window.jQuery : require('jquery');
parent_li.siblings('li.current').removeClass('current');
parent_li.siblings().find('li.current').removeClass('current');
parent_li.find('> ul li.current').removeClass('current');
parent_li.toggleClass('current');
}
$(document).ready(function() { // Sphinx theme nav state
function ThemeNav () {
var nav = {
navBar: null,
win: null,
winScroll: false,
winResize: false,
linkScroll: false,
winPosition: 0,
winHeight: null,
docHeight: null,
isRunning: null
};
nav.enable = function () {
var self = this;
jQuery(function ($) {
self.init($);
self.reset();
self.win.on('hashchange', self.reset);
// Set scroll monitor
self.win.on('scroll', function () {
if (!self.linkScroll) {
self.winScroll = true;
}
});
setInterval(function () { if (self.winScroll) self.onScroll(); }, 25);
// Set resize monitor
self.win.on('resize', function () {
self.winResize = true;
});
setInterval(function () { if (self.winResize) self.onResize(); }, 25);
self.onResize();
});
};
nav.init = function ($) {
var doc = $(document),
self = this;
this.navBar = $('div.wy-side-scroll:first');
this.win = $(window);
// Set up javascript UX bits
$(document)
// Shift nav in mobile when clicking the menu. // Shift nav in mobile when clicking the menu.
$(document).on('click', "[data-toggle='wy-nav-top']", function() { .on('click', "[data-toggle='wy-nav-top']", function() {
$("[data-toggle='wy-nav-shift']").toggleClass("shift"); $("[data-toggle='wy-nav-shift']").toggleClass("shift");
$("[data-toggle='rst-versions']").toggleClass("shift"); $("[data-toggle='rst-versions']").toggleClass("shift");
}); })
// Nav menu link click operations // Nav menu link click operations
$(document).on('click', ".wy-menu-vertical .current ul li a", function() { .on('click', ".wy-menu-vertical .current ul li a", function() {
var target = $(this); var target = $(this);
// Close menu when you click a link. // Close menu when you click a link.
$("[data-toggle='wy-nav-shift']").removeClass("shift"); $("[data-toggle='wy-nav-shift']").removeClass("shift");
$("[data-toggle='rst-versions']").toggleClass("shift"); $("[data-toggle='rst-versions']").toggleClass("shift");
// Handle dynamic display of l3 and l4 nav lists // Handle dynamic display of l3 and l4 nav lists
toggleCurrent(target); self.toggleCurrent(target);
if (typeof(window.SphinxRtdTheme) != 'undefined') { self.hashChange();
window.SphinxRtdTheme.StickyNav.hashChange(); })
} .on('click', "[data-toggle='rst-current-version']", function() {
});
$(document).on('click', "[data-toggle='rst-current-version']", function() {
$("[data-toggle='rst-versions']").toggleClass("shift-up"); $("[data-toggle='rst-versions']").toggleClass("shift-up");
}); })
// Make tables responsive // Make tables responsive
$("table.docutils:not(.field-list)").wrap("<div class='wy-table-responsive'></div>"); $("table.docutils:not(.field-list)")
.wrap("<div class='wy-table-responsive'></div>");
// Add expand links to all parents of nested ul // Add expand links to all parents of nested ul
$('.wy-menu-vertical ul').not('.simple').siblings('a').each(function () { $('.wy-menu-vertical ul').not('.simple').siblings('a').each(function () {
var link = $(this); var link = $(this);
expand = $('<span class="toctree-expand"></span>'); expand = $('<span class="toctree-expand"></span>');
expand.on('click', function (ev) { expand.on('click', function (ev) {
toggleCurrent(link); self.toggleCurrent(link);
ev.stopPropagation(); ev.stopPropagation();
return false; return false;
}); });
link.prepend(expand); link.prepend(expand);
}); });
}); };
// Sphinx theme state nav.reset = function () {
window.SphinxRtdTheme = (function (jquery) {
var stickyNav = (function () {
var navBar,
win,
winScroll = false,
winResize = false,
linkScroll = false,
winPosition = 0,
winHeight,
docHeight,
enable = function () {
init();
reset();
win.on('hashchange', reset);
// Set scroll monitor
win.on('scroll', function () {
if (!linkScroll) {
winScroll = true;
}
});
setInterval(function () { if (winScroll) scroll(); }, 25);
// Set resize monitor
win.on('resize', function () {
winResize = true;
});
setInterval(function () { if (winResize) resize(); }, 25);
resize();
},
init = function () {
navBar = jquery('div.wy-side-scroll:first');
win = jquery(window);
},
reset = function () {
// Get anchor from URL and open up nested nav // Get anchor from URL and open up nested nav
var anchor = encodeURI(window.location.hash); var anchor = encodeURI(window.location.hash);
if (anchor) { if (anchor) {
@ -95,37 +105,49 @@ window.SphinxRtdTheme = (function (jquery) {
console.log("Error expanding nav for anchor", err); console.log("Error expanding nav for anchor", err);
} }
} }
}, };
scroll = function () {
winScroll = false; nav.onScroll = function () {
var newWinPosition = win.scrollTop(), this.winScroll = false;
winBottom = newWinPosition + winHeight, var newWinPosition = this.win.scrollTop(),
navPosition = navBar.scrollTop(), winBottom = newWinPosition + this.winHeight,
newNavPosition = navPosition + (newWinPosition - winPosition); navPosition = this.navBar.scrollTop(),
if (newWinPosition < 0 || winBottom > docHeight) { newNavPosition = navPosition + (newWinPosition - this.winPosition);
if (newWinPosition < 0 || winBottom > this.docHeight) {
return; return;
} }
navBar.scrollTop(newNavPosition); this.navBar.scrollTop(newNavPosition);
winPosition = newWinPosition; this.winPosition = newWinPosition;
}, };
resize = function () {
winResize = false; nav.onResize = function () {
winHeight = win.height(); this.winResize = false;
docHeight = $(document).height(); this.winHeight = this.win.height();
}, this.docHeight = $(document).height();
hashChange = function () { };
linkScroll = true;
win.one('hashchange', function () { nav.hashChange = function () {
linkScroll = false; this.linkScroll = true;
this.win.one('hashchange', function () {
this.linkScroll = false;
}); });
}; };
jquery(init);
return { nav.toggleCurrent = function (elem) {
enable: enable, var parent_li = elem.closest('li');
hashChange: hashChange parent_li.siblings('li.current').removeClass('current');
}; parent_li.siblings().find('li.current').removeClass('current');
}()); parent_li.find('> ul li.current').removeClass('current');
return { parent_li.toggleClass('current');
StickyNav: stickyNav }
};
}($)); return nav;
};
module.exports.ThemeNav = ThemeNav();
if (typeof(window) != 'undefined') {
window.SphinxRtdTheme = { StickyNav: module.exports.ThemeNav };
}
},{"jquery":"jquery"}]},{},["sphinx-rtd-theme"]);