`
+ }
+ return output
+ }
+ })
+ this.md.use(require('markdown-it-imsize'))
+ this.md.use(require('markdown-it-footnote'))
+ this.md.use(require('markdown-it-multimd-table'))
+ this.md.use(require('markdown-it-named-headers'), {
+ slugify: (header) => {
+ return encodeURI(header.trim()
+ .replace(/[\]\[\!\"\#\$\%\&\'\(\)\*\+\,\.\/\:\;\<\=\>\?\@\\\^\_\{\|\}\~]/g, '')
+ .replace(/\s+/g, '-'))
+ .replace(/\-+$/, '')
+ }
+ })
+ this.md.use(require('markdown-it-kbd'))
+
+ const deflate = require('markdown-it-plantuml/lib/deflate')
+ this.md.use(require('markdown-it-plantuml'), '', {
+ generateSource: function (umlCode) {
+ const s = unescape(encodeURIComponent(umlCode))
+ const zippedCode = deflate.encode64(
+ deflate.zip_deflate(`@startuml\n${s}\n@enduml`, 9)
+ )
+ return `http://www.plantuml.com/plantuml/svg/${zippedCode}`
+ }
+ })
+
+ // Override task item
+ this.md.block.ruler.at('paragraph', function (state, startLine/*, endLine */) {
+ let content, terminate, i, l, token
+ let nextLine = startLine + 1
+ const terminatorRules = state.md.block.ruler.getRules('paragraph')
+ const endLine = state.lineMax
+
+ // jump line-by-line until empty one or EOF
+ for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) {
+ // this would be a code block normally, but after paragraph
+ // it's considered a lazy continuation regardless of what's there
+ if (state.sCount[nextLine] - state.blkIndent > 3) { continue }
+
+ // quirk for blockquotes, this line should already be checked by that rule
+ if (state.sCount[nextLine] < 0) { continue }
+
+ // Some tags can terminate paragraph without empty line.
+ terminate = false
+ for (i = 0, l = terminatorRules.length; i < l; i++) {
+ if (terminatorRules[i](state, nextLine, endLine, true)) {
+ terminate = true
+ break
+ }
+ }
+ if (terminate) { break }
+ }
+
+ content = state.getLines(startLine, nextLine, state.blkIndent, false).trim()
+
+ state.line = nextLine
+
+ token = state.push('paragraph_open', 'p', 1)
+ token.map = [startLine, state.line]
+
+ if (state.parentType === 'list') {
+ const match = content.match(/^\[( |x)\] ?(.+)/i)
+ if (match) {
+ const liToken = lastFindInArray(state.tokens, token => token.type === 'list_item_open')
+ if (liToken) {
+ if (!liToken.attrs) {
+ liToken.attrs = []
+ }
+ liToken.attrs.push(['class', 'taskListItem'])
+ }
+ content = ``
+ }
+ }
+
+ token = state.push('inline', '', 0)
+ token.content = content
+ token.map = [startLine, state.line]
+ token.children = []
+
+ token = state.push('paragraph_close', 'p', -1)
+
+ return true
+ })
+
+ // Add line number attribute for scrolling
+ const originalRender = this.md.renderer.render
+ this.md.renderer.render = (tokens, options, env) => {
+ tokens.forEach((token) => {
+ switch (token.type) {
+ case 'heading_open':
+ case 'paragraph_open':
+ case 'blockquote_open':
+ case 'table_open':
+ token.attrPush(['data-line', token.map[0]])
+ }
+ })
+ const result = originalRender.call(this.md.renderer, tokens, options, env)
+ return result
+ }
+ // FIXME We should not depend on global variable.
+ window.md = this.md
}
- token = state.push('inline', '', 0)
- token.content = content
- token.map = [startLine, state.line]
- token.children = []
-
- token = state.push('paragraph_close', 'p', -1)
-
- return true
-})
-
-// Add line number attribute for scrolling
-const originalRender = md.renderer.render
-md.renderer.render = function render (tokens, options, env) {
- tokens.forEach((token) => {
- switch (token.type) {
- case 'heading_open':
- case 'paragraph_open':
- case 'blockquote_open':
- case 'table_open':
- token.attrPush(['data-line', token.map[0]])
- }
- })
- const result = originalRender.call(md.renderer, tokens, options, env)
- return result
-}
-// FIXME We should not depend on global variable.
-window.md = md
-
-function normalizeLinkText (linkText) {
- return md.normalizeLinkText(linkText)
-}
-
-const markdown = {
- render: function markdown (content) {
+ render (content) {
if (!_.isString(content)) content = ''
- const renderedContent = md.render(content)
- return renderedContent
- },
- normalizeLinkText
+ return this.md.render(content)
+ }
+
+ normalizeLinkText (linkText) {
+ return this.md.normalizeLinkText(linkText)
+ }
}
-export default markdown
+export default Markdown
+
diff --git a/browser/main/lib/ConfigManager.js b/browser/main/lib/ConfigManager.js
index e7e82a9b..1c4d955b 100644
--- a/browser/main/lib/ConfigManager.js
+++ b/browser/main/lib/ConfigManager.js
@@ -48,7 +48,8 @@ export const DEFAULT_CONFIG = {
latexInlineClose: '$',
latexBlockOpen: '$$',
latexBlockClose: '$$',
- scrollPastEnd: false
+ scrollPastEnd: false,
+ smartQuotes: true
},
blog: {
type: 'wordpress', // Available value: wordpress, add more types in the future plz
diff --git a/browser/main/modals/PreferencesModal/UiTab.js b/browser/main/modals/PreferencesModal/UiTab.js
index 50e13f6c..ddffe6d9 100644
--- a/browser/main/modals/PreferencesModal/UiTab.js
+++ b/browser/main/modals/PreferencesModal/UiTab.js
@@ -88,7 +88,8 @@ class UiTab extends React.Component {
latexInlineClose: this.refs.previewLatexInlineClose.value,
latexBlockOpen: this.refs.previewLatexBlockOpen.value,
latexBlockClose: this.refs.previewLatexBlockClose.value,
- scrollPastEnd: this.refs.previewScrollPastEnd.checked
+ scrollPastEnd: this.refs.previewScrollPastEnd.checked,
+ smartQuotes: this.refs.previewSmartQuotes.checked
}
}
@@ -402,6 +403,16 @@ class UiTab extends React.Component {
Show line numbers for preview code blocks
+
+
+
LaTeX Inline Open Delimiter
diff --git a/docs/zh_TW/build.md b/docs/zh_TW/build.md
new file mode 100644
index 00000000..ff17d9c5
--- /dev/null
+++ b/docs/zh_TW/build.md
@@ -0,0 +1,86 @@
+# 編譯
+此文件還提供下列的語言 [日文](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/build.md), [韓文](https://github.com/BoostIO/Boostnote/blob/master/docs/ko/build.md), [俄文](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/build.md), [簡體中文](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/build.md), [法文](https://github.com/BoostIO/Boostnote/blob/master/docs/fr/build.md) and [德文](https://github.com/BoostIO/Boostnote/blob/master/docs/de/build.md).
+
+## 環境
+* npm: 4.x
+* node: 7.x
+
+`$ grunt pre-build` 在 `npm v5.x` 有問題,所以只能用 `npm v4.x` 。
+
+## 開發
+
+我們使用 Webpack HMR 來開發 Boostnote。
+
+在專案根目錄底下執行下列指令,將會以原始設置啟動 Boostnote。
+
+**用 yarn 來安裝必要 packages**
+
+```bash
+$ yarn
+```
+
+**開始開發**
+
+```
+$ yarn run dev-start
+```
+
+上述指令同時運行了 `yarn run webpack` 及 `yarn run hot`,相當於將這兩個指令在不同的 terminal 中運行。
+
+`webpack` 會同時監控修改過的程式碼,並
+The `webpack` will watch for code changes and then apply them automatically.
+
+If the following error occurs: `Failed to load resource: net::ERR_CONNECTION_REFUSED`, please reload Boostnote.
+
+
+
+> ### Notice
+> There are some cases where you have to refresh the app manually.
+> 1. When editing a constructor method of a component
+> 2. When adding a new css class (similar to 1: the CSS class is re-written by each component. This process occurs at the Constructor method.)
+
+## Deploy
+
+We use Grunt to automate deployment.
+You can build the program by using `grunt`. However, we don't recommend this because the default task includes codesign and authenticode.
+
+So, we've prepared a separate script which just makes an executable file.
+
+This build doesn't work on npm v5.3.0. So you need to use v5.2.0 when you build it.
+
+```
+grunt pre-build
+```
+
+You will find the executable in the `dist` directory. Note, the auto updater won't work because the app isn't signed.
+
+If you find it necessary, you can use codesign or authenticode with this executable.
+
+## Make own distribution packages (deb, rpm)
+
+Distribution packages are created by exec `grunt build` on Linux platform (e.g. Ubuntu, Fedora).
+
+> Note: You can create both `.deb` and `.rpm` in a single environment.
+
+After installing the supported version of `node` and `npm`, install build dependency packages.
+
+
+Ubuntu/Debian:
+
+```
+$ sudo apt-get install -y rpm fakeroot
+```
+
+Fedora:
+
+```
+$ sudo dnf install -y dpkg dpkg-dev rpm-build fakeroot
+```
+
+Then execute `grunt build`.
+
+```
+$ grunt build
+```
+
+You will find `.deb` and `.rpm` in the `dist` directory.