1
0
mirror of https://github.com/BoostIo/Boostnote synced 2025-12-13 01:36:22 +00:00

Merge branch 'fence-attrs' into chart-yaml

This commit is contained in:
Baptiste Augrain
2018-09-30 21:46:09 +02:00
78 changed files with 2321 additions and 589 deletions

View File

@@ -3,6 +3,17 @@ export function findNoteTitle (value) {
let title = null
let isInsideCodeBlock = false
if (splitted[0] === '---') {
let line = 0
while (++line < splitted.length) {
if (splitted[line] === '---') {
splitted.splice(0, line + 1)
break
}
}
}
splitted.some((line, index) => {
const trimmedLine = line.trim()
const trimmedNextLine = splitted[index + 1] === undefined ? '' : splitted[index + 1].trim()

View File

@@ -66,7 +66,7 @@ module.exports = function (md, renderers, defaultRenderer) {
const parameters = {}
let langType = ''
let fileName = ''
let firstLineNumber = 0
let firstLineNumber = 1
let match = paramsRE.exec(params)
if (match) {
@@ -122,7 +122,7 @@ module.exports = function (md, renderers, defaultRenderer) {
alt: ['paragraph', 'reference', 'blockquote', 'list']
})
for (let name in renderers) {
for (const name in renderers) {
md.renderer.rules[`${name}_fence`] = (tokens, index) => renderers[name](tokens[index])
}

View File

@@ -0,0 +1,24 @@
'use strict'
module.exports = function frontMatterPlugin (md) {
function frontmatter (state, startLine, endLine, silent) {
if (startLine !== 0 || state.src.substr(startLine, state.eMarks[0]) !== '---') {
return false
}
let line = 0
while (++line < state.lineMax) {
if (state.src.substring(state.bMarks[line], state.eMarks[line]) === '---') {
state.line = line + 1
return true
}
}
return false
}
md.block.ruler.before('table', 'frontmatter', frontmatter, {
alt: [ 'paragraph', 'reference', 'blockquote', 'list' ]
})
}

View File

@@ -14,7 +14,7 @@ module.exports = function sanitizePlugin (md, options) {
options
)
}
if (state.tokens[tokenIdx].type === 'fence') {
if (state.tokens[tokenIdx].type === '_fence') {
// escapeHtmlCharacters has better performance
state.tokens[tokenIdx].content = escapeHtmlCharacters(
state.tokens[tokenIdx].content,

View File

@@ -0,0 +1,100 @@
/**
* @fileoverview Markdown table of contents generator
*/
import toc from 'markdown-toc'
import diacritics from 'diacritics-map'
import stripColor from 'strip-color'
const EOL = require('os').EOL
/**
* @caseSensitiveSlugify Custom slugify function
* Same implementation that the original used by markdown-toc (node_modules/markdown-toc/lib/utils.js),
* but keeps original case to properly handle https://github.com/BoostIO/Boostnote/issues/2067
*/
function caseSensitiveSlugify (str) {
function replaceDiacritics (str) {
return str.replace(/[À-ž]/g, function (ch) {
return diacritics[ch] || ch
})
}
function getTitle (str) {
if (/^\[[^\]]+\]\(/.test(str)) {
var m = /^\[([^\]]+)\]/.exec(str)
if (m) return m[1]
}
return str
}
str = getTitle(str)
str = stripColor(str)
// str = str.toLowerCase() //let's be case sensitive
// `.split()` is often (but not always) faster than `.replace()`
str = str.split(' ').join('-')
str = str.split(/\t/).join('--')
str = str.split(/<\/?[^>]+>/).join('')
str = str.split(/[|$&`~=\\\/@+*!?({[\]})<>=.,;:'"^]/).join('')
str = str.split(/[。?!,、;:“”【】()〔〕[]﹃﹄“ ”‘’﹁﹂—…-~《》〈〉「」]/).join('')
str = replaceDiacritics(str)
return str
}
const TOC_MARKER_START = '<!-- toc -->'
const TOC_MARKER_END = '<!-- tocstop -->'
/**
* Takes care of proper updating given editor with TOC.
* If TOC doesn't exit in the editor, it's inserted at current caret position.
* Otherwise,TOC is updated in place.
* @param editor CodeMirror editor to be updated with TOC
*/
export function generateInEditor (editor) {
const tocRegex = new RegExp(`${TOC_MARKER_START}[\\s\\S]*?${TOC_MARKER_END}`)
function tocExistsInEditor () {
return tocRegex.test(editor.getValue())
}
function updateExistingToc () {
const toc = generate(editor.getValue())
const search = editor.getSearchCursor(tocRegex)
while (search.findNext()) {
search.replace(toc)
}
}
function addTocAtCursorPosition () {
const toc = generate(editor.getRange(editor.getCursor(), {line: Infinity}))
editor.replaceRange(wrapTocWithEol(toc, editor), editor.getCursor())
}
if (tocExistsInEditor()) {
updateExistingToc()
} else {
addTocAtCursorPosition()
}
}
/**
* Generates MD TOC based on MD document passed as string.
* @param markdownText MD document
* @returns generatedTOC String containing generated TOC
*/
export function generate (markdownText) {
const generatedToc = toc(markdownText, {slugify: caseSensitiveSlugify})
return TOC_MARKER_START + EOL + EOL + generatedToc.content + EOL + EOL + TOC_MARKER_END
}
function wrapTocWithEol (toc, editor) {
const leftWrap = editor.getCursor().ch === 0 ? '' : EOL
const rightWrap = editor.getLine(editor.getCursor().line).length === editor.getCursor().ch ? '' : EOL
return leftWrap + toc + rightWrap
}
export default {
generate,
generateInEditor
}

View File

@@ -122,7 +122,9 @@ class Markdown {
}
})
this.md.use(require('markdown-it-kbd'))
this.md.use(require('markdown-it-admonition'))
this.md.use(require('markdown-it-admonition'), {types: ['note', 'hint', 'attention', 'caution', 'danger', 'error']})
this.md.use(require('./markdown-it-frontmatter'))
this.md.use(require('./markdown-it-fence'), {
chart: token => {
@@ -130,31 +132,31 @@ class Markdown {
token.parameters.format = 'yaml'
}
return `<pre class="fence">
return `<pre class="fence" data-line="${token.map[0]}">
<span class="filename">${token.fileName}</span>
<div class="chart" data-height="${token.parameters.height}" data-format="${token.parameters.format || 'json'}">${token.content}</div>
</pre>`
},
flowchart: token => {
return `<pre class="fence">
return `<pre class="fence" data-line="${token.map[0]}">
<span class="filename">${token.fileName}</span>
<div class="flowchart" data-height="${token.parameters.height}">${token.content}</div>
</pre>`
},
mermaid: token => {
return `<pre class="fence">
return `<pre class="fence" data-line="${token.map[0]}">
<span class="filename">${token.fileName}</span>
<div class="mermaid" data-height="${token.parameters.height}">${token.content}</div>
</pre>`
},
sequence: token => {
return `<pre class="fence">
return `<pre class="fence" data-line="${token.map[0]}">
<span class="filename">${token.fileName}</span>
<div class="sequence" data-height="${token.parameters.height}">${token.content}</div>
</pre>`
}
}, token => {
return `<pre class="code CodeMirror">
return `<pre class="code CodeMirror" data-line="${token.map[0]}">
<span class="filename">${token.fileName}</span>
${createGutter(token.content, token.firstLineNumber)}
<code class="${token.langType}">${token.content}</code>

62
browser/lib/newNote.js Normal file
View File

@@ -0,0 +1,62 @@
import { hashHistory } from 'react-router'
import dataApi from 'browser/main/lib/dataApi'
import ee from 'browser/main/lib/eventEmitter'
import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig'
export function createMarkdownNote (storage, folder, dispatch, location) {
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_MARKDOWN')
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_ALLNOTE')
return dataApi
.createNote(storage, {
type: 'MARKDOWN_NOTE',
folder: folder,
title: '',
content: ''
})
.then(note => {
const noteHash = note.key
dispatch({
type: 'UPDATE_NOTE',
note: note
})
hashHistory.push({
pathname: location.pathname,
query: { key: noteHash }
})
ee.emit('list:jump', noteHash)
ee.emit('detail:focus')
})
}
export function createSnippetNote (storage, folder, dispatch, location, config) {
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_SNIPPET')
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_ALLNOTE')
return dataApi
.createNote(storage, {
type: 'SNIPPET_NOTE',
folder: folder,
title: '',
description: '',
snippets: [
{
name: '',
mode: config.editor.snippetDefaultLanguage || 'text',
content: ''
}
]
})
.then(note => {
const noteHash = note.key
dispatch({
type: 'UPDATE_NOTE',
note: note
})
hashHistory.push({
pathname: location.pathname,
query: { key: noteHash }
})
ee.emit('list:jump', noteHash)
ee.emit('detail:focus')
})
}