530 lines
17 KiB
JavaScript
530 lines
17 KiB
JavaScript
|
// bigblow.js --- BigBlow JS file
|
|||
|
//
|
|||
|
// Copyright (C) 2011-2016 All Right Reserved, Fabrice Niessen
|
|||
|
//
|
|||
|
// This file is free software: you can redistribute it and/or
|
|||
|
// modify it under the terms of the GNU General Public License as
|
|||
|
// published by the Free Software Foundation, either version 3 of
|
|||
|
// the License, or (at your option) any later version.
|
|||
|
//
|
|||
|
// This file is distributed in the hope that it will be useful,
|
|||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|||
|
// GNU General Public License for more details.
|
|||
|
//
|
|||
|
// Author: Fabrice Niessen <(concat "fniessen" at-sign "pirilampo.org")>
|
|||
|
// URL: https://github.com/fniessen/org-html-themes/
|
|||
|
// Version: 20140515.1841
|
|||
|
|
|||
|
$(function() {
|
|||
|
$('p').
|
|||
|
html(function(index, old) {
|
|||
|
return old.replace('FIXME',
|
|||
|
'<span class="fixme">FIXME</span>');
|
|||
|
});
|
|||
|
$('p').
|
|||
|
html(function(index, old) {
|
|||
|
return old.replace('XXX',
|
|||
|
'<span class="fixme">XXX</span>');
|
|||
|
});
|
|||
|
});
|
|||
|
|
|||
|
// Remove leading section number
|
|||
|
$(function() {
|
|||
|
$('.section-number-2').text("");
|
|||
|
for (var i = 3; i <= 5; i++) {
|
|||
|
$('.section-number-' + i).each(function() {
|
|||
|
$(this).text($(this).text().replace(/^[0-9]+\./g, ""));
|
|||
|
});
|
|||
|
}
|
|||
|
});
|
|||
|
|
|||
|
$(function() {
|
|||
|
$('<div id="minitoc" class="dontprint"></div>').prependTo('body');
|
|||
|
});
|
|||
|
|
|||
|
// generate contents of minitoc
|
|||
|
function generateMiniToc(divId) {
|
|||
|
$('#minitoc').empty().append('<h2>In this section</h2>');
|
|||
|
$('#' + divId).find('h3').each(function(i) {
|
|||
|
$("#minitoc").append("<a href='#" + $(this).attr("id") + "'>"
|
|||
|
+ $(this).text() + "</a>");
|
|||
|
});
|
|||
|
// Ensure that the target is expanded (hideShow)
|
|||
|
$('#minitoc a[href^="#"]').click(function() {
|
|||
|
var href = $(this).attr('href');
|
|||
|
hsExpandAnchor(href);
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
// display tabs
|
|||
|
function tabifySections() {
|
|||
|
|
|||
|
// hide TOC (if present)
|
|||
|
$('#table-of-contents').hide();
|
|||
|
|
|||
|
// grab the list of `h2' from the page
|
|||
|
var allSections = [];
|
|||
|
$('h2')
|
|||
|
.each(function() {
|
|||
|
// Remove TODO keywords and tags (contained in spans)
|
|||
|
var tabText = $(this).clone().find('span').remove().end()
|
|||
|
.text().trim();
|
|||
|
var tabId = $(this).parent().attr('id');
|
|||
|
if (tabText) {
|
|||
|
// - remove heading number (all leading digits)
|
|||
|
// - remove progress logging (between square brackets)
|
|||
|
// - remove leading and trailing spaces
|
|||
|
tabText = tabText.replace(/^\d+\s+/, '').replace(/\[[\d/%]+\]/, '').trim();
|
|||
|
|
|||
|
allSections.push({
|
|||
|
text: tabText,
|
|||
|
id: tabId
|
|||
|
});
|
|||
|
}
|
|||
|
});
|
|||
|
|
|||
|
// create the tab links
|
|||
|
var tabs = $('<ul id="tabs"></ul>');
|
|||
|
for (i = 0; i < allSections.length; i++) {
|
|||
|
var item = allSections[i];
|
|||
|
html = $('<li><a href="#' + item.id + '">' + item.text + '</a></li>');
|
|||
|
tabs.append(html);
|
|||
|
}
|
|||
|
|
|||
|
// insert tabs menu after title (`h1'), or at the beginning of the content
|
|||
|
if($('.title').length !== 0) {
|
|||
|
$('.title').after(tabs);
|
|||
|
}
|
|||
|
else {
|
|||
|
$('#content').prepend(tabs);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function selectTabAndScroll(href) {
|
|||
|
// At this point we assume that href is local (starts with #)
|
|||
|
// alert(href);
|
|||
|
|
|||
|
// Find the tab to activate
|
|||
|
var targetTab = $(href).closest('.ui-tabs-panel');
|
|||
|
var targetTabId = targetTab.attr('id');
|
|||
|
var targetTabAriaLabel = targetTab.attr('aria-labelledby');
|
|||
|
|
|||
|
var targetTabIndex = $("#content ul li")
|
|||
|
.index($('[aria-labelledby="' + targetTabAriaLabel + '"]'));
|
|||
|
|
|||
|
// Activate target tab
|
|||
|
$('#content').tabs('option', 'active', targetTabIndex);
|
|||
|
|
|||
|
// Rebuild minitoc
|
|||
|
generateMiniToc(targetTabId);
|
|||
|
|
|||
|
// Set the location hash
|
|||
|
// document.location.hash = href;
|
|||
|
|
|||
|
// Scroll to top if href was a tab
|
|||
|
if (href == '#' + targetTabId) {
|
|||
|
// alert(targetTabId);
|
|||
|
$.scrollTo(0);
|
|||
|
}
|
|||
|
// Scroll to href if href was not a tab
|
|||
|
else {
|
|||
|
$.scrollTo(href);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
$(document).ready(function() {
|
|||
|
$('#preamble').remove();
|
|||
|
$('#table-of-contents').remove();
|
|||
|
|
|||
|
// Prepare for tabs
|
|||
|
tabifySections();
|
|||
|
|
|||
|
// Build the tabs from the #content div
|
|||
|
$('#content').tabs();
|
|||
|
|
|||
|
// Set default animation
|
|||
|
$('#content').tabs('option', 'show', true);
|
|||
|
|
|||
|
// Rebuild minitoc when a tab is activated
|
|||
|
$('#content').tabs({
|
|||
|
activate: function(event, ui) {
|
|||
|
var divId = ui.newTab.attr('aria-controls');
|
|||
|
generateMiniToc(divId);
|
|||
|
}
|
|||
|
});
|
|||
|
|
|||
|
// Required to get the link of the tab in URL
|
|||
|
$('#content ul').localScroll({
|
|||
|
target: '#content',
|
|||
|
duration: 0,
|
|||
|
hash: true
|
|||
|
});
|
|||
|
|
|||
|
// Handle hash in URL
|
|||
|
if ($('#content') && document.location.hash) {
|
|||
|
hsExpandAnchor(document.location.hash);
|
|||
|
selectTabAndScroll(document.location.hash);
|
|||
|
}
|
|||
|
// If no hash, build the minitoc anyway for selected tab
|
|||
|
else {
|
|||
|
var divId = $('#content div[aria-expanded=true]').attr('id');
|
|||
|
generateMiniToc(divId);
|
|||
|
}
|
|||
|
|
|||
|
// Handle click on internal links
|
|||
|
$('.ui-tabs-panel a[href^="#"]').click(function(e) {
|
|||
|
var href = $(this).attr('href');
|
|||
|
hsExpandAnchor(href);
|
|||
|
selectTabAndScroll(href);
|
|||
|
e.preventDefault();
|
|||
|
});
|
|||
|
|
|||
|
// Initialize hideShow
|
|||
|
hsInit();
|
|||
|
|
|||
|
// add sticky headers to tables
|
|||
|
$('table').stickyTableHeaders();
|
|||
|
});
|
|||
|
|
|||
|
function copyToClipboard(text)
|
|||
|
{
|
|||
|
if (window.clipboardData && window.clipboardData.setData) { // Internet Explorer
|
|||
|
window.clipboardData.setData("Text", text);
|
|||
|
}
|
|||
|
else { // Fallback solution
|
|||
|
window.prompt("Copy to clipboard: Ctrl+C, Enter", text);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
$(document).ready(function() {
|
|||
|
// Assuming that the ZeroClipboard swf file is in the same folder than bigblow,
|
|||
|
// get the path to it (it will be relative to the current page location).
|
|||
|
var bbScriptPath = $('script[src$="bigblow.js"]').attr('src'); // the js file path
|
|||
|
var bbPathToZeroClipboardSwf = bbScriptPath.replace('bigblow.js', 'ZeroClipboard.swf');
|
|||
|
|
|||
|
// Add copy to clipboard snippets
|
|||
|
$('.org-src-container').prepend('<div class="snippet-copy-to-clipboard"><span class="copy-to-clipboard-button">[copy]</span></div>');
|
|||
|
|
|||
|
// Display/hide snippets on source block mouseenter/mouseleave
|
|||
|
$(document).on('mouseenter', '.org-src-container', function () {
|
|||
|
$(this).find('.snippet-copy-to-clipboard').show();
|
|||
|
|
|||
|
// Need to call zclip here, once the button is visible.
|
|||
|
// Beacause when the button is not visible, zclip does nothing.
|
|||
|
if ((window.location.protocol != 'file:') && ($(this).find('.zclip').length == 0)) {
|
|||
|
$(this).find('.copy-to-clipboard-button').zclip({
|
|||
|
//path: 'http://www.steamdev.com/zclip/js/ZeroClipboard.swf',
|
|||
|
//path: 'styles/bigblow/js/ZeroClipboard.swf',
|
|||
|
path: bbPathToZeroClipboardSwf,
|
|||
|
copy: function() {
|
|||
|
return $(this).parent().parent().find('.src').text();
|
|||
|
}
|
|||
|
});
|
|||
|
}
|
|||
|
}).on('mouseleave', '.org-src-container', function () {
|
|||
|
$(this).find('.snippet-copy-to-clipboard').hide();
|
|||
|
});
|
|||
|
|
|||
|
// Handle copy to clipboard (here, for a local file only 'file://...'
|
|||
|
if (window.location.protocol == 'file:') { // if local file use browser-specific code
|
|||
|
$('.copy-to-clipboard-button').click(function() {
|
|||
|
// Get the text to be copied
|
|||
|
var text = $(this).parent().parent().find('.src').text();
|
|||
|
text = text.replace(/\n/g, "\r\n");
|
|||
|
// alert(text);
|
|||
|
copyToClipboard(text);
|
|||
|
});
|
|||
|
}
|
|||
|
});
|
|||
|
|
|||
|
$(function() {
|
|||
|
$('li > code :contains("[X]")')
|
|||
|
.parent()
|
|||
|
.addClass('checked')
|
|||
|
.end()
|
|||
|
.remove();
|
|||
|
$('li > code :contains("[-]")')
|
|||
|
.parent()
|
|||
|
.addClass('halfchecked')
|
|||
|
.end()
|
|||
|
.remove();
|
|||
|
$('li > code :contains("[ ]")')
|
|||
|
.parent()
|
|||
|
.addClass('unchecked')
|
|||
|
.end()
|
|||
|
.remove();
|
|||
|
});
|
|||
|
|
|||
|
$(function() {
|
|||
|
$('i :contains("[#A]")')
|
|||
|
.replaceWith('<i><span style="color: #F67777;">[#A]</span></i>');
|
|||
|
$('i :contains("[#B]")')
|
|||
|
.replaceWith('<i><span style="color: #B6E864;">[#B]</span></i>');
|
|||
|
$('i :contains("[#C]")')
|
|||
|
.replaceWith('<i><span style="color: #C3DCFF;">[#C]</span></i>');
|
|||
|
});
|
|||
|
|
|||
|
$(function() {
|
|||
|
$('<div id="toTop" class="dontprint"><span>^ Back to Top</span></div>').appendTo('body');
|
|||
|
|
|||
|
$(window).scroll(function() {
|
|||
|
if ($(this).scrollTop() != 0) {
|
|||
|
$('#toTop').fadeIn();
|
|||
|
} else {
|
|||
|
$('#toTop').fadeOut();
|
|||
|
}
|
|||
|
});
|
|||
|
|
|||
|
$('#toTop').click(function(e) {
|
|||
|
$('html, body').animate({scrollTop: 0}, 800);
|
|||
|
e.preventDefault(); // Disable default browser behavior
|
|||
|
});
|
|||
|
});
|
|||
|
|
|||
|
function togglePanel(e) {
|
|||
|
e.preventDefault();
|
|||
|
|
|||
|
$("#left-panel-contents").toggleClass('active').toggle(200);
|
|||
|
$("#right-panel-contents").toggleClass('active').toggle(200);
|
|||
|
|
|||
|
var slidePos =
|
|||
|
$("#left-panel-button").css("left") == "-23px"? '182px': '-23px';
|
|||
|
|
|||
|
$("#left-panel-button").
|
|||
|
animate({"left": slidePos, "opacity": 0.9}, {duration: "200" });
|
|||
|
|
|||
|
// if ($("#left-panel-contents").hasClass('active')) {
|
|||
|
// hsHideTodoKeyword('done');
|
|||
|
// } else {
|
|||
|
// hsShowTodoKeyword('done');
|
|||
|
// }
|
|||
|
|
|||
|
// return false;
|
|||
|
}
|
|||
|
|
|||
|
$(function() {
|
|||
|
$('<div id="left-panel-wrapper" class="dontprint"><div id="left-panel-contents" style="opacity: 0.9"></div><div id="left-panel-button" class="dontprint"><a href="#">Dashboard</a></div></div>')
|
|||
|
.appendTo('body');
|
|||
|
|
|||
|
$('<div id="right-panel-wrapper" class="dontprint"><div id="right-panel-contents" style="opacity: 0.9"></div></div>')
|
|||
|
.appendTo('body');
|
|||
|
|
|||
|
$('#left-panel-button').click(togglePanel);
|
|||
|
});
|
|||
|
|
|||
|
$(function() {
|
|||
|
var ul = $('<ul id="listOfTodo"></ul>').appendTo('#left-panel-contents');
|
|||
|
var countOfTodo = {}, listOfTodo = [], totalOfTodo = 0;
|
|||
|
|
|||
|
// assign the counts (avoid double-counting elements from the ToC)
|
|||
|
$('span.todo').not($('#table-of-contents span.todo')).each(function() {
|
|||
|
var $thisTodo = $(this).text().trim();
|
|||
|
|
|||
|
if ($.inArray($thisTodo, listOfTodo) == -1) {
|
|||
|
countOfTodo[$thisTodo] = 1;
|
|||
|
listOfTodo.push($thisTodo);
|
|||
|
}
|
|||
|
else
|
|||
|
countOfTodo[$thisTodo] += 1;
|
|||
|
totalOfTodo += 1;
|
|||
|
});
|
|||
|
|
|||
|
function scoreTodo(t) {
|
|||
|
switch (t) {
|
|||
|
case 'NEW': return 1;
|
|||
|
case 'TODO': return 2;
|
|||
|
case 'STRT': return 3;
|
|||
|
case 'WAIT': return 4;
|
|||
|
case 'DLGT': return 5;
|
|||
|
case 'SDAY': return 6;
|
|||
|
case 'DFRD': return 7;
|
|||
|
case 'DONE': return 8;
|
|||
|
case 'CANX': return 9;
|
|||
|
default: return 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function compareTodo(a, b) {
|
|||
|
if (scoreTodo(a) < scoreTodo(b)) return -1;
|
|||
|
if (scoreTodo(a) > scoreTodo(b)) return 1;
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
listOfTodo.sort(compareTodo);
|
|||
|
|
|||
|
// display
|
|||
|
for (i = 0; i < listOfTodo.length; i++) {
|
|||
|
var $thisTodo = listOfTodo[i];
|
|||
|
$(ul).append('<li><span class="todo ' + $thisTodo + '">'+ $thisTodo + '</span>'
|
|||
|
+ ' <small>(' + countOfTodo[$thisTodo] + ')</small></li>');
|
|||
|
}
|
|||
|
|
|||
|
$('#listOfTodo')
|
|||
|
.before('<b>Next Actions</b> <small>(' + totalOfTodo + ')</small>:<br>');
|
|||
|
});
|
|||
|
|
|||
|
$(function() {
|
|||
|
var ul = $('<ul id="listOfDone"></ul>').appendTo('#left-panel-contents');
|
|||
|
var countOfDone = {}, listOfDone = [], totalOfDone = 0;
|
|||
|
|
|||
|
// assign the counts (avoid double-counting elements from the ToC)
|
|||
|
$('span.done').not($('#table-of-contents span.done')).each(function() {
|
|||
|
var $thisDone = $(this).text().trim();
|
|||
|
|
|||
|
if ($.inArray($thisDone, listOfDone) == -1) {
|
|||
|
countOfDone[$thisDone] = 1;
|
|||
|
listOfDone.push($thisDone);
|
|||
|
}
|
|||
|
else
|
|||
|
countOfDone[$thisDone] += 1;
|
|||
|
totalOfDone += 1;
|
|||
|
});
|
|||
|
|
|||
|
// display
|
|||
|
for (i = 0; i < listOfDone.length; i++) {
|
|||
|
var $thisDone = listOfDone[i];
|
|||
|
$(ul).append('<li><span class="done ' + $thisDone + '">'+ $thisDone + '</span>'
|
|||
|
+ ' <small>(' + countOfDone[$thisDone] + ')</small></li>');
|
|||
|
}
|
|||
|
|
|||
|
$('#listOfDone')
|
|||
|
.before('<b>Done Actions</b> <small>(' + totalOfDone + '):</small><br>');
|
|||
|
});
|
|||
|
|
|||
|
$(function() {
|
|||
|
var ul = $('<ul id="listOfTags"></ul>').appendTo('#right-panel-contents');
|
|||
|
var countOfTags = {}, listOfTags = [], totalOfTags = 0;
|
|||
|
|
|||
|
// assign the counts (avoid double-counting elements from the ToC)
|
|||
|
$('span.tag').not($('#table-of-contents span.tag')).each(function() {
|
|||
|
var $thisTagGroup = $(this).text().trim().split(/\s/);
|
|||
|
// \s matches spaces, tabs, new lines, etc.
|
|||
|
|
|||
|
for (tag in $thisTagGroup) {
|
|||
|
if ($.inArray($thisTagGroup[tag], listOfTags) == -1) {
|
|||
|
countOfTags[$thisTagGroup[tag]] = 1;
|
|||
|
listOfTags.push($thisTagGroup[tag]);
|
|||
|
}
|
|||
|
else
|
|||
|
countOfTags[$thisTagGroup[tag]] += 1;
|
|||
|
totalOfTags += 1;
|
|||
|
}
|
|||
|
});
|
|||
|
|
|||
|
listOfTags.sort();
|
|||
|
|
|||
|
// display
|
|||
|
for (i = 0; i < listOfTags.length; i++) {
|
|||
|
var $thisTag = listOfTags[i];
|
|||
|
// $(ul).append('<li><span class="tag ' + $thisTag + '">'+
|
|||
|
// $thisTag + '</span> <small>(' + countOfTags[$thisTag] + ')</small></li>');
|
|||
|
$(ul).append('<li><span class="tag"><span class="' + $thisTag + '">' + $thisTag
|
|||
|
+ '</span></span>'
|
|||
|
+ ' <small>(' + countOfTags[$thisTag] + ')</small></li>');
|
|||
|
}
|
|||
|
|
|||
|
$('#listOfTags')
|
|||
|
.before('<b>Contexts</b> <small>(' + totalOfTags + '):</small><br>');
|
|||
|
});
|
|||
|
|
|||
|
$(function() {
|
|||
|
$('.done').parent(':header').parent().find(':header').addClass('DONEheader');
|
|||
|
$('.done').parent(':header').parent().css({color: '#999999'});
|
|||
|
});
|
|||
|
|
|||
|
$(function() {
|
|||
|
$('span.todo').click(function(e) {
|
|||
|
var orgKeyword = $(this).text().trim();
|
|||
|
$('.' + orgKeyword).toggleClass('selected');
|
|||
|
$('#content .' + orgKeyword).parent().parent()
|
|||
|
.toggleClass('match' + orgKeyword);
|
|||
|
$('#left-panel-wrapper .' + orgKeyword).parent()
|
|||
|
.toggleClass('match' + orgKeyword);
|
|||
|
e.preventDefault();
|
|||
|
})
|
|||
|
});
|
|||
|
|
|||
|
$(function() {
|
|||
|
$('.tag span').click(function(e) {
|
|||
|
var orgTag = $(this).text().trim();
|
|||
|
$('.' + orgTag).toggleClass('selected');
|
|||
|
$('#content .' + orgTag).parent().parent().parent()
|
|||
|
.toggleClass('matchtag');
|
|||
|
$('#right-panel-wrapper .' + orgTag).parent().parent()
|
|||
|
.toggleClass('matchtag');
|
|||
|
e.preventDefault();
|
|||
|
})
|
|||
|
});
|
|||
|
|
|||
|
function clickPreviousTab() {
|
|||
|
var active = $('#content').tabs('option', 'active');
|
|||
|
// Avoid going back to last tab
|
|||
|
if (active == 0) return;
|
|||
|
|
|||
|
$('#content').tabs('option', 'active', active - 1);
|
|||
|
|
|||
|
// Set the location href
|
|||
|
var href = $('#content div[aria-expanded=true]').attr('id');
|
|||
|
document.location.hash = href;
|
|||
|
$.scrollTo(0);
|
|||
|
}
|
|||
|
|
|||
|
function clickNextTab() {
|
|||
|
var active = $('#content').tabs('option', 'active');
|
|||
|
$('#content').tabs('option', 'active', active + 1);
|
|||
|
|
|||
|
// Set the location href
|
|||
|
var href = $('#content div[aria-expanded=true]').attr('id');
|
|||
|
document.location.hash = href;
|
|||
|
$.scrollTo(0);
|
|||
|
}
|
|||
|
|
|||
|
function orgDefkey(e) {
|
|||
|
if (!e)
|
|||
|
var e = window.event;
|
|||
|
var keycode = (e.keyCode) ? e.keyCode : e.which;
|
|||
|
var actualkey = String.fromCharCode(keycode);
|
|||
|
switch (actualkey) {
|
|||
|
case "?": // help (dashboard)
|
|||
|
case "h":
|
|||
|
togglePanel(e);
|
|||
|
break;
|
|||
|
case "n": // next
|
|||
|
clickNextTab();
|
|||
|
break;
|
|||
|
case "p": // previous
|
|||
|
clickPreviousTab();
|
|||
|
break;
|
|||
|
// case "b": // scroll down - should be mapped to Shift-SPC
|
|||
|
// $(window).scrollTop($(window).scrollTop()-$(window).height());
|
|||
|
// break;
|
|||
|
case "<": // scroll to top
|
|||
|
$(window).scrollTop(0);
|
|||
|
break;
|
|||
|
case ">": // scroll to bottom
|
|||
|
$(window).scrollTop($(document).height());
|
|||
|
break;
|
|||
|
case "-": // collapse all
|
|||
|
hsCollapseAll();
|
|||
|
break;
|
|||
|
case "+": // expand all
|
|||
|
hsExpandAll();
|
|||
|
break;
|
|||
|
case "r": // go to next task
|
|||
|
hsReviewTaskNext();
|
|||
|
break;
|
|||
|
case "R": // go to previous task
|
|||
|
hsReviewTaskPrev();
|
|||
|
break;
|
|||
|
case "q": // quit reviewing
|
|||
|
hsReviewTaskQuit();
|
|||
|
break;
|
|||
|
case "g": // refresh the page (from the server, rather than the cache)
|
|||
|
location.reload(true);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
document.onkeypress = orgDefkey;
|