From b631949acd54f01330dc5be313ff0e632047e901 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Wed, 3 Nov 2021 12:19:36 +0100 Subject: [PATCH] Core: Added `setLanguage` util function (#3167) --- components/prism-core.js | 32 +++++++++--- components/prism-core.min.js | 2 +- docs/Prism.hooks.html | 6 +-- docs/Prism.html | 10 ++-- docs/Prism.languages.html | 6 +-- docs/Token.html | 8 +-- docs/global.html | 10 ++-- docs/prism-core.js.html | 32 +++++++++--- .../file-highlight/prism-file-highlight.js | 19 +------ .../prism-file-highlight.min.js | 2 +- prism.js | 51 ++++++++++--------- 11 files changed, 101 insertions(+), 77 deletions(-) diff --git a/components/prism-core.js b/components/prism-core.js index bb68e597df..d69fd99105 100644 --- a/components/prism-core.js +++ b/components/prism-core.js @@ -19,7 +19,7 @@ var _self = (typeof window !== 'undefined') var Prism = (function (_self) { // Private helper vars - var lang = /\blang(?:uage)?-([\w-]+)\b/i; + var lang = /(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i; var uniqueId = 0; // The grammar object for plaintext @@ -184,15 +184,33 @@ var Prism = (function (_self) { * @returns {string} */ getLanguage: function (element) { - while (element && !lang.test(element.className)) { + while (element) { + var m = lang.exec(element.className); + if (m) { + return m[1].toLowerCase(); + } element = element.parentElement; } - if (element) { - return (element.className.match(lang) || [, 'none'])[1].toLowerCase(); - } return 'none'; }, + /** + * Sets the Prism `language-xxxx` class of the given element. + * + * @param {Element} element + * @param {string} language + * @returns {void} + */ + setLanguage: function (element, language) { + // remove all `language-xxxx` classes + // (this might leave behind a leading space) + element.className = element.className.replace(RegExp(lang, 'gi'), ''); + + // add the new `language-xxxx` class + // (using `classList` will automatically clean up spaces for us) + element.classList.add('language-' + language); + }, + /** * Returns the script element that is currently executing. * @@ -547,12 +565,12 @@ var Prism = (function (_self) { var grammar = _.languages[language]; // Set language on the element, if not present - element.className = element.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language; + _.util.setLanguage(element, language); // Set language on the parent, for styling var parent = element.parentElement; if (parent && parent.nodeName.toLowerCase() === 'pre') { - parent.className = parent.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language; + _.util.setLanguage(parent, language); } var code = element.textContent; diff --git a/components/prism-core.min.js b/components/prism-core.min.js index 13c0f35928..6aa6722ed1 100644 --- a/components/prism-core.min.js +++ b/components/prism-core.min.js @@ -1 +1 @@ -var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(u){var c=/\blang(?:uage)?-([\w-]+)\b/i,n=0,e={},M={manual:u.Prism&&u.Prism.manual,disableWorkerMessageHandler:u.Prism&&u.Prism.disableWorkerMessageHandler,util:{encode:function e(n){return n instanceof W?new W(n.type,e(n.content),n.alias):Array.isArray(n)?n.map(e):n.replace(/&/g,"&").replace(/=l.reach);y+=m.value.length,m=m.next){var b=m.value;if(t.length>n.length)return;if(!(b instanceof W)){var k,x=1;if(h){if(!(k=z(v,y,n,f))||k.index>=n.length)break;var w=k.index,A=k.index+k[0].length,P=y;for(P+=m.value.length;P<=w;)m=m.next,P+=m.value.length;if(P-=m.value.length,y=P,m.value instanceof W)continue;for(var E=m;E!==t.tail&&(Pl.reach&&(l.reach=N);var j=m.prev;O&&(j=I(t,j,O),y+=O.length),q(t,j,x);var C=new W(o,g?M.tokenize(S,g):S,d,S);if(m=I(t,j,C),L&&I(t,m,L),1l.reach&&(l.reach=_.reach)}}}}}}(e,a,n,a.head,0),function(e){var n=[],t=e.head.next;for(;t!==e.tail;)n.push(t.value),t=t.next;return n}(a)},hooks:{all:{},add:function(e,n){var t=M.hooks.all;t[e]=t[e]||[],t[e].push(n)},run:function(e,n){var t=M.hooks.all[e];if(t&&t.length)for(var r,a=0;r=t[a++];)r(n)}},Token:W};function W(e,n,t,r){this.type=e,this.content=n,this.alias=t,this.length=0|(r||"").length}function z(e,n,t,r){e.lastIndex=n;var a=e.exec(t);if(a&&r&&a[1]){var i=a[1].length;a.index+=i,a[0]=a[0].slice(i)}return a}function i(){var e={value:null,prev:null,next:null},n={value:null,prev:e,next:null};e.next=n,this.head=e,this.tail=n,this.length=0}function I(e,n,t){var r=n.next,a={value:t,prev:n,next:r};return n.next=a,r.prev=a,e.length++,a}function q(e,n,t){for(var r=n.next,a=0;a"+a.content+""},!u.document)return u.addEventListener&&(M.disableWorkerMessageHandler||u.addEventListener("message",function(e){var n=JSON.parse(e.data),t=n.language,r=n.code,a=n.immediateClose;u.postMessage(M.highlight(r,M.languages[t],t)),a&&u.close()},!1)),M;var t=M.util.currentScript();function r(){M.manual||M.highlightAll()}if(t&&(M.filename=t.src,t.hasAttribute("data-manual")&&(M.manual=!0)),!M.manual){var a=document.readyState;"loading"===a||"interactive"===a&&t&&t.defer?document.addEventListener("DOMContentLoaded",r):window.requestAnimationFrame?window.requestAnimationFrame(r):window.setTimeout(r,16)}return M}(_self);"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism); \ No newline at end of file +var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(u){var t=/(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i,n=0,e={},M={manual:u.Prism&&u.Prism.manual,disableWorkerMessageHandler:u.Prism&&u.Prism.disableWorkerMessageHandler,util:{encode:function e(n){return n instanceof W?new W(n.type,e(n.content),n.alias):Array.isArray(n)?n.map(e):n.replace(/&/g,"&").replace(/=l.reach);y+=m.value.length,m=m.next){var k=m.value;if(t.length>n.length)return;if(!(k instanceof W)){var x,b=1;if(h){if(!(x=z(p,y,n,f))||x.index>=n.length)break;var w=x.index,A=x.index+x[0].length,P=y;for(P+=m.value.length;P<=w;)m=m.next,P+=m.value.length;if(P-=m.value.length,y=P,m.value instanceof W)continue;for(var E=m;E!==t.tail&&(Pl.reach&&(l.reach=j);var C=m.prev;S&&(C=I(t,C,S),y+=S.length),q(t,C,b);var N=new W(o,g?M.tokenize(L,g):L,d,L);if(m=I(t,C,N),O&&I(t,m,O),1l.reach&&(l.reach=_.reach)}}}}}}(e,a,n,a.head,0),function(e){var n=[],t=e.head.next;for(;t!==e.tail;)n.push(t.value),t=t.next;return n}(a)},hooks:{all:{},add:function(e,n){var t=M.hooks.all;t[e]=t[e]||[],t[e].push(n)},run:function(e,n){var t=M.hooks.all[e];if(t&&t.length)for(var r,a=0;r=t[a++];)r(n)}},Token:W};function W(e,n,t,r){this.type=e,this.content=n,this.alias=t,this.length=0|(r||"").length}function z(e,n,t,r){e.lastIndex=n;var a=e.exec(t);if(a&&r&&a[1]){var i=a[1].length;a.index+=i,a[0]=a[0].slice(i)}return a}function i(){var e={value:null,prev:null,next:null},n={value:null,prev:e,next:null};e.next=n,this.head=e,this.tail=n,this.length=0}function I(e,n,t){var r=n.next,a={value:t,prev:n,next:r};return n.next=a,r.prev=a,e.length++,a}function q(e,n,t){for(var r=n.next,a=0;a"+a.content+""},!u.document)return u.addEventListener&&(M.disableWorkerMessageHandler||u.addEventListener("message",function(e){var n=JSON.parse(e.data),t=n.language,r=n.code,a=n.immediateClose;u.postMessage(M.highlight(r,M.languages[t],t)),a&&u.close()},!1)),M;var r=M.util.currentScript();function a(){M.manual||M.highlightAll()}if(r&&(M.filename=r.src,r.hasAttribute("data-manual")&&(M.manual=!0)),!M.manual){var l=document.readyState;"loading"===l||"interactive"===l&&r&&r.defer?document.addEventListener("DOMContentLoaded",a):window.requestAnimationFrame?window.requestAnimationFrame(a):window.setTimeout(a,16)}return M}(_self);"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism); \ No newline at end of file diff --git a/docs/Prism.hooks.html b/docs/Prism.hooks.html index 5b37950723..8b88b4a96b 100644 --- a/docs/Prism.hooks.html +++ b/docs/Prism.hooks.html @@ -73,7 +73,7 @@

Source:
@@ -152,7 +152,7 @@

(static) addSource:
@@ -314,7 +314,7 @@

(static) runSource:
diff --git a/docs/Prism.html b/docs/Prism.html index 0ed222d5df..e27a9e1e7f 100644 --- a/docs/Prism.html +++ b/docs/Prism.html @@ -350,7 +350,7 @@

(static) hi
Source:
@@ -567,7 +567,7 @@

(static) Source:
@@ -763,7 +763,7 @@

(static) <
Source:
@@ -998,7 +998,7 @@

(static) Source:
@@ -1244,7 +1244,7 @@

(static) tok
Source:
diff --git a/docs/Prism.languages.html b/docs/Prism.languages.html index 9c63cbdc98..0acd142d73 100644 --- a/docs/Prism.languages.html +++ b/docs/Prism.languages.html @@ -73,7 +73,7 @@

Source:
@@ -154,7 +154,7 @@

(static) exten
Source:
@@ -354,7 +354,7 @@

(static) Source:
diff --git a/docs/Token.html b/docs/Token.html index e92d7e6ef1..fceef025e6 100644 --- a/docs/Token.html +++ b/docs/Token.html @@ -80,7 +80,7 @@

new TokenSource:
@@ -364,7 +364,7 @@

aliasSource:
@@ -447,7 +447,7 @@

contentSource:
@@ -524,7 +524,7 @@

typeSource:
diff --git a/docs/global.html b/docs/global.html index 387c0688e0..e4a62cd7ee 100644 --- a/docs/global.html +++ b/docs/global.html @@ -143,7 +143,7 @@

Grammar

Source:
@@ -274,7 +274,7 @@

GrammarToken

Source:
@@ -559,7 +559,7 @@

High
Source:
@@ -713,7 +713,7 @@

HookCallb
Source:
@@ -859,7 +859,7 @@

TokenStream

Source:
diff --git a/docs/prism-core.js.html b/docs/prism-core.js.html index ab8a02214e..c1e9c99d5e 100644 --- a/docs/prism-core.js.html +++ b/docs/prism-core.js.html @@ -72,7 +72,7 @@

prism-core.js

var Prism = (function (_self) { // Private helper vars - var lang = /\blang(?:uage)?-([\w-]+)\b/i; + var lang = /(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i; var uniqueId = 0; // The grammar object for plaintext @@ -237,15 +237,33 @@

prism-core.js

* @returns {string} */ getLanguage: function (element) { - while (element && !lang.test(element.className)) { + while (element) { + var m = lang.exec(element.className); + if (m) { + return m[1].toLowerCase(); + } element = element.parentElement; } - if (element) { - return (element.className.match(lang) || [, 'none'])[1].toLowerCase(); - } return 'none'; }, + /** + * Sets the Prism `language-xxxx` class of the given element. + * + * @param {Element} element + * @param {string} language + * @returns {void} + */ + setLanguage: function (element, language) { + // remove all `language-xxxx` classes + // (this might leave behind a leading space) + element.className = element.className.replace(RegExp(lang, 'gi'), ''); + + // add the new `language-xxxx` class + // (using `classList` will automatically clean up spaces for us) + element.classList.add('language-' + language); + }, + /** * Returns the script element that is currently executing. * @@ -600,12 +618,12 @@

prism-core.js

var grammar = _.languages[language]; // Set language on the element, if not present - element.className = element.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language; + _.util.setLanguage(element, language); // Set language on the parent, for styling var parent = element.parentElement; if (parent && parent.nodeName.toLowerCase() === 'pre') { - parent.className = parent.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language; + _.util.setLanguage(parent, language); } var code = element.textContent; diff --git a/plugins/file-highlight/prism-file-highlight.js b/plugins/file-highlight/prism-file-highlight.js index 0a87ac5403..1247e19fae 100644 --- a/plugins/file-highlight/prism-file-highlight.js +++ b/plugins/file-highlight/prism-file-highlight.js @@ -35,21 +35,6 @@ var SELECTOR = 'pre[data-src]:not([' + STATUS_ATTR + '="' + STATUS_LOADED + '"])' + ':not([' + STATUS_ATTR + '="' + STATUS_LOADING + '"])'; - var lang = /\blang(?:uage)?-([\w-]+)\b/i; - - /** - * Sets the Prism `language-xxxx` or `lang-xxxx` class to the given language. - * - * @param {HTMLElement} element - * @param {string} language - * @returns {void} - */ - function setLanguageClass(element, language) { - var className = element.className; - className = className.replace(lang, ' ') + ' language-' + language; - element.className = className.replace(/\s+/g, ' ').trim(); - } - /** * Loads the given file. * @@ -128,8 +113,8 @@ } // set language classes - setLanguageClass(code, language); - setLanguageClass(pre, language); + Prism.util.setLanguage(code, language); + Prism.util.setLanguage(pre, language); // preload the language var autoloader = Prism.plugins.autoloader; diff --git a/plugins/file-highlight/prism-file-highlight.min.js b/plugins/file-highlight/prism-file-highlight.min.js index b8ec530347..23bacb136e 100644 --- a/plugins/file-highlight/prism-file-highlight.min.js +++ b/plugins/file-highlight/prism-file-highlight.min.js @@ -1 +1 @@ -!function(){if("undefined"!=typeof Prism&&"undefined"!=typeof document){Element.prototype.matches||(Element.prototype.matches=Element.prototype.msMatchesSelector||Element.prototype.webkitMatchesSelector);var l={js:"javascript",py:"python",rb:"ruby",ps1:"powershell",psm1:"powershell",sh:"bash",bat:"batch",h:"c",tex:"latex"},o="data-src-status",h="loading",g="loaded",u="pre[data-src]:not(["+o+'="'+g+'"]):not(['+o+'="'+h+'"])',n=/\blang(?:uage)?-([\w-]+)\b/i;Prism.hooks.add("before-highlightall",function(t){t.selector+=", "+u}),Prism.hooks.add("before-sanity-check",function(t){var r=t.element;if(r.matches(u)){t.code="",r.setAttribute(o,h);var s=r.appendChild(document.createElement("CODE"));s.textContent="Loading…";var e=r.getAttribute("data-src"),i=t.language;if("none"===i){var n=(/\.(\w+)$/.exec(e)||[,"none"])[1];i=l[n]||n}c(s,i),c(r,i);var a=Prism.plugins.autoloader;a&&a.loadLanguages(i),function(t,e,i){var n=new XMLHttpRequest;n.open("GET",t,!0),n.onreadystatechange=function(){4==n.readyState&&(n.status<400&&n.responseText?e(n.responseText):400<=n.status?i(function(t,e){return"✖ Error "+t+" while fetching file: "+e}(n.status,n.statusText)):i("✖ Error: File does not exist or is empty"))},n.send(null)}(e,function(t){r.setAttribute(o,g);var e=function(t){var e=/^\s*(\d+)\s*(?:(,)\s*(?:(\d+)\s*)?)?$/.exec(t||"");if(e){var i=Number(e[1]),n=e[2],a=e[3];return n?a?[i,Number(a)]:[i,void 0]:[i,i]}}(r.getAttribute("data-range"));if(e){var i=t.split(/\r\n?|\n/g),n=e[0],a=null==e[1]?i.length:e[1];n<0&&(n+=i.length),n=Math.max(0,Math.min(n-1,i.length)),a<0&&(a+=i.length),a=Math.max(0,Math.min(a,i.length)),t=i.slice(n,a).join("\n"),r.hasAttribute("data-start")||r.setAttribute("data-start",String(n+1))}s.textContent=t,Prism.highlightElement(s)},function(t){r.setAttribute(o,"failed"),s.textContent=t})}});var t=!(Prism.plugins.fileHighlight={highlight:function(t){for(var e,i=(t||document).querySelectorAll(u),n=0;e=i[n++];)Prism.highlightElement(e)}});Prism.fileHighlight=function(){t||(console.warn("Prism.fileHighlight is deprecated. Use `Prism.plugins.fileHighlight.highlight` instead."),t=!0),Prism.plugins.fileHighlight.highlight.apply(this,arguments)}}function c(t,e){var i=t.className;i=i.replace(n," ")+" language-"+e,t.className=i.replace(/\s+/g," ").trim()}}(); \ No newline at end of file +!function(){if("undefined"!=typeof Prism&&"undefined"!=typeof document){Element.prototype.matches||(Element.prototype.matches=Element.prototype.msMatchesSelector||Element.prototype.webkitMatchesSelector);var l={js:"javascript",py:"python",rb:"ruby",ps1:"powershell",psm1:"powershell",sh:"bash",bat:"batch",h:"c",tex:"latex"},o="data-src-status",h="loading",g="loaded",u="pre[data-src]:not(["+o+'="'+g+'"]):not(['+o+'="'+h+'"])';Prism.hooks.add("before-highlightall",function(t){t.selector+=", "+u}),Prism.hooks.add("before-sanity-check",function(t){var r=t.element;if(r.matches(u)){t.code="",r.setAttribute(o,h);var s=r.appendChild(document.createElement("CODE"));s.textContent="Loading…";var e=r.getAttribute("data-src"),i=t.language;if("none"===i){var n=(/\.(\w+)$/.exec(e)||[,"none"])[1];i=l[n]||n}Prism.util.setLanguage(s,i),Prism.util.setLanguage(r,i);var a=Prism.plugins.autoloader;a&&a.loadLanguages(i),function(t,e,i){var n=new XMLHttpRequest;n.open("GET",t,!0),n.onreadystatechange=function(){4==n.readyState&&(n.status<400&&n.responseText?e(n.responseText):400<=n.status?i(function(t,e){return"✖ Error "+t+" while fetching file: "+e}(n.status,n.statusText)):i("✖ Error: File does not exist or is empty"))},n.send(null)}(e,function(t){r.setAttribute(o,g);var e=function(t){var e=/^\s*(\d+)\s*(?:(,)\s*(?:(\d+)\s*)?)?$/.exec(t||"");if(e){var i=Number(e[1]),n=e[2],a=e[3];return n?a?[i,Number(a)]:[i,void 0]:[i,i]}}(r.getAttribute("data-range"));if(e){var i=t.split(/\r\n?|\n/g),n=e[0],a=null==e[1]?i.length:e[1];n<0&&(n+=i.length),n=Math.max(0,Math.min(n-1,i.length)),a<0&&(a+=i.length),a=Math.max(0,Math.min(a,i.length)),t=i.slice(n,a).join("\n"),r.hasAttribute("data-start")||r.setAttribute("data-start",String(n+1))}s.textContent=t,Prism.highlightElement(s)},function(t){r.setAttribute(o,"failed"),s.textContent=t})}});var t=!(Prism.plugins.fileHighlight={highlight:function(t){for(var e,i=(t||document).querySelectorAll(u),n=0;e=i[n++];)Prism.highlightElement(e)}});Prism.fileHighlight=function(){t||(console.warn("Prism.fileHighlight is deprecated. Use `Prism.plugins.fileHighlight.highlight` instead."),t=!0),Prism.plugins.fileHighlight.highlight.apply(this,arguments)}}}(); \ No newline at end of file diff --git a/prism.js b/prism.js index faa7c5891c..7d2bc604f4 100644 --- a/prism.js +++ b/prism.js @@ -24,7 +24,7 @@ var _self = (typeof window !== 'undefined') var Prism = (function (_self) { // Private helper vars - var lang = /\blang(?:uage)?-([\w-]+)\b/i; + var lang = /(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i; var uniqueId = 0; // The grammar object for plaintext @@ -189,15 +189,33 @@ var Prism = (function (_self) { * @returns {string} */ getLanguage: function (element) { - while (element && !lang.test(element.className)) { + while (element) { + var m = lang.exec(element.className); + if (m) { + return m[1].toLowerCase(); + } element = element.parentElement; } - if (element) { - return (element.className.match(lang) || [, 'none'])[1].toLowerCase(); - } return 'none'; }, + /** + * Sets the Prism `language-xxxx` class of the given element. + * + * @param {Element} element + * @param {string} language + * @returns {void} + */ + setLanguage: function (element, language) { + // remove all `language-xxxx` classes + // (this might leave behind a leading space) + element.className = element.className.replace(RegExp(lang, 'gi'), ''); + + // add the new `language-xxxx` class + // (using `classList` will automatically clean up spaces for us) + element.classList.add('language-' + language); + }, + /** * Returns the script element that is currently executing. * @@ -552,12 +570,12 @@ var Prism = (function (_self) { var grammar = _.languages[language]; // Set language on the element, if not present - element.className = element.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language; + _.util.setLanguage(element, language); // Set language on the parent, for styling var parent = element.parentElement; if (parent && parent.nodeName.toLowerCase() === 'pre') { - parent.className = parent.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language; + _.util.setLanguage(parent, language); } var code = element.textContent; @@ -1746,21 +1764,6 @@ Prism.languages.js = Prism.languages.javascript; var SELECTOR = 'pre[data-src]:not([' + STATUS_ATTR + '="' + STATUS_LOADED + '"])' + ':not([' + STATUS_ATTR + '="' + STATUS_LOADING + '"])'; - var lang = /\blang(?:uage)?-([\w-]+)\b/i; - - /** - * Sets the Prism `language-xxxx` or `lang-xxxx` class to the given language. - * - * @param {HTMLElement} element - * @param {string} language - * @returns {void} - */ - function setLanguageClass(element, language) { - var className = element.className; - className = className.replace(lang, ' ') + ' language-' + language; - element.className = className.replace(/\s+/g, ' ').trim(); - } - /** * Loads the given file. * @@ -1839,8 +1842,8 @@ Prism.languages.js = Prism.languages.javascript; } // set language classes - setLanguageClass(code, language); - setLanguageClass(pre, language); + Prism.util.setLanguage(code, language); + Prism.util.setLanguage(pre, language); // preload the language var autoloader = Prism.plugins.autoloader;