diff --git a/plugins/autoloader/prism-autoloader.js b/plugins/autoloader/prism-autoloader.js index 79d6aed2ec..953cdc5684 100644 --- a/plugins/autoloader/prism-autoloader.js +++ b/plugins/autoloader/prism-autoloader.js @@ -269,42 +269,54 @@ } /** - * Returns the path to a grammar, using the language_path and use_minified config keys. + * Returns all additional dependencies of the given element defined by the `data-dependencies` attribute. * - * @param {string} lang - * @returns {string} + * @param {Element} element + * @returns {string[]} */ - function getLanguagePath(lang) { - return config.languages_path + - 'prism-' + lang - + (config.use_minified ? '.min' : '') + '.js' + function getDependencies(element) { + var deps = (element.getAttribute('data-dependencies') || '').trim(); + if (!deps) { + var parent = element.parentElement; + if (parent && parent.tagName.toLowerCase() === 'pre') { + deps = (parent.getAttribute('data-dependencies') || '').trim(); + } + } + return deps ? deps.split(/\s*,\s*/g) : []; } /** - * Tries to load the grammar(s) and once loaded, highlights the given element again. + * Returns whether the given language is currently loaded. * * @param {string} lang - * @param {HTMLElement} elt + * @returns {boolean} */ - function registerElement(lang, elt) { - if (lang in lang_aliases) { - lang = lang_aliases[lang]; + function isLoaded(lang) { + if (lang.indexOf('!') >= 0) { + // forced reload + return false; } - // Look for additional dependencies defined on the or
 tags
-		var deps = (elt.getAttribute('data-dependencies') || '').trim();
-		if (!deps) {
-			var parent = elt.parentElement;
-			if (parent && parent.tagName.toLowerCase() === 'pre') {
-				deps = (parent.getAttribute('data-dependencies') || '').trim();
-			}
+		lang = lang_aliases[lang] || lang; // resolve alias
+
+		if (lang in Prism.languages) {
+			// the given language is already loaded
+			return true;
 		}
 
-		loadLanguages(deps ? deps.split(/\s*,\s*/g) : [], function () {
-			loadLanguage(lang, function () {
-				Prism.highlightElement(elt);
-			});
-		});
+		// this will catch extensions like CSS extras that don't add a grammar to Prism.languages
+		var data = lang_data[lang];
+		return data && !data.error && data.loading === false;
+	}
+
+	/**
+	 * Returns the path to a grammar, using the language_path and use_minified config keys.
+	 *
+	 * @param {string} lang
+	 * @returns {string}
+	 */
+	function getLanguagePath(lang) {
+		return config.languages_path + 'prism-' + lang + (config.use_minified ? '.min' : '') + '.js'
 	}
 
 	/**
@@ -364,7 +376,7 @@
 		lang = lang.replace('!', '');
 		lang = lang_aliases[lang] || lang;
 
-		var load = function () {
+		function load() {
 			var data = lang_data[lang];
 			if (!data) {
 				data = lang_data[lang] = {
@@ -376,21 +388,25 @@
 				error: error
 			});
 
-			if (!force && Prism.languages[lang]) {
-				languageCallback(lang, "success");
+			if (!force && isLoaded(lang)) {
+				// the language is already loaded and we aren't forced to reload
+				languageCallback(lang, 'success');
 			} else if (!force && data.error) {
-				languageCallback(lang, "error");
+				// the language failed to load before and we don't reload
+				languageCallback(lang, 'error');
 			} else if (force || !data.loading) {
+				// the language isn't currently loading and/or we are forced to reload
 				data.loading = true;
-				var src = getLanguagePath(lang);
-				addScript(src, function () {
+				data.error = false;
+
+				addScript(getLanguagePath(lang), function () {
 					data.loading = false;
-					languageCallback(lang, "success");
+					languageCallback(lang, 'success');
 
 				}, function () {
 					data.loading = false;
 					data.error = true;
-					languageCallback(lang, "error");
+					languageCallback(lang, 'error');
 				});
 			}
 		};
@@ -423,10 +439,20 @@
 	}
 
 	Prism.hooks.add('complete', function (env) {
-		if (env.element && env.language && !env.grammar) {
-			if (env.language !== ignored_language) {
-				registerElement(env.language, env.element);
-			}
+		var element = env.element;
+		var language = env.language;
+		if (!element || !language || language === ignored_language) {
+			return;
+		}
+
+		var deps = getDependencies(element);
+		deps.push(language);
+
+		if (!deps.every(isLoaded)) {
+			// the language or some dependencies aren't loaded
+			loadLanguages(dependencies, function () {
+				Prism.highlightElement(element);
+			});
 		}
 	});
 
diff --git a/plugins/autoloader/prism-autoloader.min.js b/plugins/autoloader/prism-autoloader.min.js
index b8996496c6..d21f2d10d9 100644
--- a/plugins/autoloader/prism-autoloader.min.js
+++ b/plugins/autoloader/prism-autoloader.min.js
@@ -1 +1 @@
-!function(){if("undefined"!=typeof self&&self.Prism&&self.document&&document.createElement){var c={javascript:"clike",actionscript:"javascript",arduino:"cpp",aspnet:["markup","csharp"],bison:"c",c:"clike",csharp:"clike",cpp:"c",coffeescript:"javascript",crystal:"ruby","css-extras":"css",d:"clike",dart:"clike",django:"markup-templating",ejs:["javascript","markup-templating"],etlua:["lua","markup-templating"],erb:["ruby","markup-templating"],fsharp:"clike","firestore-security-rules":"clike",flow:"javascript",ftl:"markup-templating",gml:"clike",glsl:"c",go:"clike",groovy:"clike",haml:"ruby",handlebars:"markup-templating",haxe:"clike",hlsl:"c",java:"clike",javadoc:["markup","java","javadoclike"],jolie:"clike",jsdoc:["javascript","javadoclike"],"js-extras":"javascript",json5:"json",jsonp:"json","js-templates":"javascript",kotlin:"clike",latte:["clike","markup-templating","php"],less:"css",lilypond:"scheme",markdown:"markup","markup-templating":"markup",n4js:"javascript",nginx:"clike",objectivec:"c",opencl:"c",parser:"markup",php:["clike","markup-templating"],phpdoc:["php","javadoclike"],"php-extras":"php",plsql:"sql",processing:"clike",protobuf:"clike",pug:["markup","javascript"],purebasic:"clike",qml:"javascript",qore:"clike",racket:"scheme",jsx:["markup","javascript"],tsx:["jsx","typescript"],reason:"clike",ruby:"clike",sass:"css",scss:"css",scala:"java","shell-session":"bash",smarty:"markup-templating",solidity:"clike",soy:"markup-templating",sparql:"turtle",sqf:"clike",swift:"clike","t4-cs":["t4-templating","csharp"],"t4-vb":["t4-templating","vbnet"],tap:"yaml",tt2:["clike","markup-templating"],textile:"markup",twig:"markup",typescript:"javascript",vala:"clike",vbnet:"basic",velocity:"markup",wiki:"markup",xeora:"markup","xml-doc":"markup",xquery:"markup"},l={html:"markup",xml:"markup",svg:"markup",mathml:"markup",ssml:"markup",atom:"markup",rss:"markup",js:"javascript",g4:"antlr4",adoc:"asciidoc",shell:"bash",shortcode:"bbcode",rbnf:"bnf",cs:"csharp",dotnet:"csharp",coffee:"coffeescript",conc:"concurnas",jinja2:"django","dns-zone":"dns-zone-file",dockerfile:"docker",eta:"ejs",xlsx:"excel-formula",xls:"excel-formula",gamemakerlanguage:"gml",hs:"haskell",webmanifest:"json",tex:"latex",context:"latex",ly:"lilypond",emacs:"lisp",elisp:"lisp","emacs-lisp":"lisp",md:"markdown",moon:"moonscript",n4jsd:"n4js",objc:"objectivec",objectpascal:"pascal",px:"pcaxis",pcode:"peoplecode",pq:"powerquery",mscript:"powerquery",pbfasm:"purebasic",py:"python",rkt:"racket",rpy:"renpy",robot:"robotframework",rb:"ruby",sol:"solidity",sln:"solution-file",rq:"sparql",t4:"t4-cs",trig:"turtle",ts:"typescript",uscript:"unrealscript",uc:"unrealscript",vb:"visual-basic",xeoracube:"xeora",yml:"yaml"},n={},e="components/",a=Prism.util.currentScript();if(a){var t=/\bplugins\/autoloader\/prism-autoloader\.(?:min\.)js(?:\?[^\r\n/]*)?$/i,r=/(^|\/)[\w-]+\.(?:min\.)js(?:\?[^\r\n/]*)?$/i,s=a.getAttribute("data-autoloader-path");if(null!=s)e=s.trim().replace(/\/?$/,"/");else{var i=a.src;t.test(i)?e=i.replace(t,"components/"):r.test(i)&&(e=i.replace(r,"$1components/"))}}var p=Prism.plugins.autoloader={languages_path:e,use_minified:!0,loadLanguages:o};Prism.hooks.add("complete",function(e){e.element&&e.language&&!e.grammar&&"none"!==e.language&&function(e,a){e in l&&(e=l[e]);var t=(a.getAttribute("data-dependencies")||"").trim();if(!t){var r=a.parentElement;r&&"pre"===r.tagName.toLowerCase()&&(t=(r.getAttribute("data-dependencies")||"").trim())}o(t?t.split(/\s*,\s*/g):[],function(){m(e,function(){Prism.highlightElement(a)})})}(e.language,e.element)})}function o(e,a,t){"string"==typeof e&&(e=[e]);var r=e.length,s=0,i=!1;function c(){i||++s===r&&a&&a(e)}0!==r?e.forEach(function(e){m(e,c,function(){i||(i=!0,t&&t(e))})}):a&&setTimeout(a,0)}function m(a,t,r){var s=0<=a.indexOf("!");a=a.replace("!",""),a=l[a]||a;var e=function(){var e=n[a];if(e||(e=n[a]={callbacks:[]}),e.callbacks.push({success:t,error:r}),!s&&Prism.languages[a])u(a,"success");else if(!s&&e.error)u(a,"error");else if(s||!e.loading){e.loading=!0,function(e,a,t){var r=document.createElement("script");r.src=e,r.async=!0,r.onload=function(){document.body.removeChild(r),a&&a()},r.onerror=function(){document.body.removeChild(r),t&&t()},document.body.appendChild(r)}(function(e){return p.languages_path+"prism-"+e+(p.use_minified?".min":"")+".js"}(a),function(){e.loading=!1,u(a,"success")},function(){e.loading=!1,e.error=!0,u(a,"error")})}},i=c[a];i&&i.length?o(i,e,r):e()}function u(e,a){if(n[e]){for(var t=n[e].callbacks,r=0,s=t.length;r