From 5c294d4cabc5a279048341614729997103c36514 Mon Sep 17 00:00:00 2001 From: RunDevelopment Date: Sat, 29 Feb 2020 16:10:16 +0100 Subject: [PATCH 1/3] Fixed line highlight top offset --- plugins/line-highlight/index.html | 9 +++ .../line-highlight/prism-line-highlight.js | 59 +++++++++++++++---- .../prism-line-highlight.min.js | 2 +- 3 files changed, 58 insertions(+), 12 deletions(-) diff --git a/plugins/line-highlight/index.html b/plugins/line-highlight/index.html index 5c37fb7eb4..b18acf1a8e 100644 --- a/plugins/line-highlight/index.html +++ b/plugins/line-highlight/index.html @@ -9,6 +9,7 @@ + @@ -69,12 +70,20 @@

Line 43, starting from line 41


 
 	

Linking example

+ +

Compatible with Line numbers

+

+
+	

Even with some extra content before the code element.

+
Some content

+ + diff --git a/plugins/line-highlight/prism-line-highlight.js b/plugins/line-highlight/prism-line-highlight.js index bebbcbf1cf..5918dd99d6 100644 --- a/plugins/line-highlight/prism-line-highlight.js +++ b/plugins/line-highlight/prism-line-highlight.js @@ -26,8 +26,8 @@ var d = document.createElement('div'); d.style.fontSize = '13px'; d.style.lineHeight = '1.5'; - d.style.padding = 0; - d.style.border = 0; + d.style.padding = '0'; + d.style.border = '0'; d.innerHTML = ' 
 '; document.body.appendChild(d); // Browsers that round the line-height should have offsetHeight === 38 @@ -39,6 +39,29 @@ } }()); + /** + * Returns the top offset of the content box of the given parent and the content box of one of its children. + * + * @param {HTMLElement} parent + * @param {HTMLElement} child + */ + function getContentBoxTopOffset(parent, child) { + var parentStyle = getComputedStyle(parent); + var childStyle = getComputedStyle(child); + + /** + * Returns the numeric value of the given pixel value. + * + * @param {string} px + */ + function pxToNumber(px) { + return +px.substr(0, px.length - 2); + } + + return child.offsetTop + pxToNumber(childStyle.borderTopWidth) + pxToNumber(childStyle.paddingTop) + - pxToNumber(parentStyle.paddingTop); + } + /** * Highlights the lines of the given pre. * @@ -46,7 +69,7 @@ * The returned function mutates the DOM when called. * * @param {HTMLElement} pre - * @param {string} [lines] + * @param {string | null} [lines] * @param {string} [classes=''] * @returns {() => void} */ @@ -54,20 +77,34 @@ lines = typeof lines === 'string' ? lines : pre.getAttribute('data-line'); var ranges = lines.replace(/\s+/g, '').split(','); - var offset = +pre.getAttribute('data-line-offset') || 0; + var offset = Number(pre.getAttribute('data-line-offset')); var parseMethod = isLineHeightRounded() ? parseInt : parseFloat; var lineHeight = parseMethod(getComputedStyle(pre).lineHeight); var hasLineNumbers = hasClass(pre, 'line-numbers'); - var parentElement = hasLineNumbers ? pre : pre.querySelector('code') || pre; + var codeElement = pre.querySelector('code'); + var parentElement = hasLineNumbers ? pre : codeElement || pre; var mutateActions = /** @type {(() => void)[]} */ ([]); + /** + * The top offset between the content box of the element and the content box of the parent element of + * the line highlight element (either `
` or ``).
+		 *
+		 * This offset might not be zero for some themes where the  element has a top margin. Some plugins
+		 * (or users) might also add element above the  element. Because the line highlight is aligned relative
+		 * to the 
 element, we have to take this into account.
+		 *
+		 * This offset will be 0 if the parent element of the line highlight element is the `` element.
+		 */
+		var codePreOffset = !codeElement || parentElement == codeElement ? 0 : getContentBoxTopOffset(pre, codeElement);
+
 		ranges.forEach(function (currentRange) {
 			var range = currentRange.split('-');
 
 			var start = +range[0];
 			var end = +range[1] || start;
 
+			/** @type {HTMLElement} */
 			var line = pre.querySelector('.line-highlight[data-range="' + currentRange + '"]') || document.createElement('div');
 
 			mutateActions.push(function () {
@@ -82,7 +119,7 @@
 				var endNode = Prism.plugins.lineNumbers.getLine(pre, end);
 
 				if (startNode) {
-					var top = startNode.offsetTop + 'px';
+					var top = startNode.offsetTop + codePreOffset + 'px';
 					mutateActions.push(function () {
 						line.style.top = top;
 					});
@@ -96,13 +133,13 @@
 				}
 			} else {
 				mutateActions.push(function () {
-					line.setAttribute('data-start', start);
+					line.setAttribute('data-start', String(start));
 
 					if (end > start) {
-						line.setAttribute('data-end', end);
+						line.setAttribute('data-end', String(end));
 					}
 
-					line.style.top = (start - offset - 1) * lineHeight + 'px';
+					line.style.top = (start - offset - 1) * lineHeight + codePreOffset + 'px';
 
 					line.textContent = new Array(end - start + 2).join(' \n');
 				});
@@ -154,7 +191,7 @@
 	var fakeTimer = 0; // Hack to limit the number of times applyHash() runs
 
 	Prism.hooks.add('before-sanity-check', function (env) {
-		var pre = env.element.parentNode;
+		var pre = env.element.parentElement;
 		var lines = pre && pre.getAttribute('data-line');
 
 		if (!pre || !lines || !/pre/i.test(pre.nodeName)) {
@@ -180,7 +217,7 @@
 	});
 
 	Prism.hooks.add('complete', function completeHook(env) {
-		var pre = env.element.parentNode;
+		var pre = env.element.parentElement;
 		var lines = pre && pre.getAttribute('data-line');
 
 		if (!pre || !lines || !/pre/i.test(pre.nodeName)) {
diff --git a/plugins/line-highlight/prism-line-highlight.min.js b/plugins/line-highlight/prism-line-highlight.min.js
index adfe7f3738..da9042e0f8 100644
--- a/plugins/line-highlight/prism-line-highlight.min.js
+++ b/plugins/line-highlight/prism-line-highlight.min.js
@@ -1 +1 @@
-!function(){if("undefined"!=typeof self&&self.Prism&&self.document&&document.querySelector){var t,n=function(){if(void 0===t){var e=document.createElement("div");e.style.fontSize="13px",e.style.lineHeight="1.5",e.style.padding=0,e.style.border=0,e.innerHTML=" 
 ",document.body.appendChild(e),t=38===e.offsetHeight,document.body.removeChild(e)}return t},a=0;Prism.hooks.add("before-sanity-check",function(e){var t=e.element.parentNode,n=t&&t.getAttribute("data-line");if(t&&n&&/pre/i.test(t.nodeName)){var i=0;r(".line-highlight",t).forEach(function(e){i+=e.textContent.length,e.parentNode.removeChild(e)}),i&&/^( \n)+$/.test(e.code.slice(-i))&&(e.code=e.code.slice(0,-i))}}),Prism.hooks.add("complete",function e(t){var n=t.element.parentNode,i=n&&n.getAttribute("data-line");if(n&&i&&/pre/i.test(n.nodeName)){clearTimeout(a);var r=Prism.plugins.lineNumbers,o=t.plugins&&t.plugins.lineNumbers;if(l(n,"line-numbers")&&r&&!o)Prism.hooks.add("line-numbers",e);else s(n,i)(),a=setTimeout(u,1)}}),window.addEventListener("hashchange",u),window.addEventListener("resize",function(){var t=[];r("pre[data-line]").forEach(function(e){t.push(s(e))}),t.forEach(i)})}function r(e,t){return Array.prototype.slice.call((t||document).querySelectorAll(e))}function l(e,t){return t=" "+t+" ",-1<(" "+e.className+" ").replace(/[\n\t]/g," ").indexOf(t)}function i(e){e()}function s(u,e,d){var t=(e="string"==typeof e?e:u.getAttribute("data-line")).replace(/\s+/g,"").split(","),c=+u.getAttribute("data-line-offset")||0,f=(n()?parseInt:parseFloat)(getComputedStyle(u).lineHeight),h=l(u,"line-numbers"),p=h?u:u.querySelector("code")||u,m=[];return t.forEach(function(e){var t=e.split("-"),n=+t[0],i=+t[1]||n,r=u.querySelector('.line-highlight[data-range="'+e+'"]')||document.createElement("div");if(m.push(function(){r.setAttribute("aria-hidden","true"),r.setAttribute("data-range",e),r.className=(d||"")+" line-highlight"}),h&&Prism.plugins.lineNumbers){var o=Prism.plugins.lineNumbers.getLine(u,n),a=Prism.plugins.lineNumbers.getLine(u,i);if(o){var l=o.offsetTop+"px";m.push(function(){r.style.top=l})}if(a){var s=a.offsetTop-o.offsetTop+a.offsetHeight+"px";m.push(function(){r.style.height=s})}}else m.push(function(){r.setAttribute("data-start",n),n ",document.body.appendChild(e),t=38===e.offsetHeight,document.body.removeChild(e)}return t},a=0;Prism.hooks.add("before-sanity-check",function(e){var t=e.element.parentElement,n=t&&t.getAttribute("data-line");if(t&&n&&/pre/i.test(t.nodeName)){var i=0;r(".line-highlight",t).forEach(function(e){i+=e.textContent.length,e.parentNode.removeChild(e)}),i&&/^( \n)+$/.test(e.code.slice(-i))&&(e.code=e.code.slice(0,-i))}}),Prism.hooks.add("complete",function e(t){var n=t.element.parentElement,i=n&&n.getAttribute("data-line");if(n&&i&&/pre/i.test(n.nodeName)){clearTimeout(a);var r=Prism.plugins.lineNumbers,o=t.plugins&&t.plugins.lineNumbers;if(l(n,"line-numbers")&&r&&!o)Prism.hooks.add("line-numbers",e);else s(n,i)(),a=setTimeout(u,1)}}),window.addEventListener("hashchange",u),window.addEventListener("resize",function(){var t=[];r("pre[data-line]").forEach(function(e){t.push(s(e))}),t.forEach(o)})}function r(e,t){return Array.prototype.slice.call((t||document).querySelectorAll(e))}function l(e,t){return t=" "+t+" ",-1<(" "+e.className+" ").replace(/[\n\t]/g," ").indexOf(t)}function o(e){e()}function s(u,e,d){var t=(e="string"==typeof e?e:u.getAttribute("data-line")).replace(/\s+/g,"").split(","),c=Number(u.getAttribute("data-line-offset")),f=(i()?parseInt:parseFloat)(getComputedStyle(u).lineHeight),p=l(u,"line-numbers"),n=u.querySelector("code"),h=p?u:n||u,m=[],g=n&&h!=n?function(e,t){var n=getComputedStyle(e),i=getComputedStyle(t);function r(e){return+e.substr(0,e.length-2)}return t.offsetTop+r(i.borderTopWidth)+r(i.paddingTop)-r(n.paddingTop)}(u,n):0;return t.forEach(function(e){var t=e.split("-"),n=+t[0],i=+t[1]||n,r=u.querySelector('.line-highlight[data-range="'+e+'"]')||document.createElement("div");if(m.push(function(){r.setAttribute("aria-hidden","true"),r.setAttribute("data-range",e),r.className=(d||"")+" line-highlight"}),p&&Prism.plugins.lineNumbers){var o=Prism.plugins.lineNumbers.getLine(u,n),a=Prism.plugins.lineNumbers.getLine(u,i);if(o){var l=o.offsetTop+g+"px";m.push(function(){r.style.top=l})}if(a){var s=a.offsetTop-o.offsetTop+a.offsetHeight+"px";m.push(function(){r.style.height=s})}}else m.push(function(){r.setAttribute("data-start",String(n)),n Date: Wed, 23 Dec 2020 14:48:43 +0100 Subject: [PATCH 2/3] Addressed nit --- plugins/line-highlight/prism-line-highlight.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/line-highlight/prism-line-highlight.js b/plugins/line-highlight/prism-line-highlight.js index c585949cee..7cd9006ff9 100644 --- a/plugins/line-highlight/prism-line-highlight.js +++ b/plugins/line-highlight/prism-line-highlight.js @@ -76,7 +76,9 @@ return +px.substr(0, px.length - 2); } - return child.offsetTop + pxToNumber(childStyle.borderTopWidth) + pxToNumber(childStyle.paddingTop) + return child.offsetTop + + pxToNumber(childStyle.borderTopWidth) + + pxToNumber(childStyle.paddingTop) - pxToNumber(parentStyle.paddingTop); } From f381d40544f702e9acf2683da02921fa88abf339 Mon Sep 17 00:00:00 2001 From: RunDevelopment Date: Wed, 23 Dec 2020 14:53:23 +0100 Subject: [PATCH 3/3] Minor adjustment to webpage --- plugins/line-highlight/index.html | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/plugins/line-highlight/index.html b/plugins/line-highlight/index.html index fa22f83e28..099e505d9d 100644 --- a/plugins/line-highlight/index.html +++ b/plugins/line-highlight/index.html @@ -74,17 +74,15 @@

Line 43, starting from line 41

Linking example

Compatible with Line numbers

-

+	

 
-	

With line numbers

-

+	

Even with some extra content before the code element.

+
Some content

+

With linkable line numbers


 
-	

Even with some extra content before the code element.

-
Some content

-