Skip to content

Commit

Permalink
feat: added capability to add css class and id to images + links + re…
Browse files Browse the repository at this point in the history
…factoring (#820)

* method extraction

* support for CSS class and id

* Update package.json

* Added tests for refactored render-methods

* minor refactoring
  • Loading branch information
arelstone committed Feb 8, 2020
1 parent 6184e50 commit 724ac02
Show file tree
Hide file tree
Showing 14 changed files with 369 additions and 133 deletions.
1 change: 0 additions & 1 deletion cypress/integration/sidebar/config.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,6 @@ context('sidebar.configurations', () => {
'set-target-attribute-for-link',
'disable-link',
'github-task-lists',
'image-resizing',
'customise-id-for-headings',
'markdown-in-html-tag'
]
Expand Down
Binary file not shown.
17 changes: 16 additions & 1 deletion docs/helpers.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,12 @@ You will get `<a href="/demo/">link</a>`html. Do not worry, you can still set ti
- [ ] bim
- [ ] lim

## Image resizing
## Image

### Resizing

```md
![logo](https://docsify.js.org/_media/icon.svg ':size=WIDTHxHEIGHT')
![logo](https://docsify.js.org/_media/icon.svg ':size=50x100')
![logo](https://docsify.js.org/_media/icon.svg ':size=100')

Expand All @@ -96,6 +99,18 @@ You will get `<a href="/demo/">link</a>`html. Do not worry, you can still set ti
![logo](https://docsify.js.org/_media/icon.svg ':size=100')
![logo](https://docsify.js.org/_media/icon.svg ':size=10%')

### Customise class

```md
![logo](https://docsify.js.org/_media/icon.svg ':class=someCssClass')
```

### Customise ID

```md
![logo](https://docsify.js.org/_media/icon.svg ':id=someCssId')
```

## Customise ID for headings

```md
Expand Down
41 changes: 30 additions & 11 deletions package-lock.json

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

2 changes: 1 addition & 1 deletion packages/docsify-server-renderer/package-lock.json

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

133 changes: 15 additions & 118 deletions src/core/render/compiler.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import marked from 'marked'
import Prism from 'prismjs'
import { helper as helperTpl, tree as treeTpl } from './tpl'
import { tree as treeTpl } from './tpl'
import { genTree } from './gen-tree'
import { slugify } from './slugify'
import { emojify } from './emojify'
import { isAbsolutePath, getPath, getParentPath } from '../router/util'
import { isFn, merge, cached, isPrimitive } from '../util/core'

// See https://github.com/PrismJS/prism/pull/1367
import 'prismjs/components/prism-markup-templating'
import { imageCompiler } from './compiler/image'
import { highlightCodeCompiler } from './compiler/code'
import { paragraphCompiler } from './compiler/paragraph'
import { taskListCompiler } from './compiler/taskList'
import { taskListItemCompiler } from './compiler/taskListItem'
import { linkCompiler } from './compiler/link'
import marked from 'marked'

const cachedLinks = {}

Expand Down Expand Up @@ -189,7 +191,7 @@ export class Compiler {

_initRenderer() {
const renderer = new marked.Renderer()
const { linkTarget, linkRel, router, contentBase } = this
const { linkTarget, router, contentBase } = this
const _self = this
const origin = {}

Expand Down Expand Up @@ -224,117 +226,12 @@ export class Compiler {
return `<h${level} id="${slug}"><a href="${url}" data-id="${slug}" class="anchor"><span>${str}</span></a></h${level}>`
}

// Highlight code
origin.code = renderer.code = function (code, lang = '') {
code = code.replace(/@DOCSIFY_QM@/g, '`')
const hl = Prism.highlight(
code,
Prism.languages[lang] || Prism.languages.markup
)

return `<pre v-pre data-lang="${lang}"><code class="lang-${lang}">${hl}</code></pre>`
}

origin.link = renderer.link = function (href, title = '', text) {
let attrs = ''

const { str, config } = getAndRemoveConfig(title)
title = str

if (
!isAbsolutePath(href) &&
!_self._matchNotCompileLink(href) &&
!config.ignore
) {
if (href === _self.config.homepage) {
href = 'README'
}

href = router.toURL(href, null, router.getCurrentPath())
} else {
attrs += href.indexOf('mailto:') === 0 ? '' : ` target="${linkTarget}"`
attrs += href.indexOf('mailto:') === 0 ? '' : (linkRel !== '' ? ` rel="${linkRel}"` : '')
}

if (config.target) {
attrs += ' target=' + config.target
}

if (config.disabled) {
attrs += ' disabled'
href = 'javascript:void(0)'
}

if (title) {
attrs += ` title="${title}"`
}

return `<a href="${href}"${attrs}>${text}</a>`
}

origin.paragraph = renderer.paragraph = function (text) {
let result
if (/^!&gt;/.test(text)) {
result = helperTpl('tip', text)
} else if (/^\?&gt;/.test(text)) {
result = helperTpl('warn', text)
} else {
result = `<p>${text}</p>`
}

return result
}

origin.image = renderer.image = function (href, title, text) {
let url = href
let attrs = ''

const { str, config } = getAndRemoveConfig(title)
title = str

if (config['no-zoom']) {
attrs += ' data-no-zoom'
}

if (title) {
attrs += ` title="${title}"`
}

const size = config.size
if (size) {
const sizes = size.split('x')
if (sizes[1]) {
attrs += 'width=' + sizes[0] + ' height=' + sizes[1]
} else {
attrs += 'width=' + sizes[0]
}
}

if (!isAbsolutePath(href)) {
url = getPath(contentBase, getParentPath(router.getCurrentPath()), href)
}

return `<img src="${url}"data-origin="${href}" alt="${text}"${attrs}>`
}

origin.list = renderer.list = function (body, ordered, start) {
const isTaskList = /<li class="task-list-item">/.test(body.split('class="task-list"')[0])
const isStartReq = start && start > 1
const tag = ordered ? 'ol' : 'ul'
const tagAttrs = [
(isTaskList ? 'class="task-list"' : ''),
(isStartReq ? `start="${start}"` : '')
].join(' ').trim()

return `<${tag} ${tagAttrs}>${body}</${tag}>`
}

origin.listitem = renderer.listitem = function (text) {
const isTaskItem = /^(<input.*type="checkbox"[^>]*>)/.test(text)
const html = isTaskItem ? `<li class="task-list-item"><label>${text}</label></li>` : `<li>${text}</li>`

return html
}
origin.code = highlightCodeCompiler({ renderer })
origin.link = linkCompiler({ renderer, router, linkTarget, compilerClass: _self })
origin.paragraph = paragraphCompiler({ renderer })
origin.image = imageCompiler({ renderer, contentBase, router })
origin.list = taskListCompiler({ renderer })
origin.listitem = taskListItemCompiler({ renderer })

renderer.origin = origin

Expand Down
10 changes: 10 additions & 0 deletions src/core/render/compiler/code.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import Prism from 'prismjs'
// See https://github.com/PrismJS/prism/pull/1367
import 'prismjs/components/prism-markup-templating'

export const highlightCodeCompiler = ({ renderer }) => renderer.code = function (code, lang = '') {
const langOrMarkup = Prism.languages[lang] || Prism.languages.markup
const text = Prism.highlight(code.replace(/@DOCSIFY_QM@/g, '`'), langOrMarkup)

return `<pre v-pre data-lang="${lang}"><code class="lang-${lang}">${text}</code></pre>`
}
Loading

0 comments on commit 724ac02

Please sign in to comment.