mirror of
https://github.com/fniessen/org-html-themes.git
synced 2024-06-26 07:39:01 +02:00
I make a distinction between searching the whole doc contents or just the current section, as I've adapted bigblow to not tabify main sections
526 lines
16 KiB
JavaScript
526 lines
16 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) {
|
||
let headers = null;
|
||
if(divId) {
|
||
$('#minitoc').empty().append('<h2>In this section</h2>');
|
||
headers = $('#' + divId).find('h3');
|
||
}
|
||
else {
|
||
$('#minitoc').empty().append('<h2>In this document</h2>');
|
||
headers = $('div#content').find(':header');
|
||
}
|
||
headers.each(function(i) {
|
||
let text = $(this)
|
||
.clone() //clone the element
|
||
.children() //select all the children
|
||
.remove() //remove all the children
|
||
.end() //again go back to selected element
|
||
.text().trim();
|
||
var level = parseInt(this.nodeName.substring(1), 10);
|
||
let prefix = "".padStart(level-1, " ");
|
||
$("#minitoc").append("<a href='#" + $(this).attr("id") + "'>"
|
||
+ prefix + 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();
|
||
});
|
||
|
||
$(document).ready(function() {
|
||
// 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();
|
||
});
|
||
$(document).on('mouseleave', '.org-src-container', function () {
|
||
$(this).find('.snippet-copy-to-clipboard').hide();
|
||
});
|
||
|
||
$('.copy-to-clipboard-button').click( function() {
|
||
var element = $(this).parent().parent().find('.src');
|
||
var val = element.text();
|
||
val = val.replace(/\n/g, "\r\n");
|
||
|
||
var $copyElement = $("<textarea>");
|
||
$("body").append($copyElement);
|
||
|
||
$copyElement.val(val);
|
||
|
||
$copyElement.trigger('select');
|
||
document.execCommand('copy');
|
||
|
||
$copyElement.remove();
|
||
|
||
$(this).parent().parent().find('.snippet-copy-to-clipboard').hide();
|
||
});
|
||
});
|
||
|
||
$(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;
|