Path: blob/main/src/resources/formats/revealjs/reveal/plugin/search/plugin.js
12923 views
/*!1* Handles finding a text string anywhere in the slides and showing the next occurrence to the user2* by navigatating to that slide and highlighting it.3*4* @author Jon Snyder <[email protected]>, February 20135*/67const Plugin = () => {89// The reveal.js instance this plugin is attached to10let deck;1112let searchElement;13let searchButton;14let searchInput;1516let matchedSlides;17let currentMatchedIndex;18let searchboxDirty;19let hilitor;2021function render() {2223searchElement = document.createElement( 'div' );24searchElement.classList.add( 'searchbox' );25searchElement.style.position = 'absolute';26searchElement.style.top = '10px';27searchElement.style.right = '10px';28searchElement.style.zIndex = 10;2930//embedded base64 search icon Designed by Sketchdock - http://www.sketchdock.com/:31searchElement.innerHTML = `<input type="search" class="searchinput" placeholder="Search..." style="vertical-align: top;"/>32</span>`;3334searchInput = searchElement.querySelector( '.searchinput' );35searchInput.style.width = '240px';36searchInput.style.fontSize = '14px';37searchInput.style.padding = '4px 6px';38searchInput.style.color = '#000';39searchInput.style.background = '#fff';40searchInput.style.borderRadius = '2px';41searchInput.style.border = '0';42searchInput.style.outline = '0';43searchInput.style.boxShadow = '0 2px 18px rgba(0, 0, 0, 0.2)';44searchInput.style['-webkit-appearance'] = 'none';4546deck.getRevealElement().appendChild( searchElement );4748// searchButton.addEventListener( 'click', function(event) {49// doSearch();50// }, false );5152searchInput.addEventListener( 'keyup', function( event ) {53switch (event.keyCode) {54case 13:55event.preventDefault();56doSearch();57searchboxDirty = false;58break;59default:60searchboxDirty = true;61}62}, false );6364closeSearch();6566}6768function openSearch() {69if( !searchElement ) render();7071searchElement.style.display = 'inline';72searchInput.focus();73searchInput.select();74}7576function closeSearch() {77if( !searchElement ) render();7879searchElement.style.display = 'none';80if(hilitor) hilitor.remove();81}8283function toggleSearch() {84if( !searchElement ) render();8586if (searchElement.style.display !== 'inline') {87openSearch();88}89else {90closeSearch();91}92}9394function doSearch() {95//if there's been a change in the search term, perform a new search:96if (searchboxDirty) {97var searchstring = searchInput.value;9899if (searchstring === '') {100if(hilitor) hilitor.remove();101matchedSlides = null;102}103else {104//find the keyword amongst the slides105hilitor = new Hilitor("slidecontent");106matchedSlides = hilitor.apply(searchstring);107currentMatchedIndex = 0;108}109}110111if (matchedSlides) {112//navigate to the next slide that has the keyword, wrapping to the first if necessary113if (matchedSlides.length && (matchedSlides.length <= currentMatchedIndex)) {114currentMatchedIndex = 0;115}116if (matchedSlides.length > currentMatchedIndex) {117deck.slide(matchedSlides[currentMatchedIndex].h, matchedSlides[currentMatchedIndex].v);118currentMatchedIndex++;119}120}121}122123// Original JavaScript code by Chirp Internet: www.chirp.com.au124// Please acknowledge use of this code by including this header.125// 2/2013 jon: modified regex to display any match, not restricted to word boundaries.126function Hilitor(id, tag) {127128var targetNode = document.getElementById(id) || document.body;129var hiliteTag = tag || "EM";130var skipTags = new RegExp("^(?:" + hiliteTag + "|SCRIPT|FORM)$");131var colors = ["#ff6", "#a0ffff", "#9f9", "#f99", "#f6f"];132var wordColor = [];133var colorIdx = 0;134var matchRegex = "";135var matchingSlides = [];136137this.setRegex = function(input)138{139input = input.trim();140matchRegex = new RegExp("(" + input + ")","i");141}142143this.getRegex = function()144{145return matchRegex.toString().replace(/^\/\\b\(|\)\\b\/i$/g, "").replace(/\|/g, " ");146}147148// recursively apply word highlighting149this.hiliteWords = function(node)150{151if(node == undefined || !node) return;152if(!matchRegex) return;153if(skipTags.test(node.nodeName)) return;154155if(node.hasChildNodes()) {156for(var i=0; i < node.childNodes.length; i++)157this.hiliteWords(node.childNodes[i]);158}159if(node.nodeType == 3) { // NODE_TEXT160var nv, regs;161if((nv = node.nodeValue) && (regs = matchRegex.exec(nv))) {162//find the slide's section element and save it in our list of matching slides163var secnode = node;164while (secnode != null && secnode.nodeName != 'SECTION') {165secnode = secnode.parentNode;166}167168var slideIndex = deck.getIndices(secnode);169var slidelen = matchingSlides.length;170var alreadyAdded = false;171for (var i=0; i < slidelen; i++) {172if ( (matchingSlides[i].h === slideIndex.h) && (matchingSlides[i].v === slideIndex.v) ) {173alreadyAdded = true;174}175}176if (! alreadyAdded) {177matchingSlides.push(slideIndex);178}179180if(!wordColor[regs[0].toLowerCase()]) {181wordColor[regs[0].toLowerCase()] = colors[colorIdx++ % colors.length];182}183184var match = document.createElement(hiliteTag);185match.appendChild(document.createTextNode(regs[0]));186match.style.backgroundColor = wordColor[regs[0].toLowerCase()];187match.style.fontStyle = "inherit";188match.style.color = "#000";189190var after = node.splitText(regs.index);191after.nodeValue = after.nodeValue.substring(regs[0].length);192node.parentNode.insertBefore(match, after);193}194}195};196197// remove highlighting198this.remove = function()199{200var arr = document.getElementsByTagName(hiliteTag);201var el;202while(arr.length && (el = arr[0])) {203el.parentNode.replaceChild(el.firstChild, el);204}205};206207// start highlighting at target node208this.apply = function(input)209{210if(input == undefined || !input) return;211this.remove();212this.setRegex(input);213this.hiliteWords(targetNode);214return matchingSlides;215};216217}218219return {220221id: 'search',222223init: reveal => {224225deck = reveal;226deck.registerKeyboardShortcut( 'CTRL + Shift + F', 'Search' );227228document.addEventListener( 'keydown', function( event ) {229if( event.key == "F" && (event.ctrlKey || event.metaKey) ) { //Control+Shift+f230event.preventDefault();231toggleSearch();232}233}, false );234235},236237open: openSearch238239}240};241242export default Plugin;243244