Commit 238f1163b59c51e4984595382f717cc88dbc35b9

Michael Schmidt 2020-02-08T17:07:33

Toolbar: `data-toolbar-order` is now inherited (#2205) The `data-toolbar-order` property is now inherited allowing for custom orderings/selections on an per-element basis.

diff --git a/plugins/toolbar/index.html b/plugins/toolbar/index.html
index 720a04c..31eb3e2 100644
--- a/plugins/toolbar/index.html
+++ b/plugins/toolbar/index.html
@@ -35,6 +35,8 @@
 
 	<pre><code>&lt;template id=&quot;my-label-button&quot;&gt;&lt;button onclick=&quot;console.log('This is an inline-handler');&quot;&gt;My button&lt;/button&gt;&lt;/template&gt;</code></pre>
 
+	<h2>Registering buttons</h2>
+
 	<p>For more flexibility, the Toolbar exposes a JavaScript function that can be used to register new buttons or labels to the Toolbar,
 		<code>Prism.plugins.toolbar.registerButton</code>.</p>
 
@@ -78,9 +80,17 @@
 
 	<p>The above function creates the Select Code button you see, and when you click it, the code gets highlighted.</p>
 
+	<h2>Ordering buttons</h2>
+
 	<p>By default, the buttons will be added to the code snippet in the order they were registered. If more control over
-		the order is needed, an HTML attribute can be added to the <code>body</code> tag with a comma-separated string indicating the
-		order.</p>
+		the order is needed, the <code>data-toolbar-order</code> attribute can be used. Given a comma-separated list of button names, it will ensure that these buttons will be displayed in the given order. <br>
+		Buttons not listed will not be displayed. This means that buttons can be disabled using this technique.</p>
+
+	<p>Example: The "Hello World!" button will appear before the "Select Code" button and the custom label button will not be displayed.</p>
+
+	<pre data-toolbar-order="hello-world,select-code" data-label="Hello World!"><code>&lt;pre data-toolbar-order="hello-world,select-code" data-label="Hello World!">&lt;code>&lt;/code>&lt;/pre></code></pre>
+
+	<p>The <code>data-toolbar-order</code> attribute is inherited, so you can define the button order for the whole document by adding the attribute to the <code>body</code> of the page.</p>
 
 	<pre><code>&lt;body data-toolbar-order="select-code,hello-world,label"&gt;</code></pre>
 </section>
diff --git a/plugins/toolbar/prism-toolbar.js b/plugins/toolbar/prism-toolbar.js
index 893bded..60be9ce 100644
--- a/plugins/toolbar/prism-toolbar.js
+++ b/plugins/toolbar/prism-toolbar.js
@@ -64,6 +64,27 @@
 	};
 
 	/**
+	 * Returns the callback order of the given element.
+	 *
+	 * @param {HTMLElement} element
+	 * @returns {string[] | undefined}
+	 */
+	function getOrder(element) {
+		while (element) {
+			var order = element.getAttribute('data-toolbar-order');
+			if (order != null) {
+				order = order.trim();
+				if (order.length) {
+					return order.split(/\s*,\s*/g);
+				} else {
+					return [];
+				}
+			}
+			element = element.parentElement;
+		}
+	}
+
+	/**
 	 * Post-highlight Prism hook callback.
 	 *
 	 * @param env
@@ -81,8 +102,8 @@
 		}
 
 		// Create wrapper for <pre> to prevent scrolling toolbar with content
-		var wrapper = document.createElement("div");
-		wrapper.classList.add("code-toolbar");
+		var wrapper = document.createElement('div');
+		wrapper.classList.add('code-toolbar');
 		pre.parentNode.insertBefore(wrapper, pre);
 		wrapper.appendChild(pre);
 
@@ -90,13 +111,16 @@
 		var toolbar = document.createElement('div');
 		toolbar.classList.add('toolbar');
 
-		if (document.body.hasAttribute('data-toolbar-order')) {
-			callbacks = document.body.getAttribute('data-toolbar-order').split(',').map(function(key) {
+		// order callbacks
+		var elementCallbacks = callbacks;
+		var order = getOrder(env.element);
+		if (order) {
+			elementCallbacks = order.map(function (key) {
 				return map[key] || noop;
 			});
 		}
 
-		callbacks.forEach(function(callback) {
+		elementCallbacks.forEach(function(callback) {
 			var element = callback(env);
 
 			if (!element) {
diff --git a/plugins/toolbar/prism-toolbar.min.js b/plugins/toolbar/prism-toolbar.min.js
index 3b9f082..e692394 100644
--- a/plugins/toolbar/prism-toolbar.min.js
+++ b/plugins/toolbar/prism-toolbar.min.js
@@ -1 +1 @@
-!function(){if("undefined"!=typeof self&&self.Prism&&self.document){var r=[],i={},a=function(){};Prism.plugins.toolbar={};var t=Prism.plugins.toolbar.registerButton=function(t,a){var e;e="function"==typeof a?a:function(t){var e;return"function"==typeof a.onClick?((e=document.createElement("button")).type="button",e.addEventListener("click",function(){a.onClick.call(this,t)})):"string"==typeof a.url?(e=document.createElement("a")).href=a.url:e=document.createElement("span"),a.className&&e.classList.add(a.className),e.textContent=a.text,e},t in i?console.warn('There is a button with the key "'+t+'" registered already.'):r.push(i[t]=e)},e=Prism.plugins.toolbar.hook=function(n){var t=n.element.parentNode;if(t&&/pre/i.test(t.nodeName)&&!t.parentNode.classList.contains("code-toolbar")){var e=document.createElement("div");e.classList.add("code-toolbar"),t.parentNode.insertBefore(e,t),e.appendChild(t);var o=document.createElement("div");o.classList.add("toolbar"),document.body.hasAttribute("data-toolbar-order")&&(r=document.body.getAttribute("data-toolbar-order").split(",").map(function(t){return i[t]||a})),r.forEach(function(t){var e=t(n);if(e){var a=document.createElement("div");a.classList.add("toolbar-item"),a.appendChild(e),o.appendChild(a)}}),e.appendChild(o)}};t("label",function(t){var e=t.element.parentNode;if(e&&/pre/i.test(e.nodeName)&&e.hasAttribute("data-label")){var a,n,o=e.getAttribute("data-label");try{n=document.querySelector("template#"+o)}catch(t){}return n?a=n.content:(e.hasAttribute("data-url")?(a=document.createElement("a")).href=e.getAttribute("data-url"):a=document.createElement("span"),a.textContent=o),a}}),Prism.hooks.add("complete",e)}}();
\ No newline at end of file
+!function(){if("undefined"!=typeof self&&self.Prism&&self.document){var i=[],l={},c=function(){};Prism.plugins.toolbar={};var e=Prism.plugins.toolbar.registerButton=function(e,n){var t;t="function"==typeof n?n:function(e){var t;return"function"==typeof n.onClick?((t=document.createElement("button")).type="button",t.addEventListener("click",function(){n.onClick.call(this,e)})):"string"==typeof n.url?(t=document.createElement("a")).href=n.url:t=document.createElement("span"),n.className&&t.classList.add(n.className),t.textContent=n.text,t},e in l?console.warn('There is a button with the key "'+e+'" registered already.'):i.push(l[e]=t)},t=Prism.plugins.toolbar.hook=function(a){var e=a.element.parentNode;if(e&&/pre/i.test(e.nodeName)&&!e.parentNode.classList.contains("code-toolbar")){var t=document.createElement("div");t.classList.add("code-toolbar"),e.parentNode.insertBefore(t,e),t.appendChild(e);var r=document.createElement("div");r.classList.add("toolbar");var n=i,o=function(e){for(;e;){var t=e.getAttribute("data-toolbar-order");if(null!=t)return(t=t.trim()).length?t.split(/\s*,\s*/g):[];e=e.parentElement}}(a.element);o&&(n=o.map(function(e){return l[e]||c})),n.forEach(function(e){var t=e(a);if(t){var n=document.createElement("div");n.classList.add("toolbar-item"),n.appendChild(t),r.appendChild(n)}}),t.appendChild(r)}};e("label",function(e){var t=e.element.parentNode;if(t&&/pre/i.test(t.nodeName)&&t.hasAttribute("data-label")){var n,a,r=t.getAttribute("data-label");try{a=document.querySelector("template#"+r)}catch(e){}return a?n=a.content:(t.hasAttribute("data-url")?(n=document.createElement("a")).href=t.getAttribute("data-url"):n=document.createElement("span"),n.textContent=r),n}}),Prism.hooks.add("complete",t)}}();
\ No newline at end of file