From 5892700b5cee3db59036d98e8c33775edbaa965a Mon Sep 17 00:00:00 2001 From: Christopher Rogers Date: Thu, 10 Apr 2014 14:55:00 -0700 Subject: [PATCH] Fixes toc alignment on search and adds highlight library Signed-off-by: Christopher Rogers --- source/javascripts/app/search.js | 32 +++--- source/javascripts/app/toc.js | 55 +++++++---- source/javascripts/lib/jquery.highlight.js | 108 +++++++++++++++++++++ source/stylesheets/screen.css.scss | 4 + 4 files changed, 167 insertions(+), 32 deletions(-) create mode 100644 source/javascripts/lib/jquery.highlight.js diff --git a/source/javascripts/app/search.js b/source/javascripts/app/search.js index 0ce6eb4..a7441bf 100644 --- a/source/javascripts/app/search.js +++ b/source/javascripts/app/search.js @@ -1,5 +1,6 @@ (function (global) { + var $global = $(global); var index = lunr(function () { this.ref('id'); this.field('title', { boost: 10 }); @@ -29,17 +30,26 @@ } function bind () { - $('#input-search').on('keyup', function () { - if (this.value) { - var items = index.search(this.value); - $('section, #toc .tocify-item').hide(); - items.forEach(function (item) { - $('#section-' + item.ref + ', .tocify-item[data-unique=' + item.ref).show(); - }); - } else { - $('section, #toc .tocify-item').show(); - } - }); + $('#input-search').on('keyup', search); + } + + function search () { + var sections = $('section, #toc .tocify-header'); + + if (this.value) { + var items = index.search(this.value); + sections.hide(); + items.forEach(function (item) { + $('#section-' + item.ref).show(); + $('.tocify-item[data-unique=' + item.ref + ']').closest('.tocify-header').show(); + }); + } else { + sections.show(); + } + + // HACK trigger tocify height recalculation + $global.triggerHandler('scroll.tocify'); + $global.triggerHandler('resize'); } })(window); diff --git a/source/javascripts/app/toc.js b/source/javascripts/app/toc.js index b56ecb3..3761c2b 100644 --- a/source/javascripts/app/toc.js +++ b/source/javascripts/app/toc.js @@ -1,24 +1,37 @@ -$(function() { - var toc = $("#toc").tocify({ - selectors: "h1,h2", - extendPage: false, - theme: "none", - smoothScroll: false, - showEffectSpeed: 0, - hideEffectSpeed: 180, - ignoreSelector: ".toc-ignore", - hashGenerator: 'pretty', - highlightOffset: 60, - scrollTo: -2, - scrollHistory: true, - hashGenerator: function(text, element) { - return element[0].getAttribute('id'); - } - }).data("toc-tocify"); +(function (global) { + + var toc; + + global.toc = toc; + + $(toc); + $(animate); + + function toc () { + toc = $("#toc").tocify({ + selectors: 'h1, h2', + extendPage: false, + theme: 'none', + smoothScroll: false, + showEffectSpeed: 0, + hideEffectSpeed: 180, + ignoreSelector: '.toc-ignore', + highlightOffset: 60, + scrollTo: -2, + scrollHistory: true, + hashGenerator: function (text, element) { + return element.prop('id'); + } + }).data('toc-tocify'); + } // Hack to make already open sections to start opened, // instead of displaying an ugly animation - setTimeout(function() { - toc.setOption("showEffectSpeed", 180); - }, 50); -}); + function animate () { + setTimeout(function() { + toc.setOption('showEffectSpeed', 180); + }, 50); + } + +})(window); + diff --git a/source/javascripts/lib/jquery.highlight.js b/source/javascripts/lib/jquery.highlight.js new file mode 100644 index 0000000..9dcf3c7 --- /dev/null +++ b/source/javascripts/lib/jquery.highlight.js @@ -0,0 +1,108 @@ +/* + * jQuery Highlight plugin + * + * Based on highlight v3 by Johann Burkard + * http://johannburkard.de/blog/programming/javascript/highlight-javascript-text-higlighting-jquery-plugin.html + * + * Code a little bit refactored and cleaned (in my humble opinion). + * Most important changes: + * - has an option to highlight only entire words (wordsOnly - false by default), + * - has an option to be case sensitive (caseSensitive - false by default) + * - highlight element tag and class names can be specified in options + * + * Usage: + * // wrap every occurrance of text 'lorem' in content + * // with (default options) + * $('#content').highlight('lorem'); + * + * // search for and highlight more terms at once + * // so you can save some time on traversing DOM + * $('#content').highlight(['lorem', 'ipsum']); + * $('#content').highlight('lorem ipsum'); + * + * // search only for entire word 'lorem' + * $('#content').highlight('lorem', { wordsOnly: true }); + * + * // don't ignore case during search of term 'lorem' + * $('#content').highlight('lorem', { caseSensitive: true }); + * + * // wrap every occurrance of term 'ipsum' in content + * // with + * $('#content').highlight('ipsum', { element: 'em', className: 'important' }); + * + * // remove default highlight + * $('#content').unhighlight(); + * + * // remove custom highlight + * $('#content').unhighlight({ element: 'em', className: 'important' }); + * + * + * Copyright (c) 2009 Bartek Szopka + * + * Licensed under MIT license. + * + */ + +jQuery.extend({ + highlight: function (node, re, nodeName, className) { + if (node.nodeType === 3) { + var match = node.data.match(re); + if (match) { + var highlight = document.createElement(nodeName || 'span'); + highlight.className = className || 'highlight'; + var wordNode = node.splitText(match.index); + wordNode.splitText(match[0].length); + var wordClone = wordNode.cloneNode(true); + highlight.appendChild(wordClone); + wordNode.parentNode.replaceChild(highlight, wordNode); + return 1; //skip added node in parent + } + } else if ((node.nodeType === 1 && node.childNodes) && // only element nodes that have children + !/(script|style)/i.test(node.tagName) && // ignore script and style nodes + !(node.tagName === nodeName.toUpperCase() && node.className === className)) { // skip if already highlighted + for (var i = 0; i < node.childNodes.length; i++) { + i += jQuery.highlight(node.childNodes[i], re, nodeName, className); + } + } + return 0; + } +}); + +jQuery.fn.unhighlight = function (options) { + var settings = { className: 'highlight', element: 'span' }; + jQuery.extend(settings, options); + + return this.find(settings.element + "." + settings.className).each(function () { + var parent = this.parentNode; + parent.replaceChild(this.firstChild, this); + parent.normalize(); + }).end(); +}; + +jQuery.fn.highlight = function (words, options) { + var settings = { className: 'highlight', element: 'span', caseSensitive: false, wordsOnly: false }; + jQuery.extend(settings, options); + + if (words.constructor === String) { + words = [words]; + } + words = jQuery.grep(words, function(word, i){ + return word != ''; + }); + words = jQuery.map(words, function(word, i) { + return word.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); + }); + if (words.length == 0) { return this; }; + + var flag = settings.caseSensitive ? "" : "i"; + var pattern = "(" + words.join("|") + ")"; + if (settings.wordsOnly) { + pattern = "\\b" + pattern + "\\b"; + } + var re = new RegExp(pattern, flag); + + return this.each(function () { + jQuery.highlight(this, re, settings.element, settings.className); + }); +}; + diff --git a/source/stylesheets/screen.css.scss b/source/stylesheets/screen.css.scss index bbebcd0..eb8b562 100644 --- a/source/stylesheets/screen.css.scss +++ b/source/stylesheets/screen.css.scss @@ -35,6 +35,10 @@ html, body { background-color: $main-bg; } +.highlight { + background-color: #FFFF88; +} + //////////////////////////////////////////////////////////////////////////////// // TABLE OF CONTENTS ////////////////////////////////////////////////////////////////////////////////