diff --git a/app/com/gitpitch/views/frags/SlideshowCodeFragHighlightStyle.scala.html b/app/com/gitpitch/views/frags/SlideshowCodeFragHighlightStyle.scala.html
index 7a13d22..e31821a 100644
--- a/app/com/gitpitch/views/frags/SlideshowCodeFragHighlightStyle.scala.html
+++ b/app/com/gitpitch/views/frags/SlideshowCodeFragHighlightStyle.scala.html
@@ -1,23 +1,15 @@
\ No newline at end of file
+ }
+ .line {
+ display: block;
+ }
+ .line.focus {
+ /* opacity: 1.0; */
+ }
+
diff --git a/app/com/gitpitch/views/frags/SlideshowReveal.scala.html b/app/com/gitpitch/views/frags/SlideshowReveal.scala.html
index d11196c..029d289 100644
--- a/app/com/gitpitch/views/frags/SlideshowReveal.scala.html
+++ b/app/com/gitpitch/views/frags/SlideshowReveal.scala.html
@@ -38,7 +38,7 @@
{ src: "@deps.revealjs(offline, ssm.fetchRevealVersionOverride())/plugin/highlight/highlight.js", async: true, callback: function() { hljs.initHighlightingOnLoad(); } },
} else {
{ src: '@deps.highlightjs(offline)/highlight.js' },
- { src: '@deps.highlightjs(offline)/reveal-code-focus.js',
+ { src: '@deps.highlightjs(offline)/reveal-code-focus-1.0.0-mod.js',
callback: function() {
RevealCodeFocus();
}
diff --git a/public/libs/highlight.js/9.6.0/reveal-code-focus-1.0.0-mod.js b/public/libs/highlight.js/9.6.0/reveal-code-focus-1.0.0-mod.js
new file mode 100644
index 0000000..44fbd8f
--- /dev/null
+++ b/public/libs/highlight.js/9.6.0/reveal-code-focus-1.0.0-mod.js
@@ -0,0 +1,270 @@
+/*!
+ * reveal-code-focus 1.0.0
+ * Copyright 2015-2017 Benjamin Tan
+ * Available under MIT license
+ *
+ * Modified by @gitpitch with support for updateCodeOpacity() and
+ * resetCodeOpacity() respectively.
+ */
+;(function(window, Reveal, hljs) {
+ if (typeof window.RevealCodeFocus == 'function') {
+ return;
+ }
+
+ var currentSlide, currentFragments, scrollToFocused = true, prevSlideData = null;
+
+ // Iterates through `array`, running `callback` for each `array` element.
+ function forEach(array, callback) {
+ var i = -1, length = array ? array.length : 0;
+ while (++i < length) {
+ callback(array[i]);
+ }
+ }
+
+ function indexOf(array, elem) {
+ var i = -1, length = array ? array.length : 0;
+ while (++i < length) {
+ if (array[i] === elem) {
+ return i;
+ }
+ }
+ }
+
+ function initialize(e) {
+ // Initialize code only once.
+ // TODO: figure out why `initialize` is being called twice.
+ if (initialize.ran) {
+ return;
+ }
+ initialize.ran = true;
+
+ // TODO: mark as parsed.
+ forEach(document.querySelectorAll('pre code'), function(element) {
+ // Trim whitespace if the `data-trim` attribute is present.
+ if (element.hasAttribute('data-trim') && typeof element.innerHTML.trim == 'function') {
+ element.innerHTML = element.innerHTML.trim();
+ }
+
+ // Highlight code using highlight.js.
+ hljs.highlightBlock(element);
+
+ // Split highlighted code into lines.
+ var openTags = [], reHtmlTag = /<(\/?)span(?:\s+(?:class=(['"])hljs-.*?\2)?\s*|\s*)>/g;
+ element.innerHTML = element.innerHTML.replace(/(.*?)\r?\n/g, function(_, string) {
+ if (!string) {
+ return ' ';
+ }
+ var openTag, stringPrepend;
+ // Re-open all tags that were previously closed.
+ if (openTags.length) {
+ stringPrepend = openTags.join('');
+ }
+ // Match all HTML `` tags.
+ reHtmlTag.lastIndex = 0;
+ while (openTag = reHtmlTag.exec(string)) {
+ // If it is a closing tag, remove the opening tag from the list.
+ if (openTag[1]) {
+ openTags.pop();
+ }
+ // Otherwise if it is an opening tag, push it to the list.
+ else {
+ openTags.push(openTag[0]);
+ }
+ }
+ // Close all opened tags, so that strings can be wrapped with `span.line`.
+ if (openTags.length) {
+ string += Array(openTags.length + 1).join('');
+ }
+ if (stringPrepend) {
+ string = stringPrepend + string;
+ }
+ return '' + string + '';
+ });
+ });
+
+ Reveal.addEventListener('slidechanged', updateCurrentSlide);
+
+ Reveal.addEventListener('fragmentshown', function(e) {
+ focusFragment(e.fragment);
+ });
+
+ // TODO: make this configurable.
+ // When a fragment is hidden, clear the current focused fragment,
+ // and focus on the previous fragment.
+ Reveal.addEventListener('fragmenthidden', function(e) {
+ var index = indexOf(currentFragments, e.fragment);
+ focusFragment(currentFragments[index - 1]);
+ });
+
+ updateCurrentSlide(e);
+ }
+ initialize.ran = false;
+
+ function updateCurrentSlide(e) {
+ currentSlide = e.currentSlide;
+ currentFragments = currentSlide.getElementsByClassName('fragment');
+ clearPreviousFocus();
+
+ // If moving back to a previous slide…
+ if (
+ currentFragments.length &&
+ prevSlideData &&
+ (
+ prevSlideData.indexh > e.indexh ||
+ (prevSlideData.indexh == e.indexh && prevSlideData.indexv > e.indexv)
+ )
+ ) {
+ // …return to the last fragment and highlight the code.
+ while (Reveal.nextFragment()) {}
+ var currentFragment = currentFragments[currentFragments.length - 1];
+ currentFragment.classList.add('current-fragment');
+ focusFragment(currentFragment);
+ }
+
+ // Update previous slide information.
+ prevSlideData = {
+ 'indexh': e.indexh,
+ 'indexv': e.indexv
+ };
+
+ }
+
+ // Removes any previously focused lines.
+ function clearPreviousFocus() {
+ forEach(currentSlide.querySelectorAll('pre code .line.focus'), function(line) {
+ line.classList.remove('focus');
+ });
+ }
+
+ function updateCodeOpacity() {
+
+ linesOfCode = currentSlide.querySelectorAll('pre code .line')
+ linesInFocus = currentSlide.querySelectorAll('pre code .line.focus')
+
+ if(linesInFocus.length == 0) {
+ // No linesInFocus, make all lines full opacity.
+ forEach(linesOfCode, function(line) {
+ line.style.opacity = 1.0;
+ });
+ } else {
+ // Some linesInFocus, reduce opacity on all linesNotInFocus.
+ forEach(linesOfCode, function(line) {
+ if(line.classList.contains('focus')) {
+ line.style.opacity = 1.0;
+ } else {
+ line.style.opacity = 0.20;
+ }
+ });
+ }
+
+ }
+
+ function resetCodeOpacity() {
+
+ linesOfCode = currentSlide.querySelectorAll('pre code .line')
+
+ forEach(linesOfCode, function(line) {
+ line.style.opacity = 1.0;
+ });
+
+ }
+
+ function focusFragment(fragment) {
+ clearPreviousFocus();
+ if (!fragment) {
+ resetCodeOpacity();
+ return;
+ }
+
+ var lines = fragment.getAttribute('data-code-focus');
+ if (!lines) {
+ return;
+ }
+
+ var codeBlock = parseInt(fragment.getAttribute('data-code-block'));
+ if (isNaN(codeBlock)) {
+ codeBlock = 1;
+ }
+
+ var preElems = currentSlide.querySelectorAll('pre');
+ if (!preElems.length) {
+ return;
+ }
+
+ var pre = preElems[codeBlock - 1];
+ var code = pre.querySelectorAll('code .line');
+ if (!code.length) {
+ return;
+ }
+
+ var topLineNumber, bottomLineNumber;
+
+ forEach(lines.split(','), function(line) {
+ lines = line.split('-');
+ if (lines.length == 1) {
+ focusLine(lines[0]);
+ } else {
+ var i = lines[0] - 1, j = lines[1];
+
+ while (++i <= j) {
+ focusLine(i);
+ }
+ }
+ });
+
+ updateCodeOpacity();
+
+ function focusLine(lineNumber) {
+ // Convert from 1-based index to 0-based index.
+ lineNumber -= 1;
+
+ var line = code[lineNumber];
+ if (!line) {
+ return;
+ }
+
+ line.classList.add('focus');
+
+ if (scrollToFocused) {
+ if (topLineNumber == null) {
+ topLineNumber = bottomLineNumber = lineNumber;
+ } else {
+ if (lineNumber < topLineNumber) {
+ topLineNumber = lineNumber;
+ }
+ if (lineNumber > bottomLineNumber) {
+ bottomLineNumber = lineNumber;
+ }
+ }
+ }
+ }
+
+ if (scrollToFocused && topLineNumber != null) {
+ var topLine = code[topLineNumber];
+ var bottomLine = code[bottomLineNumber];
+ var codeParent = topLine.parentNode;
+ var scrollTop = topLine.offsetTop;
+ var scrollBottom = bottomLine.offsetTop + bottomLine.clientHeight;
+ codeParent.scrollTop = scrollTop - (codeParent.clientHeight - (scrollBottom - scrollTop)) / 2;
+ }
+
+ }
+
+ function RevealCodeFocus(options) {
+ options || (options = {
+ 'scrollToFocused': true
+ });
+
+ if (options.scrollToFocused != null) {
+ scrollToFocused = options.scrollToFocused;
+ }
+
+ if (Reveal.isReady()) {
+ initialize({ 'currentSlide': Reveal.getCurrentSlide() });
+ } else {
+ Reveal.addEventListener('ready', initialize);
+ }
+ }
+
+ window.RevealCodeFocus = RevealCodeFocus;
+}(this, this.Reveal, this.hljs));