From 89c07e6ef49d007fb1792de50a893a6fdde559b0 Mon Sep 17 00:00:00 2001 From: RunDevelopment Date: Sat, 13 Jul 2019 00:47:39 +0200 Subject: [PATCH 1/5] File Highlight & JSONP Highlight update --- .../file-highlight/prism-file-highlight.js | 178 ++++++++++-------- .../prism-file-highlight.min.js | 2 +- .../jsonp-highlight/prism-jsonp-highlight.js | 146 +++++++++----- .../prism-jsonp-highlight.min.js | 2 +- prism.js | 176 ++++++++++------- 5 files changed, 310 insertions(+), 194 deletions(-) diff --git a/plugins/file-highlight/prism-file-highlight.js b/plugins/file-highlight/prism-file-highlight.js index f3bc6ccf7b..2190d959f9 100644 --- a/plugins/file-highlight/prism-file-highlight.js +++ b/plugins/file-highlight/prism-file-highlight.js @@ -1,105 +1,135 @@ (function () { - if (typeof self === 'undefined' || !self.Prism || !self.document || !document.querySelector) { + if (typeof self === 'undefined' || !self.Prism || !self.document) { return; } - /** - * @param {Element} [container=document] - */ - self.Prism.fileHighlight = function(container) { - container = container || document; - - var Extensions = { - 'js': 'javascript', - 'py': 'python', - 'rb': 'ruby', - 'ps1': 'powershell', - 'psm1': 'powershell', - 'sh': 'bash', - 'bat': 'batch', - 'h': 'c', - 'tex': 'latex' - }; - - Array.prototype.slice.call(container.querySelectorAll('pre[data-src]')).forEach(function (pre) { - // ignore if already loaded - if (pre.hasAttribute('data-src-loaded')) { - return; - } + var Prism = window.Prism; + + var LOADING_MESSAGE = 'Loading…'; + var FAILURE_MESSAGE = '✖ Error {status} while fetching file: {message}'; + var FAILURE_EMPTY_MESSAGE = '✖ Error: File does not exist or is empty'; + + var EXTENSIONS = { + 'js': 'javascript', + 'py': 'python', + 'rb': 'ruby', + 'ps1': 'powershell', + 'psm1': 'powershell', + 'sh': 'bash', + 'bat': 'batch', + 'h': 'c', + 'tex': 'latex' + }; - // load current - var src = pre.getAttribute('data-src'); + var ATTR_LOADING = 'data-src-loading'; + var ATTR_LOADED = 'data-src-loaded'; + var ATTR_FAILED = 'data-src-failed'; + var SELECTOR = 'pre[data-src]:not([' + ATTR_LOADED + ']):not([' + ATTR_LOADING + ']):empty'; - var language, parent = pre; - var lang = /\blang(?:uage)?-([\w-]+)\b/i; - while (parent && !lang.test(parent.className)) { - parent = parent.parentNode; - } + var lang = /\blang(?:uage)?-([\w-]+)\b/i; - if (parent) { - language = (pre.className.match(lang) || [, ''])[1]; - } - if (!language) { - var extension = (src.match(/\.(\w+)$/) || [, ''])[1]; - language = Extensions[extension] || extension; - } + Prism.hooks.add('before-highlightall', function (env) { + env.selector += ', ' + SELECTOR; + }); - var code = document.createElement('code'); - code.className = 'language-' + language; + Prism.hooks.add('before-sanity-check', function (env) { + /** @type {HTMLPreElement} */ + var pre = env.element; + if (pre.matches(SELECTOR)) { + env.code = ''; // fast-path the whole thing and go to complete + + pre.setAttribute(ATTR_LOADING, ''); // mark as loading - pre.textContent = ''; + // add code element with loading message + var code = pre.appendChild(document.createElement('CODE')); + code.textContent = LOADING_MESSAGE; - code.textContent = 'Loading…'; + var src = pre.getAttribute('data-src'); - pre.appendChild(code); + var language = env.language; + if (language === 'none') { + // the language might be 'none' because there is no language set; + // in this case, we want to use the extension as the language + var extension = (/\.(\w+)$/.exec(src) || [, 'none'])[1]; + language = EXTENSIONS[extension] || extension; + } - var xhr = new XMLHttpRequest(); + // TODO: Preload language using Autoloader - xhr.open('GET', src, true); + // set language classes + code.className = 'language-' + language; + pre.className = (pre.className.replace(lang, ' ') + ' language-' + language).replace(/\s+/g, ' '); + // load file + var xhr = new XMLHttpRequest(); + xhr.open('GET', src, true); xhr.onreadystatechange = function () { if (xhr.readyState == 4) { - if (xhr.status < 400 && xhr.responseText) { - code.textContent = xhr.responseText; + // mark as loaded + pre.removeAttribute(ATTR_LOADING); + pre.setAttribute(ATTR_LOADED, ''); + // highlight code + code.textContent = xhr.responseText; Prism.highlightElement(code); - // mark as loaded - pre.setAttribute('data-src-loaded', ''); - } - else if (xhr.status >= 400) { - code.textContent = '✖ Error ' + xhr.status + ' while fetching file: ' + xhr.statusText; - } - else { - code.textContent = '✖ Error: File does not exist or is empty'; + + } else { + // mark as failed + pre.removeAttribute(ATTR_LOADING); + pre.setAttribute(ATTR_FAILED, ''); + + if (xhr.status >= 400) { + code.textContent = FAILURE_MESSAGE.replace('{status}', xhr.status).replace('{message}', xhr.statusText); + } else { + code.textContent = FAILURE_EMPTY_MESSAGE; + } } } }; - xhr.send(null); + } + }); + + + // register download file plugin + if (Prism.plugins.toolbar) { + Prism.plugins.toolbar.registerButton('download-file', function (env) { + var pre = env.element.parentNode; + if (!pre || !/^pre$/i.test(pre.nodeName) || !pre.hasAttribute('data-src') || !pre.hasAttribute('data-download-link')) { + return; + } + var src = pre.getAttribute('data-src'); + var a = document.createElement('a'); + a.textContent = pre.getAttribute('data-download-link-label') || 'Download'; + a.setAttribute('download', ''); + a.href = src; + return a; }); + } - if (Prism.plugins.toolbar) { - Prism.plugins.toolbar.registerButton('download-file', function (env) { - var pre = env.element.parentNode; - if (!pre || !/pre/i.test(pre.nodeName) || !pre.hasAttribute('data-src') || !pre.hasAttribute('data-download-link')) { - return; - } - var src = pre.getAttribute('data-src'); - var a = document.createElement('a'); - a.textContent = pre.getAttribute('data-download-link-label') || 'Download'; - a.setAttribute('download', ''); - a.href = src; - return a; - }); + Prism.plugins.fileHighlight = { + /** + * Executes the File Highlight plugin for all matching `pre` elements under the given container. + * + * Note: Elements which are already loaded or currently loading will not be touched by this method. + * + * @param {Element | Document} [container=document] + */ + highlight: function highlight(container) { + var elements = (container || document).querySelectorAll(SELECTOR); + + for (var i = 0, element; element = elements[i++];) { + Prism.highlightElement(element); + } } - }; - document.addEventListener('DOMContentLoaded', function () { - // execute inside handler, for dropping Event as argument - self.Prism.fileHighlight(); - }); + /** @deprecated Use `Prism.plugins.fileHighlight.highlight` instead. */ + Prism.fileHighlight = function () { + console.warn('Prism.fileHighlight is deprecated. Use `Prism.plugins.fileHighlight.highlight` instead.'); + Prism.plugins.fileHighlight.highlight.apply(this, arguments); + } })(); diff --git a/plugins/file-highlight/prism-file-highlight.min.js b/plugins/file-highlight/prism-file-highlight.min.js index f212f9da97..5d64ed49f8 100644 --- a/plugins/file-highlight/prism-file-highlight.min.js +++ b/plugins/file-highlight/prism-file-highlight.min.js @@ -1 +1 @@ -"undefined"!=typeof self&&self.Prism&&self.document&&document.querySelector&&(self.Prism.fileHighlight=function(t){t=t||document;var i={js:"javascript",py:"python",rb:"ruby",ps1:"powershell",psm1:"powershell",sh:"bash",bat:"batch",h:"c",tex:"latex"};Array.prototype.slice.call(t.querySelectorAll("pre[data-src]")).forEach(function(t){if(!t.hasAttribute("data-src-loaded")){for(var e,a=t.getAttribute("data-src"),n=t,r=/\blang(?:uage)?-([\w-]+)\b/i;n&&!r.test(n.className);)n=n.parentNode;if(n&&(e=(t.className.match(r)||[,""])[1]),!e){var s=(a.match(/\.(\w+)$/)||[,""])[1];e=i[s]||s}var o=document.createElement("code");o.className="language-"+e,t.textContent="",o.textContent="Loading…",t.appendChild(o);var l=new XMLHttpRequest;l.open("GET",a,!0),l.onreadystatechange=function(){4==l.readyState&&(l.status<400&&l.responseText?(o.textContent=l.responseText,Prism.highlightElement(o),t.setAttribute("data-src-loaded","")):400<=l.status?o.textContent="✖ Error "+l.status+" while fetching file: "+l.statusText:o.textContent="✖ Error: File does not exist or is empty")},l.send(null)}}),Prism.plugins.toolbar&&Prism.plugins.toolbar.registerButton("download-file",function(t){var e=t.element.parentNode;if(e&&/pre/i.test(e.nodeName)&&e.hasAttribute("data-src")&&e.hasAttribute("data-download-link")){var a=e.getAttribute("data-src"),n=document.createElement("a");return n.textContent=e.getAttribute("data-download-link-label")||"Download",n.setAttribute("download",""),n.href=a,n}})},document.addEventListener("DOMContentLoaded",function(){self.Prism.fileHighlight()})); \ No newline at end of file +!function(){if("undefined"!=typeof self&&self.Prism&&self.document){var r=window.Prism,o={js:"javascript",py:"python",rb:"ruby",ps1:"powershell",psm1:"powershell",sh:"bash",bat:"batch",h:"c",tex:"latex"},h="data-src-loading",d="data-src-loaded",g="pre[data-src]:not(["+d+"]):not(["+h+"]):empty",u=/\blang(?:uage)?-([\w-]+)\b/i;r.hooks.add("before-highlightall",function(e){e.selector+=", "+g}),r.hooks.add("before-sanity-check",function(e){var t=e.element;if(t.matches(g)){e.code="",t.setAttribute(h,"");var a=t.appendChild(document.createElement("CODE"));a.textContent="Loading…";var i=t.getAttribute("data-src"),n=e.language;if("none"===n){var s=(/\.(\w+)$/.exec(i)||[,"none"])[1];n=o[s]||s}a.className="language-"+n,t.className=(t.className.replace(u," ")+" language-"+n).replace(/\s+/g," ");var l=new XMLHttpRequest;l.open("GET",i,!0),l.onreadystatechange=function(){4==l.readyState&&(l.status<400&&l.responseText?(t.removeAttribute(h),t.setAttribute(d,""),a.textContent=l.responseText,r.highlightElement(a)):(t.removeAttribute(h),t.setAttribute("data-src-failed",""),400<=l.status?a.textContent="✖ Error {status} while fetching file: {message}".replace("{status}",l.status).replace("{message}",l.statusText):a.textContent="✖ Error: File does not exist or is empty"))},l.send(null)}}),r.plugins.toolbar&&r.plugins.toolbar.registerButton("download-file",function(e){var t=e.element.parentNode;if(t&&/^pre$/i.test(t.nodeName)&&t.hasAttribute("data-src")&&t.hasAttribute("data-download-link")){var a=t.getAttribute("data-src"),i=document.createElement("a");return i.textContent=t.getAttribute("data-download-link-label")||"Download",i.setAttribute("download",""),i.href=a,i}}),r.plugins.fileHighlight={highlight:function(e){for(var t,a=(e||document).querySelectorAll(g),i=0;t=a[i++];)r.highlightElement(t)}},r.fileHighlight=function(){console.warn("Prism.fileHighlight is deprecated. Use `Prism.plugins.fileHighlight.highlight` instead."),r.plugins.fileHighlight.highlight.apply(this,arguments)}}}(); \ No newline at end of file diff --git a/plugins/jsonp-highlight/prism-jsonp-highlight.js b/plugins/jsonp-highlight/prism-jsonp-highlight.js index 8b6f65ea9a..1952dd02e3 100644 --- a/plugins/jsonp-highlight/prism-jsonp-highlight.js +++ b/plugins/jsonp-highlight/prism-jsonp-highlight.js @@ -1,11 +1,13 @@ (function () { - if (!self.Prism || !self.document || !document.querySelectorAll || ![].filter) return; + if (!self.Prism || !self.document || !document.querySelectorAll || ![].filter) { + return; + } /** * @callback Adapter * @param {any} response * @param {HTMLPreElement} [pre] - * @returns {string} + * @returns {string | null} */ /** @@ -120,63 +122,93 @@ return null; }, 'bitbucket'); - var jsonpcb = 0, - loadMsg = "Loading\u2026"; - /** - * Highlights all `pre` elements with an `data-jsonp` by requesting the specified JSON and using the specified adapter - * or a registered adapter to extract the code to highlight from the response. The highlighted code will be inserted - * into the `pre` element. - */ - function highlight() { - Array.prototype.slice.call(document.querySelectorAll("pre[data-jsonp]")).forEach(function (pre) { - pre.textContent = ""; + var jsonpCallbackCounter = 0; + + var LOADING_MESSAGE = 'Loading…'; + var MISSING_ADAPTER_MESSAGE = '✖ Error: JSONP adapter function "{name}" doesn\'t exist'; + var TIMEOUT_MESSAGE = '✖ Error: Timeout loading {url}'; + var UNKNOWN_FAILURE_MESSAGE = '✖ Error: Cannot parse response (perhaps you need an adapter function?)'; + + var ATTR_LOADING = 'data-jsonp-loading'; + var ATTR_LOADED = 'data-jsonp-loaded'; + var ATTR_FAILED = 'data-jsonp-failed'; + var SELECTOR = 'pre[data-jsonp]:not([' + ATTR_LOADED + ']):not([' + ATTR_LOADING + ']):empty'; + + + Prism.hooks.add('before-highlightall', function (env) { + env.selector += ', ' + SELECTOR; + }); + + Prism.hooks.add('before-sanity-check', function (env) { + /** @type {HTMLPreElement} */ + var pre = env.element; + if (pre.matches(SELECTOR)) { + env.code = ''; // fast-path the whole thing and go to complete - var code = document.createElement("code"); - code.textContent = loadMsg; - pre.appendChild(code); + // mark as loading + pre.setAttribute(ATTR_LOADING, ''); - var adapterName = pre.getAttribute("data-adapter"); + // add code element with loading message + var code = pre.appendChild(document.createElement('CODE')); + code.textContent = LOADING_MESSAGE; + + // set language + var language = env.language; + code.className = 'language-' + language; + + // TODO: Preload language with Autoloader + + var adapterName = pre.getAttribute('data-adapter'); var adapter = null; if (adapterName) { - if (typeof window[adapterName] === "function") { + if (typeof window[adapterName] === 'function') { adapter = window[adapterName]; - } - else { - code.textContent = "JSONP adapter function '" + adapterName + "' doesn't exist"; + } else { + // mark as failed + pre.removeAttribute(ATTR_LOADING); + pre.setAttribute(ATTR_FAILED, ''); + + code.textContent = MISSING_ADAPTER_MESSAGE.replace('{name}', adapterName); return; } } - var cb = "prismjsonp" + jsonpcb++; + var callbackName = 'prismjsonp' + jsonpCallbackCounter++; + + var uri = document.createElement('a'); + var src = uri.href = pre.getAttribute('data-jsonp'); + uri.href += (uri.search ? '&' : '?') + (pre.getAttribute('data-callback') || 'callback') + '=' + callbackName; - var uri = document.createElement("a"); - var src = uri.href = pre.getAttribute("data-jsonp"); - uri.href += (uri.search ? "&" : "?") + (pre.getAttribute("data-callback") || "callback") + "=" + cb; var timeout = setTimeout(function () { // we could clean up window[cb], but if the request finally succeeds, keeping it around is a good thing - if (code.textContent === loadMsg) { - code.textContent = "Timeout loading '" + src + "'"; - } - }, 5000); - var script = document.createElement("script"); + // mark as failed + pre.removeAttribute(ATTR_LOADING); + pre.setAttribute(ATTR_FAILED, ''); + + code.textContent = TIMEOUT_MESSAGE.replace('{url}', src); + }, Prism.plugins.jsonphighlight.timeout); + + + var script = document.createElement('script'); script.src = uri.href; - window[cb] = function (rsp) { + // the JSONP callback function + window[callbackName] = function (response) { + // clean up document.head.removeChild(script); clearTimeout(timeout); - delete window[cb]; - - var data = ""; + delete window[callbackName]; + // interpret the received data using the adapter(s) + var data = null; if (adapter) { - data = adapter(rsp, pre); - } - else { - for (var p in adapters) { - data = adapters[p].adapter(rsp, pre); + data = adapter(response, pre); + } else { + for (var i = 0, l = adapters.length; i < l; i++) { + data = adapters[i].adapter(response, pre); if (data !== null) { break; } @@ -184,23 +216,47 @@ } if (data === null) { - code.textContent = "Cannot parse response (perhaps you need an adapter function?)"; - } - else { + // mark as failed + pre.removeAttribute(ATTR_LOADING); + pre.setAttribute(ATTR_FAILED, ''); + + code.textContent = UNKNOWN_FAILURE_MESSAGE; + } else { + // mark as loaded + pre.removeAttribute(ATTR_LOADING); + pre.setAttribute(ATTR_LOADED, ''); + code.textContent = data; Prism.highlightElement(code); } }; document.head.appendChild(script); - }); - } + } + }); + Prism.plugins.jsonphighlight = { + timeout: 5000, registerAdapter: registerAdapter, removeAdapter: removeAdapter, - highlight: highlight + + /** + * Highlights all `pre` elements under the given container with a `data-jsonp` attribute by requesting the + * specified JSON and using the specified adapter or a registered adapter to extract the code to highlight + * from the response. The highlighted code will be inserted into the `pre` element. + * + * Note: Elements which are already loaded or currently loading will not be touched by this method. + * + * @param {Element | Document} [container=document] + */ + highlight: function (container) { + var elements = (container || document).querySelectorAll(SELECTOR); + + for (var i = 0, element; element = elements[i++];) { + Prism.highlightElement(element); + } + } }; - highlight(); })(); diff --git a/plugins/jsonp-highlight/prism-jsonp-highlight.min.js b/plugins/jsonp-highlight/prism-jsonp-highlight.min.js index f969cf41d2..0143d98a39 100644 --- a/plugins/jsonp-highlight/prism-jsonp-highlight.min.js +++ b/plugins/jsonp-highlight/prism-jsonp-highlight.min.js @@ -1 +1 @@ -!function(){if(self.Prism&&self.document&&document.querySelectorAll&&[].filter){var d=[];t(function(t,e){if(t&&t.meta&&t.data){if(t.meta.status&&400<=t.meta.status)return"Error: "+(t.data.message||t.meta.status);if("string"==typeof t.data.content)return"function"==typeof atob?atob(t.data.content.replace(/\s/g,"")):"Your browser cannot decode base64"}return null},"github"),t(function(t,e){if(t&&t.meta&&t.data&&t.data.files){if(t.meta.status&&400<=t.meta.status)return"Error: "+(t.data.message||t.meta.status);var n=t.data.files,a=e.getAttribute("data-filename");if(null==a)for(var r in n)if(n.hasOwnProperty(r)){a=r;break}return void 0!==n[a]?n[a].content:"Error: unknown or missing gist file "+a}return null},"gist"),t(function(t,e){return t&&t.node&&"string"==typeof t.data?t.data:null},"bitbucket");var s=0,l="Loading…";Prism.plugins.jsonphighlight={registerAdapter:t,removeAdapter:function(t){if("string"==typeof t&&(t=n(t)),"function"==typeof t){var e=d.map(function(t){return t.adapter}).indexOf(t);0<=e&&d.splice(e,1)}},highlight:e},e()}function t(t,e){e=e||t.name,"function"!=typeof t||n(t)||n(e)||d.push({adapter:t,name:e})}function n(t){if("function"==typeof t){for(var e=0;n=d[e++];)if(n.adapter.valueOf()===t.valueOf())return n.adapter}else if("string"==typeof t){var n;for(e=0;n=d[e++];)if(n.name===t)return n.adapter}return null}function e(){Array.prototype.slice.call(document.querySelectorAll("pre[data-jsonp]")).forEach(function(a){a.textContent="";var r=document.createElement("code");r.textContent=l,a.appendChild(r);var t=a.getAttribute("data-adapter"),o=null;if(t){if("function"!=typeof window[t])return void(r.textContent="JSONP adapter function '"+t+"' doesn't exist");o=window[t]}var i="prismjsonp"+s++,e=document.createElement("a"),n=e.href=a.getAttribute("data-jsonp");e.href+=(e.search?"&":"?")+(a.getAttribute("data-callback")||"callback")+"="+i;var u=setTimeout(function(){r.textContent===l&&(r.textContent="Timeout loading '"+n+"'")},5e3),f=document.createElement("script");f.src=e.href,window[i]=function(t){document.head.removeChild(f),clearTimeout(u),delete window[i];var e="";if(o)e=o(t,a);else for(var n in d)if(null!==(e=d[n].adapter(t,a)))break;null===e?r.textContent="Cannot parse response (perhaps you need an adapter function?)":(r.textContent=e,Prism.highlightElement(r))},document.head.appendChild(f)})}}(); \ No newline at end of file +!function(){if(self.Prism&&self.document&&document.querySelectorAll&&[].filter){var f=[];t(function(t,e){if(t&&t.meta&&t.data){if(t.meta.status&&400<=t.meta.status)return"Error: "+(t.data.message||t.meta.status);if("string"==typeof t.data.content)return"function"==typeof atob?atob(t.data.content.replace(/\s/g,"")):"Your browser cannot decode base64"}return null},"github"),t(function(t,e){if(t&&t.meta&&t.data&&t.data.files){if(t.meta.status&&400<=t.meta.status)return"Error: "+(t.data.message||t.meta.status);var n=t.data.files,r=e.getAttribute("data-filename");if(null==r)for(var a in n)if(n.hasOwnProperty(a)){r=a;break}return void 0!==n[r]?n[r].content:"Error: unknown or missing gist file "+r}return null},"gist"),t(function(t,e){return t&&t.node&&"string"==typeof t.data?t.data:null},"bitbucket");var c=0,m="data-jsonp-loading",p="data-jsonp-loaded",g="data-jsonp-failed",h="pre[data-jsonp]:not(["+p+"]):not(["+m+"]):empty";Prism.hooks.add("before-highlightall",function(t){t.selector+=", "+h}),Prism.hooks.add("before-sanity-check",function(t){var a=t.element;if(a.matches(h)){t.code="",a.setAttribute(m,"");var i=a.appendChild(document.createElement("CODE"));i.textContent="Loading…";var e=t.language;i.className="language-"+e;var n=a.getAttribute("data-adapter"),o=null;if(n){if("function"!=typeof window[n])return a.removeAttribute(m),a.setAttribute(g,""),void(i.textContent='✖ Error: JSONP adapter function "{name}" doesn\'t exist'.replace("{name}",n));o=window[n]}var u="prismjsonp"+c++,r=document.createElement("a"),s=r.href=a.getAttribute("data-jsonp");r.href+=(r.search?"&":"?")+(a.getAttribute("data-callback")||"callback")+"="+u;var l=setTimeout(function(){a.removeAttribute(m),a.setAttribute(g,""),i.textContent="✖ Error: Timeout loading {url}".replace("{url}",s)},Prism.plugins.jsonphighlight.timeout),d=document.createElement("script");d.src=r.href,window[u]=function(t){document.head.removeChild(d),clearTimeout(l),delete window[u];var e=null;if(o)e=o(t,a);else for(var n=0,r=f.length;n= 400) { - code.textContent = '✖ Error ' + xhr.status + ' while fetching file: ' + xhr.statusText; - } - else { - code.textContent = '✖ Error: File does not exist or is empty'; + + } else { + // mark as failed + pre.removeAttribute(ATTR_LOADING); + pre.setAttribute(ATTR_FAILED, ''); + + if (xhr.status >= 400) { + code.textContent = FAILURE_MESSAGE.replace('{status}', xhr.status).replace('{message}', xhr.statusText); + } else { + code.textContent = FAILURE_EMPTY_MESSAGE; + } } } }; - xhr.send(null); + } + }); + + + // register download file plugin + if (Prism.plugins.toolbar) { + Prism.plugins.toolbar.registerButton('download-file', function (env) { + var pre = env.element.parentNode; + if (!pre || !/^pre$/i.test(pre.nodeName) || !pre.hasAttribute('data-src') || !pre.hasAttribute('data-download-link')) { + return; + } + var src = pre.getAttribute('data-src'); + var a = document.createElement('a'); + a.textContent = pre.getAttribute('data-download-link-label') || 'Download'; + a.setAttribute('download', ''); + a.href = src; + return a; }); + } - if (Prism.plugins.toolbar) { - Prism.plugins.toolbar.registerButton('download-file', function (env) { - var pre = env.element.parentNode; - if (!pre || !/pre/i.test(pre.nodeName) || !pre.hasAttribute('data-src') || !pre.hasAttribute('data-download-link')) { - return; - } - var src = pre.getAttribute('data-src'); - var a = document.createElement('a'); - a.textContent = pre.getAttribute('data-download-link-label') || 'Download'; - a.setAttribute('download', ''); - a.href = src; - return a; - }); - } + Prism.plugins.fileHighlight = { + /** + * Executes the File Highlight plugin for all matching `pre` elements under the given container. + * + * Note: Elements which are already loaded or currently loading will not be touched by this method. + * + * @param {Element | Document} [container=document] + */ + highlight: function highlight(container) { + var elements = (container || document).querySelectorAll(SELECTOR); + for (var i = 0, element; element = elements[i++];) { + Prism.highlightElement(element); + } + } }; - document.addEventListener('DOMContentLoaded', function () { - // execute inside handler, for dropping Event as argument - self.Prism.fileHighlight(); - }); + /** @deprecated Use `Prism.plugins.fileHighlight.highlight` instead. */ + Prism.fileHighlight = function () { + console.warn('Prism.fileHighlight is deprecated. Use `Prism.plugins.fileHighlight.highlight` instead.'); + Prism.plugins.fileHighlight.highlight.apply(this, arguments); + } })(); From 2aa3d0d43b1f4e3eca19cec0446e00fd0c56e2a0 Mon Sep 17 00:00:00 2001 From: RunDevelopment Date: Sat, 13 Jul 2019 00:52:12 +0200 Subject: [PATCH 2/5] Minor change --- plugins/jsonp-highlight/prism-jsonp-highlight.js | 2 +- plugins/jsonp-highlight/prism-jsonp-highlight.min.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/jsonp-highlight/prism-jsonp-highlight.js b/plugins/jsonp-highlight/prism-jsonp-highlight.js index 1952dd02e3..3abbc1c85d 100644 --- a/plugins/jsonp-highlight/prism-jsonp-highlight.js +++ b/plugins/jsonp-highlight/prism-jsonp-highlight.js @@ -1,5 +1,5 @@ (function () { - if (!self.Prism || !self.document || !document.querySelectorAll || ![].filter) { + if (typeof self === 'undefined' || !self.Prism || !self.document) { return; } diff --git a/plugins/jsonp-highlight/prism-jsonp-highlight.min.js b/plugins/jsonp-highlight/prism-jsonp-highlight.min.js index 0143d98a39..9d0854ab53 100644 --- a/plugins/jsonp-highlight/prism-jsonp-highlight.min.js +++ b/plugins/jsonp-highlight/prism-jsonp-highlight.min.js @@ -1 +1 @@ -!function(){if(self.Prism&&self.document&&document.querySelectorAll&&[].filter){var f=[];t(function(t,e){if(t&&t.meta&&t.data){if(t.meta.status&&400<=t.meta.status)return"Error: "+(t.data.message||t.meta.status);if("string"==typeof t.data.content)return"function"==typeof atob?atob(t.data.content.replace(/\s/g,"")):"Your browser cannot decode base64"}return null},"github"),t(function(t,e){if(t&&t.meta&&t.data&&t.data.files){if(t.meta.status&&400<=t.meta.status)return"Error: "+(t.data.message||t.meta.status);var n=t.data.files,r=e.getAttribute("data-filename");if(null==r)for(var a in n)if(n.hasOwnProperty(a)){r=a;break}return void 0!==n[r]?n[r].content:"Error: unknown or missing gist file "+r}return null},"gist"),t(function(t,e){return t&&t.node&&"string"==typeof t.data?t.data:null},"bitbucket");var c=0,m="data-jsonp-loading",p="data-jsonp-loaded",g="data-jsonp-failed",h="pre[data-jsonp]:not(["+p+"]):not(["+m+"]):empty";Prism.hooks.add("before-highlightall",function(t){t.selector+=", "+h}),Prism.hooks.add("before-sanity-check",function(t){var a=t.element;if(a.matches(h)){t.code="",a.setAttribute(m,"");var i=a.appendChild(document.createElement("CODE"));i.textContent="Loading…";var e=t.language;i.className="language-"+e;var n=a.getAttribute("data-adapter"),o=null;if(n){if("function"!=typeof window[n])return a.removeAttribute(m),a.setAttribute(g,""),void(i.textContent='✖ Error: JSONP adapter function "{name}" doesn\'t exist'.replace("{name}",n));o=window[n]}var u="prismjsonp"+c++,r=document.createElement("a"),s=r.href=a.getAttribute("data-jsonp");r.href+=(r.search?"&":"?")+(a.getAttribute("data-callback")||"callback")+"="+u;var l=setTimeout(function(){a.removeAttribute(m),a.setAttribute(g,""),i.textContent="✖ Error: Timeout loading {url}".replace("{url}",s)},Prism.plugins.jsonphighlight.timeout),d=document.createElement("script");d.src=r.href,window[u]=function(t){document.head.removeChild(d),clearTimeout(l),delete window[u];var e=null;if(o)e=o(t,a);else for(var n=0,r=f.length;n Date: Fri, 10 Jan 2020 15:05:36 +0100 Subject: [PATCH 3/5] Minor changes --- .../file-highlight/prism-file-highlight.js | 16 ++++++++++------ .../prism-file-highlight.min.js | 2 +- .../jsonp-highlight/prism-jsonp-highlight.js | 19 ++++++++++++------- .../prism-jsonp-highlight.min.js | 2 +- prism.js | 16 ++++++++++------ 5 files changed, 34 insertions(+), 21 deletions(-) diff --git a/plugins/file-highlight/prism-file-highlight.js b/plugins/file-highlight/prism-file-highlight.js index 5e1d4c6873..96265b12dd 100644 --- a/plugins/file-highlight/prism-file-highlight.js +++ b/plugins/file-highlight/prism-file-highlight.js @@ -6,7 +6,9 @@ var Prism = window.Prism; var LOADING_MESSAGE = 'Loading…'; - var FAILURE_MESSAGE = '✖ Error {status} while fetching file: {message}'; + var FAILURE_MESSAGE = function (status, message) { + return '✖ Error ' + status + ' while fetching file: ' + message; + }; var FAILURE_EMPTY_MESSAGE = '✖ Error: File does not exist or is empty'; var EXTENSIONS = { @@ -34,8 +36,7 @@ }); Prism.hooks.add('before-sanity-check', function (env) { - /** @type {HTMLPreElement} */ - var pre = env.element; + var pre = /** @type {HTMLPreElement} */ (env.element); if (pre.matches(SELECTOR)) { env.code = ''; // fast-path the whole thing and go to complete @@ -55,7 +56,10 @@ language = EXTENSIONS[extension] || extension; } - // TODO: Preload language using Autoloader + // preload the language + if (Prism.plugins.autoloader) { + Prism.plugins.autoloader.loadLanguages(language); + } // set language classes code.className = 'language-' + language; @@ -81,7 +85,7 @@ pre.setAttribute(ATTR_FAILED, ''); if (xhr.status >= 400) { - code.textContent = FAILURE_MESSAGE.replace('{status}', xhr.status).replace('{message}', xhr.statusText); + code.textContent = FAILURE_MESSAGE(xhr.status, xhr.statusText); } else { code.textContent = FAILURE_EMPTY_MESSAGE; } @@ -98,7 +102,7 @@ * * Note: Elements which are already loaded or currently loading will not be touched by this method. * - * @param {Element | Document} [container=document] + * @param {ParentNode} [container=document] */ highlight: function highlight(container) { var elements = (container || document).querySelectorAll(SELECTOR); diff --git a/plugins/file-highlight/prism-file-highlight.min.js b/plugins/file-highlight/prism-file-highlight.min.js index 1cf5c99428..b88c97b962 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 self&&self.Prism&&self.document){var r=window.Prism,o={js:"javascript",py:"python",rb:"ruby",ps1:"powershell",psm1:"powershell",sh:"bash",bat:"batch",h:"c",tex:"latex"},h="data-src-loading",g="data-src-loaded",c="pre[data-src]:not(["+g+"]):not(["+h+"]):empty",u=/\blang(?:uage)?-([\w-]+)\b/i;r.hooks.add("before-highlightall",function(e){e.selector+=", "+c}),r.hooks.add("before-sanity-check",function(e){var t=e.element;if(t.matches(c)){e.code="",t.setAttribute(h,"");var a=t.appendChild(document.createElement("CODE"));a.textContent="Loading…";var s=t.getAttribute("data-src"),i=e.language;if("none"===i){var n=(/\.(\w+)$/.exec(s)||[,"none"])[1];i=o[n]||n}a.className="language-"+i,t.className=(t.className.replace(u," ")+" language-"+i).replace(/\s+/g," ");var l=new XMLHttpRequest;l.open("GET",s,!0),l.onreadystatechange=function(){4==l.readyState&&(l.status<400&&l.responseText?(t.removeAttribute(h),t.setAttribute(g,""),a.textContent=l.responseText,r.highlightElement(a)):(t.removeAttribute(h),t.setAttribute("data-src-failed",""),400<=l.status?a.textContent="✖ Error {status} while fetching file: {message}".replace("{status}",l.status).replace("{message}",l.statusText):a.textContent="✖ Error: File does not exist or is empty"))},l.send(null)}}),r.plugins.fileHighlight={highlight:function(e){for(var t,a=(e||document).querySelectorAll(c),s=0;t=a[s++];)r.highlightElement(t)}},r.fileHighlight=function(){console.warn("Prism.fileHighlight is deprecated. Use `Prism.plugins.fileHighlight.highlight` instead."),r.plugins.fileHighlight.highlight.apply(this,arguments)}}}(); \ No newline at end of file +!function(){if("undefined"!=typeof self&&self.Prism&&self.document){var r=window.Prism,o={js:"javascript",py:"python",rb:"ruby",ps1:"powershell",psm1:"powershell",sh:"bash",bat:"batch",h:"c",tex:"latex"},h="data-src-loading",g="data-src-loaded",u="pre[data-src]:not(["+g+"]):not(["+h+"]):empty",c=/\blang(?:uage)?-([\w-]+)\b/i;r.hooks.add("before-highlightall",function(e){e.selector+=", "+u}),r.hooks.add("before-sanity-check",function(e){var t=e.element;if(t.matches(u)){e.code="",t.setAttribute(h,"");var a=t.appendChild(document.createElement("CODE"));a.textContent="Loading…";var i=t.getAttribute("data-src"),n=e.language;if("none"===n){var s=(/\.(\w+)$/.exec(i)||[,"none"])[1];n=o[s]||s}r.plugins.autoloader&&r.plugins.autoloader.loadLanguages(n),a.className="language-"+n,t.className=(t.className.replace(c," ")+" language-"+n).replace(/\s+/g," ");var l=new XMLHttpRequest;l.open("GET",i,!0),l.onreadystatechange=function(){4==l.readyState&&(l.status<400&&l.responseText?(t.removeAttribute(h),t.setAttribute(g,""),a.textContent=l.responseText,r.highlightElement(a)):(t.removeAttribute(h),t.setAttribute("data-src-failed",""),400<=l.status?a.textContent=function(e,t){return"✖ Error "+e+" while fetching file: "+t}(l.status,l.statusText):a.textContent="✖ Error: File does not exist or is empty"))},l.send(null)}}),r.plugins.fileHighlight={highlight:function(e){for(var t,a=(e||document).querySelectorAll(u),i=0;t=a[i++];)r.highlightElement(t)}},r.fileHighlight=function(){console.warn("Prism.fileHighlight is deprecated. Use `Prism.plugins.fileHighlight.highlight` instead."),r.plugins.fileHighlight.highlight.apply(this,arguments)}}}(); \ No newline at end of file diff --git a/plugins/jsonp-highlight/prism-jsonp-highlight.js b/plugins/jsonp-highlight/prism-jsonp-highlight.js index 3abbc1c85d..bc0699c35b 100644 --- a/plugins/jsonp-highlight/prism-jsonp-highlight.js +++ b/plugins/jsonp-highlight/prism-jsonp-highlight.js @@ -68,7 +68,9 @@ adapter = getAdapter(adapter); } if (typeof adapter === "function") { - var index = adapters.map(function (item) { return item.adapter; }).indexOf(adapter); + var index = adapters.findIndex(function (item) { + return item.adapter === adapter; + }); if (index >= 0) { adapters.splice(index, 1); } @@ -126,8 +128,12 @@ var jsonpCallbackCounter = 0; var LOADING_MESSAGE = 'Loading…'; - var MISSING_ADAPTER_MESSAGE = '✖ Error: JSONP adapter function "{name}" doesn\'t exist'; - var TIMEOUT_MESSAGE = '✖ Error: Timeout loading {url}'; + var MISSING_ADAPTER_MESSAGE = function (name) { + return '✖ Error: JSONP adapter function "' + name + '" doesn\'t exist'; + }; + var TIMEOUT_MESSAGE = function (url) { + return '✖ Error: Timeout loading ' + url; + }; var UNKNOWN_FAILURE_MESSAGE = '✖ Error: Cannot parse response (perhaps you need an adapter function?)'; var ATTR_LOADING = 'data-jsonp-loading'; @@ -141,8 +147,7 @@ }); Prism.hooks.add('before-sanity-check', function (env) { - /** @type {HTMLPreElement} */ - var pre = env.element; + var pre = /** @type {HTMLPreElement} */ (env.element); if (pre.matches(SELECTOR)) { env.code = ''; // fast-path the whole thing and go to complete @@ -169,7 +174,7 @@ pre.removeAttribute(ATTR_LOADING); pre.setAttribute(ATTR_FAILED, ''); - code.textContent = MISSING_ADAPTER_MESSAGE.replace('{name}', adapterName); + code.textContent = MISSING_ADAPTER_MESSAGE(adapterName); return; } } @@ -188,7 +193,7 @@ pre.removeAttribute(ATTR_LOADING); pre.setAttribute(ATTR_FAILED, ''); - code.textContent = TIMEOUT_MESSAGE.replace('{url}', src); + code.textContent = TIMEOUT_MESSAGE(src); }, Prism.plugins.jsonphighlight.timeout); diff --git a/plugins/jsonp-highlight/prism-jsonp-highlight.min.js b/plugins/jsonp-highlight/prism-jsonp-highlight.min.js index 9d0854ab53..5d915f32d3 100644 --- a/plugins/jsonp-highlight/prism-jsonp-highlight.min.js +++ b/plugins/jsonp-highlight/prism-jsonp-highlight.min.js @@ -1 +1 @@ -!function(){if("undefined"!=typeof self&&self.Prism&&self.document){var f=[];t(function(t,e){if(t&&t.meta&&t.data){if(t.meta.status&&400<=t.meta.status)return"Error: "+(t.data.message||t.meta.status);if("string"==typeof t.data.content)return"function"==typeof atob?atob(t.data.content.replace(/\s/g,"")):"Your browser cannot decode base64"}return null},"github"),t(function(t,e){if(t&&t.meta&&t.data&&t.data.files){if(t.meta.status&&400<=t.meta.status)return"Error: "+(t.data.message||t.meta.status);var n=t.data.files,a=e.getAttribute("data-filename");if(null==a)for(var r in n)if(n.hasOwnProperty(r)){a=r;break}return void 0!==n[a]?n[a].content:"Error: unknown or missing gist file "+a}return null},"gist"),t(function(t,e){return t&&t.node&&"string"==typeof t.data?t.data:null},"bitbucket");var c=0,m="data-jsonp-loading",p="data-jsonp-loaded",g="data-jsonp-failed",h="pre[data-jsonp]:not(["+p+"]):not(["+m+"]):empty";Prism.hooks.add("before-highlightall",function(t){t.selector+=", "+h}),Prism.hooks.add("before-sanity-check",function(t){var r=t.element;if(r.matches(h)){t.code="",r.setAttribute(m,"");var i=r.appendChild(document.createElement("CODE"));i.textContent="Loading…";var e=t.language;i.className="language-"+e;var n=r.getAttribute("data-adapter"),o=null;if(n){if("function"!=typeof window[n])return r.removeAttribute(m),r.setAttribute(g,""),void(i.textContent='✖ Error: JSONP adapter function "{name}" doesn\'t exist'.replace("{name}",n));o=window[n]}var u="prismjsonp"+c++,a=document.createElement("a"),s=a.href=r.getAttribute("data-jsonp");a.href+=(a.search?"&":"?")+(r.getAttribute("data-callback")||"callback")+"="+u;var l=setTimeout(function(){r.removeAttribute(m),r.setAttribute(g,""),i.textContent="✖ Error: Timeout loading {url}".replace("{url}",s)},Prism.plugins.jsonphighlight.timeout),d=document.createElement("script");d.src=a.href,window[u]=function(t){document.head.removeChild(d),clearTimeout(l),delete window[u];var e=null;if(o)e=o(t,r);else for(var n=0,a=f.length;n= 400) { - code.textContent = FAILURE_MESSAGE.replace('{status}', xhr.status).replace('{message}', xhr.statusText); + code.textContent = FAILURE_MESSAGE(xhr.status, xhr.statusText); } else { code.textContent = FAILURE_EMPTY_MESSAGE; } @@ -1035,7 +1039,7 @@ Prism.languages.js = Prism.languages.javascript; * * Note: Elements which are already loaded or currently loading will not be touched by this method. * - * @param {Element | Document} [container=document] + * @param {ParentNode} [container=document] */ highlight: function highlight(container) { var elements = (container || document).querySelectorAll(SELECTOR); From e499c05d5351da019a0051f718dcaf3d829edc60 Mon Sep 17 00:00:00 2001 From: RunDevelopment Date: Fri, 10 Jan 2020 15:11:38 +0100 Subject: [PATCH 4/5] Resolved incompatability --- plugins/copy-to-clipboard/prism-copy-to-clipboard.js | 4 +++- plugins/copy-to-clipboard/prism-copy-to-clipboard.min.js | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/copy-to-clipboard/prism-copy-to-clipboard.js b/plugins/copy-to-clipboard/prism-copy-to-clipboard.js index ac73efebca..ce52a79143 100644 --- a/plugins/copy-to-clipboard/prism-copy-to-clipboard.js +++ b/plugins/copy-to-clipboard/prism-copy-to-clipboard.js @@ -39,6 +39,8 @@ var linkCopy = document.createElement('button'); linkCopy.textContent = 'Copy'; + var element = env.element; + if (!ClipboardJS) { callbacks.push(registerClipboard); } else { @@ -50,7 +52,7 @@ function registerClipboard() { var clip = new ClipboardJS(linkCopy, { 'text': function () { - return env.code; + return element.textContent; } }); diff --git a/plugins/copy-to-clipboard/prism-copy-to-clipboard.min.js b/plugins/copy-to-clipboard/prism-copy-to-clipboard.min.js index 199b42549d..3c8b52560e 100644 --- a/plugins/copy-to-clipboard/prism-copy-to-clipboard.min.js +++ b/plugins/copy-to-clipboard/prism-copy-to-clipboard.min.js @@ -1 +1 @@ -!function(){if("undefined"!=typeof self&&self.Prism&&self.document)if(Prism.plugins.toolbar){var r=window.ClipboardJS||void 0;r||"function"!=typeof require||(r=require("clipboard"));var i=[];if(!r){var o=document.createElement("script"),e=document.querySelector("head");o.onload=function(){if(r=window.ClipboardJS)for(;i.length;)i.pop()()},o.src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.0/clipboard.min.js",e.appendChild(o)}Prism.plugins.toolbar.registerButton("copy-to-clipboard",function(e){var t=document.createElement("button");return t.textContent="Copy",r?o():i.push(o),t;function o(){var o=new r(t,{text:function(){return e.code}});o.on("success",function(){t.textContent="Copied!",n()}),o.on("error",function(){t.textContent="Press Ctrl+C to copy",n()})}function n(){setTimeout(function(){t.textContent="Copy"},5e3)}})}else console.warn("Copy to Clipboard plugin loaded before Toolbar plugin.")}(); \ No newline at end of file +!function(){if("undefined"!=typeof self&&self.Prism&&self.document)if(Prism.plugins.toolbar){var i=window.ClipboardJS||void 0;i||"function"!=typeof require||(i=require("clipboard"));var c=[];if(!i){var o=document.createElement("script"),t=document.querySelector("head");o.onload=function(){if(i=window.ClipboardJS)for(;c.length;)c.pop()()},o.src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.0/clipboard.min.js",t.appendChild(o)}Prism.plugins.toolbar.registerButton("copy-to-clipboard",function(o){var t=document.createElement("button");t.textContent="Copy";var e=o.element;return i?n():c.push(n),t;function n(){var o=new i(t,{text:function(){return e.textContent}});o.on("success",function(){t.textContent="Copied!",r()}),o.on("error",function(){t.textContent="Press Ctrl+C to copy",r()})}function r(){setTimeout(function(){t.textContent="Copy"},5e3)}})}else console.warn("Copy to Clipboard plugin loaded before Toolbar plugin.")}(); \ No newline at end of file From 6312e81f580ed8f4db09d4a41243bb6b40b55f8f Mon Sep 17 00:00:00 2001 From: RunDevelopment Date: Fri, 21 Feb 2020 22:29:18 +0100 Subject: [PATCH 5/5] Attribute change and minor improvements --- .../file-highlight/prism-file-highlight.js | 51 +++++++++++++------ .../prism-file-highlight.min.js | 2 +- .../jsonp-highlight/prism-jsonp-highlight.js | 37 +++++++++----- .../prism-jsonp-highlight.min.js | 2 +- prism.js | 51 +++++++++++++------ 5 files changed, 95 insertions(+), 48 deletions(-) diff --git a/plugins/file-highlight/prism-file-highlight.js b/plugins/file-highlight/prism-file-highlight.js index 96265b12dd..93db3acb2b 100644 --- a/plugins/file-highlight/prism-file-highlight.js +++ b/plugins/file-highlight/prism-file-highlight.js @@ -23,13 +23,29 @@ 'tex': 'latex' }; - var ATTR_LOADING = 'data-src-loading'; - var ATTR_LOADED = 'data-src-loaded'; - var ATTR_FAILED = 'data-src-failed'; - var SELECTOR = 'pre[data-src]:not([' + ATTR_LOADED + ']):not([' + ATTR_LOADING + ']):empty'; + var STATUS_ATTR = 'data-src-status'; + var STATUS_LOADING = 'loading'; + var STATUS_LOADED = 'loaded'; + var STATUS_FAILED = 'failed'; + + 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(); + } + Prism.hooks.add('before-highlightall', function (env) { env.selector += ', ' + SELECTOR; @@ -40,7 +56,7 @@ if (pre.matches(SELECTOR)) { env.code = ''; // fast-path the whole thing and go to complete - pre.setAttribute(ATTR_LOADING, ''); // mark as loading + pre.setAttribute(STATUS_ATTR, STATUS_LOADING); // mark as loading // add code element with loading message var code = pre.appendChild(document.createElement('CODE')); @@ -56,15 +72,16 @@ language = EXTENSIONS[extension] || extension; } + // set language classes + setLanguageClass(code, language); + setLanguageClass(pre, language); + // preload the language - if (Prism.plugins.autoloader) { - Prism.plugins.autoloader.loadLanguages(language); + var autoloader = Prism.plugins.autoloader; + if (autoloader) { + autoloader.loadLanguages(language); } - // set language classes - code.className = 'language-' + language; - pre.className = (pre.className.replace(lang, ' ') + ' language-' + language).replace(/\s+/g, ' '); - // load file var xhr = new XMLHttpRequest(); xhr.open('GET', src, true); @@ -72,8 +89,7 @@ if (xhr.readyState == 4) { if (xhr.status < 400 && xhr.responseText) { // mark as loaded - pre.removeAttribute(ATTR_LOADING); - pre.setAttribute(ATTR_LOADED, ''); + pre.setAttribute(STATUS_ATTR, STATUS_LOADED); // highlight code code.textContent = xhr.responseText; @@ -81,8 +97,7 @@ } else { // mark as failed - pre.removeAttribute(ATTR_LOADING); - pre.setAttribute(ATTR_FAILED, ''); + pre.setAttribute(STATUS_ATTR, STATUS_FAILED); if (xhr.status >= 400) { code.textContent = FAILURE_MESSAGE(xhr.status, xhr.statusText); @@ -113,9 +128,13 @@ } }; + var logged = false; /** @deprecated Use `Prism.plugins.fileHighlight.highlight` instead. */ Prism.fileHighlight = function () { - console.warn('Prism.fileHighlight is deprecated. Use `Prism.plugins.fileHighlight.highlight` instead.'); + if (!logged) { + console.warn('Prism.fileHighlight is deprecated. Use `Prism.plugins.fileHighlight.highlight` instead.'); + logged = true; + } Prism.plugins.fileHighlight.highlight.apply(this, arguments); } diff --git a/plugins/file-highlight/prism-file-highlight.min.js b/plugins/file-highlight/prism-file-highlight.min.js index b88c97b962..843072dff8 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 self&&self.Prism&&self.document){var r=window.Prism,o={js:"javascript",py:"python",rb:"ruby",ps1:"powershell",psm1:"powershell",sh:"bash",bat:"batch",h:"c",tex:"latex"},h="data-src-loading",g="data-src-loaded",u="pre[data-src]:not(["+g+"]):not(["+h+"]):empty",c=/\blang(?:uage)?-([\w-]+)\b/i;r.hooks.add("before-highlightall",function(e){e.selector+=", "+u}),r.hooks.add("before-sanity-check",function(e){var t=e.element;if(t.matches(u)){e.code="",t.setAttribute(h,"");var a=t.appendChild(document.createElement("CODE"));a.textContent="Loading…";var i=t.getAttribute("data-src"),n=e.language;if("none"===n){var s=(/\.(\w+)$/.exec(i)||[,"none"])[1];n=o[s]||s}r.plugins.autoloader&&r.plugins.autoloader.loadLanguages(n),a.className="language-"+n,t.className=(t.className.replace(c," ")+" language-"+n).replace(/\s+/g," ");var l=new XMLHttpRequest;l.open("GET",i,!0),l.onreadystatechange=function(){4==l.readyState&&(l.status<400&&l.responseText?(t.removeAttribute(h),t.setAttribute(g,""),a.textContent=l.responseText,r.highlightElement(a)):(t.removeAttribute(h),t.setAttribute("data-src-failed",""),400<=l.status?a.textContent=function(e,t){return"✖ Error "+e+" while fetching file: "+t}(l.status,l.statusText):a.textContent="✖ Error: File does not exist or is empty"))},l.send(null)}}),r.plugins.fileHighlight={highlight:function(e){for(var t,a=(e||document).querySelectorAll(u),i=0;t=a[i++];)r.highlightElement(t)}},r.fileHighlight=function(){console.warn("Prism.fileHighlight is deprecated. Use `Prism.plugins.fileHighlight.highlight` instead."),r.plugins.fileHighlight.highlight.apply(this,arguments)}}}(); \ No newline at end of file +!function(){if("undefined"!=typeof self&&self.Prism&&self.document){var o=window.Prism,h={js:"javascript",py:"python",rb:"ruby",ps1:"powershell",psm1:"powershell",sh:"bash",bat:"batch",h:"c",tex:"latex"},g="data-src-status",u="loading",c="loaded",d="pre[data-src]:not(["+g+'="'+c+'"]):not(['+g+'="'+u+'"])',n=/\blang(?:uage)?-([\w-]+)\b/i;o.hooks.add("before-highlightall",function(e){e.selector+=", "+d}),o.hooks.add("before-sanity-check",function(e){var t=e.element;if(t.matches(d)){e.code="",t.setAttribute(g,u);var i=t.appendChild(document.createElement("CODE"));i.textContent="Loading…";var n=t.getAttribute("data-src"),a=e.language;if("none"===a){var s=(/\.(\w+)$/.exec(n)||[,"none"])[1];a=h[s]||s}f(i,a),f(t,a);var l=o.plugins.autoloader;l&&l.loadLanguages(a);var r=new XMLHttpRequest;r.open("GET",n,!0),r.onreadystatechange=function(){4==r.readyState&&(r.status<400&&r.responseText?(t.setAttribute(g,c),i.textContent=r.responseText,o.highlightElement(i)):(t.setAttribute(g,"failed"),400<=r.status?i.textContent=function(e,t){return"✖ Error "+e+" while fetching file: "+t}(r.status,r.statusText):i.textContent="✖ Error: File does not exist or is empty"))},r.send(null)}});var e=!(o.plugins.fileHighlight={highlight:function(e){for(var t,i=(e||document).querySelectorAll(d),n=0;t=i[n++];)o.highlightElement(t)}});o.fileHighlight=function(){e||(console.warn("Prism.fileHighlight is deprecated. Use `Prism.plugins.fileHighlight.highlight` instead."),e=!0),o.plugins.fileHighlight.highlight.apply(this,arguments)}}function f(e,t){var i=e.className;i=i.replace(n," ")+" language-"+t,e.className=i.replace(/\s+/g," ").trim()}}(); \ No newline at end of file diff --git a/plugins/jsonp-highlight/prism-jsonp-highlight.js b/plugins/jsonp-highlight/prism-jsonp-highlight.js index bc0699c35b..f49940f161 100644 --- a/plugins/jsonp-highlight/prism-jsonp-highlight.js +++ b/plugins/jsonp-highlight/prism-jsonp-highlight.js @@ -136,10 +136,13 @@ }; var UNKNOWN_FAILURE_MESSAGE = '✖ Error: Cannot parse response (perhaps you need an adapter function?)'; - var ATTR_LOADING = 'data-jsonp-loading'; - var ATTR_LOADED = 'data-jsonp-loaded'; - var ATTR_FAILED = 'data-jsonp-failed'; - var SELECTOR = 'pre[data-jsonp]:not([' + ATTR_LOADED + ']):not([' + ATTR_LOADING + ']):empty'; + var STATUS_ATTR = 'data-jsonp-status'; + var STATUS_LOADING = 'loading'; + var STATUS_LOADED = 'loaded'; + var STATUS_FAILED = 'failed'; + + var SELECTOR = 'pre[data-jsonp]:not([' + STATUS_ATTR + '="' + STATUS_LOADED + '"])' + + ':not([' + STATUS_ATTR + '="' + STATUS_LOADING + '"])'; Prism.hooks.add('before-highlightall', function (env) { @@ -152,7 +155,7 @@ env.code = ''; // fast-path the whole thing and go to complete // mark as loading - pre.setAttribute(ATTR_LOADING, ''); + pre.setAttribute(STATUS_ATTR, STATUS_LOADING); // add code element with loading message var code = pre.appendChild(document.createElement('CODE')); @@ -162,7 +165,11 @@ var language = env.language; code.className = 'language-' + language; - // TODO: Preload language with Autoloader + // preload the language + var autoloader = Prism.plugins.autoloader; + if (autoloader) { + autoloader.loadLanguages(language); + } var adapterName = pre.getAttribute('data-adapter'); var adapter = null; @@ -171,8 +178,7 @@ adapter = window[adapterName]; } else { // mark as failed - pre.removeAttribute(ATTR_LOADING); - pre.setAttribute(ATTR_FAILED, ''); + pre.setAttribute(STATUS_ATTR, STATUS_FAILED); code.textContent = MISSING_ADAPTER_MESSAGE(adapterName); return; @@ -190,8 +196,7 @@ // we could clean up window[cb], but if the request finally succeeds, keeping it around is a good thing // mark as failed - pre.removeAttribute(ATTR_LOADING); - pre.setAttribute(ATTR_FAILED, ''); + pre.setAttribute(STATUS_ATTR, STATUS_FAILED); code.textContent = TIMEOUT_MESSAGE(src); }, Prism.plugins.jsonphighlight.timeout); @@ -222,14 +227,12 @@ if (data === null) { // mark as failed - pre.removeAttribute(ATTR_LOADING); - pre.setAttribute(ATTR_FAILED, ''); + pre.setAttribute(STATUS_ATTR, STATUS_FAILED); code.textContent = UNKNOWN_FAILURE_MESSAGE; } else { // mark as loaded - pre.removeAttribute(ATTR_LOADING); - pre.setAttribute(ATTR_LOADED, ''); + pre.setAttribute(STATUS_ATTR, STATUS_LOADED); code.textContent = data; Prism.highlightElement(code); @@ -242,6 +245,12 @@ Prism.plugins.jsonphighlight = { + /** + * The timeout after which an error message will be displayed. + * + * __Note:__ If the request succeeds after the timeout, it will still be processed and will override any + * displayed error messages. + */ timeout: 5000, registerAdapter: registerAdapter, removeAdapter: removeAdapter, diff --git a/plugins/jsonp-highlight/prism-jsonp-highlight.min.js b/plugins/jsonp-highlight/prism-jsonp-highlight.min.js index 5d915f32d3..e647679723 100644 --- a/plugins/jsonp-highlight/prism-jsonp-highlight.min.js +++ b/plugins/jsonp-highlight/prism-jsonp-highlight.min.js @@ -1 +1 @@ -!function(){if("undefined"!=typeof self&&self.Prism&&self.document){var l=[];t(function(t,e){if(t&&t.meta&&t.data){if(t.meta.status&&400<=t.meta.status)return"Error: "+(t.data.message||t.meta.status);if("string"==typeof t.data.content)return"function"==typeof atob?atob(t.data.content.replace(/\s/g,"")):"Your browser cannot decode base64"}return null},"github"),t(function(t,e){if(t&&t.meta&&t.data&&t.data.files){if(t.meta.status&&400<=t.meta.status)return"Error: "+(t.data.message||t.meta.status);var n=t.data.files,r=e.getAttribute("data-filename");if(null==r)for(var a in n)if(n.hasOwnProperty(a)){r=a;break}return void 0!==n[r]?n[r].content:"Error: unknown or missing gist file "+r}return null},"gist"),t(function(t,e){return t&&t.node&&"string"==typeof t.data?t.data:null},"bitbucket");var c=0,m="data-jsonp-loading",p="data-jsonp-loaded",g="data-jsonp-failed",h="pre[data-jsonp]:not(["+p+"]):not(["+m+"]):empty";Prism.hooks.add("before-highlightall",function(t){t.selector+=", "+h}),Prism.hooks.add("before-sanity-check",function(t){var a=t.element;if(a.matches(h)){t.code="",a.setAttribute(m,"");var i=a.appendChild(document.createElement("CODE"));i.textContent="Loading…";var e=t.language;i.className="language-"+e;var n=a.getAttribute("data-adapter"),o=null;if(n){if("function"!=typeof window[n])return a.removeAttribute(m),a.setAttribute(g,""),void(i.textContent=function(t){return'✖ Error: JSONP adapter function "'+t+"\" doesn't exist"}(n));o=window[n]}var u="prismjsonp"+c++,r=document.createElement("a"),s=r.href=a.getAttribute("data-jsonp");r.href+=(r.search?"&":"?")+(a.getAttribute("data-callback")||"callback")+"="+u;var f=setTimeout(function(){a.removeAttribute(m),a.setAttribute(g,""),i.textContent=function(t){return"✖ Error: Timeout loading "+t}(s)},Prism.plugins.jsonphighlight.timeout),d=document.createElement("script");d.src=r.href,window[u]=function(t){document.head.removeChild(d),clearTimeout(f),delete window[u];var e=null;if(o)e=o(t,a);else for(var n=0,r=l.length;n= 400) { code.textContent = FAILURE_MESSAGE(xhr.status, xhr.statusText); @@ -1061,9 +1076,13 @@ Prism.languages.js = Prism.languages.javascript; } }; + var logged = false; /** @deprecated Use `Prism.plugins.fileHighlight.highlight` instead. */ Prism.fileHighlight = function () { - console.warn('Prism.fileHighlight is deprecated. Use `Prism.plugins.fileHighlight.highlight` instead.'); + if (!logged) { + console.warn('Prism.fileHighlight is deprecated. Use `Prism.plugins.fileHighlight.highlight` instead.'); + logged = true; + } Prism.plugins.fileHighlight.highlight.apply(this, arguments); }