github.com/mweagle/Sparta@v1.15.0/docs_source/static/presentations/reveal.js-3.9.2/plugin/search/search.js (about) 1 /* 2 * Handles finding a text string anywhere in the slides and showing the next occurrence to the user 3 * by navigatating to that slide and highlighting it. 4 * 5 * By Jon Snyder <snyder.jon@gmail.com>, February 2013 6 */ 7 8 var RevealSearch = (function() { 9 10 var matchedSlides; 11 var currentMatchedIndex; 12 var searchboxDirty; 13 var myHilitor; 14 15 // Original JavaScript code by Chirp Internet: www.chirp.com.au 16 // Please acknowledge use of this code by including this header. 17 // 2/2013 jon: modified regex to display any match, not restricted to word boundaries. 18 19 function Hilitor(id, tag) 20 { 21 22 var targetNode = document.getElementById(id) || document.body; 23 var hiliteTag = tag || "EM"; 24 var skipTags = new RegExp("^(?:" + hiliteTag + "|SCRIPT|FORM)$"); 25 var colors = ["#ff6", "#a0ffff", "#9f9", "#f99", "#f6f"]; 26 var wordColor = []; 27 var colorIdx = 0; 28 var matchRegex = ""; 29 var matchingSlides = []; 30 31 this.setRegex = function(input) 32 { 33 input = input.replace(/^[^\w]+|[^\w]+$/g, "").replace(/[^\w'-]+/g, "|"); 34 matchRegex = new RegExp("(" + input + ")","i"); 35 } 36 37 this.getRegex = function() 38 { 39 return matchRegex.toString().replace(/^\/\\b\(|\)\\b\/i$/g, "").replace(/\|/g, " "); 40 } 41 42 // recursively apply word highlighting 43 this.hiliteWords = function(node) 44 { 45 if(node == undefined || !node) return; 46 if(!matchRegex) return; 47 if(skipTags.test(node.nodeName)) return; 48 49 if(node.hasChildNodes()) { 50 for(var i=0; i < node.childNodes.length; i++) 51 this.hiliteWords(node.childNodes[i]); 52 } 53 if(node.nodeType == 3) { // NODE_TEXT 54 if((nv = node.nodeValue) && (regs = matchRegex.exec(nv))) { 55 //find the slide's section element and save it in our list of matching slides 56 var secnode = node; 57 while (secnode != null && secnode.nodeName != 'SECTION') { 58 secnode = secnode.parentNode; 59 } 60 61 var slideIndex = Reveal.getIndices(secnode); 62 var slidelen = matchingSlides.length; 63 var alreadyAdded = false; 64 for (var i=0; i < slidelen; i++) { 65 if ( (matchingSlides[i].h === slideIndex.h) && (matchingSlides[i].v === slideIndex.v) ) { 66 alreadyAdded = true; 67 } 68 } 69 if (! alreadyAdded) { 70 matchingSlides.push(slideIndex); 71 } 72 73 if(!wordColor[regs[0].toLowerCase()]) { 74 wordColor[regs[0].toLowerCase()] = colors[colorIdx++ % colors.length]; 75 } 76 77 var match = document.createElement(hiliteTag); 78 match.appendChild(document.createTextNode(regs[0])); 79 match.style.backgroundColor = wordColor[regs[0].toLowerCase()]; 80 match.style.fontStyle = "inherit"; 81 match.style.color = "#000"; 82 83 var after = node.splitText(regs.index); 84 after.nodeValue = after.nodeValue.substring(regs[0].length); 85 node.parentNode.insertBefore(match, after); 86 } 87 } 88 }; 89 90 // remove highlighting 91 this.remove = function() 92 { 93 var arr = document.getElementsByTagName(hiliteTag); 94 while(arr.length && (el = arr[0])) { 95 el.parentNode.replaceChild(el.firstChild, el); 96 } 97 }; 98 99 // start highlighting at target node 100 this.apply = function(input) 101 { 102 if(input == undefined || !input) return; 103 this.remove(); 104 this.setRegex(input); 105 this.hiliteWords(targetNode); 106 return matchingSlides; 107 }; 108 109 } 110 111 function openSearch() { 112 //ensure the search term input dialog is visible and has focus: 113 var inputboxdiv = document.getElementById("searchinputdiv"); 114 var inputbox = document.getElementById("searchinput"); 115 inputboxdiv.style.display = "inline"; 116 inputbox.focus(); 117 inputbox.select(); 118 } 119 120 function closeSearch() { 121 var inputboxdiv = document.getElementById("searchinputdiv"); 122 inputboxdiv.style.display = "none"; 123 if(myHilitor) myHilitor.remove(); 124 } 125 126 function toggleSearch() { 127 var inputboxdiv = document.getElementById("searchinputdiv"); 128 if (inputboxdiv.style.display !== "inline") { 129 openSearch(); 130 } 131 else { 132 closeSearch(); 133 } 134 } 135 136 function doSearch() { 137 //if there's been a change in the search term, perform a new search: 138 if (searchboxDirty) { 139 var searchstring = document.getElementById("searchinput").value; 140 141 if (searchstring === '') { 142 if(myHilitor) myHilitor.remove(); 143 matchedSlides = null; 144 } 145 else { 146 //find the keyword amongst the slides 147 myHilitor = new Hilitor("slidecontent"); 148 matchedSlides = myHilitor.apply(searchstring); 149 currentMatchedIndex = 0; 150 } 151 } 152 153 if (matchedSlides) { 154 //navigate to the next slide that has the keyword, wrapping to the first if necessary 155 if (matchedSlides.length && (matchedSlides.length <= currentMatchedIndex)) { 156 currentMatchedIndex = 0; 157 } 158 if (matchedSlides.length > currentMatchedIndex) { 159 Reveal.slide(matchedSlides[currentMatchedIndex].h, matchedSlides[currentMatchedIndex].v); 160 currentMatchedIndex++; 161 } 162 } 163 } 164 165 var dom = {}; 166 dom.wrapper = document.querySelector( '.reveal' ); 167 168 if( !dom.wrapper.querySelector( '.searchbox' ) ) { 169 var searchElement = document.createElement( 'div' ); 170 searchElement.id = "searchinputdiv"; 171 searchElement.classList.add( 'searchdiv' ); 172 searchElement.style.position = 'absolute'; 173 searchElement.style.top = '10px'; 174 searchElement.style.right = '10px'; 175 searchElement.style.zIndex = 10; 176 //embedded base64 search icon Designed by Sketchdock - http://www.sketchdock.com/: 177 searchElement.innerHTML = '<span><input type="search" id="searchinput" class="searchinput" style="vertical-align: top;"/><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJiSURBVHjatFZNaxNBGH5md+Mmu92NVdKDRipSAyqCghgQD4L4cRe86UUtAQ+eFCxoa4/25EXBFi8eBE+eRPoDhB6KgiiixdAPCEkx2pjvTXadd9yNsflwuyUDD/O+u8PzzDPvzOwyx3EwyCZhwG3gAkp7MnpjgbopjsltcD4gjuXZZKeAR348MYLYTm3LzOs/y3j3JTfZxgXWXmTuwPHIc4VmoOmv5IrI53+AO2DdHLjkDWQ3GoEEVFXtXQOvkSnPWcyUceviLhwbDYv8/XIVj97kse7TodLvZXxYxrPUHkQ1ufXs3FEdybEIxucySOesoNvUgWU1cP3MkCBfTFdw9fGaAMVmRELq7LBw2Q3/FaAxxWIRpw+ZIr/7IouPqzUBiqmdHAv7EuhRAwf1er2Vy4x1jW3b2d5Jfvu5IPp7l2LYbcgCFFNb+FoJ7oBqEAqFMPNqFcmEgVMJDfMT+1tvN0pNjERlMS6QA5pFOKxiKVPFhakPeL3It+WGJUDxt2wFR+JhzI7v5ctkd8DXOZAkCYYxhO+lKm4+Xfqz/rIixBuNBl7eOYzkQQNzqX249mRl6zUgEcYkaJrGhUwBinVdh6IouPzwE6/DL5w4oLkH8y981aDf+uq6hlKpJESiUdNfDZi7/ehG9K6KfiA3pml0PLcsq+cSMTj2NL9ukc4UOmz7AZ3+crkC4mHujFvXNaMFB3bEr8xPS6p5O+jXxq4VZtaen7/PwzrntjcLUE0iHPS1Ud1cdiEJl/8WivZk0wXd7zWOMkeF8s0CcAmkNrC2nvXZDbbbN73ccYnZoH9bfgswAFzAe9/h3dbKAAAAAElFTkSuQmCC" id="searchbutton" class="searchicon" style="vertical-align: top; margin-top: -1px;"/></span>'; 178 dom.wrapper.appendChild( searchElement ); 179 } 180 181 document.getElementById( 'searchbutton' ).addEventListener( 'click', function(event) { 182 doSearch(); 183 }, false ); 184 185 document.getElementById( 'searchinput' ).addEventListener( 'keyup', function( event ) { 186 switch (event.keyCode) { 187 case 13: 188 event.preventDefault(); 189 doSearch(); 190 searchboxDirty = false; 191 break; 192 default: 193 searchboxDirty = true; 194 } 195 }, false ); 196 197 document.addEventListener( 'keydown', function( event ) { 198 if( event.key == "F" && (event.ctrlKey || event.metaKey) ) { //Control+Shift+f 199 event.preventDefault(); 200 toggleSearch(); 201 } 202 }, false ); 203 if( window.Reveal ) Reveal.registerKeyboardShortcut( 'CTRL + Shift + F', 'Search' ); 204 closeSearch(); 205 return { open: openSearch }; 206 })();