Added new Filter highlightAll plugin (#2074)

This adds a new plugin to Prism which allows users to filter which elements will be highlighted by the `highlightAll` and `highlightAllUnder` methods.
This commit is contained in:
Michael Schmidt 2019-12-02 14:10:53 +01:00 committed by GitHub
parent 9908ca69e7
commit a7f7009019
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 328 additions and 44 deletions

File diff suppressed because one or more lines are too long

View File

@ -1209,6 +1209,12 @@
"description": "Highlights the code inside diff blocks.",
"owner": "RunDevelopment",
"require": "diff"
},
"filter-highlight-all": {
"title": "Filter highlightAll",
"description": "Filters the elements the <code>highlightAll</code> and <code>highlightAllUnder</code> methods actually highlight.",
"owner": "RunDevelopment",
"noCSS": true
}
}
}

View File

@ -18,24 +18,6 @@ var Prism = (function (_self){
var lang = /\blang(?:uage)?-([\w-]+)\b/i;
var uniqueId = 0;
/**
* Returns the Prism language of the given element set by a `language-xxxx` or `lang-xxxx` class.
*
* If no language is set for the element or the element is `null` or `undefined`, `none` will be returned.
*
* @param {Element} element
* @returns {string}
*/
function getLanguage(element) {
while (element && !lang.test(element.className)) {
element = element.parentNode;
}
if (element) {
return (element.className.match(lang) || [, 'none'])[1].toLowerCase();
}
return 'none';
}
var _ = {
manual: _self.Prism && _self.Prism.manual,
@ -103,6 +85,24 @@ var _ = {
}
},
/**
* Returns the Prism language of the given element set by a `language-xxxx` or `lang-xxxx` class.
*
* If no language is set for the element or the element is `null` or `undefined`, `none` will be returned.
*
* @param {Element} element
* @returns {string}
*/
getLanguage: function (element) {
while (element && !lang.test(element.className)) {
element = element.parentElement;
}
if (element) {
return (element.className.match(lang) || [, 'none'])[1].toLowerCase();
}
return 'none';
},
/**
* Returns the script element that is currently executing.
*
@ -236,21 +236,24 @@ var _ = {
highlightAllUnder: function(container, async, callback) {
var env = {
callback: callback,
container: container,
selector: 'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'
};
_.hooks.run('before-highlightall', env);
var elements = container.querySelectorAll(env.selector);
env.elements = Array.prototype.slice.apply(env.container.querySelectorAll(env.selector));
for (var i=0, element; element = elements[i++];) {
_.hooks.run('before-all-elements-highlight', env);
for (var i = 0, element; element = env.elements[i++];) {
_.highlightElement(element, async === true, env.callback);
}
},
highlightElement: function(element, async, callback) {
// Find language
var language = getLanguage(element);
var language = _.util.getLanguage(element);
var grammar = _.languages[language];
// Set language on the element, if not present

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,146 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="favicon.png" />
<title>Filter highlightAll ▲ Prism plugins</title>
<base href="../.." />
<link rel="stylesheet" href="style.css" />
<link rel="stylesheet" href="themes/prism.css" data-noprefix />
<script src="scripts/prefixfree.min.js"></script>
<script>var _gaq = [['_setAccount', 'UA-33746269-1'], ['_trackPageview']];</script>
<script src="https://www.google-analytics.com/ga.js" async></script>
<style>
dt {
font-size: 100%;
}
</style>
</head>
<body>
<header data-plugin-header="filter-highlight-all"></header>
<section class="language-typescript">
<h1>How to use</h1>
<p>Filter highlightAll provides you with ways to filter the element the <code>highlightAll</code> and <code>highlightAllUnder</code> methods actually highlight. This can be very useful when you use Prism's automatic highlighting when loading the page but want to exclude certain code blocks.</p>
</section>
<section class="language-typescript">
<h1>API</h1>
<p>In <code>Prism.plugins.filterHighlightAll</code> you can find the following:</p>
<dl>
<dt><code>add(condition: (value: { element, language: string }) => boolean): void</code></dt>
<dd>
Adds a new filter which will only allow an element to be highlighted if the given function returns <code>true</code> for that element. <br>
This can be used to define a custom language filter.
</dd>
<dt><code>addSelector(selector: string): void</code></dt>
<dd>
Adds a new filter which will only allow an element to be highlighted if the element matches the given CSS selector.
</dd>
<dt><code>reject.add(condition: (value: { element, language: string }) => boolean): void</code></dt>
<dd>
Same as <code>add</code>, but only elements which do <strong>not</strong> fulfill the condition will be highlighted.
</dd>
<dt><code>reject.addSelector(selector: string): void</code></dt>
<dd>
Same as <code>addSelector</code>, but only elements which do <strong>not</strong> match the selector will be highlighted.
</dd>
<dt><code>filterKnown: boolean = false</code></dt>
<dd>
Set this to <code>true</code> to only allow known languages.
Code blocks without a set language or an unknown language will not be highlighted.
</dd>
</dl>
<p>An element will only be highlighted by the <code>highlightAll</code> and <code>highlightAllUnder</code> methods if all of the above accept the element.</p>
<h2>Attributes</h2>
<p>You can also add the following <code class="language-none">data-*</code> attributes to the script which contains the Filter highlightAll plugin.</p>
<dl>
<dt><code class="language-markup">&lt;script src="..." data-filter-selector="&lt;css selector>"></code></dt>
<dd>
This attribute is a shorthand for <code>Prism.plugins.filterHighlightAll.addSelector</code>.
The value of the attribute will be passed as is to the <code>addSelector</code> function.
</dd>
<dt><code class="language-markup">&lt;script src="..." data-reject-selector="&lt;css selector>"></code></dt>
<dd>
This attribute is a shorthand for <code>Prism.plugins.filterHighlightAll.reject.addSelector</code>.
The value of the attribute will be passed as is to the <code>rejectSelector</code> function.
</dd>
<dt><code class="language-markup">&lt;script src="..." data-filter-known></code></dt>
<dd>
This attribute can be used to set the value of <code>Prism.plugins.filterHighlightAll.filterKnown</code>.
<code>filterKnown</code> will be set to <code>true</code> if the attribute is present, <code>false</code> otherwise.
</dd>
</dl>
</section>
<section>
<h1>Examples</h1>
<p>The following code is used to define a filter on this page.</p>
<pre><code class="language-javascript">// &lt;code> elements with a .no-highlight class will be ignored
Prism.plugins.filterHighlightAll.reject.addSelector('code.no-highlight');
Prism.plugins.filterHighlightAll.reject.addSelector('pre.no-highlight > code');
// don't highlight CSS code
Prism.plugins.filterHighlightAll.add(function (env) {
return env.language !== 'css';
});</code></pre>
<p>The results:</p>
<pre class="language-javascript no-highlight"><code class="language-javascript">let foo = "I'm not being highlighted";</code></pre>
<pre class="language-css"><code class="language-css">a.link::after {
content: 'also not being highlighted';
color: #F00;
}</code></pre>
<p>Prism will ignore these blocks, so you can even define your own static highlighting which Prism would normally remove.</p>
<pre class="language-css"><code class="language-css">a.link::before {
cont<span class="token selector">ent: 'I just do my o</span>wn highlighted';
color: <span class="token constant">#F00</span>;
}</code></pre>
</section>
<footer data-src="templates/footer.html" data-type="text/html"></footer>
<script src="prism.js"></script>
<script src="components/prism-typescript.js"></script>
<script src="plugins/filter-highlight-all/prism-filter-highlight-all.js"></script>
<script src="scripts/utopia.js"></script>
<script src="components.js"></script>
<script src="scripts/code.js"></script>
<script>
// elements with a .no-highlight class will be ignored
Prism.plugins.filterHighlightAll.reject.addSelector('code.no-highlight');
Prism.plugins.filterHighlightAll.reject.addSelector('pre.no-highlight > code');
// don't highlight CSS code
Prism.plugins.filterHighlightAll.add(function (env) {
return env.language !== 'css';
});
</script>
</body>
</html>

View File

@ -0,0 +1,125 @@
(function () {
if (typeof self !== 'undefined' && !self.Prism) {
return;
}
// https://developer.mozilla.org/en-US/docs/Web/API/Element/matches#Polyfill
if (!Element.prototype.matches) {
Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
}
var script = Prism.util.currentScript();
/**
* @type {Array<(element: HTMLElement) => boolean>}
*/
var filters = [];
var config = Prism.plugins.filterHighlightAll = {
/**
* Adds a new filter for the elements of `highlightAll` and `highlightAllUnder` such that only elements for
* which the given function returns `true` will be highlighted.
*
* @param {(value: { element: HTMLElement, language: string }) => boolean} condition
*/
add: function (condition) {
filters.push(function (element) {
return condition({
element: element,
language: Prism.util.getLanguage(element)
});
});
},
/**
* Adds a new filter for the elements of `highlightAll` and `highlightAllUnder` such that only elements that
* match the given CSS selection will be highlighted.
*
* @param {string} selector
*/
addSelector: function (selector) {
filters.push(function (element) {
return element.matches(selector);
});
},
reject: {
/**
* Adds a new filter for the elements of `highlightAll` and `highlightAllUnder` such that only elements for
* which the given function returns `false` will be highlighted.
*
* @param {(value: { element: HTMLElement, language: string }) => boolean} condition
*/
add: function (condition) {
filters.push(function (element) {
return !condition({
element: element,
language: Prism.util.getLanguage(element)
});
});
},
/**
* Adds a new filter for the elements of `highlightAll` and `highlightAllUnder` such that only elements that do
* not match the given CSS selection will be highlighted.
*
* @param {string} selector
*/
addSelector: function (selector) {
filters.push(function (element) {
return !element.matches(selector);
});
},
},
/**
* Filters the elements of `highlightAll` and `highlightAllUnder` such that only elements with a known language
* will be highlighted. All elements with an unset or unknown language will be ignored.
*
* __Note:__ This will effectively disable the AutoLoader plugin.
*
* @type {boolean}
*/
filterKnown: !!script && script.hasAttribute('data-filter-known')
};
config.add(function filterKnown(env) {
return !config.filterKnown || typeof Prism.languages[env.language] === 'object';
});
if (script) {
var attr;
if (attr = script.getAttribute('data-filter-selector')) {
config.addSelector(attr);
}
if (attr = script.getAttribute('data-reject-selector')) {
config.reject.addSelector(attr);
}
}
/**
* Applies all filters to the given element and returns true if and only if every filter returned true on the
* given element.
*
* @param {HTMLElement} element
* @returns {boolean}
*/
function combinedFilter(element) {
for (var i = 0, l = filters.length; i < l; i++) {
if (!filters[i](element)) {
return false;
}
}
return true;
}
Prism.hooks.add('before-all-elements-highlight', function (env) {
env.elements = env.elements.filter(combinedFilter);
});
}());

View File

@ -0,0 +1 @@
!function(){if("undefined"==typeof self||self.Prism){Element.prototype.matches||(Element.prototype.matches=Element.prototype.msMatchesSelector||Element.prototype.webkitMatchesSelector);var e,t=Prism.util.currentScript(),r=[],n=Prism.plugins.filterHighlightAll={add:function(t){r.push(function(e){return t({element:e,language:Prism.util.getLanguage(e)})})},addSelector:function(t){r.push(function(e){return e.matches(t)})},reject:{add:function(t){r.push(function(e){return!t({element:e,language:Prism.util.getLanguage(e)})})},addSelector:function(t){r.push(function(e){return!e.matches(t)})}},filterKnown:!!t&&t.hasAttribute("data-filter-known")};if(n.add(function(e){return!n.filterKnown||"object"==typeof Prism.languages[e.language]}),t)(e=t.getAttribute("data-filter-selector"))&&n.addSelector(e),(e=t.getAttribute("data-reject-selector"))&&n.reject.addSelector(e);Prism.hooks.add("before-all-elements-highlight",function(e){e.elements=e.elements.filter(i)})}function i(e){for(var t=0,n=r.length;t<n;t++)if(!r[t](e))return!1;return!0}}();

View File

@ -23,24 +23,6 @@ var Prism = (function (_self){
var lang = /\blang(?:uage)?-([\w-]+)\b/i;
var uniqueId = 0;
/**
* Returns the Prism language of the given element set by a `language-xxxx` or `lang-xxxx` class.
*
* If no language is set for the element or the element is `null` or `undefined`, `none` will be returned.
*
* @param {Element} element
* @returns {string}
*/
function getLanguage(element) {
while (element && !lang.test(element.className)) {
element = element.parentNode;
}
if (element) {
return (element.className.match(lang) || [, 'none'])[1].toLowerCase();
}
return 'none';
}
var _ = {
manual: _self.Prism && _self.Prism.manual,
@ -108,6 +90,24 @@ var _ = {
}
},
/**
* Returns the Prism language of the given element set by a `language-xxxx` or `lang-xxxx` class.
*
* If no language is set for the element or the element is `null` or `undefined`, `none` will be returned.
*
* @param {Element} element
* @returns {string}
*/
getLanguage: function (element) {
while (element && !lang.test(element.className)) {
element = element.parentElement;
}
if (element) {
return (element.className.match(lang) || [, 'none'])[1].toLowerCase();
}
return 'none';
},
/**
* Returns the script element that is currently executing.
*
@ -241,21 +241,24 @@ var _ = {
highlightAllUnder: function(container, async, callback) {
var env = {
callback: callback,
container: container,
selector: 'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'
};
_.hooks.run('before-highlightall', env);
var elements = container.querySelectorAll(env.selector);
env.elements = Array.prototype.slice.apply(env.container.querySelectorAll(env.selector));
for (var i=0, element; element = elements[i++];) {
_.hooks.run('before-all-elements-highlight', env);
for (var i = 0, element; element = env.elements[i++];) {
_.highlightElement(element, async === true, env.callback);
}
},
highlightElement: function(element, async, callback) {
// Find language
var language = getLanguage(element);
var language = _.util.getLanguage(element);
var grammar = _.languages[language];
// Set language on the element, if not present