UNPKG

4.17 kBJavaScriptView Raw
1(function(){
2 if (typeof self === 'undefined' || !self.Prism || !self.document) {
3 return;
4 }
5
6 var callbacks = [];
7 var map = {};
8 var noop = function() {};
9
10 Prism.plugins.toolbar = {};
11
12 /**
13 * @typedef ButtonOptions
14 * @property {string} text The text displayed.
15 * @property {string} [url] The URL of the link which will be created.
16 * @property {Function} [onClick] The event listener for the `click` event of the created button.
17 * @property {string} [className] The class attribute to include with element.
18 */
19
20 /**
21 * Register a button callback with the toolbar.
22 *
23 * @param {string} key
24 * @param {ButtonOptions|Function} opts
25 */
26 var registerButton = Prism.plugins.toolbar.registerButton = function (key, opts) {
27 var callback;
28
29 if (typeof opts === 'function') {
30 callback = opts;
31 } else {
32 callback = function (env) {
33 var element;
34
35 if (typeof opts.onClick === 'function') {
36 element = document.createElement('button');
37 element.type = 'button';
38 element.addEventListener('click', function () {
39 opts.onClick.call(this, env);
40 });
41 } else if (typeof opts.url === 'string') {
42 element = document.createElement('a');
43 element.href = opts.url;
44 } else {
45 element = document.createElement('span');
46 }
47
48 if (opts.className) {
49 element.classList.add(opts.className);
50 }
51
52 element.textContent = opts.text;
53
54 return element;
55 };
56 }
57
58 if (key in map) {
59 console.warn('There is a button with the key "' + key + '" registered already.');
60 return;
61 }
62
63 callbacks.push(map[key] = callback);
64 };
65
66 /**
67 * Returns the callback order of the given element.
68 *
69 * @param {HTMLElement} element
70 * @returns {string[] | undefined}
71 */
72 function getOrder(element) {
73 while (element) {
74 var order = element.getAttribute('data-toolbar-order');
75 if (order != null) {
76 order = order.trim();
77 if (order.length) {
78 return order.split(/\s*,\s*/g);
79 } else {
80 return [];
81 }
82 }
83 element = element.parentElement;
84 }
85 }
86
87 /**
88 * Post-highlight Prism hook callback.
89 *
90 * @param env
91 */
92 var hook = Prism.plugins.toolbar.hook = function (env) {
93 // Check if inline or actual code block (credit to line-numbers plugin)
94 var pre = env.element.parentNode;
95 if (!pre || !/pre/i.test(pre.nodeName)) {
96 return;
97 }
98
99 // Autoloader rehighlights, so only do this once.
100 if (pre.parentNode.classList.contains('code-toolbar')) {
101 return;
102 }
103
104 // Create wrapper for <pre> to prevent scrolling toolbar with content
105 var wrapper = document.createElement('div');
106 wrapper.classList.add('code-toolbar');
107 pre.parentNode.insertBefore(wrapper, pre);
108 wrapper.appendChild(pre);
109
110 // Setup the toolbar
111 var toolbar = document.createElement('div');
112 toolbar.classList.add('toolbar');
113
114 // order callbacks
115 var elementCallbacks = callbacks;
116 var order = getOrder(env.element);
117 if (order) {
118 elementCallbacks = order.map(function (key) {
119 return map[key] || noop;
120 });
121 }
122
123 elementCallbacks.forEach(function(callback) {
124 var element = callback(env);
125
126 if (!element) {
127 return;
128 }
129
130 var item = document.createElement('div');
131 item.classList.add('toolbar-item');
132
133 item.appendChild(element);
134 toolbar.appendChild(item);
135 });
136
137 // Add our toolbar to the currently created wrapper of <pre> tag
138 wrapper.appendChild(toolbar);
139 };
140
141 registerButton('label', function(env) {
142 var pre = env.element.parentNode;
143 if (!pre || !/pre/i.test(pre.nodeName)) {
144 return;
145 }
146
147 if (!pre.hasAttribute('data-label')) {
148 return;
149 }
150
151 var element, template;
152 var text = pre.getAttribute('data-label');
153 try {
154 // Any normal text will blow up this selector.
155 template = document.querySelector('template#' + text);
156 } catch (e) {}
157
158 if (template) {
159 element = template.content;
160 } else {
161 if (pre.hasAttribute('data-url')) {
162 element = document.createElement('a');
163 element.href = pre.getAttribute('data-url');
164 } else {
165 element = document.createElement('span');
166 }
167
168 element.textContent = text;
169 }
170
171 return element;
172 });
173
174 /**
175 * Register the toolbar with Prism.
176 */
177 Prism.hooks.add('complete', hook);
178})();