feat: Native emoji w/ image-based fallbacks and improved parsing (#1746)
* Render native emoji with image fallback Fix #779 * Deprecate emoji plugin * Add emoji tests * Remove console.log statement * Fix emoji image alt attribute * Set nativeEmoji to false by default (non-breaking) * Fix parsing emoji in HTML comments and script tags * Add nativeEmoji and update noEmoji details * Add Emoji plugin deprecation notice * Fix ESLint issues * Create build:emoji task - Auto-generate emoji data from GitHub API - Auto-generate emoji markdown for website - Add emoji page to navigation * Fix rendering of GitHub emoji without unicode * Adjust and match size of native and image emoji * Update emoji test snapshot * Update docs test snapshot * Fix ci/codesandbox error * Update native emoji font-stack * Fix rendering of native multi-character emoji * Kick GitHub Workflow * Replace rollup’s uglify plugin with terser * Switch “npm ci” instead of “npm i” for stability * Change emoji data from default to named export * Revert "Replace rollup’s uglify plugin with terser" This reverts commit7ba8513636
. * Revert "Switch “npm ci” instead of “npm i” for stability" This reverts commitd52b476a38
. * Revert "Change emoji data from default to named export" This reverts commit3f2dd467cf
. * Specify codesandbox template and node version * Update codesandbox config * Revert "Revert "Replace rollup’s uglify plugin with terser"" This reverts commite06fed49f0
. * Revert "Revert "Revert "Replace rollup’s uglify plugin with terser""" This reverts commit27d49521f6
. * Update codesandbox config * Revert "Update codesandbox config" This reverts commit5120dd23d4
. * Fix codesandbox uglify error * Emoji docs tweaks * Restore and update emoji plugin code * Restore and update emoji plugin docs * Prettier updates * Match lowercase shortcodes only Co-authored-by: Koy Zhuang <369491420@qq.com>
This commit is contained in:
parent
fd883e62de
commit
35002c92b7
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"sandboxes": ["2d17z"],
|
||||
"packages": [".", "packages/docsify-server-renderer"]
|
||||
"packages": [".", "packages/docsify-server-renderer"],
|
||||
"node": "16"
|
||||
}
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
const axios = require('axios');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const filePaths = {
|
||||
emojiMarkdown: path.resolve(process.cwd(), 'docs', 'emoji.md'),
|
||||
emojiJS: path.resolve(
|
||||
process.cwd(),
|
||||
'src',
|
||||
'core',
|
||||
'render',
|
||||
'emojify-data.js'
|
||||
),
|
||||
};
|
||||
|
||||
async function getEmojiData() {
|
||||
const emojiDataURL = 'https://api.github.com/emojis';
|
||||
const response = await axios.get(emojiDataURL);
|
||||
const baseURL = Object.values(response.data)
|
||||
.find(url => /unicode\//)
|
||||
.split('unicode/')[0];
|
||||
const data = { ...response.data };
|
||||
|
||||
// Remove base URL from emoji URLs
|
||||
Object.entries(data).forEach(
|
||||
([key, value]) => (data[key] = value.replace(baseURL, ''))
|
||||
);
|
||||
|
||||
return {
|
||||
baseURL,
|
||||
data,
|
||||
};
|
||||
}
|
||||
|
||||
function writeEmojiPage(emojiData) {
|
||||
const emojiPage =
|
||||
(fs.existsSync(filePaths.emojiMarkdown) &&
|
||||
fs.readFileSync(filePaths.emojiMarkdown, 'utf8')) ||
|
||||
`<!-- START -->\n\n<!-- END -->`;
|
||||
const emojiRegEx = /(<!--\s*START.*-->\n)([\s\S]*)(\n<!--\s*END.*-->)/;
|
||||
const emojiMatch = emojiPage.match(emojiRegEx);
|
||||
const emojiMarkdownStart = emojiMatch[1].trim();
|
||||
const emojiMarkdown = emojiMatch[2].trim();
|
||||
const emojiMarkdownEnd = emojiMatch[3].trim();
|
||||
const newEmojiMarkdown = Object.keys(emojiData.data)
|
||||
.reduce(
|
||||
(preVal, curVal) =>
|
||||
(preVal += `:${curVal}: ` + '`' + `:${curVal}:` + '`' + '\n\n'),
|
||||
''
|
||||
)
|
||||
.trim();
|
||||
|
||||
if (emojiMarkdown !== newEmojiMarkdown) {
|
||||
const newEmojiPage = emojiPage.replace(
|
||||
emojiMatch[0],
|
||||
`${emojiMarkdownStart}\n${newEmojiMarkdown}\n${emojiMarkdownEnd}`
|
||||
);
|
||||
|
||||
fs.writeFileSync(filePaths.emojiMarkdown, newEmojiPage);
|
||||
console.info(`- Created new file: ${filePaths.emojiMarkdown}`);
|
||||
} else {
|
||||
console.info(`- No changes to file: ${filePaths.emojiMarkdown}`);
|
||||
}
|
||||
}
|
||||
|
||||
function writeEmojiJS(emojiData) {
|
||||
const emojiJS =
|
||||
fs.existsSync(filePaths.emojiJS) &&
|
||||
fs.readFileSync(filePaths.emojiJS, 'utf8');
|
||||
const newEmojiJS = `export default ${JSON.stringify(emojiData, {}, 2)}`;
|
||||
|
||||
if (!emojiJS || emojiJS !== newEmojiJS) {
|
||||
fs.writeFileSync(filePaths.emojiJS, newEmojiJS);
|
||||
console.info(`- Created new file: ${filePaths.emojiJS}`);
|
||||
} else {
|
||||
console.info(`- No changes to file: ${filePaths.emojiJS}`);
|
||||
}
|
||||
}
|
||||
|
||||
(async () => {
|
||||
console.log('Build emoji');
|
||||
|
||||
try {
|
||||
const emojiData = await getEmojiData();
|
||||
|
||||
writeEmojiPage(emojiData);
|
||||
writeEmojiJS(emojiData);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
})();
|
|
@ -13,6 +13,7 @@
|
|||
- [Write a Plugin](write-a-plugin.md)
|
||||
- [Markdown configuration](markdown.md)
|
||||
- [Language highlighting](language-highlight.md)
|
||||
- [Emoji](emoji.md)
|
||||
|
||||
- Guide
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ The config can also be defined as a function, in which case the first argument i
|
|||
|
||||
```html
|
||||
<script>
|
||||
window.$docsify = function(vm) {
|
||||
window.$docsify = function (vm) {
|
||||
return {
|
||||
markdown: {
|
||||
renderer: {
|
||||
|
@ -319,14 +319,14 @@ window.$docsify = {
|
|||
markdown: {
|
||||
smartypants: true,
|
||||
renderer: {
|
||||
link: function() {
|
||||
link: function () {
|
||||
// ...
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// function
|
||||
markdown: function(marked, renderer) {
|
||||
markdown: function (marked, renderer) {
|
||||
// ...
|
||||
return marked;
|
||||
},
|
||||
|
@ -398,11 +398,65 @@ window.$docsify = {
|
|||
|
||||
Note that if you are running an external script, e.g. an embedded jsfiddle demo, make sure to include the [external-script](plugins.md?id=external-script) plugin.
|
||||
|
||||
## nativeEmoji
|
||||
|
||||
- type: `Boolean`
|
||||
- default: `false`
|
||||
|
||||
Render emoji shorthand codes using GitHub-style emoji images or platform-native emoji characters.
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
nativeEmoji: true,
|
||||
};
|
||||
```
|
||||
|
||||
```markdown
|
||||
:smile:
|
||||
:partying_face:
|
||||
:joy:
|
||||
:+1:
|
||||
:-1:
|
||||
```
|
||||
|
||||
GitHub-style images when `false`:
|
||||
|
||||
<output data-lang="output">
|
||||
<img class="emoji" src="https://github.githubassets.com/images/icons/emoji/unicode/1f604.png" alt="smile">
|
||||
<img class="emoji" src="https://github.githubassets.com/images/icons/emoji/unicode/1f973.png" alt="partying_face">
|
||||
<img class="emoji" src="https://github.githubassets.com/images/icons/emoji/unicode/1f602.png" alt="joy">
|
||||
<img class="emoji" src="https://github.githubassets.com/images/icons/emoji/unicode/1f44d.png" alt="+1">
|
||||
<img class="emoji" src="https://github.githubassets.com/images/icons/emoji/unicode/1f44e.png" alt="-1">
|
||||
</output>
|
||||
|
||||
Platform-native characters when `true`:
|
||||
|
||||
<output data-lang="output">
|
||||
<span class="emoji">😄︎</span>
|
||||
<span class="emoji">🥳︎</span>
|
||||
<span class="emoji">😂︎</span>
|
||||
<span class="emoji">👍︎</span>
|
||||
<span class="emoji">👎︎</span>
|
||||
</output>
|
||||
|
||||
To render shorthand codes as text, replace `:` characters with the `:` HTML entity.
|
||||
|
||||
```markdown
|
||||
:100:
|
||||
```
|
||||
|
||||
<output data-lang="output">
|
||||
|
||||
:100:
|
||||
|
||||
</output>
|
||||
|
||||
## noEmoji
|
||||
|
||||
- type: `Boolean`
|
||||
- default: `false`
|
||||
|
||||
Disabled emoji parse.
|
||||
Disabled emoji parsing and render all emoji shorthand as text.
|
||||
|
||||
```js
|
||||
window.$docsify = {
|
||||
|
@ -410,7 +464,31 @@ window.$docsify = {
|
|||
};
|
||||
```
|
||||
|
||||
?> If this option is `false` but you don't want to emojify some specific colons, [refer to this](https://github.com/docsifyjs/docsify/issues/742#issuecomment-586313143)
|
||||
```markdown
|
||||
:100:
|
||||
```
|
||||
|
||||
<output data-lang="output">
|
||||
|
||||
:100:
|
||||
|
||||
</output>
|
||||
|
||||
To disable emoji parsing of individual shorthand codes, replace `:` characters with the `:` HTML entity.
|
||||
|
||||
```markdown
|
||||
:100:
|
||||
|
||||
:100:
|
||||
```
|
||||
|
||||
<output data-lang="output">
|
||||
|
||||
:100:
|
||||
|
||||
:100:
|
||||
|
||||
</output>
|
||||
|
||||
## mergeNavbar
|
||||
|
||||
|
@ -435,7 +513,7 @@ See https://github.com/lukeed/tinydate#patterns
|
|||
window.$docsify = {
|
||||
formatUpdated: '{MM}/{DD} {HH}:{mm}',
|
||||
|
||||
formatUpdated: function(time) {
|
||||
formatUpdated: function (time) {
|
||||
// ...
|
||||
|
||||
return time;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -4,12 +4,13 @@
|
|||
|
||||
By default, the hyperlink on the current page is recognized and the content is saved in `localStorage`. You can also specify the path to the files.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```html
|
||||
<script>
|
||||
window.$docsify = {
|
||||
search: 'auto', // default
|
||||
|
||||
search : [
|
||||
search: [
|
||||
'/', // => /README.md
|
||||
'/guide', // => /guide.md
|
||||
'/get-started', // => /get-started.md
|
||||
|
@ -25,7 +26,7 @@ By default, the hyperlink on the current page is recognized and the content is s
|
|||
// Localization
|
||||
placeholder: {
|
||||
'/zh-cn/': '搜索',
|
||||
'/': 'Type to search'
|
||||
'/': 'Type to search',
|
||||
},
|
||||
|
||||
noData: 'No Results!',
|
||||
|
@ -33,7 +34,7 @@ By default, the hyperlink on the current page is recognized and the content is s
|
|||
// Localization
|
||||
noData: {
|
||||
'/zh-cn/': '找不到结果',
|
||||
'/': 'No Results'
|
||||
'/': 'No Results',
|
||||
},
|
||||
|
||||
// Headline depth, 1 - 6
|
||||
|
@ -54,9 +55,9 @@ By default, the hyperlink on the current page is recognized and the content is s
|
|||
|
||||
// You can provide a regexp to match prefixes. In this case,
|
||||
// the matching substring will be used to identify the index
|
||||
pathNamespaces: /^(\/(zh-cn|ru-ru))?(\/(v1|v2))?/
|
||||
}
|
||||
}
|
||||
pathNamespaces: /^(\/(zh-cn|ru-ru))?(\/(v1|v2))?/,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify/lib/docsify.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/search.min.js"></script>
|
||||
|
@ -75,8 +76,8 @@ Install the plugin and configure the track id.
|
|||
```html
|
||||
<script>
|
||||
window.$docsify = {
|
||||
ga: 'UA-XXXXX-Y'
|
||||
}
|
||||
ga: 'UA-XXXXX-Y',
|
||||
};
|
||||
</script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify/lib/docsify.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/ga.min.js"></script>
|
||||
|
@ -84,21 +85,22 @@ Install the plugin and configure the track id.
|
|||
|
||||
Configure by `data-ga`.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```html
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify/lib/docsify.min.js" data-ga="UA-XXXXX-Y"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/ga.min.js"></script>
|
||||
```
|
||||
|
||||
## emoji
|
||||
## Emoji
|
||||
|
||||
The default is to support parsing emoji. For example `:100:` will be parsed to :100:. But it is not precise because there is no matching non-emoji string. If you need to correctly parse the emoji string, you need install this plugin.
|
||||
Renders a larger collection of emoji shorthand codes. Without this plugin, Docsify is able to render only a limited number of emoji shorthand codes.
|
||||
|
||||
!> Deprecated as of v4.13. Docsify no longer requires this plugin for full emoji support.
|
||||
|
||||
```html
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/emoji.min.js"></script>
|
||||
```
|
||||
|
||||
?> If you don't want to parse to emoji, you can use __colon_<span>_</span> or `:`. If you need to use in the title, we recommend using `:`. For example, `:100:`
|
||||
|
||||
## External Script
|
||||
|
||||
If the script on the page is an external one (imports a js file via `src` attribute), you'll need this plugin to make it work.
|
||||
|
@ -118,7 +120,7 @@ Medium's image zoom. Based on [medium-zoom](https://github.com/francoischalifour
|
|||
Exclude the special image
|
||||
|
||||
```markdown
|
||||
![](image.png ":no-zoom")
|
||||
![](image.png ':no-zoom')
|
||||
```
|
||||
|
||||
## Edit on github
|
||||
|
@ -150,8 +152,8 @@ Disqus comments. https://disqus.com/
|
|||
```html
|
||||
<script>
|
||||
window.$docsify = {
|
||||
disqus: 'shortname'
|
||||
}
|
||||
disqus: 'shortname',
|
||||
};
|
||||
</script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/disqus.min.js"></script>
|
||||
```
|
||||
|
@ -161,7 +163,7 @@ Disqus comments. https://disqus.com/
|
|||
[Gitalk](https://github.com/gitalk/gitalk) is a modern comment component based on Github Issue and Preact.
|
||||
|
||||
```html
|
||||
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/gitalk/dist/gitalk.css">
|
||||
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/gitalk/dist/gitalk.css" />
|
||||
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/gitalk.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/gitalk/dist/gitalk.min.js"></script>
|
||||
|
@ -171,10 +173,12 @@ Disqus comments. https://disqus.com/
|
|||
clientSecret: 'Github Application Client Secret',
|
||||
repo: 'Github repo',
|
||||
owner: 'Github repo owner',
|
||||
admin: ['Github repo collaborators, only these guys can initialize github issues'],
|
||||
admin: [
|
||||
'Github repo collaborators, only these guys can initialize github issues',
|
||||
],
|
||||
// facebook-like distraction free mode
|
||||
distractionFreeMode: false
|
||||
})
|
||||
distractionFreeMode: false,
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
|
|
|
@ -18,9 +18,9 @@ docsify init ./docs
|
|||
|
||||
After the `init` is complete, you can see the file list in the `./docs` subdirectory.
|
||||
|
||||
* `index.html` as the entry file
|
||||
* `README.md` as the home page
|
||||
* `.nojekyll` prevents GitHub Pages from ignoring files that begin with an underscore
|
||||
- `index.html` as the entry file
|
||||
- `README.md` as the home page
|
||||
- `.nojekyll` prevents GitHub Pages from ignoring files that begin with an underscore
|
||||
|
||||
You can easily update the documentation in `./docs/README.md`, of course you can add [more pages](more-pages.md).
|
||||
|
||||
|
@ -43,21 +43,24 @@ If you don't like `npm` or have trouble installing the tool, you can manually cr
|
|||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<meta charset="UTF-8">
|
||||
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify@4/themes/vue.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script>
|
||||
window.$docsify = {
|
||||
//...
|
||||
}
|
||||
</script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify@4"></script>
|
||||
</body>
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<meta charset="UTF-8" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="//cdn.jsdelivr.net/npm/docsify@4/themes/vue.css"
|
||||
/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script>
|
||||
window.$docsify = {
|
||||
//...
|
||||
};
|
||||
</script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify@4"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
|
@ -75,7 +78,10 @@ Specifying a major version in the URL (`@4`) will allow your site will receive n
|
|||
If you prefer to lock docsify to a specific version, specify the full version after the `@` symbol in the URL. This is the safest way to ensure your site will look and behave the same way regardless of any changes made to future versions of docsify.
|
||||
|
||||
```html
|
||||
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify@4.11.4/themes/vue.css">
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="//cdn.jsdelivr.net/npm/docsify@4.11.4/themes/vue.css"
|
||||
/>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify@4.11.4"></script>
|
||||
```
|
||||
|
||||
|
@ -86,6 +92,7 @@ If you have Python installed on your system, you can easily use it to run a stat
|
|||
```python2
|
||||
cd docs && python -m SimpleHTTPServer 3000
|
||||
```
|
||||
|
||||
```python3
|
||||
cd docs && python -m http.server 3000
|
||||
```
|
||||
|
@ -107,11 +114,11 @@ You should set the `data-app` attribute if you changed `el`:
|
|||
|
||||
<div data-app id="main">Please wait...</div>
|
||||
|
||||
<script>
|
||||
window.$docsify = {
|
||||
el: '#main'
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
window.$docsify = {
|
||||
el: '#main',
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
Compare [el configuration](configuration.md#el).
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
"build:cover": "node build/cover.js",
|
||||
"build:css:min": "mkdirp lib/themes && npm run css -- -o lib/themes && node build/mincss.js",
|
||||
"build:css": "mkdirp themes && npm run css -- -o themes",
|
||||
"build:emoji": "node ./build/emoji.js && eslint ./src/core/render/emojify-data.js --fix --quiet",
|
||||
"build:js": "cross-env NODE_ENV=production node build/build.js",
|
||||
"build:ssr": "node build/ssr.js",
|
||||
"build:test": "npm run build && npm test",
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"template": "node",
|
||||
"node": "16"
|
||||
}
|
|
@ -21,6 +21,7 @@ export default function (vm) {
|
|||
nameLink: window.location.pathname,
|
||||
autoHeader: false,
|
||||
executeScript: null,
|
||||
nativeEmoji: false,
|
||||
noEmoji: false,
|
||||
ga: '',
|
||||
ext: '.md',
|
||||
|
|
|
@ -104,7 +104,7 @@ export class Compiler {
|
|||
html = compile.parser(text);
|
||||
}
|
||||
|
||||
html = config.noEmoji ? html : emojify(html);
|
||||
html = config.noEmoji ? html : emojify(html, config.nativeEmoji);
|
||||
slugify.clear();
|
||||
|
||||
return html;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,20 +1,45 @@
|
|||
import { inBrowser } from '../util/env';
|
||||
import emojiData from './emoji-data.js';
|
||||
|
||||
function replace(m, $1) {
|
||||
function replaceEmojiShorthand(m, $1, useNativeEmoji) {
|
||||
const emojiMatch = emojiData.data[$1];
|
||||
|
||||
let result = m;
|
||||
|
||||
if (emojiMatch) {
|
||||
if (useNativeEmoji && /unicode/.test(emojiMatch)) {
|
||||
const emojiUnicode = emojiMatch
|
||||
.replace('unicode/', '')
|
||||
.replace(/\.png.*/, '')
|
||||
.split('-')
|
||||
.map(u => `&#x${u};`)
|
||||
// Separate multi-character emoji with zero width joiner sequence (ZWJ)
|
||||
// Hat tip: https://about.gitlab.com/blog/2018/05/30/journey-in-native-unicode-emoji/#emoji-made-up-of-multiple-characters
|
||||
.join('‍')
|
||||
.concat('︎');
|
||||
result = `<span class="emoji">${emojiUnicode}</span>`;
|
||||
} else {
|
||||
result = `<img src="${emojiData.baseURL}${emojiMatch}.png" alt="${$1}" class="emoji" loading="lazy">`;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export function emojify(text, useNativeEmoji) {
|
||||
return (
|
||||
'<img class="emoji" src="https://github.githubassets.com/images/icons/emoji/' +
|
||||
$1 +
|
||||
'.png" alt="' +
|
||||
$1 +
|
||||
'" />'
|
||||
text
|
||||
// Mark colons in tags
|
||||
.replace(
|
||||
/<(code|pre|script|template)[^>]*?>[\s\S]+?<\/(code|pre|script|template)>/g,
|
||||
m => m.replace(/:/g, '__colon__')
|
||||
)
|
||||
// Mark colons in comments
|
||||
.replace(/<!--[\s\S]+?-->/g, m => m.replace(/:/g, '__colon__'))
|
||||
// Replace emoji shorthand codes
|
||||
.replace(/:([a-z0-9_\-+]+?):/g, (m, $1) =>
|
||||
replaceEmojiShorthand(m, $1, useNativeEmoji)
|
||||
)
|
||||
// Restore colons in tags and comments
|
||||
.replace(/__colon__/g, ':')
|
||||
);
|
||||
}
|
||||
|
||||
export function emojify(text) {
|
||||
return text
|
||||
.replace(/<(pre|template|code)[^>]*?>[\s\S]+?<\/(pre|template|code)>/g, m =>
|
||||
m.replace(/:/g, '__colon__')
|
||||
)
|
||||
.replace(/:([a-z0-9_\-+]+?):/g, (inBrowser && window.emojify) || replace)
|
||||
.replace(/__colon__/g, ':');
|
||||
}
|
||||
|
|
1893
src/plugins/emoji.js
1893
src/plugins/emoji.js
File diff suppressed because it is too large
Load Diff
|
@ -21,8 +21,13 @@ div#app
|
|||
&:empty::before
|
||||
content 'Loading...'
|
||||
|
||||
.emoji
|
||||
height 1.2rem
|
||||
img.emoji
|
||||
height 1.2em
|
||||
vertical-align middle
|
||||
|
||||
span.emoji
|
||||
font-family "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"
|
||||
font-size 1.2em
|
||||
vertical-align middle
|
||||
|
||||
.progress
|
||||
|
|
|
@ -7,6 +7,6 @@ exports[`Docs Site coverpage renders and is unchanged 1`] = `
|
|||
<a href=\\"#/?id=docsify\\">Getting Started</a></p></div></section>"
|
||||
`;
|
||||
|
||||
exports[`Docs Site navbar renders and is unchanged 1`] = `"<nav class=\\"app-nav no-badge\\"><ul><li>Translations<ul><li><a href=\\"#/\\" title=\\"undefined\\" class=\\"active\\"><img class=\\"emoji\\" src=\\"https://github.githubassets.com/images/icons/emoji/uk.png\\" alt=\\"uk\\"> English</a></li><li><a href=\\"#/zh-cn/\\" title=\\"undefined\\"><img class=\\"emoji\\" src=\\"https://github.githubassets.com/images/icons/emoji/cn.png\\" alt=\\"cn\\"> 中文</a></li><li><a href=\\"#/de-de/\\" title=\\"undefined\\"><img class=\\"emoji\\" src=\\"https://github.githubassets.com/images/icons/emoji/de.png\\" alt=\\"de\\"> Deutsch</a></li><li><a href=\\"#/es/\\" title=\\"undefined\\"><img class=\\"emoji\\" src=\\"https://github.githubassets.com/images/icons/emoji/es.png\\" alt=\\"es\\"> Español</a></li><li><a href=\\"#/ru-ru/\\" title=\\"undefined\\"><img class=\\"emoji\\" src=\\"https://github.githubassets.com/images/icons/emoji/ru.png\\" alt=\\"ru\\"> Русский</a></li></ul></li></ul></nav>"`;
|
||||
exports[`Docs Site navbar renders and is unchanged 1`] = `"<nav class=\\"app-nav no-badge\\"><ul><li>Translations<ul><li><a href=\\"#/\\" title=\\"undefined\\" class=\\"active\\"><img src=\\"https://github.githubassets.com/images/icons/emoji/unicode/1f1ec-1f1e7.png?v8.png\\" alt=\\"uk\\" class=\\"emoji\\" loading=\\"lazy\\"> English</a></li><li><a href=\\"#/zh-cn/\\" title=\\"undefined\\"><img src=\\"https://github.githubassets.com/images/icons/emoji/unicode/1f1e8-1f1f3.png?v8.png\\" alt=\\"cn\\" class=\\"emoji\\" loading=\\"lazy\\"> 中文</a></li><li><a href=\\"#/de-de/\\" title=\\"undefined\\"><img src=\\"https://github.githubassets.com/images/icons/emoji/unicode/1f1e9-1f1ea.png?v8.png\\" alt=\\"de\\" class=\\"emoji\\" loading=\\"lazy\\"> Deutsch</a></li><li><a href=\\"#/es/\\" title=\\"undefined\\"><img src=\\"https://github.githubassets.com/images/icons/emoji/unicode/1f1ea-1f1f8.png?v8.png\\" alt=\\"es\\" class=\\"emoji\\" loading=\\"lazy\\"> Español</a></li><li><a href=\\"#/ru-ru/\\" title=\\"undefined\\"><img src=\\"https://github.githubassets.com/images/icons/emoji/unicode/1f1f7-1f1fa.png?v8.png\\" alt=\\"ru\\" class=\\"emoji\\" loading=\\"lazy\\"> Русский</a></li></ul></li></ul></nav>"`;
|
||||
|
||||
exports[`Docs Site sidebar renders and is unchanged 1`] = `"<aside class=\\"sidebar\\"><div class=\\"sidebar-nav\\"><ul><li><p>Getting started</p><ul><li><a href=\\"#/quickstart\\" title=\\"undefined\\">Quick start</a></li><li><a href=\\"#/more-pages\\" title=\\"undefined\\">Writing more pages</a></li><li><a href=\\"#/custom-navbar\\" title=\\"undefined\\">Custom navbar</a></li><li><a href=\\"#/cover\\" title=\\"undefined\\">Cover page</a></li></ul></li><li><p>Customization</p><ul><li><a href=\\"#/configuration\\" title=\\"undefined\\">Configuration</a></li><li><a href=\\"#/themes\\" title=\\"undefined\\">Themes</a></li><li><a href=\\"#/plugins\\" title=\\"undefined\\">List of Plugins</a></li><li><a href=\\"#/write-a-plugin\\" title=\\"undefined\\">Write a Plugin</a></li><li><a href=\\"#/markdown\\" title=\\"undefined\\">Markdown configuration</a></li><li><a href=\\"#/language-highlight\\" title=\\"undefined\\">Language highlighting</a></li></ul></li><li><p>Guide</p><ul><li><a href=\\"#/deploy\\" title=\\"undefined\\">Deploy</a></li><li><a href=\\"#/helpers\\" title=\\"undefined\\">Helpers</a></li><li><a href=\\"#/vue\\" title=\\"undefined\\">Vue compatibility</a></li><li><a href=\\"#/cdn\\" title=\\"undefined\\">CDN</a></li><li><a href=\\"#/pwa\\" title=\\"undefined\\">Offline Mode (PWA)</a></li><li><a href=\\"#/ssr\\" title=\\"undefined\\">Server-Side Rendering (SSR)</a></li><li><a href=\\"#/embed-files\\" title=\\"undefined\\">Embed Files</a></li></ul></li><li><p><a href=\\"#/awesome\\" title=\\"undefined\\">Awesome docsify</a></p></li><li><p><a href=\\"#/changelog\\" title=\\"undefined\\">Changelog</a></p></li></ul></div></aside>"`;
|
||||
exports[`Docs Site sidebar renders and is unchanged 1`] = `"<aside class=\\"sidebar\\"><div class=\\"sidebar-nav\\"><ul><li><p>Getting started</p><ul><li><a href=\\"#/quickstart\\" title=\\"undefined\\">Quick start</a></li><li><a href=\\"#/more-pages\\" title=\\"undefined\\">Writing more pages</a></li><li><a href=\\"#/custom-navbar\\" title=\\"undefined\\">Custom navbar</a></li><li><a href=\\"#/cover\\" title=\\"undefined\\">Cover page</a></li></ul></li><li><p>Customization</p><ul><li><a href=\\"#/configuration\\" title=\\"undefined\\">Configuration</a></li><li><a href=\\"#/themes\\" title=\\"undefined\\">Themes</a></li><li><a href=\\"#/plugins\\" title=\\"undefined\\">List of Plugins</a></li><li><a href=\\"#/write-a-plugin\\" title=\\"undefined\\">Write a Plugin</a></li><li><a href=\\"#/markdown\\" title=\\"undefined\\">Markdown configuration</a></li><li><a href=\\"#/language-highlight\\" title=\\"undefined\\">Language highlighting</a></li><li><a href=\\"#/emoji\\" title=\\"undefined\\">Emoji</a></li></ul></li><li><p>Guide</p><ul><li><a href=\\"#/deploy\\" title=\\"undefined\\">Deploy</a></li><li><a href=\\"#/helpers\\" title=\\"undefined\\">Helpers</a></li><li><a href=\\"#/vue\\" title=\\"undefined\\">Vue compatibility</a></li><li><a href=\\"#/cdn\\" title=\\"undefined\\">CDN</a></li><li><a href=\\"#/pwa\\" title=\\"undefined\\">Offline Mode (PWA)</a></li><li><a href=\\"#/ssr\\" title=\\"undefined\\">Server-Side Rendering (SSR)</a></li><li><a href=\\"#/embed-files\\" title=\\"undefined\\">Embed Files</a></li></ul></li><li><p><a href=\\"#/awesome\\" title=\\"undefined\\">Awesome docsify</a></p></li><li><p><a href=\\"#/changelog\\" title=\\"undefined\\">Changelog</a></p></li></ul></div></aside>"`;
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Emoji Ignores all emoji shorthand codes (noEmoji:true) 1`] = `"<p>:smile:</p><p>:smile::smile:</p><p>:smile: :smile:</p><p>:smile::smile::smile:</p><p>:smile: :smile: :smile:</p><p>text:smile:</p><p>:smile:text</p><p>text:smile:text</p>"`;
|
||||
|
||||
exports[`Emoji Ignores emoji shorthand codes in code, pre, script, and template tags 1`] = `
|
||||
"<pre>:100:</pre>
|
||||
|
||||
<p><code>:100:</code></p><script>
|
||||
var test = ':100:';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<p>:100</p>
|
||||
</template>"
|
||||
`;
|
||||
|
||||
exports[`Emoji Ignores emoji shorthand codes in comments 1`] = `"<p>Text <!-- :foo: :100: --></p>"`;
|
||||
|
||||
exports[`Emoji Ignores unmatched emoji shorthand codes 1`] = `"<p>hh:mm</p><p>hh:mm:ss</p><p>Namespace::SubNameSpace</p><p>Namespace::SubNameSpace::Class</p><p>2014-12-29T16:11:20+00:00</p>"`;
|
||||
|
||||
exports[`Emoji Renders GitHub emoji images (nativeEmoji:false) 1`] = `"<p><img src=\\"https://github.githubassets.com/images/icons/emoji/unicode/1f604.png?v8.png\\" alt=\\"smile\\" class=\\"emoji\\" loading=\\"lazy\\"></p><p><img src=\\"https://github.githubassets.com/images/icons/emoji/unicode/1f604.png?v8.png\\" alt=\\"smile\\" class=\\"emoji\\" loading=\\"lazy\\"><img src=\\"https://github.githubassets.com/images/icons/emoji/unicode/1f604.png?v8.png\\" alt=\\"smile\\" class=\\"emoji\\" loading=\\"lazy\\"></p><p><img src=\\"https://github.githubassets.com/images/icons/emoji/unicode/1f604.png?v8.png\\" alt=\\"smile\\" class=\\"emoji\\" loading=\\"lazy\\"> <img src=\\"https://github.githubassets.com/images/icons/emoji/unicode/1f604.png?v8.png\\" alt=\\"smile\\" class=\\"emoji\\" loading=\\"lazy\\"></p><p><img src=\\"https://github.githubassets.com/images/icons/emoji/unicode/1f604.png?v8.png\\" alt=\\"smile\\" class=\\"emoji\\" loading=\\"lazy\\"><img src=\\"https://github.githubassets.com/images/icons/emoji/unicode/1f604.png?v8.png\\" alt=\\"smile\\" class=\\"emoji\\" loading=\\"lazy\\"><img src=\\"https://github.githubassets.com/images/icons/emoji/unicode/1f604.png?v8.png\\" alt=\\"smile\\" class=\\"emoji\\" loading=\\"lazy\\"></p><p><img src=\\"https://github.githubassets.com/images/icons/emoji/unicode/1f604.png?v8.png\\" alt=\\"smile\\" class=\\"emoji\\" loading=\\"lazy\\"> <img src=\\"https://github.githubassets.com/images/icons/emoji/unicode/1f604.png?v8.png\\" alt=\\"smile\\" class=\\"emoji\\" loading=\\"lazy\\"> <img src=\\"https://github.githubassets.com/images/icons/emoji/unicode/1f604.png?v8.png\\" alt=\\"smile\\" class=\\"emoji\\" loading=\\"lazy\\"></p><p>text<img src=\\"https://github.githubassets.com/images/icons/emoji/unicode/1f604.png?v8.png\\" alt=\\"smile\\" class=\\"emoji\\" loading=\\"lazy\\"></p><p><img src=\\"https://github.githubassets.com/images/icons/emoji/unicode/1f604.png?v8.png\\" alt=\\"smile\\" class=\\"emoji\\" loading=\\"lazy\\">text</p><p>text<img src=\\"https://github.githubassets.com/images/icons/emoji/unicode/1f604.png?v8.png\\" alt=\\"smile\\" class=\\"emoji\\" loading=\\"lazy\\">text</p>"`;
|
||||
|
||||
exports[`Emoji Renders native emoji characters (nativeEmoji:true) 1`] = `"<p><span class=\\"emoji\\">😄︎</span></p><p><span class=\\"emoji\\">😄︎</span><span class=\\"emoji\\">😄︎</span></p><p><span class=\\"emoji\\">😄︎</span> <span class=\\"emoji\\">😄︎</span></p><p><span class=\\"emoji\\">😄︎</span><span class=\\"emoji\\">😄︎</span><span class=\\"emoji\\">😄︎</span></p><p><span class=\\"emoji\\">😄︎</span> <span class=\\"emoji\\">😄︎</span> <span class=\\"emoji\\">😄︎</span></p><p>text<span class=\\"emoji\\">😄︎</span></p><p><span class=\\"emoji\\">😄︎</span>text</p><p>text<span class=\\"emoji\\">😄︎</span>text</p>"`;
|
|
@ -0,0 +1,134 @@
|
|||
const docsifyInit = require('../helpers/docsify-init');
|
||||
|
||||
// Suite
|
||||
// -----------------------------------------------------------------------------
|
||||
describe('Emoji', function () {
|
||||
// Tests
|
||||
// ---------------------------------------------------------------------------
|
||||
const emojiMarkdown = `
|
||||
:smile:
|
||||
|
||||
:smile::smile:
|
||||
|
||||
:smile: :smile:
|
||||
|
||||
:smile::smile::smile:
|
||||
|
||||
:smile: :smile: :smile:
|
||||
|
||||
text:smile:
|
||||
|
||||
:smile:text
|
||||
|
||||
text:smile:text
|
||||
`;
|
||||
|
||||
test('Renders native emoji characters (nativeEmoji:true)', async () => {
|
||||
await docsifyInit({
|
||||
config: {
|
||||
nativeEmoji: true,
|
||||
},
|
||||
markdown: {
|
||||
homepage: emojiMarkdown,
|
||||
},
|
||||
// _logHTML: true,
|
||||
});
|
||||
|
||||
const mainElm = document.querySelector('#main');
|
||||
|
||||
expect(mainElm.innerHTML).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('Renders GitHub emoji images (nativeEmoji:false)', async () => {
|
||||
await docsifyInit({
|
||||
config: {
|
||||
nativeEmoji: false,
|
||||
},
|
||||
markdown: {
|
||||
homepage: emojiMarkdown,
|
||||
},
|
||||
// _logHTML: true,
|
||||
});
|
||||
|
||||
const mainElm = document.querySelector('#main');
|
||||
|
||||
expect(mainElm.innerHTML).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('Ignores all emoji shorthand codes (noEmoji:true)', async () => {
|
||||
await docsifyInit({
|
||||
config: {
|
||||
noEmoji: true,
|
||||
},
|
||||
markdown: {
|
||||
homepage: emojiMarkdown,
|
||||
},
|
||||
// _logHTML: true,
|
||||
});
|
||||
|
||||
const mainElm = document.querySelector('#main');
|
||||
|
||||
expect(mainElm.innerHTML).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('Ignores unmatched emoji shorthand codes', async () => {
|
||||
await docsifyInit({
|
||||
markdown: {
|
||||
homepage: `
|
||||
hh:mm
|
||||
|
||||
hh:mm:ss
|
||||
|
||||
Namespace::SubNameSpace
|
||||
|
||||
Namespace::SubNameSpace::Class
|
||||
|
||||
2014-12-29T16:11:20+00:00
|
||||
`,
|
||||
},
|
||||
// _logHTML: true,
|
||||
});
|
||||
|
||||
const mainElm = document.querySelector('#main');
|
||||
|
||||
expect(mainElm.innerHTML).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('Ignores emoji shorthand codes in comments', async () => {
|
||||
await docsifyInit({
|
||||
markdown: {
|
||||
homepage: 'Text <!-- :foo: :100: -->',
|
||||
},
|
||||
// _logHTML: true,
|
||||
});
|
||||
|
||||
const mainElm = document.querySelector('#main');
|
||||
|
||||
expect(mainElm.innerHTML).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('Ignores emoji shorthand codes in code, pre, script, and template tags', async () => {
|
||||
await docsifyInit({
|
||||
markdown: {
|
||||
homepage: `
|
||||
<pre>:100:</pre>
|
||||
|
||||
<code>:100:</code>
|
||||
|
||||
<script>
|
||||
var test = ':100:';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<p>:100</p>
|
||||
</template>
|
||||
`,
|
||||
},
|
||||
// _logHTML: true,
|
||||
});
|
||||
|
||||
const mainElm = document.querySelector('#main');
|
||||
|
||||
expect(mainElm.innerHTML).toMatchSnapshot();
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue