[epiphany] highlight.js: add new plugin highlightjs-line-numbers v2.8.0
- From: Jan-Michael Brummer <jbrummer src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [epiphany] highlight.js: add new plugin highlightjs-line-numbers v2.8.0
- Date: Sun, 14 Jun 2020 16:01:46 +0000 (UTC)
commit 6b8b957033f1c88e7b8fb1181baea454a759433b
Author: Jim Mason <jmason ibinx com>
Date: Mon May 18 18:39:04 2020 +0100
highlight.js: add new plugin highlightjs-line-numbers v2.8.0
embed/ephy-view-source-handler.c | 5 +-
.../highlightjs/LICENSE.highlightjs-line-numbers | 22 ++
third-party/highlightjs/README.epiphany | 9 +
third-party/highlightjs/epiphany.css | 36 ++
.../highlightjs/highlightjs-line-numbers.js | 366 +++++++++++++++++++++
third-party/highlightjs/highlightjs.gresource.xml | 2 +
6 files changed, 439 insertions(+), 1 deletion(-)
---
diff --git a/embed/ephy-view-source-handler.c b/embed/ephy-view-source-handler.c
index 55878e105..52e29519c 100644
--- a/embed/ephy-view-source-handler.c
+++ b/embed/ephy-view-source-handler.c
@@ -126,11 +126,14 @@ web_resource_data_cb (WebKitWebResource *resource,
html = g_strdup_printf ("<head>"
" <link rel='stylesheet'
href='ephy-resource:///org/gnome/epiphany/highlightjs/nnfx.css' media='(prefers-color-scheme: no-preference),
(prefers-color-scheme: light)'>"
" <link rel='stylesheet'
href='ephy-resource:///org/gnome/epiphany/highlightjs/nnfx-dark.css' media='(prefers-color-scheme: dark)'>"
+ " <link rel='stylesheet'
href='ephy-resource:///org/gnome/epiphany/highlightjs/epiphany.css'>"
" <title>%s</title>"
"</head>"
"<body class='hljs'>"
" <script
src='ephy-resource:///org/gnome/epiphany/highlightjs/highlight.js'></script>"
- " <script>hljs.initHighlightingOnLoad();</script>"
+ " <script
src='ephy-resource:///org/gnome/epiphany/highlightjs/highlightjs-line-numbers.js'></script>"
+ " <script>hljs.initHighlightingOnLoad();"
+ " hljs.initLineNumbersOnLoad();</script>"
" <pre><code class='html'>%s</code></pre>"
"</body>",
webkit_web_resource_get_uri (resource),
diff --git a/third-party/highlightjs/LICENSE.highlightjs-line-numbers
b/third-party/highlightjs/LICENSE.highlightjs-line-numbers
new file mode 100644
index 000000000..4f023b7ee
--- /dev/null
+++ b/third-party/highlightjs/LICENSE.highlightjs-line-numbers
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2017 Yauheni Pakala
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/third-party/highlightjs/README.epiphany b/third-party/highlightjs/README.epiphany
index c26df05ec..a86599554 100644
--- a/third-party/highlightjs/README.epiphany
+++ b/third-party/highlightjs/README.epiphany
@@ -14,4 +14,13 @@ Copy build/highlight.js to <epiphany-source>/third-party/highlightjs/
Copy src/styles/nnfx.css to <epiphany-source>third-party/highlightjs/
Copy src/styles/nnfx-dark.css to <epiphany-source>third-party/highlightjs/
+# Highlight.js line numbers plugin:
+
+git clone https://github.com/wcoder/highlightjs-line-numbers.js.git
+cd highlightjs-line-numbers.js
+git checkout <version number>
+
+Copy src/highlightjs-line-numbers.js to <epiphany-source>/third-party/highlightjs/
+Copy LICENSE to <epiphany-source>/third-party/highlightjs/LICENSE.highlightjs-line-numbers
+
# Documentation created by Jan-Michael Brummer <jan brummer tabos org>
diff --git a/third-party/highlightjs/epiphany.css b/third-party/highlightjs/epiphany.css
new file mode 100644
index 000000000..3ef17a9eb
--- /dev/null
+++ b/third-party/highlightjs/epiphany.css
@@ -0,0 +1,36 @@
+/**
+ * Customizations for GNOME Web
+ *
+ * This file provides epiphany-specific customizations to the upstream css.
+ */
+
+.hljs {
+ /*
+ * fix overflow handling
+ *
+ * let the browser window display overflow scrollbars, if any,
+ * instead of placing scrollbars inside the content
+ */
+ overflow-x: visible;
+}
+
+/**
+ * styling for the highlightjs-line-numbers plugin
+ */
+.hljs-ln {
+ white-space: pre;
+}
+
+.hljs-ln .hljs-ln-numbers {
+ -webkit-user-select: none;
+
+ text-align: right;
+ color: #ccc;
+ vertical-align: top;
+ border-right: 1px solid;
+ padding-right: 5px;
+}
+
+.hljs-ln .hljs-ln-code {
+ padding-left: 10px;
+}
diff --git a/third-party/highlightjs/highlightjs-line-numbers.js
b/third-party/highlightjs/highlightjs-line-numbers.js
new file mode 100644
index 000000000..a6c10e814
--- /dev/null
+++ b/third-party/highlightjs/highlightjs-line-numbers.js
@@ -0,0 +1,366 @@
+// jshint multistr:true
+
+(function (w, d) {
+ 'use strict';
+
+ var TABLE_NAME = 'hljs-ln',
+ LINE_NAME = 'hljs-ln-line',
+ CODE_BLOCK_NAME = 'hljs-ln-code',
+ NUMBERS_BLOCK_NAME = 'hljs-ln-numbers',
+ NUMBER_LINE_NAME = 'hljs-ln-n',
+ DATA_ATTR_NAME = 'data-line-number',
+ BREAK_LINE_REGEXP = /\r\n|\r|\n/g;
+
+ if (w.hljs) {
+ w.hljs.initLineNumbersOnLoad = initLineNumbersOnLoad;
+ w.hljs.lineNumbersBlock = lineNumbersBlock;
+ w.hljs.lineNumbersValue = lineNumbersValue;
+
+ addStyles();
+ } else {
+ w.console.error('highlight.js not detected!');
+ }
+
+ function isHljsLnCodeDescendant(domElt) {
+ var curElt = domElt;
+ while (curElt) {
+ if (curElt.className && curElt.className.indexOf('hljs-ln-code') !== -1) {
+ return true;
+ }
+ curElt = curElt.parentNode;
+ }
+ return false;
+ }
+
+ function getHljsLnTable(hljsLnDomElt) {
+ var curElt = hljsLnDomElt;
+ while (curElt.nodeName !== 'TABLE') {
+ curElt = curElt.parentNode;
+ }
+ return curElt;
+ }
+
+ // Function to workaround a copy issue with Microsoft Edge.
+ // Due to hljs-ln wrapping the lines of code inside a <table> element,
+ // itself wrapped inside a <pre> element, window.getSelection().toString()
+ // does not contain any line breaks. So we need to get them back using the
+ // rendered code in the DOM as reference.
+ function edgeGetSelectedCodeLines(selection) {
+ // current selected text without line breaks
+ var selectionText = selection.toString();
+
+ // get the <td> element wrapping the first line of selected code
+ var tdAnchor = selection.anchorNode;
+ while (tdAnchor.nodeName !== 'TD') {
+ tdAnchor = tdAnchor.parentNode;
+ }
+
+ // get the <td> element wrapping the last line of selected code
+ var tdFocus = selection.focusNode;
+ while (tdFocus.nodeName !== 'TD') {
+ tdFocus = tdFocus.parentNode;
+ }
+
+ // extract line numbers
+ var firstLineNumber = parseInt(tdAnchor.dataset.lineNumber);
+ var lastLineNumber = parseInt(tdFocus.dataset.lineNumber);
+
+ // multi-lines copied case
+ if (firstLineNumber != lastLineNumber) {
+
+ var firstLineText = tdAnchor.textContent;
+ var lastLineText = tdFocus.textContent;
+
+ // if the selection was made backward, swap values
+ if (firstLineNumber > lastLineNumber) {
+ var tmp = firstLineNumber;
+ firstLineNumber = lastLineNumber;
+ lastLineNumber = tmp;
+ tmp = firstLineText;
+ firstLineText = lastLineText;
+ lastLineText = tmp;
+ }
+
+ // discard not copied characters in first line
+ while (selectionText.indexOf(firstLineText) !== 0) {
+ firstLineText = firstLineText.slice(1);
+ }
+
+ // discard not copied characters in last line
+ while (selectionText.lastIndexOf(lastLineText) === -1) {
+ lastLineText = lastLineText.slice(0, -1);
+ }
+
+ // reconstruct and return the real copied text
+ var selectedText = firstLineText;
+ var hljsLnTable = getHljsLnTable(tdAnchor);
+ for (var i = firstLineNumber + 1 ; i < lastLineNumber ; ++i) {
+ var codeLineSel = format('.{0}[{1}="{2}"]', [CODE_BLOCK_NAME, DATA_ATTR_NAME, i]);
+ var codeLineElt = hljsLnTable.querySelector(codeLineSel);
+ selectedText += '\n' + codeLineElt.textContent;
+ }
+ selectedText += '\n' + lastLineText;
+ return selectedText;
+ // single copied line case
+ } else {
+ return selectionText;
+ }
+ }
+
+ // ensure consistent code copy/paste behavior across all browsers
+ // (see https://github.com/wcoder/highlightjs-line-numbers.js/issues/51)
+ document.addEventListener('copy', function(e) {
+ // get current selection
+ var selection = window.getSelection();
+ // override behavior when one wants to copy line of codes
+ if (isHljsLnCodeDescendant(selection.anchorNode)) {
+ var selectionText;
+ // workaround an issue with Microsoft Edge as copied line breaks
+ // are removed otherwise from the selection string
+ if (window.navigator.userAgent.indexOf('Edge') !== -1) {
+ selectionText = edgeGetSelectedCodeLines(selection);
+ } else {
+ // other browsers can directly use the selection string
+ selectionText = selection.toString();
+ }
+ e.clipboardData.setData('text/plain', selectionText);
+ e.preventDefault();
+ }
+ });
+
+ function addStyles () {
+ var css = d.createElement('style');
+ css.type = 'text/css';
+ css.innerHTML = format(
+ '.{0}{border-collapse:collapse}' +
+ '.{0} td{padding:0}' +
+ '.{1}:before{content:attr({2})}',
+ [
+ TABLE_NAME,
+ NUMBER_LINE_NAME,
+ DATA_ATTR_NAME
+ ]);
+ d.getElementsByTagName('head')[0].appendChild(css);
+ }
+
+ function initLineNumbersOnLoad (options) {
+ if (d.readyState === 'interactive' || d.readyState === 'complete') {
+ documentReady(options);
+ } else {
+ w.addEventListener('DOMContentLoaded', function () {
+ documentReady(options);
+ });
+ }
+ }
+
+ function documentReady (options) {
+ try {
+ var blocks = d.querySelectorAll('code.hljs,code.nohighlight');
+
+ for (var i in blocks) {
+ if (blocks.hasOwnProperty(i)) {
+ if (!isPluginDisabledForBlock(blocks[i])) {
+ lineNumbersBlock(blocks[i], options);
+ }
+ }
+ }
+ } catch (e) {
+ w.console.error('LineNumbers error: ', e);
+ }
+ }
+
+ function isPluginDisabledForBlock(element) {
+ return element.classList.contains('nohljsln');
+ }
+
+ function lineNumbersBlock (element, options) {
+ if (typeof element !== 'object') return;
+
+ async(function () {
+ element.innerHTML = lineNumbersInternal(element, options);
+ });
+ }
+
+ function lineNumbersValue (value, options) {
+ if (typeof value !== 'string') return;
+
+ var element = document.createElement('code')
+ element.innerHTML = value
+
+ return lineNumbersInternal(element, options);
+ }
+
+ function lineNumbersInternal (element, options) {
+
+ var internalOptions = mapOptions(element, options);
+
+ duplicateMultilineNodes(element);
+
+ return addLineNumbersBlockFor(element.innerHTML, internalOptions);
+ }
+
+ function addLineNumbersBlockFor (inputHtml, options) {
+ var lines = getLines(inputHtml);
+
+ // if last line contains only carriage return remove it
+ if (lines[lines.length-1].trim() === '') {
+ lines.pop();
+ }
+
+ if (lines.length > 1 || options.singleLine) {
+ var html = '';
+
+ for (var i = 0, l = lines.length; i < l; i++) {
+ html += format(
+ '<tr>' +
+ '<td class="{0} {1}" {3}="{5}">' +
+ '<div class="{2}" {3}="{5}"></div>' +
+ '</td>' +
+ '<td class="{0} {4}" {3}="{5}">' +
+ '{6}' +
+ '</td>' +
+ '</tr>',
+ [
+ LINE_NAME,
+ NUMBERS_BLOCK_NAME,
+ NUMBER_LINE_NAME,
+ DATA_ATTR_NAME,
+ CODE_BLOCK_NAME,
+ i + options.startFrom,
+ lines[i].length > 0 ? lines[i] : ' '
+ ]);
+ }
+
+ return format('<table class="{0}">{1}</table>', [ TABLE_NAME, html ]);
+ }
+
+ return inputHtml;
+ }
+
+ /**
+ * @param {HTMLElement} element Code block.
+ * @param {Object} options External API options.
+ * @returns {Object} Internal API options.
+ */
+ function mapOptions (element, options) {
+ options = options || {};
+ return {
+ singleLine: getSingleLineOption(options),
+ startFrom: getStartFromOption(element, options)
+ };
+ }
+
+ function getSingleLineOption (options) {
+ var defaultValue = false;
+ if (!!options.singleLine) {
+ return options.singleLine;
+ }
+ return defaultValue;
+ }
+
+ function getStartFromOption (element, options) {
+ var defaultValue = 1;
+ var startFrom = defaultValue;
+
+ if (isFinite(options.startFrom)) {
+ startFrom = options.startFrom;
+ }
+
+ // can be overridden because local option is priority
+ var value = getAttribute(element, 'data-ln-start-from');
+ if (value !== null) {
+ startFrom = toNumber(value, defaultValue);
+ }
+
+ return startFrom;
+ }
+
+ /**
+ * Recursive method for fix multi-line elements implementation in highlight.js
+ * Doing deep passage on child nodes.
+ * @param {HTMLElement} element
+ */
+ function duplicateMultilineNodes (element) {
+ var nodes = element.childNodes;
+ for (var node in nodes) {
+ if (nodes.hasOwnProperty(node)) {
+ var child = nodes[node];
+ if (getLinesCount(child.textContent) > 0) {
+ if (child.childNodes.length > 0) {
+ duplicateMultilineNodes(child);
+ } else {
+ duplicateMultilineNode(child.parentNode);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Method for fix multi-line elements implementation in highlight.js
+ * @param {HTMLElement} element
+ */
+ function duplicateMultilineNode (element) {
+ var className = element.className;
+
+ if ( ! /hljs-/.test(className)) return;
+
+ var lines = getLines(element.innerHTML);
+
+ for (var i = 0, result = ''; i < lines.length; i++) {
+ var lineText = lines[i].length > 0 ? lines[i] : ' ';
+ result += format('<span class="{0}">{1}</span>\n', [ className, lineText ]);
+ }
+
+ element.innerHTML = result.trim();
+ }
+
+ function getLines (text) {
+ if (text.length === 0) return [];
+ return text.split(BREAK_LINE_REGEXP);
+ }
+
+ function getLinesCount (text) {
+ return (text.trim().match(BREAK_LINE_REGEXP) || []).length;
+ }
+
+ ///
+ /// HELPERS
+ ///
+
+ function async (func) {
+ w.setTimeout(func, 0);
+ }
+
+ /**
+ * {@link https://wcoder.github.io/notes/string-format-for-string-formating-in-javascript}
+ * @param {string} format
+ * @param {array} args
+ */
+ function format (format, args) {
+ return format.replace(/\{(\d+)\}/g, function(m, n){
+ return args[n] !== undefined ? args[n] : m;
+ });
+ }
+
+ /**
+ * @param {HTMLElement} element Code block.
+ * @param {String} attrName Attribute name.
+ * @returns {String} Attribute value or empty.
+ */
+ function getAttribute (element, attrName) {
+ return element.hasAttribute(attrName) ? element.getAttribute(attrName) : null;
+ }
+
+ /**
+ * @param {String} str Source string.
+ * @param {Number} fallback Fallback value.
+ * @returns Parsed number or fallback value.
+ */
+ function toNumber (str, fallback) {
+ if (!str) return fallback;
+ var number = Number(str);
+ return isFinite(number) ? number : fallback;
+ }
+
+}(window, document));
diff --git a/third-party/highlightjs/highlightjs.gresource.xml
b/third-party/highlightjs/highlightjs.gresource.xml
index 3d1ea96ee..db1415675 100644
--- a/third-party/highlightjs/highlightjs.gresource.xml
+++ b/third-party/highlightjs/highlightjs.gresource.xml
@@ -2,6 +2,8 @@
<gresources>
<gresource prefix="/org/gnome/epiphany/highlightjs">
<file compressed="true">highlight.js</file>
+ <file compressed="true">highlightjs-line-numbers.js</file>
+ <file compressed="true">epiphany.css</file>
<file compressed="true">nnfx.css</file>
<file compressed="true">nnfx-dark.css</file>
</gresource>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]