From d283f7e661e14d6ae1881fe803e5b4f1ed0689ff Mon Sep 17 00:00:00 2001 From: David Thompson Date: Mon, 24 Jun 2024 13:49:08 -0400 Subject: Add 2024 Guix social talk. --- .../reveal.js/plugin/search/plugin.js | 243 +++++++++++++++++++++ .../reveal.js/plugin/search/search.esm.js | 7 + .../reveal.js/plugin/search/search.js | 7 + 3 files changed, 257 insertions(+) create mode 100644 2024-06-18-guix-social/reveal.js/plugin/search/plugin.js create mode 100644 2024-06-18-guix-social/reveal.js/plugin/search/search.esm.js create mode 100644 2024-06-18-guix-social/reveal.js/plugin/search/search.js (limited to '2024-06-18-guix-social/reveal.js/plugin/search') diff --git a/2024-06-18-guix-social/reveal.js/plugin/search/plugin.js b/2024-06-18-guix-social/reveal.js/plugin/search/plugin.js new file mode 100644 index 0000000..fe38343 --- /dev/null +++ b/2024-06-18-guix-social/reveal.js/plugin/search/plugin.js @@ -0,0 +1,243 @@ +/*! + * Handles finding a text string anywhere in the slides and showing the next occurrence to the user + * by navigatating to that slide and highlighting it. + * + * @author Jon Snyder , February 2013 + */ + +const Plugin = () => { + + // The reveal.js instance this plugin is attached to + let deck; + + let searchElement; + let searchButton; + let searchInput; + + let matchedSlides; + let currentMatchedIndex; + let searchboxDirty; + let hilitor; + + function render() { + + searchElement = document.createElement( 'div' ); + searchElement.classList.add( 'searchbox' ); + searchElement.style.position = 'absolute'; + searchElement.style.top = '10px'; + searchElement.style.right = '10px'; + searchElement.style.zIndex = 10; + + //embedded base64 search icon Designed by Sketchdock - http://www.sketchdock.com/: + searchElement.innerHTML = ` + `; + + searchInput = searchElement.querySelector( '.searchinput' ); + searchInput.style.width = '240px'; + searchInput.style.fontSize = '14px'; + searchInput.style.padding = '4px 6px'; + searchInput.style.color = '#000'; + searchInput.style.background = '#fff'; + searchInput.style.borderRadius = '2px'; + searchInput.style.border = '0'; + searchInput.style.outline = '0'; + searchInput.style.boxShadow = '0 2px 18px rgba(0, 0, 0, 0.2)'; + searchInput.style['-webkit-appearance'] = 'none'; + + deck.getRevealElement().appendChild( searchElement ); + + // searchButton.addEventListener( 'click', function(event) { + // doSearch(); + // }, false ); + + searchInput.addEventListener( 'keyup', function( event ) { + switch (event.keyCode) { + case 13: + event.preventDefault(); + doSearch(); + searchboxDirty = false; + break; + default: + searchboxDirty = true; + } + }, false ); + + closeSearch(); + + } + + function openSearch() { + if( !searchElement ) render(); + + searchElement.style.display = 'inline'; + searchInput.focus(); + searchInput.select(); + } + + function closeSearch() { + if( !searchElement ) render(); + + searchElement.style.display = 'none'; + if(hilitor) hilitor.remove(); + } + + function toggleSearch() { + if( !searchElement ) render(); + + if (searchElement.style.display !== 'inline') { + openSearch(); + } + else { + closeSearch(); + } + } + + function doSearch() { + //if there's been a change in the search term, perform a new search: + if (searchboxDirty) { + var searchstring = searchInput.value; + + if (searchstring === '') { + if(hilitor) hilitor.remove(); + matchedSlides = null; + } + else { + //find the keyword amongst the slides + hilitor = new Hilitor("slidecontent"); + matchedSlides = hilitor.apply(searchstring); + currentMatchedIndex = 0; + } + } + + if (matchedSlides) { + //navigate to the next slide that has the keyword, wrapping to the first if necessary + if (matchedSlides.length && (matchedSlides.length <= currentMatchedIndex)) { + currentMatchedIndex = 0; + } + if (matchedSlides.length > currentMatchedIndex) { + deck.slide(matchedSlides[currentMatchedIndex].h, matchedSlides[currentMatchedIndex].v); + currentMatchedIndex++; + } + } + } + + // Original JavaScript code by Chirp Internet: www.chirp.com.au + // Please acknowledge use of this code by including this header. + // 2/2013 jon: modified regex to display any match, not restricted to word boundaries. + function Hilitor(id, tag) { + + var targetNode = document.getElementById(id) || document.body; + var hiliteTag = tag || "EM"; + var skipTags = new RegExp("^(?:" + hiliteTag + "|SCRIPT|FORM)$"); + var colors = ["#ff6", "#a0ffff", "#9f9", "#f99", "#f6f"]; + var wordColor = []; + var colorIdx = 0; + var matchRegex = ""; + var matchingSlides = []; + + this.setRegex = function(input) + { + input = input.trim(); + matchRegex = new RegExp("(" + input + ")","i"); + } + + this.getRegex = function() + { + return matchRegex.toString().replace(/^\/\\b\(|\)\\b\/i$/g, "").replace(/\|/g, " "); + } + + // recursively apply word highlighting + this.hiliteWords = function(node) + { + if(node == undefined || !node) return; + if(!matchRegex) return; + if(skipTags.test(node.nodeName)) return; + + if(node.hasChildNodes()) { + for(var i=0; i < node.childNodes.length; i++) + this.hiliteWords(node.childNodes[i]); + } + if(node.nodeType == 3) { // NODE_TEXT + var nv, regs; + if((nv = node.nodeValue) && (regs = matchRegex.exec(nv))) { + //find the slide's section element and save it in our list of matching slides + var secnode = node; + while (secnode != null && secnode.nodeName != 'SECTION') { + secnode = secnode.parentNode; + } + + var slideIndex = deck.getIndices(secnode); + var slidelen = matchingSlides.length; + var alreadyAdded = false; + for (var i=0; i < slidelen; i++) { + if ( (matchingSlides[i].h === slideIndex.h) && (matchingSlides[i].v === slideIndex.v) ) { + alreadyAdded = true; + } + } + if (! alreadyAdded) { + matchingSlides.push(slideIndex); + } + + if(!wordColor[regs[0].toLowerCase()]) { + wordColor[regs[0].toLowerCase()] = colors[colorIdx++ % colors.length]; + } + + var match = document.createElement(hiliteTag); + match.appendChild(document.createTextNode(regs[0])); + match.style.backgroundColor = wordColor[regs[0].toLowerCase()]; + match.style.fontStyle = "inherit"; + match.style.color = "#000"; + + var after = node.splitText(regs.index); + after.nodeValue = after.nodeValue.substring(regs[0].length); + node.parentNode.insertBefore(match, after); + } + } + }; + + // remove highlighting + this.remove = function() + { + var arr = document.getElementsByTagName(hiliteTag); + var el; + while(arr.length && (el = arr[0])) { + el.parentNode.replaceChild(el.firstChild, el); + } + }; + + // start highlighting at target node + this.apply = function(input) + { + if(input == undefined || !input) return; + this.remove(); + this.setRegex(input); + this.hiliteWords(targetNode); + return matchingSlides; + }; + + } + + return { + + id: 'search', + + init: reveal => { + + deck = reveal; + deck.registerKeyboardShortcut( 'CTRL + Shift + F', 'Search' ); + + document.addEventListener( 'keydown', function( event ) { + if( event.key == "F" && (event.ctrlKey || event.metaKey) ) { //Control+Shift+f + event.preventDefault(); + toggleSearch(); + } + }, false ); + + }, + + open: openSearch + + } +}; + +export default Plugin; \ No newline at end of file diff --git a/2024-06-18-guix-social/reveal.js/plugin/search/search.esm.js b/2024-06-18-guix-social/reveal.js/plugin/search/search.esm.js new file mode 100644 index 0000000..df84b6b --- /dev/null +++ b/2024-06-18-guix-social/reveal.js/plugin/search/search.esm.js @@ -0,0 +1,7 @@ +/*! + * Handles finding a text string anywhere in the slides and showing the next occurrence to the user + * by navigatating to that slide and highlighting it. + * + * @author Jon Snyder , February 2013 + */ +const e=()=>{let e,t,n,l,i,o,r;function s(){t=document.createElement("div"),t.classList.add("searchbox"),t.style.position="absolute",t.style.top="10px",t.style.right="10px",t.style.zIndex=10,t.innerHTML='\n\t\t',n=t.querySelector(".searchinput"),n.style.width="240px",n.style.fontSize="14px",n.style.padding="4px 6px",n.style.color="#000",n.style.background="#fff",n.style.borderRadius="2px",n.style.border="0",n.style.outline="0",n.style.boxShadow="0 2px 18px rgba(0, 0, 0, 0.2)",n.style["-webkit-appearance"]="none",e.getRevealElement().appendChild(t),n.addEventListener("keyup",(function(t){if(13===t.keyCode)t.preventDefault(),function(){if(o){var t=n.value;""===t?(r&&r.remove(),l=null):(r=new c("slidecontent"),l=r.apply(t),i=0)}l&&(l.length&&l.length<=i&&(i=0),l.length>i&&(e.slide(l[i].h,l[i].v),i++))}(),o=!1;else o=!0}),!1),d()}function a(){t||s(),t.style.display="inline",n.focus(),n.select()}function d(){t||s(),t.style.display="none",r&&r.remove()}function c(t,n){var l=document.getElementById(t)||document.body,i=n||"EM",o=new RegExp("^(?:"+i+"|SCRIPT|FORM)$"),r=["#ff6","#a0ffff","#9f9","#f99","#f6f"],s=[],a=0,d="",c=[];this.setRegex=function(e){e=e.trim(),d=new RegExp("("+e+")","i")},this.getRegex=function(){return d.toString().replace(/^\/\\b\(|\)\\b\/i$/g,"").replace(/\|/g," ")},this.hiliteWords=function(t){if(null!=t&&t&&d&&!o.test(t.nodeName)){if(t.hasChildNodes())for(var n=0;n{e=n,e.registerKeyboardShortcut("CTRL + Shift + F","Search"),document.addEventListener("keydown",(function(e){"F"==e.key&&(e.ctrlKey||e.metaKey)&&(e.preventDefault(),t||s(),"inline"!==t.style.display?a():d())}),!1)},open:a}};export{e as default}; diff --git a/2024-06-18-guix-social/reveal.js/plugin/search/search.js b/2024-06-18-guix-social/reveal.js/plugin/search/search.js new file mode 100644 index 0000000..aa3ad93 --- /dev/null +++ b/2024-06-18-guix-social/reveal.js/plugin/search/search.js @@ -0,0 +1,7 @@ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).RevealSearch=t()}(this,(function(){"use strict"; +/*! + * Handles finding a text string anywhere in the slides and showing the next occurrence to the user + * by navigatating to that slide and highlighting it. + * + * @author Jon Snyder , February 2013 + */return()=>{let e,t,n,i,o,l,r;function s(){t=document.createElement("div"),t.classList.add("searchbox"),t.style.position="absolute",t.style.top="10px",t.style.right="10px",t.style.zIndex=10,t.innerHTML='\n\t\t',n=t.querySelector(".searchinput"),n.style.width="240px",n.style.fontSize="14px",n.style.padding="4px 6px",n.style.color="#000",n.style.background="#fff",n.style.borderRadius="2px",n.style.border="0",n.style.outline="0",n.style.boxShadow="0 2px 18px rgba(0, 0, 0, 0.2)",n.style["-webkit-appearance"]="none",e.getRevealElement().appendChild(t),n.addEventListener("keyup",(function(t){if(13===t.keyCode)t.preventDefault(),function(){if(l){var t=n.value;""===t?(r&&r.remove(),i=null):(r=new c("slidecontent"),i=r.apply(t),o=0)}i&&(i.length&&i.length<=o&&(o=0),i.length>o&&(e.slide(i[o].h,i[o].v),o++))}(),l=!1;else l=!0}),!1),d()}function a(){t||s(),t.style.display="inline",n.focus(),n.select()}function d(){t||s(),t.style.display="none",r&&r.remove()}function c(t,n){var i=document.getElementById(t)||document.body,o=n||"EM",l=new RegExp("^(?:"+o+"|SCRIPT|FORM)$"),r=["#ff6","#a0ffff","#9f9","#f99","#f6f"],s=[],a=0,d="",c=[];this.setRegex=function(e){e=e.trim(),d=new RegExp("("+e+")","i")},this.getRegex=function(){return d.toString().replace(/^\/\\b\(|\)\\b\/i$/g,"").replace(/\|/g," ")},this.hiliteWords=function(t){if(null!=t&&t&&d&&!l.test(t.nodeName)){if(t.hasChildNodes())for(var n=0;n{e=n,e.registerKeyboardShortcut("CTRL + Shift + F","Search"),document.addEventListener("keydown",(function(e){"F"==e.key&&(e.ctrlKey||e.metaKey)&&(e.preventDefault(),t||s(),"inline"!==t.style.display?a():d())}),!1)},open:a}}})); -- cgit v1.2.3