first version of multi-step code highlights
							parent
							
								
									c636b88b2d
								
							
						
					
					
						commit
						7eb2cec6b6
					
				|  | @ -1456,6 +1456,16 @@ body { | ||||||
| .reveal .hljs[data-line-numbers]:not([data-line-numbers=""]) tr:not(.highlight-line) { | .reveal .hljs[data-line-numbers]:not([data-line-numbers=""]) tr:not(.highlight-line) { | ||||||
|   opacity: 0.4; } |   opacity: 0.4; } | ||||||
| 
 | 
 | ||||||
|  | .reveal .hljs .highlight-line .hljs-ln-numbers { | ||||||
|  |   font-weight: 600; } | ||||||
|  | 
 | ||||||
|  | .reveal .hljs:not(:first-child).fragment { | ||||||
|  |   position: absolute; | ||||||
|  |   top: 0; | ||||||
|  |   left: 0; | ||||||
|  |   width: 100%; | ||||||
|  |   box-sizing: border-box; } | ||||||
|  | 
 | ||||||
| /********************************************* | /********************************************* | ||||||
|  * ROLLING LINKS |  * ROLLING LINKS | ||||||
|  *********************************************/ |  *********************************************/ | ||||||
|  |  | ||||||
|  | @ -1594,6 +1594,18 @@ $controlsArrowAngleActive: 36deg; | ||||||
| 	opacity: 0.4; | 	opacity: 0.4; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .reveal .hljs .highlight-line .hljs-ln-numbers  { | ||||||
|  | 	font-weight: 600; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .reveal .hljs:not(:first-child).fragment { | ||||||
|  | 	position: absolute; | ||||||
|  |     top: 0; | ||||||
|  |     left: 0; | ||||||
|  |     width: 100%; | ||||||
|  |     box-sizing: border-box; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| /********************************************* | /********************************************* | ||||||
|  * ROLLING LINKS |  * ROLLING LINKS | ||||||
|  |  | ||||||
|  | @ -241,7 +241,7 @@ | ||||||
| 
 | 
 | ||||||
| 				<section> | 				<section> | ||||||
| 					<h2>Pretty Code</h2> | 					<h2>Pretty Code</h2> | ||||||
| 					<pre><code class="hljs" data-trim data-line-numbers="4,8-11"> | 					<pre><code class="hljs" data-trim data-line-numbers="4|9|4,8-11"> | ||||||
| import React, { useState } from 'react'; | import React, { useState } from 'react'; | ||||||
| 
 | 
 | ||||||
| function Example() { | function Example() { | ||||||
|  | @ -412,7 +412,7 @@ Reveal.addEventListener( 'customevent', function() { | ||||||
| 				dependencies: [ | 				dependencies: [ | ||||||
| 					{ src: 'plugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } }, | 					{ src: 'plugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } }, | ||||||
| 					{ src: 'plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } }, | 					{ src: 'plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } }, | ||||||
| 					{ src: 'plugin/highlight/highlight.js', async: true }, | 					{ src: 'plugin/highlight/highlight.js' }, | ||||||
| 					{ src: 'plugin/search/search.js', async: true }, | 					{ src: 'plugin/search/search.js', async: true }, | ||||||
| 					{ src: 'plugin/zoom-js/zoom.js', async: true }, | 					{ src: 'plugin/zoom-js/zoom.js', async: true }, | ||||||
| 					{ src: 'plugin/notes/notes.js', async: true } | 					{ src: 'plugin/notes/notes.js', async: true } | ||||||
|  |  | ||||||
|  | @ -40,8 +40,8 @@ | ||||||
| 				dependencies: [ | 				dependencies: [ | ||||||
| 					{ src: 'plugin/markdown/marked.js' }, | 					{ src: 'plugin/markdown/marked.js' }, | ||||||
| 					{ src: 'plugin/markdown/markdown.js' }, | 					{ src: 'plugin/markdown/markdown.js' }, | ||||||
| 					{ src: 'plugin/notes/notes.js', async: true }, | 					{ src: 'plugin/highlight/highlight.js' }, | ||||||
| 					{ src: 'plugin/highlight/highlight.js', async: true } | 					{ src: 'plugin/notes/notes.js', async: true } | ||||||
| 				] | 				] | ||||||
| 			}); | 			}); | ||||||
| 		</script> | 		</script> | ||||||
|  |  | ||||||
|  | @ -68,6 +68,11 @@ c:[{cN:"comment",b:/\(\*/,e:/\*\)/},e.ASM,e.QSM,e.CNM,{b:/\{/,e:/\}/,i:/:/}]}}); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	var RevealHighlight = { | 	var RevealHighlight = { | ||||||
|  | 
 | ||||||
|  | 		HIGHLIGHT_STEP_DELIMITER: '|', | ||||||
|  | 		HIGHLIGHT_LINE_DELIMITER: ',', | ||||||
|  | 		HIGHLIGHT_LINE_RANGE_DELIMITER: '-', | ||||||
|  | 
 | ||||||
| 		init: function() { | 		init: function() { | ||||||
| 
 | 
 | ||||||
| 			// Read the plugin config options and provide fallbacks
 | 			// Read the plugin config options and provide fallbacks
 | ||||||
|  | @ -103,6 +108,10 @@ c:[{cN:"comment",b:/\(\*/,e:/\*\)/},e.ASM,e.QSM,e.CNM,{b:/\{/,e:/\}/,i:/:/}]}}); | ||||||
| 		 * Highlights a code block. If the <code> node has the | 		 * Highlights a code block. If the <code> node has the | ||||||
| 		 * 'data-line-numbers' attribute we also generate slide | 		 * 'data-line-numbers' attribute we also generate slide | ||||||
| 		 * numbers. | 		 * numbers. | ||||||
|  | 		 * | ||||||
|  | 		 * If a code block contains multiple line highlight steps | ||||||
|  | 		 * we duplicate the code block once per lines that should | ||||||
|  | 		 * be highlighted. | ||||||
| 		 */ | 		 */ | ||||||
| 		highlightBlock: function( block ) { | 		highlightBlock: function( block ) { | ||||||
| 
 | 
 | ||||||
|  | @ -113,7 +122,45 @@ c:[{cN:"comment",b:/\(\*/,e:/\*\)/},e.ASM,e.QSM,e.CNM,{b:/\{/,e:/\}/,i:/:/}]}}); | ||||||
| 
 | 
 | ||||||
| 				// hljs.lineNumbersBlock runs async code on the next cycle,
 | 				// hljs.lineNumbersBlock runs async code on the next cycle,
 | ||||||
| 				// so we need to do the same to execute after it's done
 | 				// so we need to do the same to execute after it's done
 | ||||||
| 				setTimeout( RevealHighlight.highlightLines.bind( this, block ), 0 ); | 				setTimeout( function() { | ||||||
|  | 
 | ||||||
|  | 					var highlightSteps = RevealHighlight.deserializeHighlightSteps( block.getAttribute( 'data-line-numbers' ) ); | ||||||
|  | 
 | ||||||
|  | 					// If there are at least two highlight steps, generate
 | ||||||
|  | 					// fragment clones for each
 | ||||||
|  | 					if( highlightSteps.length > 1 ) { | ||||||
|  | 
 | ||||||
|  | 						// If the original code block has a fragment-index,
 | ||||||
|  | 						// each clone should increment from that index
 | ||||||
|  | 						var fragmentIndex = parseInt( block.getAttribute( 'data-fragment-index' ), 10 ); | ||||||
|  | 						if( typeof fragmentIndex !== 'number' || isNaN( fragmentIndex ) ) { | ||||||
|  | 							fragmentIndex = null; | ||||||
|  | 						} | ||||||
|  | 
 | ||||||
|  | 						// Generate fragments for all except the first step/original block
 | ||||||
|  | 						highlightSteps.slice(1).forEach( function( highlight ) { | ||||||
|  | 
 | ||||||
|  | 							var fragmentBlock = block.cloneNode( true ); | ||||||
|  | 							fragmentBlock.setAttribute( 'data-line-numbers', RevealHighlight.serializeHighlightSteps( [ highlight ] ) ); | ||||||
|  | 							fragmentBlock.classList.add( 'fragment' ); | ||||||
|  | 							block.parentNode.appendChild( fragmentBlock ); | ||||||
|  | 							RevealHighlight.highlightLines( fragmentBlock ); | ||||||
|  | 
 | ||||||
|  | 							if( fragmentIndex ) { | ||||||
|  | 								fragmentBlock.setAttribute( 'data-fragment-index', fragmentIndex ); | ||||||
|  | 								fragmentIndex += 1; | ||||||
|  | 							} | ||||||
|  | 
 | ||||||
|  | 						} ); | ||||||
|  | 
 | ||||||
|  | 						block.setAttribute( 'data-line-numbers', RevealHighlight.serializeHighlightSteps( [ highlightSteps[0] ] ) ); | ||||||
|  | 
 | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					RevealHighlight.highlightLines( block ); | ||||||
|  | 
 | ||||||
|  | 				}.bind( this ), 0 ); | ||||||
|  | 
 | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 		}, | 		}, | ||||||
|  | @ -131,34 +178,112 @@ c:[{cN:"comment",b:/\(\*/,e:/\*\)/},e.ASM,e.QSM,e.CNM,{b:/\{/,e:/\}/,i:/:/}]}}); | ||||||
| 		 */ | 		 */ | ||||||
| 		highlightLines: function( block, linesToHighlight ) { | 		highlightLines: function( block, linesToHighlight ) { | ||||||
| 
 | 
 | ||||||
| 			linesToHighlight = linesToHighlight || block.getAttribute( 'data-line-numbers' ); | 			var highlightSteps = RevealHighlight.deserializeHighlightSteps( linesToHighlight || block.getAttribute( 'data-line-numbers' ) ); | ||||||
| 
 | 
 | ||||||
| 			if( typeof linesToHighlight === 'string' && linesToHighlight !== '' ) { | 			if( highlightSteps.length ) { | ||||||
| 
 | 
 | ||||||
| 				linesToHighlight.split( ',' ).forEach( function( lineNumbers ) { | 				highlightSteps[0].forEach( function( highlight ) { | ||||||
| 
 | 
 | ||||||
| 					// Avoid failures becase of whitespace
 | 					var elementsToHighlight = []; | ||||||
| 					lineNumbers = lineNumbers.replace( /\s/g, '' ); |  | ||||||
| 
 |  | ||||||
| 					// Ensure that we looking at a valid slide number (1 or 1-2)
 |  | ||||||
| 					if( /^[\d-]+$/.test( lineNumbers ) ) { |  | ||||||
| 
 |  | ||||||
| 						lineNumbers = lineNumbers.split( '-' ); |  | ||||||
| 
 |  | ||||||
| 						var lineStart = lineNumbers[0]; |  | ||||||
| 						var lineEnd = lineNumbers[1] || lineStart; |  | ||||||
| 
 |  | ||||||
| 						[].slice.call( block.querySelectorAll( 'table tr:nth-child(n+'+lineStart+'):nth-child(-n+'+lineEnd+')' ) ).forEach( function( lineElement ) { |  | ||||||
| 							lineElement.classList.add( 'highlight-line' ); |  | ||||||
| 						} ); |  | ||||||
| 
 | 
 | ||||||
|  | 					// Highlight a range
 | ||||||
|  | 					if( typeof highlight.end === 'number' ) { | ||||||
|  | 						elementsToHighlight = [].slice.call( block.querySelectorAll( 'table tr:nth-child(n+'+highlight.start+'):nth-child(-n+'+highlight.end+')' ) ); | ||||||
| 					} | 					} | ||||||
|  | 					// Highlight a single line
 | ||||||
|  | 					else if( typeof highlight.start === 'number' ) { | ||||||
|  | 						elementsToHighlight = [].slice.call( block.querySelectorAll( 'table tr:nth-child('+highlight.start+')' ) ); | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					elementsToHighlight.forEach( function( lineElement ) { | ||||||
|  | 						lineElement.classList.add( 'highlight-line' ); | ||||||
|  | 					} ); | ||||||
| 
 | 
 | ||||||
| 				} ); | 				} ); | ||||||
| 
 | 
 | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
|  | 		}, | ||||||
|  | 
 | ||||||
|  | 		/** | ||||||
|  | 		 * Parses and formats a user-defined string of line | ||||||
|  | 		 * numbers to highlight. | ||||||
|  | 		 * | ||||||
|  | 		 * @example | ||||||
|  | 		 * RevealHighlight.deserializeHighlightSteps( '1,2|3,5-10' ) | ||||||
|  | 		 * // [
 | ||||||
|  | 		 * //   [ { start: 1 }, { start: 2 } ],
 | ||||||
|  | 		 * //   [ { start: 3 }, { start: 5, end: 10 } ]
 | ||||||
|  | 		 * // ]
 | ||||||
|  | 		 */ | ||||||
|  | 		deserializeHighlightSteps: function( highlightSteps ) { | ||||||
|  | 
 | ||||||
|  | 			// Remove whitespace
 | ||||||
|  | 			highlightSteps = highlightSteps.replace( /\s/g, '' ); | ||||||
|  | 
 | ||||||
|  | 			// Divide up our line number groups
 | ||||||
|  | 			highlightSteps = highlightSteps.split( RevealHighlight.HIGHLIGHT_STEP_DELIMITER ); | ||||||
|  | 
 | ||||||
|  | 			return highlightSteps.map( function( highlights ) { | ||||||
|  | 
 | ||||||
|  | 				return highlights.split( RevealHighlight.HIGHLIGHT_LINE_DELIMITER ).map( function( highlight ) { | ||||||
|  | 
 | ||||||
|  | 					// Parse valid line numbers
 | ||||||
|  | 					if( /^[\d-]+$/.test( highlight ) ) { | ||||||
|  | 
 | ||||||
|  | 						highlight = highlight.split( RevealHighlight.HIGHLIGHT_LINE_RANGE_DELIMITER ); | ||||||
|  | 
 | ||||||
|  | 						var lineStart = parseInt( highlight[0], 10 ), | ||||||
|  | 							lineEnd = parseInt( highlight[1], 10 ); | ||||||
|  | 
 | ||||||
|  | 						if( isNaN( lineEnd ) ) { | ||||||
|  | 							return { | ||||||
|  | 								start: lineStart | ||||||
|  | 							}; | ||||||
|  | 						} | ||||||
|  | 						else { | ||||||
|  | 							return { | ||||||
|  | 								start: lineStart, | ||||||
|  | 								end: lineEnd | ||||||
|  | 							}; | ||||||
|  | 						} | ||||||
|  | 
 | ||||||
|  | 					} | ||||||
|  | 					// If no line numbers are provided, no code will be highlighted
 | ||||||
|  | 					else { | ||||||
|  | 
 | ||||||
|  | 						return {}; | ||||||
|  | 
 | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 				} ); | ||||||
|  | 
 | ||||||
|  | 			} ); | ||||||
|  | 
 | ||||||
|  | 		}, | ||||||
|  | 
 | ||||||
|  | 		/** | ||||||
|  | 		 * Serializes parsed line number data into a string so | ||||||
|  | 		 * that we can store it in the DOM. | ||||||
|  | 		 */ | ||||||
|  | 		serializeHighlightSteps: function( highlightSteps ) { | ||||||
|  | 
 | ||||||
|  | 			return highlightSteps.map( function( highlights ) { | ||||||
|  | 				return highlights.map( function( highlight ) { | ||||||
|  | 					if( typeof highlight.end === 'number' ) { | ||||||
|  | 						return highlight.start + RevealHighlight.HIGHLIGHT_LINE_RANGE_DELIMITER + highlight.end; | ||||||
|  | 					} | ||||||
|  | 					else if( typeof highlight.start === 'number' ) { | ||||||
|  | 						return highlight.start; | ||||||
|  | 					} | ||||||
|  | 					else { | ||||||
|  | 						return ''; | ||||||
|  | 					} | ||||||
|  | 				} ).join( RevealHighlight.HIGHLIGHT_LINE_DELIMITER ); | ||||||
|  | 			} ).join( RevealHighlight.HIGHLIGHT_STEP_DELIMITER ); | ||||||
|  | 
 | ||||||
| 		} | 		} | ||||||
|  | 
 | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	Reveal.registerPlugin( 'highlight', RevealHighlight ); | 	Reveal.registerPlugin( 'highlight', RevealHighlight ); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Hakim El Hattab
						Hakim El Hattab