Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom Class: New class adder feature #2075

Merged
merged 9 commits into from
Nov 16, 2019
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion components.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion components.json
Original file line number Diff line number Diff line change
Expand Up @@ -1099,7 +1099,7 @@
},
"custom-class": {
"title": "Custom Class",
"description": "Allows you to prefix Prism default classes (e.g. <code>.comment</code> will become <code>.namespace--comment</code>) or replace them with your defined ones (like <code>.editor__comment</code> or <code>.comment_7sh3a</code>).",
"description": "This plugin allows you to prefix Prism's default classes (<code>.comment</code> can become <code>.namespace--comment</code>) or replace them with your defined ones (like <code>.editor__comment</code>). You can even add new classes.",
"owner": "dvkndn",
"noCSS": true
},
Expand Down
77 changes: 65 additions & 12 deletions plugins/custom-class/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,44 +23,62 @@ <h1>Motivation</h1>

<ul>
<li>
You want to add namespace for all of them (like <code>.prism--comment</code>) to avoid conflict with your existing classes.
You want to add namespace for all of them (like <code>.prism--comment</code>) to avoid conflict with your existing classes.
</li>
<li>
You use a naming convention (like <a href="https://en.bem.info/method">BEM</a>). You want to write classes like <code>.editor__comment</code>.
</li>
<li>You use
<a href="https://github.com/css-modules/css-modules">CSS Modules</a>. You want to use your hashed classes, like <code>.comment_7sh3a</code>.
</li>
<li>You need more granular control about the classes of certain tokens.
You can define functions which will add new classes to tokens, so selectively change the highlighting of certain parts of your code.
</li>
</ul>
</section>

<h1>Features</h1>

<p>This plugin currently provides 2 features:</p>
<section>
<h1>How to use</h1>

<h2>1. Prefix all Prism classes with a string</h2>
<h2>Prefix all Prism classes</h2>

<code>Prism.plugins.customClass.prefix('prism--')</code>
<pre><code>Prism.plugins.customClass.prefix('prism--')</code></pre>

<h2>2. Replace some Prism classes with your defined ones via an object</h2>
<h2>Replace some Prism classes with ones you defined</h2>

<pre class="language-js"><code>Prism.plugins.customClass.map({
keyword: 'special-keyword',
string: 'string_ch29s',
comment: 'comment_93jsa'
});</code></pre>

<p>Object's keys are the tokens you want to replace (eg: <code>comment</code>), with their values being the classes you want to use (eg: <code>my-comment</code>). Tokens which are not specified will stay the same.</p>
<p>Object's keys are the classes you want to replace (eg: <code>comment</code>), with their values being the classes you want to use (eg: <code>my-comment</code>). Classes which are not specified will stay as they are.</p>

<p>Alternatively you can also pass a function that takes the original class and returns the mapped class. This function can also be used implement language specific mapped classes.<br>Example:</p>

<pre class="language-js"><code>Prism.plugins.customClass.map(function (className, language) {
<pre class="language-js"><code>Prism.plugins.customClass.map((className, language) => {
if (language === 'css') {
return cssSpecificMap[className] || className;
} else {
return className;
}
});</code></pre>

<h2>Add new classes</h2>

<p>You can add new classes with per-token and per-language precision.</p>

<pre class="language-js"><code>Prism.plugins.customClass.add(({content, type, language}) => {
if (content === 'content' && type === 'property' && language === 'css') {
return 'content-property';
}
});</code></pre>

<p><b>Note:</b> The given <code>content</code> is the inner HTML of the current token. All <code>&lt;</code> and <code>&amp;</code> characters are escaped and it might contain the HTML code of nested tokens.</p>

</section>

<section>
<h1>Notes</h1>

<ul>
Expand Down Expand Up @@ -96,26 +114,61 @@ <h2>CSS Modules Usage:</h2>
<section>
<h1>Example</h1>

<h2>Input</h2>
<h2>Prefix and map classes</h2>

<p>Input</p>
<pre class="language-markup"><code>&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;
var foo = 'bar';
&lt;/code&gt;&lt;/pre&gt;</code></pre>

<h2>Options</h2>
<p>Options</p>
<pre class="language-js"><code>Prism.plugins.customClass.map({
keyword: 'special-keyword',
string: 'my-string'
});
Prism.plugins.customClass.prefix('pr-');</code></pre>

<h2>Output</h2>
<p>Output</p>
<pre class="language-markup"><code>&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;
&lt;span class=&quot;pr-token pr-special-keyword&quot;&gt;var&lt;/span&gt;
foo
&lt;span class=&quot;pr-token pr-operator&quot;&gt;=&lt;/span&gt;
&lt;span class=&quot;pr-my-string&quot;&gt;'bar'&lt;/span&gt;
&lt;span class=&quot;pr-token pr-punctuation&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;</code></pre>

<h2>Add new classes</h2>

<p>Input</p>
<pre class="language-markup"><code>&lt;pre class=&quot;language-css&quot;&gt;&lt;code&gt;
a::after {
content: '\2b00 ';
opacity: .7;
}
&lt;/code&gt;&lt;/pre&gt;</code></pre>

<p>Options</p>
<pre class="language-js"><code>Prism.plugins.customClass.add(({language, type, content}) => {
if (content === 'content' && type === 'property' && language === 'css') {
return 'content-property';
}
});</code></pre>

<p>Output</p>
<pre class="language-markup"><code>&lt;pre class=" language-css">&lt;code class=" language-css">
&lt;span class="token selector">a::after&lt;/span>
&lt;span class="token punctuation">{&lt;/span>
&lt;span class="token property content-property">content&lt;/span>
&lt;span class="token punctuation">:&lt;/span>
&lt;span class="token string">'\2b00 '&lt;/span>
&lt;span class="token punctuation">;&lt;/span>
&lt;span class="token property">opacity&lt;/span>
&lt;span class="token punctuation">:&lt;/span>
.7
&lt;span class="token punctuation">;&lt;/span>
&lt;span class="token punctuation">}&lt;/span>
&lt;/code>&lt;/pre></code></pre>

</section>

<footer data-src="templates/footer.html" data-type="text/html"></footer>
Expand Down
137 changes: 82 additions & 55 deletions plugins/custom-class/prism-custom-class.js
Original file line number Diff line number Diff line change
@@ -1,68 +1,95 @@
(function(){
(function () {

if (
(typeof self === 'undefined' || !self.Prism) &&
(typeof global === 'undefined' || !global.Prism)
) {
return;
}

/**
* @callback ClassMapper
* @param {string} className
* @param {string} language
* @returns {string}
*/
/**
* @typedef CustomClassOptions
* @property {ClassMapper} classMap
* @property {string} prefixString
*/

/** @type {ClassMapper} */
var defaultClassMap = function (className) { return className; };

/** @type {CustomClassOptions} */
var options = {
classMap: defaultClassMap,
prefixString: ''
};
if (
(typeof self === 'undefined' || !self.Prism) &&
(typeof global === 'undefined' || !global.Prism)
) {
return;
}

Prism.plugins.customClass = {
/**
* Maps all class names using the given object or map function.
* @callback ClassMapper
* @param {string} className
* @param {string} language
* @returns {string}
*
* This does not affect the prefix.
* @callback ClassAdder
* @param {ClassAdderEnvironment} env
* @returns {undefined | string | string[]}
*
* @param {Object<string, string> | ClassMapper} classMap
* @typedef ClassAdderEnvironment
* @property {string} language
* @property {string} type
* @property {string} content
*/
map: function map(classMap) {
if (typeof classMap === 'function') {
options.classMap = classMap;
} else {
options.classMap = function (className) {
return classMap[className] || className;
};

// options

/** @type {ClassAdder | undefined} */
var adder;
/** @type {ClassMapper | undefined} */
var mapper;
/** @type {string} */
var prefixString = '';


Prism.plugins.customClass = {
/**
* Sets the function which can be used to add custom aliases to any token.
*
* @param {ClassAdder} classAdder
*/
add: function (classAdder) {
adder = classAdder;
},
/**
* Maps all class names using the given object or map function.
*
* This does not affect the prefix.
*
* @param {Object<string, string> | ClassMapper} classMapper
*/
map: function map(classMapper) {
if (typeof classMapper === 'function') {
mapper = classMapper;
} else {
mapper = function (className) {
return classMapper[className] || className;
};
}
},
/**
* Adds the given prefix to all class names.
*
* @param {string} string
*/
prefix: function prefix(string) {
prefixString = string;
}
},
/**
* Adds the given prefix to all class names.
*
* @param {string} string
*/
prefix: function prefix(string) {
options.prefixString = string;
}
}

Prism.hooks.add('wrap', function (env) {
if (options.classMap === defaultClassMap && !options.prefixString) {
return;
}
Prism.hooks.add('wrap', function (env) {
if (adder) {
var result = adder({
content: env.content,
type: env.type,
language: env.language
});

if (Array.isArray(result)) {
env.classes.push.apply(env.classes, result);
} else if (result) {
env.classes.push(result);
}
}

if (!mapper && !prefixString) {
return;
}

env.classes = env.classes.map(function (c) {
return options.prefixString + options.classMap(c, env.language);
env.classes = env.classes.map(function (c) {
return prefixString + mapper(c, env.language);
RunDevelopment marked this conversation as resolved.
Show resolved Hide resolved
});
});
});

})();
2 changes: 1 addition & 1 deletion plugins/custom-class/prism-custom-class.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.