mirror of
https://github.com/marktext/marktext.git
synced 2025-05-02 15:09:10 +08:00
Update deps and automatically format style (#1168)
This commit is contained in:
parent
afe688911a
commit
2686cfafe4
19
.eslintrc.js
19
.eslintrc.js
@ -29,15 +29,24 @@ module.exports = {
|
||||
],
|
||||
rules: {
|
||||
// allow paren-less arrow functions
|
||||
'arrow-parens': 0,
|
||||
'arrow-parens': "off",
|
||||
// allow async-await
|
||||
'generator-star-spacing': 0,
|
||||
'generator-star-spacing': "off",
|
||||
// allow console
|
||||
'no-console': 0,
|
||||
'no-console': "off",
|
||||
// allow debugger during development
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? "error" : "off",
|
||||
'no-return-assign': "warn",
|
||||
'no-new': "warn",
|
||||
// disallow semicolons
|
||||
semi: [2, "never"]
|
||||
semi: [2, "never"],
|
||||
'require-atomic-updates': "off",
|
||||
// TODO: fix these errors someday
|
||||
'prefer-const': "off",
|
||||
'no-new': "off",
|
||||
'no-mixed-operators': "off",
|
||||
'no-prototype-builtins': "off",
|
||||
"no-return-await": "off"
|
||||
},
|
||||
settings: {
|
||||
'import/resolver': {
|
||||
|
78
package.json
78
package.json
@ -158,35 +158,35 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@hfelix/electron-localshortcut": "^3.1.1",
|
||||
"@octokit/rest": "^16.28.2",
|
||||
"arg": "^4.1.0",
|
||||
"@octokit/rest": "^16.28.5",
|
||||
"arg": "^4.1.1",
|
||||
"axios": "^0.19.0",
|
||||
"chokidar": "^3.0.1",
|
||||
"codemirror": "^5.46.0",
|
||||
"chokidar": "^3.0.2",
|
||||
"codemirror": "^5.48.2",
|
||||
"command-exists": "^1.2.8",
|
||||
"dayjs": "^1.8.14",
|
||||
"dayjs": "^1.8.15",
|
||||
"dom-autoscroller": "^2.3.4",
|
||||
"dompurify": "^1.0.11",
|
||||
"dragula": "^3.7.2",
|
||||
"electron-is-accelerator": "^0.1.2",
|
||||
"electron-log": "^3.0.6",
|
||||
"electron-store": "^3.3.0",
|
||||
"electron-store": "^4.0.0",
|
||||
"electron-window-state": "^5.0.3",
|
||||
"element-resize-detector": "^1.2.0",
|
||||
"element-ui": "^2.9.1",
|
||||
"element-ui": "^2.10.1",
|
||||
"file-icons-js": "^1.0.3",
|
||||
"flowchart.js": "^1.12.0",
|
||||
"fs-extra": "^8.0.1",
|
||||
"flowchart.js": "^1.12.1",
|
||||
"fs-extra": "^8.1.0",
|
||||
"fuzzaldrin": "^2.1.0",
|
||||
"github-markdown-css": "^3.0.1",
|
||||
"html-tags": "^3.0.0",
|
||||
"katex": "^0.10.2",
|
||||
"keyboard-layout": "^2.0.16",
|
||||
"keytar": "^4.10.0",
|
||||
"keytar": "^4.12.0",
|
||||
"mermaid": "^8.0.0",
|
||||
"plist": "^3.0.1",
|
||||
"popper.js": "^1.15.0",
|
||||
"prismjs": "^1.16.0",
|
||||
"prismjs": "^1.17.1",
|
||||
"snabbdom": "^0.7.3",
|
||||
"snabbdom-to-html": "^5.1.1",
|
||||
"source-map-support": "^0.5.12",
|
||||
@ -194,19 +194,19 @@
|
||||
"turndown-plugin-gfm": "^1.0.2",
|
||||
"underscore": "^1.9.1",
|
||||
"vega": "^5.4.0",
|
||||
"vega-embed": "^4.2.0",
|
||||
"vega-embed": "^4.2.1",
|
||||
"vega-lite": "^3.3.0",
|
||||
"view-image": "^0.0.1",
|
||||
"vscode-ripgrep": "^1.2.5",
|
||||
"vscode-ripgrep": "^1.5.5",
|
||||
"vue": "^2.6.10",
|
||||
"vue-electron": "^1.0.6",
|
||||
"vue-router": "^3.0.6",
|
||||
"vue-router": "^3.0.7",
|
||||
"vuex": "^3.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@markedjs/html-differ": "^2.0.1",
|
||||
"babel-core": "^6.26.3",
|
||||
"babel-eslint": "^10.0.1",
|
||||
"babel-eslint": "^10.0.2",
|
||||
"babel-loader": "^7.1.5",
|
||||
"babel-plugin-component": "^1.1.1",
|
||||
"babel-plugin-istanbul": "^5.1.1",
|
||||
@ -224,24 +224,24 @@
|
||||
"del": "^4.1.1",
|
||||
"devtron": "^1.4.0",
|
||||
"dotenv": "^8.0.0",
|
||||
"electron": "^5.0.4",
|
||||
"electron-builder": "^20.40.2",
|
||||
"electron": "^5.0.7",
|
||||
"electron-builder": "^21.1.1",
|
||||
"electron-devtools-installer": "^2.2.4",
|
||||
"electron-rebuild": "^1.8.4",
|
||||
"electron-updater": "^4.0.6",
|
||||
"eslint": "^5.16.0",
|
||||
"eslint-config-standard": "^12.0.0",
|
||||
"electron-rebuild": "^1.8.5",
|
||||
"electron-updater": "^4.1.2",
|
||||
"eslint": "^6.1.0",
|
||||
"eslint-config-standard": "^13.0.1",
|
||||
"eslint-friendly-formatter": "^4.0.1",
|
||||
"eslint-import-resolver-alias": "^1.1.2",
|
||||
"eslint-loader": "^2.1.2",
|
||||
"eslint-plugin-html": "^5.0.4",
|
||||
"eslint-plugin-import": "^2.17.2",
|
||||
"eslint-plugin-node": "^9.0.1",
|
||||
"eslint-plugin-promise": "^4.1.1",
|
||||
"eslint-loader": "^2.2.1",
|
||||
"eslint-plugin-html": "^6.0.0",
|
||||
"eslint-plugin-import": "^2.18.2",
|
||||
"eslint-plugin-node": "^9.1.0",
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"eslint-plugin-standard": "^4.0.0",
|
||||
"eslint-plugin-vue": "^5.2.2",
|
||||
"esm": "^3.2.22",
|
||||
"file-loader": "^3.0.1",
|
||||
"eslint-plugin-vue": "^5.2.3",
|
||||
"esm": "^3.2.25",
|
||||
"file-loader": "^4.1.0",
|
||||
"git-revision-webpack-plugin": "^3.0.3",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"inject-loader": "^4.0.1",
|
||||
@ -254,30 +254,30 @@
|
||||
"karma-spec-reporter": "0.0.32",
|
||||
"karma-webpack": "^3.0.5",
|
||||
"license-checker": "^25.0.1",
|
||||
"marked": "^0.6.2",
|
||||
"mini-css-extract-plugin": "^0.6.0",
|
||||
"mocha": "^6.1.4",
|
||||
"marked": "^0.7.0",
|
||||
"mini-css-extract-plugin": "^0.8.0",
|
||||
"mocha": "^6.2.0",
|
||||
"multispinner": "^0.2.1",
|
||||
"node-fetch": "^2.5.0",
|
||||
"node-fetch": "^2.6.0",
|
||||
"node-loader": "^0.6.0",
|
||||
"postcss-loader": "^3.0.0",
|
||||
"postcss-preset-env": "^6.6.0",
|
||||
"raw-loader": "^2.0.0",
|
||||
"require-dir": "^1.2.0",
|
||||
"spectron": "^5.0.0",
|
||||
"spectron": "^7.0.0",
|
||||
"style-loader": "^0.23.1",
|
||||
"svg-sprite-loader": "^4.1.6",
|
||||
"svgo": "^1.2.2",
|
||||
"svgo-loader": "^2.2.0",
|
||||
"svgo": "^1.3.0",
|
||||
"svgo-loader": "^2.2.1",
|
||||
"to-string-loader": "^1.1.5",
|
||||
"url-loader": "^1.1.2",
|
||||
"vue-html-loader": "^1.2.4",
|
||||
"vue-loader": "^15.7.0",
|
||||
"vue-loader": "^15.7.1",
|
||||
"vue-style-loader": "^4.1.2",
|
||||
"vue-template-compiler": "^2.6.10",
|
||||
"webpack": "^4.31.0",
|
||||
"webpack": "^4.36.1",
|
||||
"webpack-bundle-analyzer": "^3.3.2",
|
||||
"webpack-cli": "^3.3.2",
|
||||
"webpack-cli": "^3.3.6",
|
||||
"webpack-dev-server": "^3.7.2",
|
||||
"webpack-hot-middleware": "^2.25.0",
|
||||
"webpack-merge": "^4.2.1"
|
||||
|
@ -1,7 +1,6 @@
|
||||
import path from 'path'
|
||||
|
||||
class EnvPaths {
|
||||
|
||||
/**
|
||||
* @param {string} userDataPath The user data path.
|
||||
* @returns
|
||||
|
@ -11,7 +11,7 @@ export const exists = async p => {
|
||||
try {
|
||||
await fs.access(p)
|
||||
return true
|
||||
} catch(_) {
|
||||
} catch (_) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@ -56,7 +56,6 @@ export const isMarkdownFile = filepath => {
|
||||
return isFile(filepath) && hasMarkdownExtension(filepath)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if the path is a markdown file or symbolic link to a markdown file.
|
||||
*
|
||||
|
@ -5,11 +5,10 @@ import Keybindings from '../keyboard/shortcutHandler'
|
||||
import AppMenu from '../menu'
|
||||
|
||||
class Accessor {
|
||||
|
||||
/**
|
||||
* @param {AppEnvironment} appEnvironment The application environment instance.
|
||||
*/
|
||||
constructor(appEnvironment) {
|
||||
constructor (appEnvironment) {
|
||||
const userDataPath = appEnvironment.paths.userDataPath
|
||||
|
||||
this.env = appEnvironment
|
||||
|
@ -10,7 +10,6 @@ const patchEnvPath = () => {
|
||||
}
|
||||
|
||||
export class AppEnvironment {
|
||||
|
||||
constructor (options) {
|
||||
this._id = envId++
|
||||
this._appPaths = new AppPaths(options.userDataPath)
|
||||
@ -24,7 +23,7 @@ export class AppEnvironment {
|
||||
*
|
||||
* @returns {number} Returns an unique identifier.
|
||||
*/
|
||||
get id() {
|
||||
get id () {
|
||||
return this._id
|
||||
}
|
||||
|
||||
|
@ -17,14 +17,13 @@ import EditorWindow from '../windows/editor'
|
||||
import SettingWindow from '../windows/setting'
|
||||
|
||||
class App {
|
||||
|
||||
/**
|
||||
* @param {Accessor} accessor The application accessor for application instances.
|
||||
* @param {arg.Result} args Parsed application arguments.
|
||||
*/
|
||||
constructor (accessor, args) {
|
||||
this._accessor = accessor
|
||||
this._args = args || {_: []}
|
||||
this._args = args || { _: [] }
|
||||
this._openFilesCache = []
|
||||
this._openFilesTimer = null
|
||||
this._windowManager = this._accessor.windowManager
|
||||
@ -78,7 +77,7 @@ class App {
|
||||
|
||||
app.on('open-file', this.openFile) // macOS only
|
||||
|
||||
app.on('ready', this.ready)
|
||||
app.on('ready', this.ready)
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
// Close all the image path watcher
|
||||
@ -271,7 +270,7 @@ class App {
|
||||
* @param {boolean} openFilesInSameWindow Open all files in the same window with
|
||||
* the first directory and discard other directories.
|
||||
*/
|
||||
_openPathList (pathsToOpen, openFilesInSameWindow=false) {
|
||||
_openPathList (pathsToOpen, openFilesInSameWindow = false) {
|
||||
const { _windowManager } = this
|
||||
const openFilesInNewWindow = this._accessor.preferences.getItem('openFilesInNewWindow')
|
||||
|
||||
@ -372,12 +371,11 @@ class App {
|
||||
const { rootDirectory, fileList } = item
|
||||
this._createEditorWindow(rootDirectory, fileList)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Open each file and directory in a new window.
|
||||
|
||||
// Open each file and directory in a new window.
|
||||
else {
|
||||
for (const pathname of filesToOpen) {
|
||||
this._createEditorWindow(null, [ pathname ])
|
||||
this._createEditorWindow(null, [pathname])
|
||||
}
|
||||
|
||||
for (const item of directoriesToOpen) {
|
||||
@ -441,7 +439,7 @@ class App {
|
||||
ipcMain.on('app-open-file-by-id', (windowId, filePath) => {
|
||||
const openFilesInNewWindow = this._accessor.preferences.getItem('openFilesInNewWindow')
|
||||
if (openFilesInNewWindow) {
|
||||
this._createEditorWindow(null, [ filePath ])
|
||||
this._createEditorWindow(null, [filePath])
|
||||
} else {
|
||||
const editor = this._windowManager.get(windowId)
|
||||
if (editor) {
|
||||
@ -458,8 +456,8 @@ class App {
|
||||
if (editor) {
|
||||
editor.openTabsFromPaths(
|
||||
fileList.map(p => normalizeMarkdownPath(p))
|
||||
.filter(i => i && !i.isDir)
|
||||
.map(i => i.path))
|
||||
.filter(i => i && !i.isDir)
|
||||
.map(i => i.path))
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -467,7 +465,7 @@ class App {
|
||||
ipcMain.on('app-open-markdown-by-id', (windowId, data) => {
|
||||
const openFilesInNewWindow = this._accessor.preferences.getItem('openFilesInNewWindow')
|
||||
if (openFilesInNewWindow) {
|
||||
this._createEditorWindow(null, [], [ data ])
|
||||
this._createEditorWindow(null, [], [data])
|
||||
} else {
|
||||
const editor = this._windowManager.get(windowId)
|
||||
if (editor) {
|
||||
@ -504,6 +502,7 @@ class App {
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.on('mt::open-setting-window', () => {
|
||||
ipcMain.emit('app-create-settings-window')
|
||||
})
|
||||
|
@ -3,7 +3,6 @@ import EnvPaths from 'common/envPaths'
|
||||
import { ensureDirSync } from 'common/filesystem'
|
||||
|
||||
class AppPaths extends EnvPaths {
|
||||
|
||||
/**
|
||||
* Configure and sets all application paths.
|
||||
*
|
||||
|
@ -5,7 +5,7 @@ import Watcher, { WATCHER_STABILITY_THRESHOLD, WATCHER_STABILITY_POLL_INTERVAL }
|
||||
import { WindowType } from '../windows/base'
|
||||
|
||||
class WindowActivityList {
|
||||
constructor() {
|
||||
constructor () {
|
||||
// Oldest Newest
|
||||
// <number>, ... , <number>
|
||||
this._buf = []
|
||||
@ -51,13 +51,12 @@ class WindowActivityList {
|
||||
}
|
||||
|
||||
class WindowManager extends EventEmitter {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {AppMenu} appMenu The application menu instance.
|
||||
* @param {Preference} preferences The preference instance.
|
||||
*/
|
||||
constructor(appMenu, preferences) {
|
||||
constructor (appMenu, preferences) {
|
||||
super()
|
||||
|
||||
this._appMenu = appMenu
|
||||
@ -137,7 +136,7 @@ class WindowManager extends EventEmitter {
|
||||
window.removeAllListeners('window-focus')
|
||||
|
||||
this._windowActivity.delete(windowId)
|
||||
let nextWindowId = this._windowActivity.getNewest()
|
||||
const nextWindowId = this._windowActivity.getNewest()
|
||||
this.setActiveWindow(nextWindowId)
|
||||
|
||||
_windows.delete(windowId)
|
||||
@ -232,7 +231,7 @@ class WindowManager extends EventEmitter {
|
||||
const lastActiveEditorId = this.getActiveEditorId() // editor id or null
|
||||
|
||||
if (this.windowCount <= 1) {
|
||||
return [ { windowId: lastActiveEditorId, fileList } ]
|
||||
return [{ windowId: lastActiveEditorId, fileList }]
|
||||
}
|
||||
|
||||
// Array of scores, same order like fileList.
|
||||
|
@ -12,7 +12,7 @@ const cli = () => {
|
||||
let argv = process.argv.slice(1)
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
// Don't pass electron development arguments to Mark Text and change user data path.
|
||||
argv = [ '--user-data-dir', path.join(getPath('appData'), 'marktext-dev') ]
|
||||
argv = ['--user-data-dir', path.join(getPath('appData'), 'marktext-dev')]
|
||||
}
|
||||
|
||||
const args = parseArgs(argv, true)
|
||||
|
@ -21,7 +21,7 @@ export const defaultPreferenceWinOptions = {
|
||||
height: 650,
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
webSecurity: false,
|
||||
webSecurity: false
|
||||
},
|
||||
fullscreenable: false,
|
||||
fullscreen: false,
|
||||
|
@ -171,21 +171,21 @@ class DataCenter extends EventEmitter {
|
||||
ipcMain.on('mt::ask-for-modify-image-folder-path', e => {
|
||||
const win = BrowserWindow.fromWebContents(e.sender)
|
||||
const folder = dialog.showOpenDialog(win, {
|
||||
properties: [ 'openDirectory', 'createDirectory' ]
|
||||
properties: ['openDirectory', 'createDirectory']
|
||||
})
|
||||
if (folder && folder[0]) {
|
||||
this.setItem('imageFolderPath', folder[0])
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.on('mt::set-user-data', (e, userData) =>{
|
||||
ipcMain.on('mt::set-user-data', (e, userData) => {
|
||||
this.setItems(userData)
|
||||
})
|
||||
|
||||
ipcMain.on('mt::ask-for-image-path', e => {
|
||||
const win = BrowserWindow.fromWebContents(e.sender)
|
||||
const files = dialog.showOpenDialog(win, {
|
||||
properties: [ 'openFile' ],
|
||||
properties: ['openFile'],
|
||||
filters: [{
|
||||
name: 'Images',
|
||||
extensions: IMAGE_EXTENSIONS
|
||||
|
@ -24,7 +24,7 @@ export const normalizeAndResolvePath = pathname => {
|
||||
|
||||
export const writeFile = (pathname, content, extension) => {
|
||||
if (!pathname) {
|
||||
return Promise.reject('[ERROR] Cannot save file without path.')
|
||||
return Promise.reject(new Error('[ERROR] Cannot save file without path.'))
|
||||
}
|
||||
pathname = !extension || pathname.endsWith(extension) ? pathname : `${pathname}${extension}`
|
||||
|
||||
|
@ -35,7 +35,7 @@ const add = async (win, pathname, type, endOfLine) => {
|
||||
try {
|
||||
const data = await loadMarkdownFile(pathname, endOfLine)
|
||||
file.data = data
|
||||
} catch(err) {
|
||||
} catch (err) {
|
||||
// Only notify user about opened files.
|
||||
if (type === 'file') {
|
||||
win.webContents.send('AGANI::show-notification', {
|
||||
@ -124,7 +124,6 @@ const unlinkDir = (win, pathname, type) => {
|
||||
}
|
||||
|
||||
class Watcher {
|
||||
|
||||
/**
|
||||
* @param {Preference} preferences The preference instance.
|
||||
*/
|
||||
@ -306,7 +305,7 @@ class Watcher {
|
||||
* @param {string} pathname The path to ignore.
|
||||
* @param {number} [duration] The duration in ms to ignore the changed event.
|
||||
*/
|
||||
ignoreChangedEvent (windowId, pathname, duration=WATCHER_STABILITY_THRESHOLD + WATCHER_STABILITY_POLL_INTERVAL + 1000) {
|
||||
ignoreChangedEvent (windowId, pathname, duration = WATCHER_STABILITY_THRESHOLD + WATCHER_STABILITY_POLL_INTERVAL + 1000) {
|
||||
this._ignoreChangeEvents.push({ windowId, pathname, duration, start: new Date() })
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@ export const getVirtualLetters = () => {
|
||||
// Full list of supported virtual keys:
|
||||
// https://github.com/parro-it/keyboardevent-from-electron-accelerator/blob/afdbd57bead1e139d7bd03c763778dce6ca8c35d/main.js#L104
|
||||
const currentKeymap = getCurrentKeymap()
|
||||
let vkeys = {}
|
||||
const vkeys = {}
|
||||
for (const key in currentKeymap) {
|
||||
// TODO(fxha): Possibly, we can fix more broken accelerators without apply a manually fix later.
|
||||
if (!key.startsWith('Key')) {
|
||||
|
@ -14,7 +14,6 @@ import { getKeyboardLanguage, getVirtualLetters } from '../keyboard'
|
||||
// Upgrade Heading: Ctrl+= -> points to Ctrl+Plus which is ok; Ctrl+Plus is broken
|
||||
|
||||
class Keybindings {
|
||||
|
||||
/**
|
||||
* @param {string} userDataPath The user data path.
|
||||
*/
|
||||
@ -282,7 +281,7 @@ class Keybindings {
|
||||
|
||||
export const parseMenu = menuTemplate => {
|
||||
const { submenu, accelerator, click, id, visible } = menuTemplate
|
||||
let items = []
|
||||
const items = []
|
||||
if (Array.isArray(menuTemplate)) {
|
||||
for (const item of menuTemplate) {
|
||||
const subitems = parseMenu(item)
|
||||
|
@ -398,7 +398,7 @@ export const importFile = async win => {
|
||||
}
|
||||
|
||||
dialog.showOpenDialog(win, {
|
||||
properties: [ 'openFile' ],
|
||||
properties: ['openFile'],
|
||||
filters: [{
|
||||
name: 'All Files',
|
||||
extensions: PANDOC_EXTENSIONS
|
||||
|
@ -2,13 +2,13 @@ import { ipcMain } from 'electron'
|
||||
import { getMenuItemById } from '../../menu'
|
||||
|
||||
const MENU_ID_FORMAT_MAP = {
|
||||
'strongMenuItem': 'strong',
|
||||
'emphasisMenuItem': 'em',
|
||||
'inlineCodeMenuItem': 'inline_code',
|
||||
'strikeMenuItem': 'del',
|
||||
'hyperlinkMenuItem': 'link',
|
||||
'imageMenuItem': 'image',
|
||||
'mathMenuItem': 'inline_math'
|
||||
strongMenuItem: 'strong',
|
||||
emphasisMenuItem: 'em',
|
||||
inlineCodeMenuItem: 'inline_code',
|
||||
strikeMenuItem: 'del',
|
||||
hyperlinkMenuItem: 'link',
|
||||
imageMenuItem: 'image',
|
||||
mathMenuItem: 'inline_math'
|
||||
}
|
||||
|
||||
const selectFormat = formats => {
|
||||
|
@ -12,21 +12,21 @@ const DISABLE_LABELS = [
|
||||
]
|
||||
|
||||
const MENU_ID_MAP = {
|
||||
'heading1MenuItem': 'h1',
|
||||
'heading2MenuItem': 'h2',
|
||||
'heading3MenuItem': 'h3',
|
||||
'heading4MenuItem': 'h4',
|
||||
'heading5MenuItem': 'h5',
|
||||
'heading6MenuItem': 'h6',
|
||||
'tableMenuItem': 'figure',
|
||||
'codeFencesMenuItem': 'pre',
|
||||
'quoteBlockMenuItem': 'blockquote',
|
||||
'orderListMenuItem': 'ol',
|
||||
'bulletListMenuItem': 'ul',
|
||||
'taskListMenuItem': 'ul',
|
||||
'paragraphMenuItem': 'p',
|
||||
'horizontalLineMenuItem': 'hr',
|
||||
'frontMatterMenuItem': 'pre'
|
||||
heading1MenuItem: 'h1',
|
||||
heading2MenuItem: 'h2',
|
||||
heading3MenuItem: 'h3',
|
||||
heading4MenuItem: 'h4',
|
||||
heading5MenuItem: 'h5',
|
||||
heading6MenuItem: 'h6',
|
||||
tableMenuItem: 'figure',
|
||||
codeFencesMenuItem: 'pre',
|
||||
quoteBlockMenuItem: 'blockquote',
|
||||
orderListMenuItem: 'ol',
|
||||
bulletListMenuItem: 'ul',
|
||||
taskListMenuItem: 'ul',
|
||||
paragraphMenuItem: 'p',
|
||||
horizontalLineMenuItem: 'hr',
|
||||
frontMatterMenuItem: 'pre'
|
||||
}
|
||||
|
||||
const setParagraphMenuItemStatus = bool => {
|
||||
|
@ -14,7 +14,6 @@ export const MenuType = {
|
||||
}
|
||||
|
||||
class AppMenu {
|
||||
|
||||
/**
|
||||
* @param {Preference} preferences The preferences instances.
|
||||
* @param {Keybindings} keybindings The keybindings instances.
|
||||
@ -43,7 +42,7 @@ class AppMenu {
|
||||
if (isOsxOrWindows) app.addRecentDocument(filePath)
|
||||
if (isOsx) return
|
||||
|
||||
let recentDocuments = this.getRecentlyUsedDocuments()
|
||||
const recentDocuments = this.getRecentlyUsedDocuments()
|
||||
const index = recentDocuments.indexOf(filePath)
|
||||
let needSave = index !== 0
|
||||
if (index > 0) {
|
||||
@ -74,7 +73,7 @@ class AppMenu {
|
||||
}
|
||||
|
||||
try {
|
||||
let recentDocuments = JSON.parse(fs.readFileSync(RECENTS_PATH, 'utf-8'))
|
||||
const recentDocuments = JSON.parse(fs.readFileSync(RECENTS_PATH, 'utf-8'))
|
||||
.filter(f => f && (isFile(f) || isDirectory(f)))
|
||||
|
||||
if (recentDocuments.length > MAX_RECENTLY_USED_DOCUMENTS) {
|
||||
|
@ -6,7 +6,7 @@ import { isOsx } from '../../config'
|
||||
|
||||
export default function (keybindings, userPreference, recentlyUsedFiles) {
|
||||
const { autoSave } = userPreference.getAll()
|
||||
let fileMenu = {
|
||||
const fileMenu = {
|
||||
label: 'File',
|
||||
submenu: [{
|
||||
label: 'New Tab',
|
||||
@ -39,7 +39,7 @@ export default function (keybindings, userPreference, recentlyUsedFiles) {
|
||||
}
|
||||
|
||||
if (!isOsx) {
|
||||
let recentlyUsedMenu = {
|
||||
const recentlyUsedMenu = {
|
||||
label: 'Open Recent',
|
||||
submenu: []
|
||||
}
|
||||
@ -150,7 +150,7 @@ export default function (keybindings, userPreference, recentlyUsedFiles) {
|
||||
userSetting(menuItem, browserWindow)
|
||||
}
|
||||
}, {
|
||||
type: 'separator',
|
||||
type: 'separator'
|
||||
}, {
|
||||
label: 'Close Tab',
|
||||
accelerator: keybindings.getAccelerator('fileCloseTab'),
|
||||
|
@ -13,12 +13,12 @@ export dockMenu from './dock'
|
||||
|
||||
/**
|
||||
* Create the setting window menu.
|
||||
*
|
||||
*
|
||||
* @param {Keybindings} keybindings The keybindings instance
|
||||
*/
|
||||
export const configSettingMenu = (keybindings) => {
|
||||
return [
|
||||
...(process.platform === 'darwin' ? [ marktext(keybindings) ] : []),
|
||||
...(process.platform === 'darwin' ? [marktext(keybindings)] : []),
|
||||
prefEdit(keybindings),
|
||||
help()
|
||||
]
|
||||
@ -33,7 +33,7 @@ export const configSettingMenu = (keybindings) => {
|
||||
*/
|
||||
export default function (keybindings, preferences, recentlyUsedFiles) {
|
||||
return [
|
||||
...(process.platform === 'darwin' ? [ marktext(keybindings) ] : []),
|
||||
...(process.platform === 'darwin' ? [marktext(keybindings)] : []),
|
||||
file(keybindings, preferences, recentlyUsedFiles),
|
||||
edit(keybindings, preferences),
|
||||
paragraph(keybindings),
|
||||
|
@ -2,7 +2,7 @@ import { ipcMain } from 'electron'
|
||||
import * as actions from '../actions/view'
|
||||
|
||||
export default function (keybindings) {
|
||||
let viewMenu = {
|
||||
const viewMenu = {
|
||||
label: 'View',
|
||||
submenu: [{
|
||||
id: 'sourceCodeModeMenuItem',
|
||||
|
@ -24,7 +24,6 @@ const isDarkSystemMode = () => {
|
||||
const PREFERENCES_FILE_NAME = 'preferences'
|
||||
|
||||
class Preference extends EventEmitter {
|
||||
|
||||
/**
|
||||
* @param {AppPaths} userDataPath The path instance.
|
||||
*
|
||||
|
@ -11,7 +11,7 @@ export const getUniqueId = () => {
|
||||
export const getRecommendTitleFromMarkdownString = markdown => {
|
||||
const tokens = markdown.match(/#{1,6} {1,}(.+)(?:\n|$)/g)
|
||||
if (!tokens) return ''
|
||||
let headers = tokens.map(t => {
|
||||
const headers = tokens.map(t => {
|
||||
const matches = t.trim().match(/(#{1,6}) {1,}(.+)/)
|
||||
return {
|
||||
level: matches[1].length,
|
||||
|
@ -25,7 +25,6 @@ export const WindowLifecycle = {
|
||||
}
|
||||
|
||||
class BaseWindow extends EventEmitter {
|
||||
|
||||
/**
|
||||
* @param {Accessor} accessor The application accessor for application instances.
|
||||
*/
|
||||
|
@ -9,7 +9,6 @@ import { TITLE_BAR_HEIGHT, editorWinOptions, isLinux, isOsx } from '../config'
|
||||
import { loadMarkdownFile } from '../filesystem/markdown'
|
||||
|
||||
class EditorWindow extends BaseWindow {
|
||||
|
||||
/**
|
||||
* @param {Accessor} accessor The application accessor for application instances.
|
||||
*/
|
||||
@ -195,7 +194,7 @@ class EditorWindow extends BaseWindow {
|
||||
openTabsFromPaths (filePaths) {
|
||||
if (!filePaths || filePaths.length === 0) return
|
||||
|
||||
const fileList = filePaths.map(p => ({filePath: p, options: {}, selected: false}))
|
||||
const fileList = filePaths.map(p => ({ filePath: p, options: {}, selected: false }))
|
||||
fileList[0].selected = true
|
||||
this.openTabs(fileList)
|
||||
}
|
||||
@ -237,7 +236,7 @@ class EditorWindow extends BaseWindow {
|
||||
* @param {[boolean]} selected Whether the tab should become the selected tab (true if not set).
|
||||
* @param {[string]} markdown The markdown string.
|
||||
*/
|
||||
openUntitledTab (selected=true, markdown='') {
|
||||
openUntitledTab (selected = true, markdown = '') {
|
||||
if (this.lifecycle === WindowLifecycle.QUITTED) return
|
||||
|
||||
if (this.lifecycle === WindowLifecycle.READY) {
|
||||
@ -405,11 +404,11 @@ class EditorWindow extends BaseWindow {
|
||||
case 'material-dark':
|
||||
return '#34393f'
|
||||
case 'ulysses':
|
||||
return '#f3f3f3'
|
||||
return '#f3f3f3'
|
||||
case 'graphite':
|
||||
return '#f7f7f7'
|
||||
case 'one-dark':
|
||||
return '#282c34'
|
||||
return '#282c34'
|
||||
case 'light':
|
||||
default:
|
||||
return '#ffffff'
|
||||
|
@ -6,7 +6,6 @@ import { centerWindowOptions } from './utils'
|
||||
import { TITLE_BAR_HEIGHT, defaultPreferenceWinOptions, isLinux, isOsx } from '../config'
|
||||
|
||||
class SettingWindow extends BaseWindow {
|
||||
|
||||
/**
|
||||
* @param {Accessor} accessor The application accessor for application instances.
|
||||
*/
|
||||
|
@ -189,20 +189,20 @@ export const DEFAULT_TURNDOWN_CONFIG = {
|
||||
}
|
||||
|
||||
export const FORMAT_MARKER_MAP = {
|
||||
'em': '*',
|
||||
'inline_code': '`',
|
||||
'strong': '**',
|
||||
'del': '~~',
|
||||
'inline_math': '$',
|
||||
'u': {
|
||||
em: '*',
|
||||
inline_code: '`',
|
||||
strong: '**',
|
||||
del: '~~',
|
||||
inline_math: '$',
|
||||
u: {
|
||||
open: '<u>',
|
||||
close: '</u>'
|
||||
},
|
||||
'sub': {
|
||||
sub: {
|
||||
open: '<sub>',
|
||||
close: '</sub>'
|
||||
},
|
||||
'sup': {
|
||||
sup: {
|
||||
open: '<sup>',
|
||||
close: '</sup>'
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ import { EVENT_KEYS, CLASS_OR_ID } from '../config'
|
||||
import { findNearestParagraph } from '../selection/dom'
|
||||
import selection from '../selection'
|
||||
|
||||
// If the next block is header, put cursor after the `#{1,6} *`
|
||||
// If the next block is header, put cursor after the `#{1,6} *`
|
||||
const adjustOffset = (offset, block, event) => {
|
||||
if (/^span$/.test(block.type) && block.functionType === 'atxLine' && event.key === EVENT_KEYS.ArrowDown) {
|
||||
const match = /^\s{0,3}(?:#{1,6})(?:\s{1,}|$)/.exec(block.text)
|
||||
@ -151,7 +151,7 @@ const arrowCtrl = ContentState => {
|
||||
: (event.key === EVENT_KEYS.ArrowUp
|
||||
? activeBlock.text.length
|
||||
: 0)
|
||||
|
||||
|
||||
offset = adjustOffset(offset, activeBlock, event)
|
||||
|
||||
const key = activeBlock.type === 'p'
|
||||
|
@ -118,7 +118,7 @@ const backspaceCtrl = ContentState => {
|
||||
|
||||
if (this.isSelectAll()) {
|
||||
event.preventDefault()
|
||||
this.blocks = [ this.createBlockP() ]
|
||||
this.blocks = [this.createBlockP()]
|
||||
this.init()
|
||||
|
||||
this.render()
|
||||
|
@ -124,7 +124,7 @@ const clickCtrl = ContentState => {
|
||||
eventCenter.dispatch('format-click', {
|
||||
event,
|
||||
formatType,
|
||||
data,
|
||||
data
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
const LINE_BREAKS_REG = /\n/
|
||||
const FUNCTION_TYPE_LANG = {
|
||||
'multiplemath': 'latex',
|
||||
'flowchart': 'yaml',
|
||||
'mermaid': 'yaml',
|
||||
'sequence': 'yaml',
|
||||
multiplemath: 'latex',
|
||||
flowchart: 'yaml',
|
||||
mermaid: 'yaml',
|
||||
sequence: 'yaml',
|
||||
'vega-lite': 'yaml',
|
||||
'html': 'markup'
|
||||
html: 'markup'
|
||||
}
|
||||
|
||||
const containerCtrl = ContentState => {
|
||||
|
@ -184,7 +184,7 @@ const copyCutCtrl = ContentState => {
|
||||
const table = this.getTableBlock()
|
||||
if (!table) return
|
||||
const listIndentation = this.listIndentation
|
||||
const markdown = new ExportMarkdown([ table ], listIndentation).generate()
|
||||
const markdown = new ExportMarkdown([table], listIndentation).generate()
|
||||
event.clipboardData.setData('text/html', '')
|
||||
event.clipboardData.setData('text/plain', markdown)
|
||||
break
|
||||
|
@ -30,7 +30,7 @@ const deleteCtrl = ContentState => {
|
||||
}
|
||||
startBlock.text += nextBlock.text
|
||||
|
||||
const toBeRemoved = [ nextBlock ]
|
||||
const toBeRemoved = [nextBlock]
|
||||
|
||||
let parent = this.getParent(nextBlock)
|
||||
let target = nextBlock
|
||||
|
@ -60,7 +60,8 @@ const dragDropCtrl = ContentState => {
|
||||
ContentState.prototype.dragoverHandler = function (event) {
|
||||
// Cancel to allow tab drag&drop.
|
||||
if (!event.dataTransfer.types.length) {
|
||||
return event.dataTransfer.dropEffect = 'none'
|
||||
event.dataTransfer.dropEffect = 'none'
|
||||
return
|
||||
}
|
||||
|
||||
if (event.dataTransfer.types.includes('text/uri-list')) {
|
||||
@ -163,7 +164,7 @@ const dragDropCtrl = ContentState => {
|
||||
this.stateRender.urlMap.set(nSrc, src)
|
||||
}
|
||||
const imageWrapper = this.muya.container.querySelector(`span[data-id=${id}]`)
|
||||
|
||||
|
||||
if (imageWrapper) {
|
||||
const imageInfo = getImageInfo(imageWrapper)
|
||||
this.replaceImage(imageInfo, {
|
||||
|
@ -15,7 +15,7 @@ const emojiCtrl = ContentState => {
|
||||
delta = end - offset
|
||||
return token.children && Array.isArray(token.children) && token.children.length
|
||||
? findEmojiToken(token.children, offset)
|
||||
: token
|
||||
: token
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -167,7 +167,6 @@ const enterCtrl = ContentState => {
|
||||
cb: () => {}
|
||||
})
|
||||
this.selectedImage = null
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@ -285,7 +284,7 @@ const enterCtrl = ContentState => {
|
||||
start: { key, offset },
|
||||
end: { key, offset }
|
||||
}
|
||||
return this.partialRender([ block ])
|
||||
return this.partialRender([block])
|
||||
}
|
||||
|
||||
const getFirstBlockInNextRow = row => {
|
||||
@ -368,7 +367,7 @@ const enterCtrl = ContentState => {
|
||||
})
|
||||
const headerContent = this.createBlock('span', {
|
||||
text: post,
|
||||
functionType: block.headingStyle === 'atx'? 'atxLine' : 'paragraphContent'
|
||||
functionType: block.headingStyle === 'atx' ? 'atxLine' : 'paragraphContent'
|
||||
})
|
||||
this.appendChild(newBlock, headerContent)
|
||||
if (block.marker) {
|
||||
@ -394,10 +393,10 @@ const enterCtrl = ContentState => {
|
||||
break
|
||||
}
|
||||
case left === 0 && right === 0: {
|
||||
// paragraph is empty
|
||||
return this.enterInEmptyParagraph(block)
|
||||
// paragraph is empty
|
||||
return this.enterInEmptyParagraph(block)
|
||||
}
|
||||
case left !== 0 && right === 0:
|
||||
case left !== 0 && right === 0:
|
||||
case left === 0 && right !== 0: {
|
||||
// cursor at end of paragraph or at begin of paragraph
|
||||
if (type === 'li') {
|
||||
@ -447,9 +446,9 @@ const enterCtrl = ContentState => {
|
||||
// If block is pre block when updated, need to focus it.
|
||||
const preParagraphBlock = getParagraphBlock(block)
|
||||
const blockNeedFocus = this.codeBlockUpdate(preParagraphBlock)
|
||||
let tableNeedFocus = this.tableBlockUpdate(preParagraphBlock)
|
||||
let htmlNeedFocus = this.updateHtmlBlock(preParagraphBlock)
|
||||
let mathNeedFocus = this.updateMathBlock(preParagraphBlock)
|
||||
const tableNeedFocus = this.tableBlockUpdate(preParagraphBlock)
|
||||
const htmlNeedFocus = this.updateHtmlBlock(preParagraphBlock)
|
||||
const mathNeedFocus = this.updateMathBlock(preParagraphBlock)
|
||||
let cursorBlock
|
||||
|
||||
switch (true) {
|
||||
|
@ -27,7 +27,7 @@ const getOffset = (offset, { range: { start, end }, type, tag, anchor, alt }) =>
|
||||
if (dis >= 0 && dis < OPEN_MARKER_LEN) return -dis
|
||||
if (dis >= OPEN_MARKER_LEN && dis <= len - CLOSE_MARKER_LEN) return -OPEN_MARKER_LEN
|
||||
if (dis > len - CLOSE_MARKER_LEN && dis <= len) return len - dis - OPEN_MARKER_LEN - CLOSE_MARKER_LEN
|
||||
if (dis > len) return - OPEN_MARKER_LEN - CLOSE_MARKER_LEN
|
||||
if (dis > len) return -OPEN_MARKER_LEN - CLOSE_MARKER_LEN
|
||||
break
|
||||
}
|
||||
case 'link': {
|
||||
|
@ -63,9 +63,9 @@ class ContentState {
|
||||
|
||||
// Use to cache the keys which you don't want to remove.
|
||||
this.exemption = new Set()
|
||||
this.blocks = [ this.createBlockP() ]
|
||||
this.blocks = [this.createBlockP()]
|
||||
this.stateRender = new StateRender(muya)
|
||||
this.renderRange = [ null, null ]
|
||||
this.renderRange = [null, null]
|
||||
this.currentCursor = null
|
||||
// you'll select the outmost block of current cursor when you click the front icon.
|
||||
this.selectedBlock = null
|
||||
@ -166,7 +166,7 @@ class ContentState {
|
||||
const startOutMostBlock = this.findOutMostBlock(startBlock)
|
||||
const endOutMostBlock = this.findOutMostBlock(endBlock)
|
||||
|
||||
this.renderRange = [ startOutMostBlock.preSibling, endOutMostBlock.nextSibling ]
|
||||
this.renderRange = [startOutMostBlock.preSibling, endOutMostBlock.nextSibling]
|
||||
}
|
||||
|
||||
postRender () {
|
||||
@ -193,7 +193,7 @@ class ContentState {
|
||||
partialRender (isRenderCursor = true) {
|
||||
const { blocks, searchMatches: { matches, index } } = this
|
||||
const activeBlocks = this.getActiveBlocks()
|
||||
const [ startKey, endKey ] = this.renderRange
|
||||
const [startKey, endKey] = this.renderRange
|
||||
matches.forEach((m, i) => {
|
||||
m.active = i === index
|
||||
})
|
||||
@ -326,6 +326,7 @@ class ContentState {
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
// return block and its parents
|
||||
getParents (block) {
|
||||
const result = []
|
||||
@ -399,6 +400,7 @@ class ContentState {
|
||||
this.removeBlock(block)
|
||||
}
|
||||
}
|
||||
|
||||
// help func in removeBlocks
|
||||
findFigure (block) {
|
||||
if (block.type === 'figure') {
|
||||
@ -490,7 +492,7 @@ class ContentState {
|
||||
}
|
||||
|
||||
getActiveBlocks () {
|
||||
let result = []
|
||||
const result = []
|
||||
let block = this.getBlock(this.cursor.start.key)
|
||||
if (block) result.push(block)
|
||||
while (block && block.parent) {
|
||||
|
@ -9,10 +9,10 @@ const BRACKET_HASH = {
|
||||
'[': ']',
|
||||
'(': ')',
|
||||
'*': '*',
|
||||
'_': '_',
|
||||
_: '_',
|
||||
'"': '"',
|
||||
'\'': '\'',
|
||||
'$': '$',
|
||||
$: '$',
|
||||
'~': '~'
|
||||
}
|
||||
|
||||
@ -21,10 +21,10 @@ const BACK_HASH = {
|
||||
']': '[',
|
||||
')': '(',
|
||||
'*': '*',
|
||||
'_': '_',
|
||||
_: '_',
|
||||
'"': '"',
|
||||
'\'': '\'',
|
||||
'$': '$',
|
||||
$: '$',
|
||||
'~': '~'
|
||||
}
|
||||
|
||||
@ -86,7 +86,7 @@ const inputCtrl = ContentState => {
|
||||
const key = start.key
|
||||
const block = this.getBlock(key)
|
||||
const paragraph = document.querySelector(`#${key}`)
|
||||
let text = getTextContent(paragraph, [ CLASS_OR_ID['AG_MATH_RENDER'], CLASS_OR_ID['AG_RUBY_RENDER'] ])
|
||||
let text = getTextContent(paragraph, [CLASS_OR_ID['AG_MATH_RENDER'], CLASS_OR_ID['AG_RUBY_RENDER']])
|
||||
|
||||
let needRender = false
|
||||
let needRenderAll = false
|
||||
@ -186,7 +186,7 @@ const inputCtrl = ContentState => {
|
||||
/^\* /.test(text) &&
|
||||
preInputChar === '*' &&
|
||||
postInputChar === '*'
|
||||
) {
|
||||
) {
|
||||
text = text.substring(0, offset) + text.substring(offset + 1)
|
||||
needRender = true
|
||||
}
|
||||
|
@ -209,7 +209,7 @@ const paragraphCtrl = ContentState => {
|
||||
|
||||
ContentState.prototype.handleCodeBlockMenu = function () {
|
||||
const { start, end, affiliation } = this.selectionChange(this.cursor)
|
||||
let startBlock = this.getBlock(start.key)
|
||||
const startBlock = this.getBlock(start.key)
|
||||
const endBlock = this.getBlock(end.key)
|
||||
const startParents = this.getParents(startBlock)
|
||||
const endParents = this.getParents(endBlock)
|
||||
@ -323,7 +323,7 @@ const paragraphCtrl = ContentState => {
|
||||
lang,
|
||||
functionType: 'codeLine'
|
||||
})
|
||||
|
||||
|
||||
this.appendChild(codeBlock, codeLine)
|
||||
})
|
||||
const inputBlock = this.createBlock('span', {
|
||||
@ -547,12 +547,12 @@ const paragraphCtrl = ContentState => {
|
||||
headingStyle
|
||||
})
|
||||
const headerContent = this.createBlock('span', {
|
||||
text: headingStyle === 'atx'? newText.replace(/\n/g, ' ') : newText,
|
||||
functionType: headingStyle === 'atx'? 'atxLine' : 'paragraphContent'
|
||||
text: headingStyle === 'atx' ? newText.replace(/\n/g, ' ') : newText,
|
||||
functionType: headingStyle === 'atx' ? 'atxLine' : 'paragraphContent'
|
||||
})
|
||||
this.appendChild(header, headerContent)
|
||||
key = headerContent.key
|
||||
|
||||
|
||||
this.insertBefore(header, parent)
|
||||
this.removeBlock(parent)
|
||||
} else {
|
||||
|
@ -26,7 +26,7 @@ const pasteCtrl = ContentState => {
|
||||
if (list) {
|
||||
if (
|
||||
list.listType === fragment.listType &&
|
||||
listItem.bulletMarkerOrDelimiter === fragment.children[0].bulletMarkerOrDelimiter
|
||||
listItem.bulletMarkerOrDelimiter === fragment.children[0].bulletMarkerOrDelimiter
|
||||
) {
|
||||
return 'MERGE'
|
||||
} else {
|
||||
@ -87,7 +87,7 @@ const pasteCtrl = ContentState => {
|
||||
if (this.selectedImage) {
|
||||
this.replaceImage(this.selectedImage, {
|
||||
alt: id,
|
||||
src: imagePath,
|
||||
src: imagePath
|
||||
})
|
||||
} else {
|
||||
this.insertImage({
|
||||
@ -311,7 +311,7 @@ const pasteCtrl = ContentState => {
|
||||
case 'pasteAsPlainText': {
|
||||
const lines = text.trim().split(LINE_BREAKS_REG)
|
||||
let htmlBlock = null
|
||||
|
||||
|
||||
if (!startBlock.text || lines.length > 1) {
|
||||
htmlBlock = this.createBlockP((startBlock.text ? lines.slice(1) : lines).join('\n'))
|
||||
}
|
||||
@ -377,9 +377,9 @@ const pasteCtrl = ContentState => {
|
||||
// No matter copy loose list to tight list or vice versa, the result is one loose list.
|
||||
if (targetListType !== originListType) {
|
||||
if (!targetListType) {
|
||||
firstFragment.children.forEach(item => item.isLooseListItem = true)
|
||||
firstFragment.children.forEach(item => (item.isLooseListItem = true))
|
||||
} else {
|
||||
originList.children.forEach(item => item.isLooseListItem = true)
|
||||
originList.children.forEach(item => (item.isLooseListItem = true))
|
||||
}
|
||||
}
|
||||
|
||||
@ -422,7 +422,7 @@ const pasteCtrl = ContentState => {
|
||||
} else {
|
||||
startBlock.text += text
|
||||
}
|
||||
|
||||
|
||||
tailFragments.forEach(block => {
|
||||
this.insertAfter(block, target)
|
||||
target = block
|
||||
|
@ -70,7 +70,7 @@ const searchCtrl = ContentState => {
|
||||
|
||||
ContentState.prototype.search = function (value, opt = {}) {
|
||||
value = value.trim()
|
||||
let matches = []
|
||||
const matches = []
|
||||
const { caseSensitive, highlightIndex } = Object.assign(defaultSearchOption, opt)
|
||||
const { blocks } = this
|
||||
const search = blocks => {
|
||||
|
@ -112,7 +112,7 @@ const tabCtrl = ContentState => {
|
||||
let target = this.getNextSibling(listItem)
|
||||
while (target) {
|
||||
this.appendChild(newList, target)
|
||||
let temp = target
|
||||
const temp = target
|
||||
target = this.getNextSibling(target)
|
||||
this.removeBlock(temp, list)
|
||||
}
|
||||
@ -185,7 +185,6 @@ const tabCtrl = ContentState => {
|
||||
const tokens = tokenizer(text, [], false, labels)
|
||||
let result = null
|
||||
const walkTokens = tkns => {
|
||||
|
||||
for (const token of tkns) {
|
||||
const { marker, type, range, children, srcAndTitle, hrefAndTitle, backlash, closeTag, isFullLink, label } = token
|
||||
const { start, end } = range
|
||||
|
@ -260,7 +260,7 @@ const tableBlockCtrl = ContentState => {
|
||||
|
||||
if (target === 'row') {
|
||||
if (action === 'insert') {
|
||||
let newRow = (location === 'previous' && block.type === 'th')
|
||||
const newRow = (location === 'previous' && block.type === 'th')
|
||||
? createRow(column, true)
|
||||
: createRow(column, false)
|
||||
if (location === 'previous') {
|
||||
|
@ -234,7 +234,7 @@ const updateCtrl = ContentState => {
|
||||
this.removeBlock(nextSibling)
|
||||
this.removeBlock(block)
|
||||
const isLooseListItem = preSibling.children.some(c => c.isLooseListItem)
|
||||
preSibling.children.forEach(c => c.isLooseListItem = isLooseListItem)
|
||||
preSibling.children.forEach(c => (c.isLooseListItem = isLooseListItem))
|
||||
} else if (
|
||||
preSibling &&
|
||||
this.checkSameMarkerOrDelimiter(preSibling, bulletMarkerOrDelimiter)
|
||||
@ -242,7 +242,7 @@ const updateCtrl = ContentState => {
|
||||
this.appendChild(preSibling, newListItemBlock)
|
||||
this.removeBlock(block)
|
||||
const isLooseListItem = preSibling.children.some(c => c.isLooseListItem)
|
||||
preSibling.children.forEach(c => c.isLooseListItem = isLooseListItem)
|
||||
preSibling.children.forEach(c => (c.isLooseListItem = isLooseListItem))
|
||||
} else if (
|
||||
nextSibling &&
|
||||
this.checkSameMarkerOrDelimiter(nextSibling, bulletMarkerOrDelimiter)
|
||||
@ -250,7 +250,7 @@ const updateCtrl = ContentState => {
|
||||
this.insertBefore(newListItemBlock, nextSibling.children[0])
|
||||
this.removeBlock(block)
|
||||
const isLooseListItem = nextSibling.children.some(c => c.isLooseListItem)
|
||||
nextSibling.children.forEach(c => c.isLooseListItem = isLooseListItem)
|
||||
nextSibling.children.forEach(c => (c.isLooseListItem = isLooseListItem))
|
||||
} else {
|
||||
// Create a new list when changing list type, bullet or list delimiter
|
||||
const listBlock = this.createBlock(wrapperTag, {
|
||||
@ -284,7 +284,7 @@ const updateCtrl = ContentState => {
|
||||
}
|
||||
}
|
||||
if (TASK_LIST_REG.test(listItemText)) {
|
||||
const [,,tasklist,,,,] = listItemText.match(INLINE_UPDATE_REG) || []
|
||||
const [,, tasklist,,,,] = listItemText.match(INLINE_UPDATE_REG) || [] // eslint-disable-line comma-spacing
|
||||
return this.updateTaskListItem(block, 'tasklist', tasklist)
|
||||
} else {
|
||||
return block
|
||||
@ -420,7 +420,7 @@ const updateCtrl = ContentState => {
|
||||
|
||||
const text = line.text
|
||||
const lines = text.split('\n')
|
||||
let setextLines = []
|
||||
const setextLines = []
|
||||
const postParagraphLines = []
|
||||
let setextLineHasPushed = false
|
||||
|
||||
@ -467,7 +467,7 @@ const updateCtrl = ContentState => {
|
||||
const text = line.text
|
||||
const lines = text.split('\n')
|
||||
const preParagraphLines = []
|
||||
let quoteLines = []
|
||||
const quoteLines = []
|
||||
let quoteLinesHasPushed = false
|
||||
|
||||
for (const l of lines) {
|
||||
@ -490,7 +490,7 @@ const updateCtrl = ContentState => {
|
||||
}
|
||||
const headerContent = this.createBlock('span', {
|
||||
text: quoteLines.join('\n'),
|
||||
functionType: block.headingStyle === 'setext'? 'paragraphContent' : 'atxLine'
|
||||
functionType: block.headingStyle === 'setext' ? 'paragraphContent' : 'atxLine'
|
||||
})
|
||||
this.appendChild(quoteParagraphBlock, headerContent)
|
||||
} else {
|
||||
|
@ -5,6 +5,7 @@ class EventCenter {
|
||||
this.events = []
|
||||
this.listeners = {}
|
||||
}
|
||||
|
||||
/**
|
||||
* [attachDOMEvent] bind event listener to target, and return a unique ID,
|
||||
* this ID
|
||||
@ -22,6 +23,7 @@ class EventCenter {
|
||||
})
|
||||
return eventId
|
||||
}
|
||||
|
||||
/**
|
||||
* [detachDOMEvent removeEventListener]
|
||||
* @param {[type]} eventId [unique eventId]
|
||||
@ -34,12 +36,14 @@ class EventCenter {
|
||||
target.removeEventListener(event, listener, capture)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [detachAllDomEvents remove all the DOM events handler]
|
||||
*/
|
||||
detachAllDomEvents () {
|
||||
this.events.forEach(event => this.detachDOMEvent(event.eventId))
|
||||
}
|
||||
|
||||
/**
|
||||
* inner method for subscribe and subscribeOnce
|
||||
*/
|
||||
@ -49,15 +53,17 @@ class EventCenter {
|
||||
if (listeners && Array.isArray(listeners)) {
|
||||
listeners.push(handler)
|
||||
} else {
|
||||
this.listeners[event] = [ handler ]
|
||||
this.listeners[event] = [handler]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [subscribe] subscribe custom event
|
||||
*/
|
||||
subscribe (event, listener) {
|
||||
this._subscribe(event, listener)
|
||||
}
|
||||
|
||||
/**
|
||||
* [unsubscribe] unsubscribe custom event
|
||||
*/
|
||||
@ -68,12 +74,14 @@ class EventCenter {
|
||||
listeners.splice(index, 1)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [subscribeOnce] usbscribe event and listen once
|
||||
*/
|
||||
subscribeOnce (event, listener) {
|
||||
this._subscribe(event, listener, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* dispatch custom event
|
||||
*/
|
||||
@ -88,6 +96,7 @@ class EventCenter {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Determine whether the event has been bind
|
||||
checkHasBind (cTarget, cEvent, cListener, cCapture) {
|
||||
for (const { target, event, listener, capture } of this.events) {
|
||||
|
@ -13,9 +13,11 @@ import './assets/styles/index.css'
|
||||
|
||||
class Muya {
|
||||
static plugins = []
|
||||
|
||||
static use (plugin) {
|
||||
this.plugins.push(plugin)
|
||||
}
|
||||
|
||||
constructor (container, options) {
|
||||
this.options = Object.assign({}, MUYA_DEFAULT_OPTION, options)
|
||||
const { markdown } = this.options
|
||||
@ -64,7 +66,7 @@ class Muya {
|
||||
|
||||
// Callback function to execute when mutations are observed
|
||||
const callback = (mutationsList, observer) => {
|
||||
for(const mutation of mutationsList) {
|
||||
for (const mutation of mutationsList) {
|
||||
if (mutation.type === 'childList') {
|
||||
const { removedNodes, target } = mutation
|
||||
// If the code executes any of the following `if` statements, the editor has gone wrong.
|
||||
|
@ -15,16 +15,16 @@ export const block = {
|
||||
nptable: noop,
|
||||
blockquote: /^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,
|
||||
list: /^( {0,3})(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
|
||||
html: '^ {0,3}(?:' // optional indentation
|
||||
+ '<(script|pre|style)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)' // (1)
|
||||
+ '|comment[^\\n]*(\\n+|$)' // (2)
|
||||
+ '|<\\?[\\s\\S]*?\\?>\\n*' // (3)
|
||||
+ '|<![A-Z][\\s\\S]*?>\\n*' // (4)
|
||||
+ '|<!\\[CDATA\\[[\\s\\S]*?\\]\\]>\\n*' // (5)
|
||||
+ '|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:\\n{2,}|$)' // (6)
|
||||
+ '|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=\\h*\\n)[\\s\\S]*?(?:\\n{2,}|$)' // (7) open tag
|
||||
+ '|</(?!script|pre|style)[a-z][\\w-]*\\s*>(?=\\h*\\n)[\\s\\S]*?(?:\\n{2,}|$)' // (7) closing tag
|
||||
+ ')',
|
||||
html: '^ {0,3}(?:' + // optional indentation
|
||||
'<(script|pre|style)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)' + // (1)
|
||||
'|comment[^\\n]*(\\n+|$)' + // (2)
|
||||
'|<\\?[\\s\\S]*?\\?>\\n*' + // (3)
|
||||
'|<![A-Z][\\s\\S]*?>\\n*' + // (4)
|
||||
'|<!\\[CDATA\\[[\\s\\S]*?\\]\\]>\\n*' + // (5)
|
||||
'|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:\\n{2,}|$)' + // (6)
|
||||
'|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=\\h*\\n)[\\s\\S]*?(?:\\n{2,}|$)' + // (7) open tag
|
||||
'|</(?!script|pre|style)[a-z][\\w-]*\\s*>(?=\\h*\\n)[\\s\\S]*?(?:\\n{2,}|$)' + // (7) closing tag
|
||||
')',
|
||||
def: /^ {0,3}\[(label)\]: *\n? *<?([^\s>]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,
|
||||
table: noop,
|
||||
lheading: /^([^\n]+)\n {0,3}(=|-){2,} *(?:\n+|$)/,
|
||||
@ -38,19 +38,19 @@ export const block = {
|
||||
|
||||
block._label = /(?!\s*\])(?:\\[\[\]]|[^\[\]])+/
|
||||
block._title = /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/
|
||||
block.def = edit(block.def).
|
||||
replace('label', block._label).
|
||||
replace('title', block._title).
|
||||
getRegex()
|
||||
block.def = edit(block.def)
|
||||
.replace('label', block._label)
|
||||
.replace('title', block._title)
|
||||
.getRegex()
|
||||
|
||||
block.checkbox = /^\[([ xX])\] +/
|
||||
block.bullet = /(?:[*+-]|\d{1,9}(?:\.|\)))/ // patched: support "(" as ordered list delimiter too
|
||||
// patched: fix https://github.com/marktext/marktext/issues/831#issuecomment-477719256
|
||||
// block.item = /^( *)(bull) ?[^\n]*(?:\n(?!\1bull ?)[^\n]*)*/
|
||||
block.item = /^(( {0,3})(bull) [^\n]*(?:\n(?!(\2bull |\2bull\n))[^\n]*)*|( {0,3})(bull)(?:\n(?!(\2bull |\2bull\n)))*)/
|
||||
block.item = edit(block.item, 'gm').
|
||||
replace(/bull/g, block.bullet).
|
||||
getRegex()
|
||||
block.item = edit(block.item, 'gm')
|
||||
.replace(/bull/g, block.bullet)
|
||||
.getRegex()
|
||||
|
||||
block.list = edit(block.list)
|
||||
.replace(/bull/g, block.bullet)
|
||||
@ -58,12 +58,12 @@ block.list = edit(block.list)
|
||||
.replace('def', '\\n+(?=' + block.def.source + ')')
|
||||
.getRegex()
|
||||
|
||||
block._tag = 'address|article|aside|base|basefont|blockquote|body|caption'
|
||||
+ '|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption'
|
||||
+ '|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe'
|
||||
+ '|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option'
|
||||
+ '|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr'
|
||||
+ '|track|ul'
|
||||
block._tag = 'address|article|aside|base|basefont|blockquote|body|caption' +
|
||||
'|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption' +
|
||||
'|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe' +
|
||||
'|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option' +
|
||||
'|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr' +
|
||||
'|track|ul'
|
||||
block._comment = /<!--(?!-?>)[\s\S]*?-->/
|
||||
block.html = edit(block.html, 'i')
|
||||
.replace('comment', block._comment)
|
||||
@ -98,9 +98,9 @@ export const gfm = Object.assign({}, normal, {
|
||||
})
|
||||
|
||||
gfm.paragraph = edit(block.paragraph)
|
||||
.replace('(?!', '(?!'
|
||||
+ gfm.fences.source.replace('\\1', '\\2') + '|'
|
||||
+ block.list.source.replace('\\1', '\\3') + '|')
|
||||
.replace('(?!', '(?!' +
|
||||
gfm.fences.source.replace('\\1', '\\2') + '|' +
|
||||
block.list.source.replace('\\1', '\\3') + '|')
|
||||
.getRegex()
|
||||
|
||||
/**
|
||||
@ -118,14 +118,14 @@ export const tables = Object.assign({}, gfm, {
|
||||
|
||||
export const pedantic = Object.assign({}, normal, {
|
||||
html: edit(
|
||||
'^ *(?:comment *(?:\\n|\\s*$)'
|
||||
+ '|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)' // closed tag
|
||||
+ '|<tag(?:"[^"]*"|\'[^\']*\'|\\s[^\'"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))')
|
||||
'^ *(?:comment *(?:\\n|\\s*$)' +
|
||||
'|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)' + // closed tag
|
||||
'|<tag(?:"[^"]*"|\'[^\']*\'|\\s[^\'"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))')
|
||||
.replace('comment', block._comment)
|
||||
.replace(/tag/g, '(?!(?:'
|
||||
+ 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub'
|
||||
+ '|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)'
|
||||
+ '\\b)\\w+(?!:|[^\\w\\s@]*@)\\b')
|
||||
.replace(/tag/g, '(?!(?:' +
|
||||
'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub' +
|
||||
'|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)' +
|
||||
'\\b)\\w+(?!:|[^\\w\\s@]*@)\\b')
|
||||
.getRegex(),
|
||||
def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/
|
||||
})
|
||||
|
@ -13,8 +13,8 @@ function marked (src, opt = {}) {
|
||||
throw new Error('marked(): input parameter is undefined or null')
|
||||
}
|
||||
if (typeof src !== 'string') {
|
||||
throw new Error('marked(): input parameter is of type '
|
||||
+ Object.prototype.toString.call(src) + ', string expected')
|
||||
throw new Error('marked(): input parameter is of type ' +
|
||||
Object.prototype.toString.call(src) + ', string expected')
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -39,7 +39,7 @@ function InlineLexer (links, options) {
|
||||
if (/^(?:autolink|code|tag)$/.test(key) && this.rules[key] instanceof RegExp) {
|
||||
this.highPriorityLinkRules[key] = this.rules[key]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -48,7 +48,7 @@ function InlineLexer (links, options) {
|
||||
|
||||
InlineLexer.prototype.output = function (src) {
|
||||
// src = src
|
||||
// .replace(/\u00a0/g, ' ')
|
||||
// .replace(/\u00a0/g, ' ')
|
||||
const { disableInline, emoji, math } = this.options
|
||||
if (disableInline) {
|
||||
return escape(src)
|
||||
|
@ -119,8 +119,8 @@ export const gfm = Object.assign({}, normal, {
|
||||
emoji: /^(:)([a-z_\d+-]+?)\1/ // not real GFM but put it in here
|
||||
})
|
||||
|
||||
gfm.url = edit(gfm.url, 'i').
|
||||
replace('email', gfm._extended_email)
|
||||
gfm.url = edit(gfm.url, 'i')
|
||||
.replace('email', gfm._extended_email)
|
||||
.getRegex()
|
||||
|
||||
/**
|
||||
|
@ -333,7 +333,7 @@ Lexer.prototype.token = function (src, top) {
|
||||
// Determine whether item is loose or not. If previous item is loose
|
||||
// this item is also loose.
|
||||
// A list is loose if any of its constituent list items are separated by blank lines,
|
||||
// or if any of its constituent list items directly contain two block-level elements with a blank line between them.
|
||||
// or if any of its constituent list items directly contain two block-level elements with a blank line between them.
|
||||
// loose = next = next || /^ *([*+-]|\d{1,9}(?:\.|\)))( +\S+\n\n(?!\s*$)|\n\n(?!\s*$))/.test(itemWithBullet)
|
||||
loose = next = next || /\n\n(?!\s*$)/.test(item)
|
||||
// Check if previous line ends with a new line.
|
||||
@ -392,8 +392,8 @@ Lexer.prototype.token = function (src, top) {
|
||||
type: this.options.sanitize
|
||||
? 'paragraph'
|
||||
: 'html',
|
||||
pre: !this.options.sanitizer
|
||||
&& (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
|
||||
pre: !this.options.sanitizer &&
|
||||
(cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
|
||||
text: cap[0]
|
||||
})
|
||||
continue
|
||||
|
@ -1,7 +1,7 @@
|
||||
import Renderer from './renderer'
|
||||
import InlineLexer from './inlineLexer'
|
||||
import Slugger from './slugger'
|
||||
import TextRenderer from './textRenderer'
|
||||
import TextRenderer from './textRenderer'
|
||||
import defaultOptions from './options'
|
||||
|
||||
/**
|
||||
@ -27,7 +27,7 @@ Parser.prototype.parse = function (src) {
|
||||
// use an InlineLexer with a TextRenderer to extract pure text
|
||||
this.inlineText = new InlineLexer(
|
||||
src.links,
|
||||
Object.assign({}, this.options, {renderer: new TextRenderer()})
|
||||
Object.assign({}, this.options, { renderer: new TextRenderer() })
|
||||
)
|
||||
this.tokens = src.reverse()
|
||||
|
||||
@ -194,7 +194,7 @@ Parser.prototype.tok = function () {
|
||||
return this.renderer.paragraph(this.parseText())
|
||||
}
|
||||
default: {
|
||||
let errMsg = 'Token with "' + this.token.type + '" type was not found.'
|
||||
const errMsg = 'Token with "' + this.token.type + '" type was not found.'
|
||||
if (this.options.silent) {
|
||||
console.error(errMsg)
|
||||
} else {
|
||||
|
@ -42,7 +42,7 @@ Renderer.prototype.emoji = function (text, emoji) {
|
||||
Renderer.prototype.code = function (code, infostring, escaped, codeBlockStyle) {
|
||||
const lang = (infostring || '').match(/\S*/)[0]
|
||||
if (this.options.highlight) {
|
||||
let out = this.options.highlight(code, lang)
|
||||
const out = this.options.highlight(code, lang)
|
||||
if (out !== null && out !== code) {
|
||||
escaped = true
|
||||
code = out
|
||||
|
@ -18,7 +18,7 @@ Slugger.prototype.slug = function (value) {
|
||||
.replace(/\s/g, '-')
|
||||
|
||||
if (this.seen.hasOwnProperty(slug)) {
|
||||
let originalSlug = slug
|
||||
const originalSlug = slug
|
||||
do {
|
||||
this.seen[originalSlug]++
|
||||
slug = originalSlug + '-' + this.seen[originalSlug]
|
||||
|
@ -3,7 +3,7 @@
|
||||
* returns only the textual part of the token
|
||||
*/
|
||||
|
||||
function TextRenderer() {}
|
||||
function TextRenderer () {}
|
||||
|
||||
// no need for block level renderers
|
||||
|
||||
@ -16,12 +16,12 @@ TextRenderer.prototype.text = function (text) {
|
||||
}
|
||||
|
||||
TextRenderer.prototype.link =
|
||||
TextRenderer.prototype.image = function(href, title, text) {
|
||||
TextRenderer.prototype.image = function (href, title, text) {
|
||||
return '' + text
|
||||
}
|
||||
|
||||
TextRenderer.prototype.br = function() {
|
||||
TextRenderer.prototype.br = function () {
|
||||
return ''
|
||||
}
|
||||
|
||||
export default TextRenderer
|
||||
export default TextRenderer
|
||||
|
@ -31,7 +31,7 @@ escape.escapeReplaceNoEncode = /[<>"']|&(?!#?\w+;)/g
|
||||
|
||||
export const unescape = function unescape (html) {
|
||||
// explicitly match decimal, hex, and named HTML entities
|
||||
return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig, function(_, n) {
|
||||
return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig, function (_, n) {
|
||||
n = n.toLowerCase()
|
||||
if (n === 'colon') return ':'
|
||||
if (n.charAt(0) === '#') {
|
||||
@ -47,19 +47,19 @@ export const edit = function edit (regex, opt) {
|
||||
regex = regex.source || regex
|
||||
opt = opt || ''
|
||||
return {
|
||||
replace: function(name, val) {
|
||||
replace: function (name, val) {
|
||||
val = val.source || val
|
||||
val = val.replace(/(^|[^\[])\^/g, '$1') // eslint-disable-line no-useless-escape
|
||||
regex = regex.replace(name, val)
|
||||
return this
|
||||
},
|
||||
getRegex: function() {
|
||||
getRegex: function () {
|
||||
return new RegExp(regex, opt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const cleanUrl = function cleanUrl(sanitize, base, href) {
|
||||
export const cleanUrl = function cleanUrl (sanitize, base, href) {
|
||||
if (sanitize) {
|
||||
let prot = ''
|
||||
try {
|
||||
@ -84,7 +84,7 @@ export const cleanUrl = function cleanUrl(sanitize, base, href) {
|
||||
return href
|
||||
}
|
||||
|
||||
const resolveUrl = function resolveUrl(base, href) {
|
||||
const resolveUrl = function resolveUrl (base, href) {
|
||||
if (!baseUrls[' ' + base]) {
|
||||
// we can ignore everything in base after the last slash of its path component,
|
||||
// but we might need to add _that_
|
||||
@ -105,18 +105,18 @@ const resolveUrl = function resolveUrl(base, href) {
|
||||
return base + href
|
||||
}
|
||||
}
|
||||
let baseUrls = {}
|
||||
let originIndependentUrl = /^$|^[a-z][a-z0-9+.-]*:|^[?#]/i
|
||||
const baseUrls = {}
|
||||
const originIndependentUrl = /^$|^[a-z][a-z0-9+.-]*:|^[?#]/i
|
||||
|
||||
export const noop = function noop () {}
|
||||
noop.exec = noop
|
||||
|
||||
export const splitCells = function splitCells(tableRow, count) {
|
||||
export const splitCells = function splitCells (tableRow, count) {
|
||||
// ensure that every cell-delimiting pipe has a space
|
||||
// before it to distinguish it from an escaped pipe
|
||||
let row = tableRow.replace(/\|/g, function (match, offset, str) {
|
||||
let escaped = false,
|
||||
curr = offset
|
||||
const row = tableRow.replace(/\|/g, function (match, offset, str) {
|
||||
let escaped = false
|
||||
let curr = offset
|
||||
while (--curr >= 0 && str[curr] === '\\') escaped = !escaped
|
||||
if (escaped) {
|
||||
// odd number of slashes means | is escaped
|
||||
@ -126,9 +126,9 @@ export const splitCells = function splitCells(tableRow, count) {
|
||||
// add space before unescaped |
|
||||
return ' |'
|
||||
}
|
||||
}),
|
||||
cells = row.split(/ \|/),
|
||||
i = 0
|
||||
})
|
||||
const cells = row.split(/ \|/)
|
||||
let i = 0
|
||||
|
||||
if (cells.length > count) {
|
||||
cells.splice(count)
|
||||
@ -146,7 +146,7 @@ export const splitCells = function splitCells(tableRow, count) {
|
||||
// Remove trailing 'c's. Equivalent to str.replace(/c*$/, '').
|
||||
// /c*$/ is vulnerable to REDOS.
|
||||
// invert: Remove suffix of non-c chars instead. Default falsey.
|
||||
export const rtrim = function rtrim(str, c, invert) {
|
||||
export const rtrim = function rtrim (str, c, invert) {
|
||||
if (str.length === 0) {
|
||||
return ''
|
||||
}
|
||||
@ -156,7 +156,7 @@ export const rtrim = function rtrim(str, c, invert) {
|
||||
|
||||
// Step left until we fail to match the invert condition.
|
||||
while (suffLen < str.length) {
|
||||
let currChar = str.charAt(str.length - suffLen - 1)
|
||||
const currChar = str.charAt(str.length - suffLen - 1)
|
||||
if (currChar === c && !invert) {
|
||||
suffLen++
|
||||
} else if (currChar !== c && invert) {
|
||||
@ -169,7 +169,7 @@ export const rtrim = function rtrim(str, c, invert) {
|
||||
return str.substr(0, str.length - suffLen)
|
||||
}
|
||||
|
||||
export const findClosingBracket = function findClosingBracket(str, b) {
|
||||
export const findClosingBracket = function findClosingBracket (str, b) {
|
||||
if (str.indexOf(b[1]) === -1) {
|
||||
return -1
|
||||
}
|
||||
@ -188,4 +188,3 @@ export const findClosingBracket = function findClosingBracket(str, b) {
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
|
@ -109,8 +109,8 @@ class StateRender {
|
||||
async renderDiagram () {
|
||||
const cache = this.diagramCache
|
||||
const RENDER_MAP = {
|
||||
'flowchart': flowchart,
|
||||
'sequence': Diagram,
|
||||
flowchart: flowchart,
|
||||
sequence: Diagram,
|
||||
'vega-lite': vegaEmbed
|
||||
}
|
||||
if (cache.size) {
|
||||
@ -123,7 +123,9 @@ class StateRender {
|
||||
Object.assign(options, { theme: this.muya.options.sequenceTheme })
|
||||
} else if (functionType === 'vega-lite') {
|
||||
Object.assign(options, {
|
||||
actions: false, tooltip: false, renderer: 'svg',
|
||||
actions: false,
|
||||
tooltip: false,
|
||||
renderer: 'svg',
|
||||
theme: this.muya.options.vegaTheme
|
||||
})
|
||||
}
|
||||
@ -206,10 +208,10 @@ class StateRender {
|
||||
|
||||
/**
|
||||
* Only render one block.
|
||||
*
|
||||
* @param {object} block
|
||||
* @param {array} activeBlocks
|
||||
* @param {array} matches
|
||||
*
|
||||
* @param {object} block
|
||||
* @param {array} activeBlocks
|
||||
* @param {array} matches
|
||||
*/
|
||||
singleRender (block, activeBlocks, matches) {
|
||||
const selector = `#${block.key}`
|
||||
|
@ -4,14 +4,14 @@ import { renderEditIcon } from './renderContainerEditIcon'
|
||||
import { h } from '../snabbdom'
|
||||
|
||||
const PRE_BLOCK_HASH = {
|
||||
'fencecode': `.${CLASS_OR_ID['AG_FENCE_CODE']}`,
|
||||
'indentcode': `.${CLASS_OR_ID['AG_INDENT_CODE']}`,
|
||||
'html': `.${CLASS_OR_ID['AG_HTML_BLOCK']}`,
|
||||
'frontmatter': `.${CLASS_OR_ID['AG_FRONT_MATTER']}`,
|
||||
'multiplemath': `.${CLASS_OR_ID['AG_MULTIPLE_MATH']}`,
|
||||
'flowchart': `.${CLASS_OR_ID['AG_FLOWCHART']}`,
|
||||
'sequence': `.${CLASS_OR_ID['AG_SEQUENCE']}`,
|
||||
'mermaid': `.${CLASS_OR_ID['AG_MERMAID']}`,
|
||||
fencecode: `.${CLASS_OR_ID['AG_FENCE_CODE']}`,
|
||||
indentcode: `.${CLASS_OR_ID['AG_INDENT_CODE']}`,
|
||||
html: `.${CLASS_OR_ID['AG_HTML_BLOCK']}`,
|
||||
frontmatter: `.${CLASS_OR_ID['AG_FRONT_MATTER']}`,
|
||||
multiplemath: `.${CLASS_OR_ID['AG_MULTIPLE_MATH']}`,
|
||||
flowchart: `.${CLASS_OR_ID['AG_FLOWCHART']}`,
|
||||
sequence: `.${CLASS_OR_ID['AG_SEQUENCE']}`,
|
||||
mermaid: `.${CLASS_OR_ID['AG_MERMAID']}`,
|
||||
'vega-lite': `.${CLASS_OR_ID['AG_VEGA_LITE']}`
|
||||
}
|
||||
|
||||
|
@ -23,16 +23,16 @@ import mermaidIcon from '../../../assets/pngicon/mermaid/2.png'
|
||||
import vegaIcon from '../../../assets/pngicon/chart/2.png'
|
||||
|
||||
const FUNCTION_TYPE_HASH = {
|
||||
'mermaid': mermaidIcon,
|
||||
'flowchart': flowchartIcon,
|
||||
'sequence': sequenceIcon,
|
||||
mermaid: mermaidIcon,
|
||||
flowchart: flowchartIcon,
|
||||
sequence: sequenceIcon,
|
||||
'vega-lite': vegaIcon,
|
||||
'table': newTableIcon,
|
||||
'html': htmlIcon,
|
||||
'multiplemath': mathblockIcon,
|
||||
'fencecode': codeIcon,
|
||||
'indentcode': codeIcon,
|
||||
'frontmatter': frontMatterIcon
|
||||
table: newTableIcon,
|
||||
html: htmlIcon,
|
||||
multiplemath: mathblockIcon,
|
||||
fencecode: codeIcon,
|
||||
indentcode: codeIcon,
|
||||
frontmatter: frontMatterIcon
|
||||
}
|
||||
|
||||
export default function renderIcon (block) {
|
||||
|
@ -226,5 +226,5 @@ export default function renderLeafBlock (block, activeBlocks, matches, useCache
|
||||
return h(selector, data, [this.renderIcon(block), ...children])
|
||||
} else {
|
||||
return h(selector, data, children)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ const renderToolBar = (type, tools, activeBlocks) => {
|
||||
}
|
||||
}, iconVnode)
|
||||
})
|
||||
let selector = `div.ag-tool-${type}.${CLASS_OR_ID['AG_TOOL_BAR']}`
|
||||
const selector = `div.ag-tool-${type}.${CLASS_OR_ID['AG_TOOL_BAR']}`
|
||||
|
||||
return h(selector, {
|
||||
attrs: {
|
||||
|
@ -8,8 +8,8 @@ export default function emoji (h, cursor, block, token, outerClass) {
|
||||
const validation = validEmoji(token.content)
|
||||
const finalClass = validation ? className : CLASS_OR_ID['AG_WARN']
|
||||
const contentSelector = finalClass !== CLASS_OR_ID['AG_GRAY']
|
||||
? `span.${finalClass}.${CLASS_OR_ID['AG_INLINE_RULE']}.${CLASS_OR_ID['AG_EMOJI_MARKED_TEXT']}`
|
||||
: `span.${CLASS_OR_ID['AG_INLINE_RULE']}.${CLASS_OR_ID['AG_EMOJI_MARKED_TEXT']}`
|
||||
? `span.${finalClass}.${CLASS_OR_ID['AG_INLINE_RULE']}.${CLASS_OR_ID['AG_EMOJI_MARKED_TEXT']}`
|
||||
: `span.${CLASS_OR_ID['AG_INLINE_RULE']}.${CLASS_OR_ID['AG_EMOJI_MARKED_TEXT']}`
|
||||
|
||||
let startMarkerSelector = `span.${finalClass}.${CLASS_OR_ID['AG_EMOJI_MARKER']}`
|
||||
let endMarkerSelector = startMarkerSelector
|
||||
|
@ -11,7 +11,7 @@ export default function softLineBreak (h, cursor, block, token, outerClass) {
|
||||
]
|
||||
} else {
|
||||
return [
|
||||
h(`span.${className}`, [ h(`span.${spaceClass}`, spaces), lineBreak ])
|
||||
h(`span.${className}`, [h(`span.${spaceClass}`, spaces), lineBreak])
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ export default function htmlRuby (h, cursor, block, token, outerClass) {
|
||||
|
||||
const previewSelector = `span.${CLASS_OR_ID['AG_RUBY_RENDER']}`
|
||||
|
||||
|
||||
return children ? [
|
||||
h(`span.${className}.${CLASS_OR_ID['AG_RUBY']}`, [
|
||||
h(`span.${CLASS_OR_ID['AG_INLINE_RULE']}.${CLASS_OR_ID['AG_RUBY_TEXT']}`, content),
|
||||
|
@ -13,9 +13,9 @@ export default function htmlTag (h, cursor, block, token, outerClass) {
|
||||
|
||||
const anchor = Array.isArray(children) && tag !== 'ruby' // important
|
||||
? children.reduce((acc, to) => {
|
||||
const chunk = this[snakeToCamel(to.type)](h, cursor, block, to, className)
|
||||
return Array.isArray(chunk) ? [...acc, ...chunk] : [...acc, chunk]
|
||||
}, [])
|
||||
const chunk = this[snakeToCamel(to.type)](h, cursor, block, to, className)
|
||||
return Array.isArray(chunk) ? [...acc, ...chunk] : [...acc, chunk]
|
||||
}, [])
|
||||
: ''
|
||||
switch (tag) {
|
||||
case 'img': {
|
||||
|
@ -2,36 +2,36 @@ import { escapeCharacters } from './escapeCharacter'
|
||||
|
||||
/* eslint-disable no-useless-escape */
|
||||
export const beginRules = {
|
||||
'hr': /^(\*{3,}$|^\-{3,}$|^\_{3,}$)/,
|
||||
'code_fense': /^(`{3,})([^`]*)$/,
|
||||
'header': /(^ {0,3}#{1,6}(\s{1,}|$))/,
|
||||
'reference_definition': /^( {0,3}\[)([^\]]+?)(\\*)(\]: *)(<?)([^\s>]+)(>?)(?:( +)(["'(]?)([^\n"'\(\)]+)\9)?( *)$/,
|
||||
hr: /^(\*{3,}$|^\-{3,}$|^\_{3,}$)/,
|
||||
code_fense: /^(`{3,})([^`]*)$/,
|
||||
header: /(^ {0,3}#{1,6}(\s{1,}|$))/,
|
||||
reference_definition: /^( {0,3}\[)([^\]]+?)(\\*)(\]: *)(<?)([^\s>]+)(>?)(?:( +)(["'(]?)([^\n"'\(\)]+)\9)?( *)$/,
|
||||
|
||||
// extra syntax (not belogs to GFM)
|
||||
'multiple_math': /^(\$\$)$/
|
||||
multiple_math: /^(\$\$)$/
|
||||
}
|
||||
|
||||
export const inlineRules = {
|
||||
'strong': /^(\*\*|__)(?=\S)([\s\S]*?[^\s\\])(\\*)\1(?!(\*|_))/, // can nest
|
||||
'em': /^(\*|_)(?=\S)([\s\S]*?[^\s\*\\])(\\*)\1(?!\1)/, // can nest
|
||||
'inline_code': /^(`{1,3})([^`]+?|.{2,})\1/,
|
||||
'image': /^(\!\[)(.*?)(\\*)\]\((.*?)(\\*)\)/,
|
||||
'link': /^(\[)((?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*?)(\\*)\]\((.*?)(\\*)\)/, // can nest
|
||||
'emoji': /^(:)([a-z_\d+-]+?)\1/,
|
||||
'del': /^(~{2})(?=\S)([\s\S]*?\S)(\\*)\1/, // can nest
|
||||
'auto_link': /^(https?:\/\/[^\s]+)(?=\s|$)/,
|
||||
'reference_link': /^\[([^\]]+?)(\\*)\](?:\[([^\]]*?)(\\*)\])?/,
|
||||
'reference_image': /^\!\[([^\]]+?)(\\*)\](?:\[([^\]]*?)(\\*)\])?/,
|
||||
'tail_header': /^(\s{1,}#{1,})(\s*)$/,
|
||||
'html_tag': /^(<!--[\s\S]*?-->|(<([a-zA-Z]{1}[a-zA-Z\d-]*) *[_\.\-/:a-zA-Z\d='";\? *]* *(?:\/)?>)(?:([\s\S]*?)(<\/\3 *>))?)/, // raw html
|
||||
'html_escape': new RegExp(`^(${escapeCharacters.join('|')})`, 'i'),
|
||||
'soft_line_break': /^(\n)(?!\n)/,
|
||||
'hard_line_break': /^( {2,})(\n)(?!\n)/,
|
||||
strong: /^(\*\*|__)(?=\S)([\s\S]*?[^\s\\])(\\*)\1(?!(\*|_))/, // can nest
|
||||
em: /^(\*|_)(?=\S)([\s\S]*?[^\s\*\\])(\\*)\1(?!\1)/, // can nest
|
||||
inline_code: /^(`{1,3})([^`]+?|.{2,})\1/,
|
||||
image: /^(\!\[)(.*?)(\\*)\]\((.*?)(\\*)\)/,
|
||||
link: /^(\[)((?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*?)(\\*)\]\((.*?)(\\*)\)/, // can nest
|
||||
emoji: /^(:)([a-z_\d+-]+?)\1/,
|
||||
del: /^(~{2})(?=\S)([\s\S]*?\S)(\\*)\1/, // can nest
|
||||
auto_link: /^(https?:\/\/[^\s]+)(?=\s|$)/,
|
||||
reference_link: /^\[([^\]]+?)(\\*)\](?:\[([^\]]*?)(\\*)\])?/,
|
||||
reference_image: /^\!\[([^\]]+?)(\\*)\](?:\[([^\]]*?)(\\*)\])?/,
|
||||
tail_header: /^(\s{1,}#{1,})(\s*)$/,
|
||||
html_tag: /^(<!--[\s\S]*?-->|(<([a-zA-Z]{1}[a-zA-Z\d-]*) *[_\.\-/:a-zA-Z\d='";\? *]* *(?:\/)?>)(?:([\s\S]*?)(<\/\3 *>))?)/, // raw html
|
||||
html_escape: new RegExp(`^(${escapeCharacters.join('|')})`, 'i'),
|
||||
soft_line_break: /^(\n)(?!\n)/,
|
||||
hard_line_break: /^( {2,})(\n)(?!\n)/,
|
||||
|
||||
// patched math marker `$`
|
||||
'backlash': /^(\\)([\\`*{}\[\]()#+\-.!_>~:\|\<\>$]{1})/,
|
||||
backlash: /^(\\)([\\`*{}\[\]()#+\-.!_>~:\|\<\>$]{1})/,
|
||||
|
||||
// extra (not belongs to GFM)
|
||||
'inline_math': /^(\$)([^\$]*?[^\$\\])(\\*)\1(?!\1)/
|
||||
inline_math: /^(\$)([^\$]*?[^\$\\])(\\*)\1(?!\1)/
|
||||
}
|
||||
/* eslint-enable no-useless-escape */
|
||||
|
@ -108,7 +108,7 @@ export const parseSrcAndTitle = (text = '') => {
|
||||
const canOpenEmphasis = (src, marker, pending) => {
|
||||
const precededChar = pending.charAt(pending.length - 1) || '\n'
|
||||
const followedChar = src[marker.length]
|
||||
// not followed by Unicode whitespace,
|
||||
// not followed by Unicode whitespace,
|
||||
if (UNICODE_WHITESPACE_REG.test(followedChar)) {
|
||||
return false
|
||||
}
|
||||
@ -127,7 +127,7 @@ const canOpenEmphasis = (src, marker, pending) => {
|
||||
const canCloseEmphasis = (src, offset, marker) => {
|
||||
const precededChar = src[offset - marker.length - 1]
|
||||
const followedChar = src[offset] || '\n'
|
||||
// not preceded by Unicode whitespace,
|
||||
// not preceded by Unicode whitespace,
|
||||
if (UNICODE_WHITESPACE_REG.test(precededChar)) {
|
||||
return false
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ function initLoadLanguage (Prism) {
|
||||
})
|
||||
}
|
||||
if (arr && !arr.length) {
|
||||
return Promise.reject('The first parameter should be a list of load languages or single language.')
|
||||
return Promise.reject(new Error('The first parameter should be a list of load languages or single language.'))
|
||||
}
|
||||
|
||||
if (!Array.isArray(arr)) {
|
||||
|
@ -51,7 +51,7 @@ export const getOffsetOfParagraph = (node, paragraph) => {
|
||||
do {
|
||||
preSibling = preSibling.previousSibling
|
||||
if (preSibling) {
|
||||
offset += getTextContent(preSibling, [ CLASS_OR_ID['AG_MATH_RENDER'], CLASS_OR_ID['AG_RUBY_RENDER'] ]).length
|
||||
offset += getTextContent(preSibling, [CLASS_OR_ID['AG_MATH_RENDER'], CLASS_OR_ID['AG_RUBY_RENDER']]).length
|
||||
}
|
||||
} while (preSibling)
|
||||
return (node === paragraph || node.parentNode === paragraph)
|
||||
@ -72,7 +72,7 @@ export const findNearestParagraph = node => {
|
||||
|
||||
export const findOutMostParagraph = node => {
|
||||
do {
|
||||
let parentNode = node.parentNode
|
||||
const parentNode = node.parentNode
|
||||
if (isMuyaEditorElement(parentNode) && isAganippeParagraph(node)) return node
|
||||
node = parentNode
|
||||
} while (node)
|
||||
|
@ -209,7 +209,7 @@ class Selection {
|
||||
// to move the cursor back to the start of the correct paragraph
|
||||
importSelectionMoveCursorPastBlocks (root, index = 1, range) {
|
||||
const treeWalker = this.doc.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, filterOnlyParentElements, false)
|
||||
let startContainer = range.startContainer
|
||||
const startContainer = range.startContainer
|
||||
let startBlock
|
||||
let targetNode
|
||||
let currIndex = 0
|
||||
@ -279,8 +279,8 @@ class Selection {
|
||||
const { left } = this.getCaretOffsets(root)
|
||||
const markedText = root.textContent
|
||||
const { type, info } = getCursorPositionWithinMarkedText(markedText, left)
|
||||
let pre = markedText.slice(0, left)
|
||||
let post = markedText.slice(left)
|
||||
const pre = markedText.slice(0, left)
|
||||
const post = markedText.slice(left)
|
||||
switch (type) {
|
||||
case 'OUT':
|
||||
return {
|
||||
@ -425,7 +425,7 @@ class Selection {
|
||||
let count = 0
|
||||
for (i = 0; i < len; i++) {
|
||||
const child = childNodes[i]
|
||||
const textLength = getTextContent(child, [ CLASS_OR_ID['AG_MATH_RENDER'], CLASS_OR_ID['AG_RUBY_RENDER'] ]).length
|
||||
const textLength = getTextContent(child, [CLASS_OR_ID['AG_MATH_RENDER'], CLASS_OR_ID['AG_RUBY_RENDER']]).length
|
||||
if (child.classList && child.classList.contains(CLASS_OR_ID['AG_FRONT_ICON'])) continue
|
||||
if (count + textLength >= offset) {
|
||||
if (
|
||||
@ -547,9 +547,9 @@ class Selection {
|
||||
aOffset = 0
|
||||
if (preElement) {
|
||||
aOffset += getOffsetOfParagraph(preElement, anchorParagraph)
|
||||
aOffset += getTextContent(preElement, [ CLASS_OR_ID['AG_MATH_RENDER'], CLASS_OR_ID['AG_RUBY_RENDER'] ]).length
|
||||
aOffset += getTextContent(preElement, [CLASS_OR_ID['AG_MATH_RENDER'], CLASS_OR_ID['AG_RUBY_RENDER']]).length
|
||||
}
|
||||
aOffset += getTextContent(imageWrapper, [ CLASS_OR_ID['AG_MATH_RENDER'], CLASS_OR_ID['AG_RUBY_RENDER'] ]).length
|
||||
aOffset += getTextContent(imageWrapper, [CLASS_OR_ID['AG_MATH_RENDER'], CLASS_OR_ID['AG_RUBY_RENDER']]).length
|
||||
fOffset = aOffset
|
||||
}
|
||||
|
||||
@ -563,10 +563,10 @@ class Selection {
|
||||
aOffset = 0
|
||||
if (preElement) {
|
||||
aOffset += getOffsetOfParagraph(preElement, anchorParagraph)
|
||||
aOffset += getTextContent(preElement, [ CLASS_OR_ID['AG_MATH_RENDER'], CLASS_OR_ID['AG_RUBY_RENDER'] ]).length
|
||||
aOffset += getTextContent(preElement, [CLASS_OR_ID['AG_MATH_RENDER'], CLASS_OR_ID['AG_RUBY_RENDER']]).length
|
||||
}
|
||||
if (anchorOffset === 3) {
|
||||
aOffset += getTextContent(imageWrapper, [ CLASS_OR_ID['AG_MATH_RENDER'], CLASS_OR_ID['AG_RUBY_RENDER'] ]).length
|
||||
aOffset += getTextContent(imageWrapper, [CLASS_OR_ID['AG_MATH_RENDER'], CLASS_OR_ID['AG_RUBY_RENDER']]).length
|
||||
}
|
||||
fOffset = aOffset
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import './index.css'
|
||||
|
||||
class CodePicker extends BaseScrollFloat {
|
||||
static pluginName = 'codePicker'
|
||||
|
||||
constructor (muya) {
|
||||
const name = 'ag-list-picker'
|
||||
super(muya, name)
|
||||
|
@ -5,6 +5,7 @@ import './index.css'
|
||||
|
||||
class EmojiPicker extends BaseScrollFloat {
|
||||
static pluginName = 'emojiPicker'
|
||||
|
||||
constructor (muya) {
|
||||
const name = 'ag-emoji-picker'
|
||||
super(muya, name)
|
||||
|
@ -9,7 +9,7 @@ for (const emoji of emojis) {
|
||||
if (emojisForSearch[newEmoji.category]) {
|
||||
emojisForSearch[newEmoji.category].push(newEmoji)
|
||||
} else {
|
||||
emojisForSearch[newEmoji.category] = [ newEmoji ]
|
||||
emojisForSearch[newEmoji.category] = [newEmoji]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@ const defaultOptions = {
|
||||
|
||||
class FormatPicker extends BaseFloat {
|
||||
static pluginName = 'formatPicker'
|
||||
|
||||
constructor (muya, options = {}) {
|
||||
const name = 'ag-format-picker'
|
||||
const opts = Object.assign({}, defaultOptions, options)
|
||||
|
@ -20,6 +20,7 @@ const defaultOptions = {
|
||||
|
||||
class FrontMenu extends BaseFloat {
|
||||
static pluginName = 'frontMenu'
|
||||
|
||||
constructor (muya, options = {}) {
|
||||
const name = 'ag-front-menu'
|
||||
const opts = Object.assign({}, defaultOptions, options)
|
||||
|
@ -14,6 +14,7 @@ const iconhash = {
|
||||
|
||||
class ImagePathPicker extends BaseScrollFloat {
|
||||
static pluginName = 'imagePathPicker'
|
||||
|
||||
constructor (muya) {
|
||||
const name = 'ag-list-picker'
|
||||
super(muya, name)
|
||||
@ -41,7 +42,7 @@ class ImagePathPicker extends BaseScrollFloat {
|
||||
|
||||
render () {
|
||||
const { renderArray, oldVnode, scrollElement, activeItem } = this
|
||||
let children = renderArray.map((item) => {
|
||||
const children = renderArray.map((item) => {
|
||||
const { text, iconClass } = item
|
||||
const icon = h('div.icon-wrapper', h('svg', {
|
||||
attrs: {
|
||||
@ -60,7 +61,7 @@ class ImagePathPicker extends BaseScrollFloat {
|
||||
'xlink:href': iconhash[iconClass].url
|
||||
}
|
||||
}))
|
||||
)
|
||||
)
|
||||
const textEle = h('div.language', text)
|
||||
const selector = activeItem === item ? 'li.item.active' : 'li.item'
|
||||
return h(selector, {
|
||||
|
@ -8,6 +8,7 @@ import './index.css'
|
||||
|
||||
class ImageSelector extends BaseFloat {
|
||||
static pluginName = 'imageSelector'
|
||||
|
||||
constructor (muya) {
|
||||
const name = 'ag-image-selector'
|
||||
const options = {
|
||||
@ -35,6 +36,7 @@ class ImageSelector extends BaseFloat {
|
||||
this.floatBox.classList.add('ag-image-selector-wrapper')
|
||||
this.listen()
|
||||
}
|
||||
|
||||
listen () {
|
||||
super.listen()
|
||||
const { eventCenter } = this.muya
|
||||
@ -188,7 +190,7 @@ class ImageSelector extends BaseFloat {
|
||||
this.muya.eventCenter.dispatch('stateChange')
|
||||
}
|
||||
|
||||
async handleSelectButtonClick () {
|
||||
async handleSelectButtonClick () {
|
||||
if (!this.muya.options.imagePathPicker) {
|
||||
console.warn('You need to add a imagePathPicker option')
|
||||
return
|
||||
|
@ -30,7 +30,6 @@ const COMMAND_KEY = isOsx ? '⌘' : '⌃'
|
||||
// Caps Lock ⇪
|
||||
// Fn
|
||||
|
||||
|
||||
// Command (or Cmd) ⌘
|
||||
// Shift ⇧
|
||||
// Option (or Alt) ⌥
|
||||
@ -38,7 +37,6 @@ const COMMAND_KEY = isOsx ? '⌘' : '⌃'
|
||||
// Caps Lock ⇪
|
||||
// Fn
|
||||
|
||||
|
||||
export const quicInsertObj = {
|
||||
'basic block': [{
|
||||
title: 'Paragraph',
|
||||
@ -59,7 +57,7 @@ export const quicInsertObj = {
|
||||
shortCut: `⌥${COMMAND_KEY}Y`,
|
||||
icon: frontMatterIcon
|
||||
}],
|
||||
'header': [{
|
||||
header: [{
|
||||
title: 'Header 1',
|
||||
subTitle: '# Lorem Ipsum is simply ...',
|
||||
label: 'heading 1',
|
||||
@ -146,7 +144,7 @@ export const quicInsertObj = {
|
||||
shortCut: `⌥${COMMAND_KEY}X`,
|
||||
icon: todoListIcon
|
||||
}],
|
||||
'diagram': [{
|
||||
diagram: [{
|
||||
title: 'Vega Chart',
|
||||
subTitle: 'Render flow chart by vega-lite.js.',
|
||||
label: 'vega-lite',
|
||||
|
@ -7,6 +7,7 @@ import './index.css'
|
||||
|
||||
class QuickInsert extends BaseScrollFloat {
|
||||
static pluginName = 'quickInsert'
|
||||
|
||||
constructor (muya) {
|
||||
const name = 'ag-quick-insert'
|
||||
super(muya, name)
|
||||
@ -121,8 +122,8 @@ class QuickInsert extends BaseScrollFloat {
|
||||
selectItem (item) {
|
||||
const { contentState } = this.muya
|
||||
this.block.text = ''
|
||||
let { key } = this.block
|
||||
let offset = 0
|
||||
const { key } = this.block
|
||||
const offset = 0
|
||||
contentState.cursor = {
|
||||
start: { key, offset },
|
||||
end: { key, offset }
|
||||
|
@ -5,6 +5,7 @@ import { EVENT_KEYS } from '../../config'
|
||||
|
||||
class TablePicker extends BaseFloat {
|
||||
static pluginName = 'tablePicker'
|
||||
|
||||
constructor (muya) {
|
||||
const name = 'ag-table-picker'
|
||||
super(muya, name)
|
||||
@ -124,7 +125,7 @@ class TablePicker extends BaseFloat {
|
||||
|
||||
keyupHandler (event, type) {
|
||||
let number = +this.select[type]
|
||||
let value = +event.target.value
|
||||
const value = +event.target.value
|
||||
if (event.key === EVENT_KEYS.ArrowUp) {
|
||||
number++
|
||||
} else if (event.key === EVENT_KEYS.ArrowDown) {
|
||||
|
@ -46,7 +46,7 @@ class ExportHtml {
|
||||
theme: 'default'
|
||||
})
|
||||
mermaid.init(undefined, this.exportContainer.querySelectorAll('div.mermaid'))
|
||||
if (this.muya){
|
||||
if (this.muya) {
|
||||
mermaid.initialize({
|
||||
theme: this.muya.options.mermaidTheme
|
||||
})
|
||||
@ -56,8 +56,8 @@ class ExportHtml {
|
||||
async renderDiagram () {
|
||||
const selector = 'code.language-vega-lite, code.language-flowchart, code.language-sequence'
|
||||
const RENDER_MAP = {
|
||||
'flowchart': flowchart,
|
||||
'sequence': Diagram,
|
||||
flowchart: flowchart,
|
||||
sequence: Diagram,
|
||||
'vega-lite': vegaEmbed
|
||||
}
|
||||
const codes = this.exportContainer.querySelectorAll(selector)
|
||||
@ -74,7 +74,9 @@ class ExportHtml {
|
||||
Object.assign(options, { theme: 'hand' })
|
||||
} else if (functionType === 'vega-lite') {
|
||||
Object.assign(options, {
|
||||
actions: false, tooltip: false, renderer: 'svg',
|
||||
actions: false,
|
||||
tooltip: false,
|
||||
renderer: 'svg',
|
||||
theme: 'latimes' // only render light theme
|
||||
})
|
||||
}
|
||||
|
@ -327,7 +327,7 @@ class ExportMarkdown {
|
||||
}
|
||||
listInfo.listCount++
|
||||
|
||||
const delimiter = bulletMarkerOrDelimiter ? bulletMarkerOrDelimiter : '.'
|
||||
const delimiter = bulletMarkerOrDelimiter || '.'
|
||||
itemMarker = `${n}${delimiter} `
|
||||
}
|
||||
|
||||
|
@ -38,13 +38,13 @@ const turnSoftBreakToSpan = html => {
|
||||
const params = []
|
||||
let i = 0
|
||||
const len = tokens.length
|
||||
for (; i< len; i++) {
|
||||
for (; i < len; i++) {
|
||||
let text = tokens[i]
|
||||
if (i === 0 && startLen !== 0) {
|
||||
text = '\n'.repeat(startLen) + text
|
||||
} else if (i === len - 1 && endLen !== 0) {
|
||||
text = text + '\n'.repeat(endLen)
|
||||
}
|
||||
}
|
||||
params.push(document.createTextNode(text))
|
||||
if (i !== len - 1) {
|
||||
const softBreak = document.createElement('span')
|
||||
@ -81,7 +81,7 @@ const importRegister = ContentState => {
|
||||
let token
|
||||
let block
|
||||
let value
|
||||
let parentList = [ rootState ]
|
||||
const parentList = [rootState]
|
||||
const languageLoaded = new Set()
|
||||
|
||||
while ((token = tokens.shift())) {
|
||||
@ -133,7 +133,7 @@ const importRegister = ContentState => {
|
||||
|
||||
const headingContent = this.createBlock('span', {
|
||||
text: value,
|
||||
functionType: headingStyle === 'atx'? 'atxLine' : 'paragraphContent'
|
||||
functionType: headingStyle === 'atx' ? 'atxLine' : 'paragraphContent'
|
||||
})
|
||||
|
||||
this.appendChild(block, headingContent)
|
||||
@ -363,8 +363,8 @@ const importRegister = ContentState => {
|
||||
const { anchor, focus } = this.cursor
|
||||
const anchorBlock = this.getBlock(anchor.key)
|
||||
const focusBlock = this.getBlock(focus.key)
|
||||
let { text: anchorText } = anchorBlock
|
||||
let { text: focusText } = focusBlock
|
||||
const { text: anchorText } = anchorBlock
|
||||
const { text: focusText } = focusBlock
|
||||
if (anchor.key === focus.key) {
|
||||
const minOffset = Math.min(anchor.offset, focus.offset)
|
||||
const maxOffset = Math.max(anchor.offset, focus.offset)
|
||||
|
492
src/renderer/codeMirror/modes.js
vendored
492
src/renderer/codeMirror/modes.js
vendored
@ -1,331 +1,331 @@
|
||||
const languages = [{
|
||||
'name': 'objectivec',
|
||||
'mode': 'clike',
|
||||
'mime': 'text/x-objectivec'
|
||||
name: 'objectivec',
|
||||
mode: 'clike',
|
||||
mime: 'text/x-objectivec'
|
||||
}, {
|
||||
'name': 'swift',
|
||||
'mode': 'swift',
|
||||
'mime': 'text/x-swift'
|
||||
name: 'swift',
|
||||
mode: 'swift',
|
||||
mime: 'text/x-swift'
|
||||
}, {
|
||||
'name': 'c_cpp',
|
||||
'mode': 'clike',
|
||||
'mime': 'text/x-csrc'
|
||||
name: 'c_cpp',
|
||||
mode: 'clike',
|
||||
mime: 'text/x-csrc'
|
||||
}, {
|
||||
'name': 'c',
|
||||
'mode': 'clike',
|
||||
'mime': 'text/x-csrc'
|
||||
name: 'c',
|
||||
mode: 'clike',
|
||||
mime: 'text/x-csrc'
|
||||
}, {
|
||||
'name': 'c++',
|
||||
'mode': 'clike',
|
||||
'mime': 'text/x-c++src'
|
||||
name: 'c++',
|
||||
mode: 'clike',
|
||||
mime: 'text/x-c++src'
|
||||
}, {
|
||||
'name': 'cmake',
|
||||
'mode': 'cmake',
|
||||
'mime': 'text/x-cmake'
|
||||
name: 'cmake',
|
||||
mode: 'cmake',
|
||||
mime: 'text/x-cmake'
|
||||
}, {
|
||||
'name': 'lisp',
|
||||
'mode': 'commonlisp',
|
||||
'mime': 'text/x-common-lisp'
|
||||
name: 'lisp',
|
||||
mode: 'commonlisp',
|
||||
mime: 'text/x-common-lisp'
|
||||
}, {
|
||||
'name': 'pascal',
|
||||
'mode': 'pascal',
|
||||
'mime': 'text/x-pascal'
|
||||
name: 'pascal',
|
||||
mode: 'pascal',
|
||||
mime: 'text/x-pascal'
|
||||
}, {
|
||||
'name': 'eiffel',
|
||||
'mode': 'eiffel',
|
||||
'mime': 'text/x-eiffel'
|
||||
name: 'eiffel',
|
||||
mode: 'eiffel',
|
||||
mime: 'text/x-eiffel'
|
||||
}, {
|
||||
'name': 'yaml',
|
||||
'mode': 'yaml',
|
||||
'mime': 'text/x-yaml'
|
||||
name: 'yaml',
|
||||
mode: 'yaml',
|
||||
mime: 'text/x-yaml'
|
||||
}, {
|
||||
'name': 'xml',
|
||||
'mode': 'xml',
|
||||
'mime': 'application/xml'
|
||||
name: 'xml',
|
||||
mode: 'xml',
|
||||
mime: 'application/xml'
|
||||
}, {
|
||||
'name': 'django',
|
||||
'mode': 'django',
|
||||
'mime': 'text/x-django'
|
||||
name: 'django',
|
||||
mode: 'django',
|
||||
mime: 'text/x-django'
|
||||
}, {
|
||||
'name': 'clojure',
|
||||
'mode': 'clojure',
|
||||
'mime': 'text/x-clojure'
|
||||
name: 'clojure',
|
||||
mode: 'clojure',
|
||||
mime: 'text/x-clojure'
|
||||
}, {
|
||||
'name': 'crystal',
|
||||
'mode': 'crystal',
|
||||
'mime': 'text/x-crystal'
|
||||
name: 'crystal',
|
||||
mode: 'crystal',
|
||||
mime: 'text/x-crystal'
|
||||
}, {
|
||||
'name': 'ruby',
|
||||
'mode': 'ruby',
|
||||
'mime': 'text/x-ruby'
|
||||
name: 'ruby',
|
||||
mode: 'ruby',
|
||||
mime: 'text/x-ruby'
|
||||
}, {
|
||||
'name': 'python',
|
||||
'mode': 'python',
|
||||
'mime': 'text/x-python'
|
||||
name: 'python',
|
||||
mode: 'python',
|
||||
mime: 'text/x-python'
|
||||
}, {
|
||||
'name': 'sh',
|
||||
'mode': 'shell',
|
||||
'mime': 'text/x-sh'
|
||||
name: 'sh',
|
||||
mode: 'shell',
|
||||
mime: 'text/x-sh'
|
||||
}, { /* alias */
|
||||
'name': 'shell',
|
||||
'mode': 'shell',
|
||||
'mime': 'text/x-sh'
|
||||
name: 'shell',
|
||||
mode: 'shell',
|
||||
mime: 'text/x-sh'
|
||||
}, {
|
||||
'name': 'less',
|
||||
'mode': 'css',
|
||||
'mime': 'text/css'
|
||||
name: 'less',
|
||||
mode: 'css',
|
||||
mime: 'text/css'
|
||||
}, {
|
||||
'name': 'php',
|
||||
'mode': 'php',
|
||||
'mime': 'application/x-httpd-php'
|
||||
name: 'php',
|
||||
mode: 'php',
|
||||
mime: 'application/x-httpd-php'
|
||||
}, {
|
||||
'name': 'json',
|
||||
'mode': 'javascript',
|
||||
'mime': 'application/json'
|
||||
name: 'json',
|
||||
mode: 'javascript',
|
||||
mime: 'application/json'
|
||||
}, {
|
||||
'name': 'smarty',
|
||||
'mode': 'smarty',
|
||||
'mime': 'text/x-smarty'
|
||||
name: 'smarty',
|
||||
mode: 'smarty',
|
||||
mime: 'text/x-smarty'
|
||||
}, {
|
||||
'name': 'cobol',
|
||||
'mode': 'cobol',
|
||||
'mime': 'text/x-cobol'
|
||||
name: 'cobol',
|
||||
mode: 'cobol',
|
||||
mime: 'text/x-cobol'
|
||||
}, {
|
||||
'name': 'go',
|
||||
'mode': 'go',
|
||||
'mime': 'text/x-go'
|
||||
name: 'go',
|
||||
mode: 'go',
|
||||
mime: 'text/x-go'
|
||||
}, { /* alias */
|
||||
'name': 'golang',
|
||||
'mode': 'go',
|
||||
'mime': 'text/x-go'
|
||||
name: 'golang',
|
||||
mode: 'go',
|
||||
mime: 'text/x-go'
|
||||
}, {
|
||||
'name': 'makefile',
|
||||
'mode': 'shell', /* makefile syntax is not supported by CodeMirror */
|
||||
'mime': 'text/x-sh'
|
||||
name: 'makefile',
|
||||
mode: 'shell', /* makefile syntax is not supported by CodeMirror */
|
||||
mime: 'text/x-sh'
|
||||
}, {
|
||||
'name': 'ocaml',
|
||||
'mode': 'mllike',
|
||||
'mime': 'text/x-ocaml'
|
||||
name: 'ocaml',
|
||||
mode: 'mllike',
|
||||
mime: 'text/x-ocaml'
|
||||
}, {
|
||||
'name': 'textile',
|
||||
'mode': 'textile',
|
||||
'mime': 'text/x-textile'
|
||||
name: 'textile',
|
||||
mode: 'textile',
|
||||
mime: 'text/x-textile'
|
||||
}, {
|
||||
'name': 'd',
|
||||
'mode': 'd',
|
||||
'mime': 'text/x-d'
|
||||
name: 'd',
|
||||
mode: 'd',
|
||||
mime: 'text/x-d'
|
||||
}, {
|
||||
'name': 'jade',
|
||||
'mode': 'pug',
|
||||
'mime': 'text/x-pug'
|
||||
name: 'jade',
|
||||
mode: 'pug',
|
||||
mime: 'text/x-pug'
|
||||
}, {
|
||||
'name': 'lua',
|
||||
'mode': 'lua',
|
||||
'mime': 'text/x-lua'
|
||||
name: 'lua',
|
||||
mode: 'lua',
|
||||
mime: 'text/x-lua'
|
||||
}, {
|
||||
'name': 'coffee',
|
||||
'mode': 'coffeescript',
|
||||
'mime': 'text/x-coffeescript'
|
||||
name: 'coffee',
|
||||
mode: 'coffeescript',
|
||||
mime: 'text/x-coffeescript'
|
||||
}, {
|
||||
'name': 'html',
|
||||
'mode': 'htmlmixed',
|
||||
'mime': 'text/html'
|
||||
name: 'html',
|
||||
mode: 'htmlmixed',
|
||||
mime: 'text/html'
|
||||
}, {
|
||||
'name': 'pgsql',
|
||||
'mode': 'sql',
|
||||
'mime': 'text/x-sql'
|
||||
name: 'pgsql',
|
||||
mode: 'sql',
|
||||
mime: 'text/x-sql'
|
||||
}, {
|
||||
'name': 'haskell',
|
||||
'mode': 'haskell',
|
||||
'mime': 'text/x-haskell'
|
||||
name: 'haskell',
|
||||
mode: 'haskell',
|
||||
mime: 'text/x-haskell'
|
||||
}, {
|
||||
'name': 'jsp',
|
||||
'mode': 'htmlembedded',
|
||||
'mime': 'application/x-jsp'
|
||||
name: 'jsp',
|
||||
mode: 'htmlembedded',
|
||||
mime: 'application/x-jsp'
|
||||
}, {
|
||||
'name': 'tcl',
|
||||
'mode': 'tcl',
|
||||
'mime': 'text/x-tcl'
|
||||
name: 'tcl',
|
||||
mode: 'tcl',
|
||||
mime: 'text/x-tcl'
|
||||
}, {
|
||||
'name': 'ini',
|
||||
'mode': 'properties',
|
||||
'mime': 'text/x-properties'
|
||||
name: 'ini',
|
||||
mode: 'properties',
|
||||
mime: 'text/x-properties'
|
||||
}, {
|
||||
'name': 'jsoniq',
|
||||
'mode': 'javascript',
|
||||
'mime': 'application/json'
|
||||
name: 'jsoniq',
|
||||
mode: 'javascript',
|
||||
mime: 'application/json'
|
||||
}, {
|
||||
'name': 'vhdl',
|
||||
'mode': 'vhdl',
|
||||
'mime': 'text/x-vhdl'
|
||||
name: 'vhdl',
|
||||
mode: 'vhdl',
|
||||
mime: 'text/x-vhdl'
|
||||
}, {
|
||||
'name': 'verilog',
|
||||
'mode': 'verilog',
|
||||
'mime': 'text/x-systemverilog'
|
||||
name: 'verilog',
|
||||
mode: 'verilog',
|
||||
mime: 'text/x-systemverilog'
|
||||
}, {
|
||||
'name': 'csharp',
|
||||
'mode': 'clike',
|
||||
'mime': 'text/x-csharp'
|
||||
name: 'csharp',
|
||||
mode: 'clike',
|
||||
mime: 'text/x-csharp'
|
||||
}, {
|
||||
'name': 'rust',
|
||||
'mode': 'rust',
|
||||
'mime': 'text/x-rustsrc'
|
||||
name: 'rust',
|
||||
mode: 'rust',
|
||||
mime: 'text/x-rustsrc'
|
||||
}, {
|
||||
'name': 'livescript',
|
||||
'mode': 'livescript',
|
||||
'mime': 'text/x-livescript'
|
||||
name: 'livescript',
|
||||
mode: 'livescript',
|
||||
mime: 'text/x-livescript'
|
||||
}, {
|
||||
'name': 'jsx',
|
||||
'mode': 'jsx',
|
||||
'mime': 'text/jsx'
|
||||
name: 'jsx',
|
||||
mode: 'jsx',
|
||||
mime: 'text/jsx'
|
||||
}, {
|
||||
'name': 'protobuf',
|
||||
'mode': 'protobuf',
|
||||
'mime': 'text/x-protobuf'
|
||||
name: 'protobuf',
|
||||
mode: 'protobuf',
|
||||
mime: 'text/x-protobuf'
|
||||
}, {
|
||||
'name': 'markdown',
|
||||
'mode': 'gfm',
|
||||
'mime': 'text/x-gfm'
|
||||
name: 'markdown',
|
||||
mode: 'gfm',
|
||||
mime: 'text/x-gfm'
|
||||
}, {
|
||||
'name': 'rst',
|
||||
'mode': 'rst',
|
||||
'mime': 'text/x-rst'
|
||||
name: 'rst',
|
||||
mode: 'rst',
|
||||
mime: 'text/x-rst'
|
||||
}, {
|
||||
'name': 'LaTeX',
|
||||
'mode': 'stex',
|
||||
'mime': 'text/x-latex'
|
||||
name: 'LaTeX',
|
||||
mode: 'stex',
|
||||
mime: 'text/x-latex'
|
||||
}, {
|
||||
'name': 'java',
|
||||
'mode': 'clike',
|
||||
'mime': 'text/x-java'
|
||||
name: 'java',
|
||||
mode: 'clike',
|
||||
mime: 'text/x-java'
|
||||
}, {
|
||||
'name': 'kotlin',
|
||||
'mode': 'clike',
|
||||
'mime': 'text/x-kotlin'
|
||||
name: 'kotlin',
|
||||
mode: 'clike',
|
||||
mime: 'text/x-kotlin'
|
||||
}, {
|
||||
'name': 'javascript',
|
||||
'mode': 'javascript',
|
||||
'mime': 'text/javascript'
|
||||
name: 'javascript',
|
||||
mode: 'javascript',
|
||||
mime: 'text/javascript'
|
||||
}, {
|
||||
'name': 'erlang',
|
||||
'mode': 'erlang',
|
||||
'mime': 'text/x-erlang'
|
||||
name: 'erlang',
|
||||
mode: 'erlang',
|
||||
mime: 'text/x-erlang'
|
||||
}, {
|
||||
'name': 'scheme',
|
||||
'mode': 'scheme',
|
||||
'mime': 'text/x-scheme'
|
||||
name: 'scheme',
|
||||
mode: 'scheme',
|
||||
mime: 'text/x-scheme'
|
||||
}, {
|
||||
'name': 'sass',
|
||||
'mode': 'sass',
|
||||
'mime': 'text/x-sass'
|
||||
name: 'sass',
|
||||
mode: 'sass',
|
||||
mime: 'text/x-sass'
|
||||
}, {
|
||||
'name': 'groovy',
|
||||
'mode': 'groovy',
|
||||
'mime': 'text/x-groovy'
|
||||
name: 'groovy',
|
||||
mode: 'groovy',
|
||||
mime: 'text/x-groovy'
|
||||
}, {
|
||||
'name': 'julia',
|
||||
'mode': 'julia',
|
||||
'mime': 'text/x-julia'
|
||||
name: 'julia',
|
||||
mode: 'julia',
|
||||
mime: 'text/x-julia'
|
||||
}, {
|
||||
'name': 'haml',
|
||||
'mode': 'haml',
|
||||
'mime': 'text/x-haml'
|
||||
name: 'haml',
|
||||
mode: 'haml',
|
||||
mime: 'text/x-haml'
|
||||
}, {
|
||||
'name': 'powershell',
|
||||
'mode': 'powershell',
|
||||
'mime': 'application/x-powershell'
|
||||
name: 'powershell',
|
||||
mode: 'powershell',
|
||||
mime: 'application/x-powershell'
|
||||
}, {
|
||||
'name': 'typescript',
|
||||
'mode': 'javascript',
|
||||
'mime': 'application/typescript'
|
||||
name: 'typescript',
|
||||
mode: 'javascript',
|
||||
mime: 'application/typescript'
|
||||
}, {
|
||||
'name': 'dart',
|
||||
'mode': 'dart',
|
||||
'mime': 'application/dart'
|
||||
name: 'dart',
|
||||
mode: 'dart',
|
||||
mime: 'application/dart'
|
||||
}, {
|
||||
'name': 'xquery',
|
||||
'mode': 'xquery',
|
||||
'mime': 'application/xquery'
|
||||
name: 'xquery',
|
||||
mode: 'xquery',
|
||||
mime: 'application/xquery'
|
||||
}, {
|
||||
'name': 'elm',
|
||||
'mode': 'elm',
|
||||
'mime': 'text/x-elm'
|
||||
name: 'elm',
|
||||
mode: 'elm',
|
||||
mime: 'text/x-elm'
|
||||
}, {
|
||||
'name': 'plsql',
|
||||
'mode': 'sql',
|
||||
'mime': 'text/x-plsql'
|
||||
name: 'plsql',
|
||||
mode: 'sql',
|
||||
mime: 'text/x-plsql'
|
||||
}, {
|
||||
'name': 'forth',
|
||||
'mode': 'forth',
|
||||
'mime': 'text/x-forth'
|
||||
name: 'forth',
|
||||
mode: 'forth',
|
||||
mime: 'text/x-forth'
|
||||
}, {
|
||||
'name': 'scala',
|
||||
'mode': 'clike',
|
||||
'mime': 'text/x-scala'
|
||||
name: 'scala',
|
||||
mode: 'clike',
|
||||
mime: 'text/x-scala'
|
||||
}, {
|
||||
'name': 'perl',
|
||||
'mode': 'perl',
|
||||
'mime': 'text/x-perl'
|
||||
name: 'perl',
|
||||
mode: 'perl',
|
||||
mime: 'text/x-perl'
|
||||
}, {
|
||||
'name': 'haxe',
|
||||
'mode': 'haxe',
|
||||
'mime': 'text/x-haxe'
|
||||
name: 'haxe',
|
||||
mode: 'haxe',
|
||||
mime: 'text/x-haxe'
|
||||
}, {
|
||||
'name': 'rhtml',
|
||||
'mode': 'htmlembedded',
|
||||
'mime': 'application/x-erb'
|
||||
name: 'rhtml',
|
||||
mode: 'htmlembedded',
|
||||
mime: 'application/x-erb'
|
||||
}, {
|
||||
'name': 'scss',
|
||||
'mode': 'css',
|
||||
'mime': 'text/x-scss'
|
||||
name: 'scss',
|
||||
mode: 'css',
|
||||
mime: 'text/x-scss'
|
||||
}, {
|
||||
'name': 'sql',
|
||||
'mode': 'sql',
|
||||
'mime': 'text/x-sql'
|
||||
name: 'sql',
|
||||
mode: 'sql',
|
||||
mime: 'text/x-sql'
|
||||
}, {
|
||||
'name': 'css',
|
||||
'mode': 'css',
|
||||
'mime': 'text/css'
|
||||
name: 'css',
|
||||
mode: 'css',
|
||||
mime: 'text/css'
|
||||
}, {
|
||||
'name': 'tex',
|
||||
'mode': 'stex',
|
||||
'mime': 'text/x-stex'
|
||||
name: 'tex',
|
||||
mode: 'stex',
|
||||
mime: 'text/x-stex'
|
||||
}, {
|
||||
'name': 'r',
|
||||
'mode': 'r',
|
||||
'mime': 'text/x-rsrc'
|
||||
name: 'r',
|
||||
mode: 'r',
|
||||
mime: 'text/x-rsrc'
|
||||
}, {
|
||||
'name': 'diff',
|
||||
'mode': 'diff',
|
||||
'mime': 'text/x-diff'
|
||||
name: 'diff',
|
||||
mode: 'diff',
|
||||
mime: 'text/x-diff'
|
||||
}, {
|
||||
'name': 'twig',
|
||||
'mode': 'twig',
|
||||
'mime': 'text/x-twig'
|
||||
name: 'twig',
|
||||
mode: 'twig',
|
||||
mime: 'text/x-twig'
|
||||
}, {
|
||||
'name': 'matlab',
|
||||
'mode': 'octave',
|
||||
'mime': 'text/x-octave'
|
||||
name: 'matlab',
|
||||
mode: 'octave',
|
||||
mime: 'text/x-octave'
|
||||
}, {
|
||||
'name': 'soy_template',
|
||||
'mode': 'soy',
|
||||
'mime': 'text/x-soy'
|
||||
name: 'soy_template',
|
||||
mode: 'soy',
|
||||
mime: 'text/x-soy'
|
||||
}, {
|
||||
'name': 'dockerfile',
|
||||
'mode': 'dockerfile',
|
||||
'mime': 'text/x-dockerfile'
|
||||
name: 'dockerfile',
|
||||
mode: 'dockerfile',
|
||||
mime: 'text/x-dockerfile'
|
||||
}, {
|
||||
'name': 'toml',
|
||||
'mode': 'toml',
|
||||
'mime': 'text/x-toml'
|
||||
name: 'toml',
|
||||
mode: 'toml',
|
||||
mime: 'text/x-toml'
|
||||
}, {
|
||||
'name': 'pgp',
|
||||
'mode': 'asciiarmor',
|
||||
'mime': 'application/pgp'
|
||||
name: 'pgp',
|
||||
mode: 'asciiarmor',
|
||||
mime: 'application/pgp'
|
||||
}, {
|
||||
'name': 'Nginx',
|
||||
'mode': 'nginx',
|
||||
'mime': 'text/x-nginx-conf'
|
||||
name: 'Nginx',
|
||||
mode: 'nginx',
|
||||
mime: 'text/x-nginx-conf'
|
||||
}]
|
||||
|
||||
export default languages
|
||||
|
@ -27,36 +27,36 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import bus from '../../bus'
|
||||
import { mapState } from 'vuex'
|
||||
import bus from '../../bus'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
this.name = 'Mark Text'
|
||||
this.copyright = `Copyright © 2017-${new Date().getFullYear()} Luo Ran`
|
||||
this.copyrightContributors = `Copyright © 2018-${new Date().getFullYear()} Mark Text Contributors`
|
||||
return {
|
||||
showAboutDialog: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
'appVersion': state => state.appVersion
|
||||
})
|
||||
},
|
||||
created () {
|
||||
bus.$on('aboutDialog', this.showDialog)
|
||||
},
|
||||
beforeDestroy () {
|
||||
bus.$off('aboutDialog', this.showDialog)
|
||||
},
|
||||
methods: {
|
||||
showDialog () {
|
||||
this.showAboutDialog = true
|
||||
bus.$emit('editor-blur')
|
||||
}
|
||||
export default {
|
||||
data () {
|
||||
this.name = 'Mark Text'
|
||||
this.copyright = `Copyright © 2017-${new Date().getFullYear()} Luo Ran`
|
||||
this.copyrightContributors = `Copyright © 2018-${new Date().getFullYear()} Mark Text Contributors`
|
||||
return {
|
||||
showAboutDialog: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
appVersion: state => state.appVersion
|
||||
})
|
||||
},
|
||||
created () {
|
||||
bus.$on('aboutDialog', this.showDialog)
|
||||
},
|
||||
beforeDestroy () {
|
||||
bus.$off('aboutDialog', this.showDialog)
|
||||
},
|
||||
methods: {
|
||||
showDialog () {
|
||||
this.showAboutDialog = true
|
||||
bus.$emit('editor-blur')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
@ -1,31 +1,31 @@
|
||||
<template>
|
||||
<div class="aidou">
|
||||
<el-dialog
|
||||
<el-dialog
|
||||
:visible.sync="showAiDou"
|
||||
:show-close="false"
|
||||
:modal="true"
|
||||
custom-class="ag-dialog-table"
|
||||
width="610px"
|
||||
|
||||
|
||||
>
|
||||
<div slot="title" class="search-wrapper">
|
||||
<div class="input-wrapper">
|
||||
<svg class="icon" aria-hidden="true" @click="search()">
|
||||
<use xlink:href="#icon-search"></use>
|
||||
</svg>
|
||||
</svg>
|
||||
<input
|
||||
type="text" v-model="query" class="search"
|
||||
@keyup="handleInput"
|
||||
@input="historyIndex = -1"
|
||||
@focus = "showCollection = false"
|
||||
ref="search" placeholder="Discover you next dotu..."
|
||||
>
|
||||
>
|
||||
<svg class="icon" aria-hidden="true" @click="getCollection">
|
||||
<use xlink:href="#icon-collect"></use>
|
||||
</svg>
|
||||
<svg class="icon" aria-hidden="true" @click="shuffle">
|
||||
<use xlink:href="#icon-shuffle"></use>
|
||||
</svg>
|
||||
</svg>
|
||||
</div>
|
||||
<transition name="fade">
|
||||
<ul v-if="history.length && !query && !showCollection" class="history">
|
||||
@ -46,12 +46,12 @@
|
||||
<div class="image-container" ref="emojis">
|
||||
<div class="img-wrapper" v-for="(emoji, index) of emojis" :key="index" @click="handleEmojiClick(emoji)">
|
||||
<svg
|
||||
class="icon"
|
||||
class="icon"
|
||||
:class="{'active': emoji.collected}"
|
||||
aria-hidden="true" @click.stop="collect(emoji)"
|
||||
>
|
||||
<use xlink:href="#icon-collected"></use>
|
||||
</svg>
|
||||
</svg>
|
||||
<img :src="emoji.link" alt="doutu">
|
||||
</div>
|
||||
<loading v-if="aiLoading"></loading>
|
||||
@ -65,172 +65,172 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import bus from '../../bus'
|
||||
import loading from './loading'
|
||||
import { mapState } from 'vuex'
|
||||
import hotWords from './hotWords'
|
||||
import resource from '../../store/resource'
|
||||
import { dotuHistory, collection } from '../../util'
|
||||
import bus from '../../bus'
|
||||
import loading from './loading'
|
||||
import { mapState } from 'vuex'
|
||||
import hotWords from './hotWords'
|
||||
import resource from '../../store/resource'
|
||||
import { dotuHistory, collection } from '../../util'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
loading
|
||||
export default {
|
||||
components: {
|
||||
loading
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
showCollection: false,
|
||||
collection: collection.getItems(),
|
||||
historyIndex: -1,
|
||||
history: dotuHistory.getItems(),
|
||||
showAiDou: false,
|
||||
query: '',
|
||||
page: 1,
|
||||
size: 24,
|
||||
bindScroll: false
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.$nextTick(() => {
|
||||
bus.$on('aidou', this.handleShowAiDou)
|
||||
})
|
||||
},
|
||||
beforeDestroy () {
|
||||
const container = this.$refs.emojis
|
||||
if (container) {
|
||||
container.removeEventListener('scroll', this.handlerScroll)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
aiList: state => state.aidou.aiList,
|
||||
aiLoading: state => state.aidou.aiLoading
|
||||
}),
|
||||
emojis () {
|
||||
return this.aiList.map(e => {
|
||||
e.collected = this.collection.findIndex(c => c.link === e.link) > -1
|
||||
return e
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getCollection () {
|
||||
const data = this.collection
|
||||
const type = 'collect'
|
||||
this.$store.dispatch('AI_LIST', { data, type })
|
||||
this.showCollection = true
|
||||
this.query = ''
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
showCollection: false,
|
||||
collection: collection.getItems(),
|
||||
historyIndex: -1,
|
||||
history: dotuHistory.getItems(),
|
||||
showAiDou: false,
|
||||
query: '',
|
||||
page: 1,
|
||||
size: 24,
|
||||
bindScroll: false
|
||||
collect (emoji) {
|
||||
if (emoji.collected) {
|
||||
emoji.collected = false
|
||||
collection.deleteItem(emoji)
|
||||
} else {
|
||||
emoji.collected = true
|
||||
collection.setItem(emoji)
|
||||
}
|
||||
this.collection = collection.getItems()
|
||||
},
|
||||
async handleEmojiClick ({ link }) {
|
||||
try {
|
||||
const base64 = await resource.fetchImgToBase64(link)
|
||||
const { url } = await resource.sm(base64)
|
||||
bus.$emit('insert-image', url)
|
||||
this.showAiDou = false
|
||||
} catch (err) {
|
||||
// todo handle error
|
||||
console.log(err)
|
||||
}
|
||||
},
|
||||
created () {
|
||||
clearHistory () {
|
||||
dotuHistory.clear()
|
||||
this.history = dotuHistory.getItems()
|
||||
this.historyIndex = -1
|
||||
},
|
||||
deleteHistory (word) {
|
||||
dotuHistory.deleteItem(word)
|
||||
this.history = dotuHistory.getItems()
|
||||
this.historyIndex = -1
|
||||
},
|
||||
handleInput (event) {
|
||||
let historyIndex = this.historyIndex
|
||||
switch (event.key) {
|
||||
case 'Enter': {
|
||||
const query = this.historyIndex !== -1 ? this.history[this.historyIndex] : this.query
|
||||
if (!this.aiLoading) {
|
||||
this.search(query)
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'ArrowUp': {
|
||||
historyIndex = historyIndex - 1
|
||||
if (historyIndex === -1 || historyIndex === -2) {
|
||||
this.historyIndex = this.history.length - 1
|
||||
} else {
|
||||
this.historyIndex = historyIndex
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'ArrowDown': {
|
||||
historyIndex = historyIndex + 1
|
||||
if (historyIndex >= this.history.length) {
|
||||
this.historyIndex = 0
|
||||
} else {
|
||||
this.historyIndex = historyIndex
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
},
|
||||
handleShowAiDou () {
|
||||
this.showAiDou = true
|
||||
if (!this.bindScroll) {
|
||||
this.$nextTick(() => {
|
||||
const container = this.$refs.emojis
|
||||
container.addEventListener('scroll', this.handlerScroll)
|
||||
this.bindScroll = true
|
||||
})
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
bus.$on('aidou', this.handleShowAiDou)
|
||||
if (this.$refs.search) {
|
||||
this.$refs.search.focus()
|
||||
}
|
||||
})
|
||||
},
|
||||
beforeDestroy () {
|
||||
handlerScroll (event) {
|
||||
const container = this.$refs.emojis
|
||||
if (container) {
|
||||
container.removeEventListener('scroll', this.handlerScroll)
|
||||
const { offsetHeight, scrollHeight, scrollTop } = container
|
||||
if (scrollHeight - scrollTop - offsetHeight <= 100 && !this.aiLoading) {
|
||||
this.loadMore()
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
'aiList': state => state.aidou.aiList,
|
||||
'aiLoading': state => state.aidou.aiLoading
|
||||
}),
|
||||
emojis () {
|
||||
return this.aiList.map(e => {
|
||||
e.collected = this.collection.findIndex(c => c.link === e.link) > -1
|
||||
return e
|
||||
})
|
||||
search (word = this.query.trim()) {
|
||||
const { size } = this
|
||||
const query = this.query = word
|
||||
const page = this.page = 1
|
||||
const type = 'search'
|
||||
const params = { query, size, page }
|
||||
if (query) {
|
||||
// add query to dotuHistory
|
||||
dotuHistory.setItem(query)
|
||||
this.history = dotuHistory.getItems()
|
||||
this.historyIndex = -1
|
||||
this.$store.dispatch('AI_SEARCH', { params, type })
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getCollection () {
|
||||
const data = this.collection
|
||||
const type = 'collect'
|
||||
this.$store.dispatch('AI_LIST', { data, type })
|
||||
this.showCollection = true
|
||||
this.query = ''
|
||||
},
|
||||
collect (emoji) {
|
||||
if (emoji.collected) {
|
||||
emoji.collected = false
|
||||
collection.deleteItem(emoji)
|
||||
} else {
|
||||
emoji.collected = true
|
||||
collection.setItem(emoji)
|
||||
}
|
||||
this.collection = collection.getItems()
|
||||
},
|
||||
async handleEmojiClick ({ link }) {
|
||||
try {
|
||||
const base64 = await resource.fetchImgToBase64(link)
|
||||
const { url } = await resource.sm(base64)
|
||||
bus.$emit('insert-image', url)
|
||||
this.showAiDou = false
|
||||
} catch (err) {
|
||||
// todo handle error
|
||||
console.log(err)
|
||||
}
|
||||
},
|
||||
clearHistory () {
|
||||
dotuHistory.clear()
|
||||
this.history = dotuHistory.getItems()
|
||||
this.historyIndex = -1
|
||||
},
|
||||
deleteHistory (word) {
|
||||
dotuHistory.deleteItem(word)
|
||||
this.history = dotuHistory.getItems()
|
||||
this.historyIndex = -1
|
||||
},
|
||||
handleInput (event) {
|
||||
let historyIndex = this.historyIndex
|
||||
switch (event.key) {
|
||||
case 'Enter': {
|
||||
const query = this.historyIndex !== -1 ? this.history[this.historyIndex] : this.query
|
||||
if (!this.aiLoading) {
|
||||
this.search(query)
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'ArrowUp': {
|
||||
historyIndex = historyIndex - 1
|
||||
if (historyIndex === -1 || historyIndex === -2) {
|
||||
this.historyIndex = this.history.length - 1
|
||||
} else {
|
||||
this.historyIndex = historyIndex
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'ArrowDown': {
|
||||
historyIndex = historyIndex + 1
|
||||
if (historyIndex >= this.history.length) {
|
||||
this.historyIndex = 0
|
||||
} else {
|
||||
this.historyIndex = historyIndex
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
},
|
||||
handleShowAiDou () {
|
||||
this.showAiDou = true
|
||||
if (!this.bindScroll) {
|
||||
this.$nextTick(() => {
|
||||
const container = this.$refs.emojis
|
||||
container.addEventListener('scroll', this.handlerScroll)
|
||||
this.bindScroll = true
|
||||
})
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.search) {
|
||||
this.$refs.search.focus()
|
||||
}
|
||||
})
|
||||
},
|
||||
handlerScroll (event) {
|
||||
const container = this.$refs.emojis
|
||||
const { offsetHeight, scrollHeight, scrollTop } = container
|
||||
if (scrollHeight - scrollTop - offsetHeight <= 100 && !this.aiLoading) {
|
||||
this.loadMore()
|
||||
}
|
||||
},
|
||||
search (word = this.query.trim()) {
|
||||
const { size } = this
|
||||
const query = this.query = word
|
||||
const page = this.page = 1
|
||||
const type = 'search'
|
||||
const params = { query, size, page }
|
||||
if (query) {
|
||||
// add query to dotuHistory
|
||||
dotuHistory.setItem(query)
|
||||
this.history = dotuHistory.getItems()
|
||||
this.historyIndex = -1
|
||||
this.$store.dispatch('AI_SEARCH', { params, type })
|
||||
}
|
||||
},
|
||||
loadMore () {
|
||||
const { query, size, page } = this
|
||||
if (query.trim()) {
|
||||
const params = { query, size, page: page + 1 }
|
||||
this.$store.dispatch('AI_SEARCH', { params, type: 'loadMore' })
|
||||
}
|
||||
},
|
||||
shuffle () {
|
||||
const luckWord = hotWords[Math.random() * hotWords.length | 0]
|
||||
this.query = luckWord
|
||||
this.search()
|
||||
loadMore () {
|
||||
const { query, size, page } = this
|
||||
if (query.trim()) {
|
||||
const params = { query, size, page: page + 1 }
|
||||
this.$store.dispatch('AI_SEARCH', { params, type: 'loadMore' })
|
||||
}
|
||||
},
|
||||
shuffle () {
|
||||
const luckWord = hotWords[Math.random() * hotWords.length | 0]
|
||||
this.query = luckWord
|
||||
this.search()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
@ -27,7 +27,6 @@ export default {
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
.cpt-loading {
|
||||
position: absolute;
|
||||
@ -91,4 +90,4 @@ export default {
|
||||
transform: translateX(-20px);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -22,48 +22,48 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Tabs from './tabs.vue'
|
||||
import Editor from './editor.vue'
|
||||
import SourceCode from './sourceCode.vue'
|
||||
import Tabs from './tabs.vue'
|
||||
import Editor from './editor.vue'
|
||||
import SourceCode from './sourceCode.vue'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
filename: {
|
||||
type: String
|
||||
},
|
||||
markdown: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
cursor: {
|
||||
validator (value) {
|
||||
return typeof value === 'object'
|
||||
},
|
||||
required: true
|
||||
},
|
||||
sourceCode: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
showTabBar: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
textDirection: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
platform: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
export default {
|
||||
props: {
|
||||
filename: {
|
||||
type: String
|
||||
},
|
||||
components: {
|
||||
Tabs,
|
||||
Editor,
|
||||
SourceCode
|
||||
markdown: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
cursor: {
|
||||
validator (value) {
|
||||
return typeof value === 'object'
|
||||
},
|
||||
required: true
|
||||
},
|
||||
sourceCode: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
showTabBar: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
textDirection: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
platform: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
components: {
|
||||
Tabs,
|
||||
Editor,
|
||||
SourceCode
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
@ -7,186 +7,186 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import codeMirror, { setMode, setCursorAtLastLine, setTextDirection } from '../../codeMirror'
|
||||
import { wordCount as getWordCount } from 'muya/lib/utils'
|
||||
import { mapState } from 'vuex'
|
||||
import { adjustCursor } from '../../util'
|
||||
import bus from '../../bus'
|
||||
import { oneDarkThemes, railscastsThemes } from '@/config'
|
||||
import codeMirror, { setMode, setCursorAtLastLine, setTextDirection } from '../../codeMirror'
|
||||
import { wordCount as getWordCount } from 'muya/lib/utils'
|
||||
import { mapState } from 'vuex'
|
||||
import { adjustCursor } from '../../util'
|
||||
import bus from '../../bus'
|
||||
import { oneDarkThemes, railscastsThemes } from '@/config'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
markdown: String,
|
||||
cursor: Object,
|
||||
textDirection: {
|
||||
type: String,
|
||||
required: true
|
||||
export default {
|
||||
props: {
|
||||
markdown: String,
|
||||
cursor: Object,
|
||||
textDirection: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState({
|
||||
theme: state => state.preferences.theme,
|
||||
sourceCode: state => state.preferences.sourceCode,
|
||||
currentTab: state => state.editor.currentFile
|
||||
})
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
contentState: null,
|
||||
editor: null,
|
||||
commitTimer: null,
|
||||
viewDestroyed: false,
|
||||
tabId: null
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
textDirection: function (value, oldValue) {
|
||||
const { editor } = this
|
||||
if (value !== oldValue && editor) {
|
||||
setTextDirection(editor, value)
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState({
|
||||
'theme': state => state.preferences.theme,
|
||||
'sourceCode': state => state.preferences.sourceCode,
|
||||
'currentTab': state => state.editor.currentFile,
|
||||
})
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
contentState: null,
|
||||
editor: null,
|
||||
commitTimer: null,
|
||||
viewDestroyed: false,
|
||||
tabId: null
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
textDirection: function (value, oldValue) {
|
||||
const { editor } = this
|
||||
if (value !== oldValue && editor) {
|
||||
setTextDirection(editor, value)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.$nextTick(() => {
|
||||
// TODO: Should we load markdown from the tab or mapped vue property?
|
||||
const { id } = this.currentTab
|
||||
const { markdown = '', theme, cursor, textDirection } = this
|
||||
const container = this.$refs.sourceCode
|
||||
const codeMirrorConfig = {
|
||||
value: markdown,
|
||||
lineNumbers: true,
|
||||
autofocus: true,
|
||||
lineWrapping: true,
|
||||
styleActiveLine: true,
|
||||
direction: textDirection,
|
||||
lineNumberFormatter (line) {
|
||||
if (line % 10 === 0 || line === 1) {
|
||||
return line
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
created () {
|
||||
this.$nextTick(() => {
|
||||
// TODO: Should we load markdown from the tab or mapped vue property?
|
||||
const { id } = this.currentTab
|
||||
const { markdown = '', theme, cursor, textDirection } = this
|
||||
const container = this.$refs.sourceCode
|
||||
const codeMirrorConfig = {
|
||||
value: markdown,
|
||||
lineNumbers: true,
|
||||
autofocus: true,
|
||||
lineWrapping: true,
|
||||
styleActiveLine: true,
|
||||
direction: textDirection,
|
||||
lineNumberFormatter (line) {
|
||||
if (line % 10 === 0 || line === 1) {
|
||||
return line
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
if (railscastsThemes.includes(theme)) {
|
||||
codeMirrorConfig.theme = 'railscasts'
|
||||
} else if (oneDarkThemes.includes(theme)) {
|
||||
codeMirrorConfig.theme = 'one-dark'
|
||||
}
|
||||
const editor = this.editor = codeMirror(container, codeMirrorConfig)
|
||||
}
|
||||
if (railscastsThemes.includes(theme)) {
|
||||
codeMirrorConfig.theme = 'railscasts'
|
||||
} else if (oneDarkThemes.includes(theme)) {
|
||||
codeMirrorConfig.theme = 'one-dark'
|
||||
}
|
||||
const editor = this.editor = codeMirror(container, codeMirrorConfig)
|
||||
|
||||
bus.$on('file-loaded', this.handleFileChange)
|
||||
bus.$on('file-changed', this.handleFileChange)
|
||||
bus.$on('dotu-select', this.handleSelectDoutu)
|
||||
bus.$on('selectAll', this.handleSelectAll)
|
||||
bus.$on('file-loaded', this.handleFileChange)
|
||||
bus.$on('file-changed', this.handleFileChange)
|
||||
bus.$on('dotu-select', this.handleSelectDoutu)
|
||||
bus.$on('selectAll', this.handleSelectAll)
|
||||
|
||||
setMode(editor, 'markdown')
|
||||
this.listenChange()
|
||||
if (cursor) {
|
||||
const { anchor, focus } = cursor
|
||||
editor.setSelection(anchor, focus, { scroll: true }) // Scroll the focus into view.
|
||||
} else {
|
||||
setCursorAtLastLine(editor)
|
||||
}
|
||||
this.tabId = id
|
||||
setMode(editor, 'markdown')
|
||||
this.listenChange()
|
||||
if (cursor) {
|
||||
const { anchor, focus } = cursor
|
||||
editor.setSelection(anchor, focus, { scroll: true }) // Scroll the focus into view.
|
||||
} else {
|
||||
setCursorAtLastLine(editor)
|
||||
}
|
||||
this.tabId = id
|
||||
})
|
||||
},
|
||||
beforeDestroy () {
|
||||
// NOTE: Clear timer and manually commit changes. After mode switching and cleanup may follow
|
||||
// further key inputs, so ignore all inputs.
|
||||
this.viewDestroyed = true
|
||||
if (this.commitTimer) clearTimeout(this.commitTimer)
|
||||
|
||||
bus.$off('file-loaded', this.handleFileChange)
|
||||
bus.$off('file-changed', this.handleFileChange)
|
||||
bus.$off('dotu-select', this.handleSelectDoutu)
|
||||
bus.$off('selectAll', this.handleSelectAll)
|
||||
|
||||
const { editor } = this
|
||||
const { cursor, markdown } = this.getMarkdownAndCursor(editor)
|
||||
bus.$emit('file-changed', { id: this.tabId, markdown, cursor, renderCursor: true })
|
||||
},
|
||||
methods: {
|
||||
handleSelectDoutu (url) {
|
||||
const { editor } = this
|
||||
if (editor) {
|
||||
editor.replaceSelection(``)
|
||||
}
|
||||
},
|
||||
listenChange () {
|
||||
const { editor } = this
|
||||
editor.on('cursorActivity', cm => {
|
||||
const { cursor, markdown } = this.getMarkdownAndCursor(cm)
|
||||
const wordCount = getWordCount(markdown)
|
||||
if (this.commitTimer) clearTimeout(this.commitTimer)
|
||||
this.commitTimer = setTimeout(() => {
|
||||
// See "beforeDestroy" note
|
||||
if (!this.viewDestroyed) {
|
||||
if (this.tabId) {
|
||||
this.$store.dispatch('LISTEN_FOR_CONTENT_CHANGE', { id: this.tabId, markdown, wordCount, cursor })
|
||||
} else {
|
||||
// This may occur during tab switching but should not occur otherwise.
|
||||
console.warn(`LISTEN_FOR_CONTENT_CHANGE: Cannot commit changes because not tab id was set!`)
|
||||
}
|
||||
}
|
||||
}, 1000)
|
||||
})
|
||||
},
|
||||
beforeDestroy () {
|
||||
// NOTE: Clear timer and manually commit changes. After mode switching and cleanup may follow
|
||||
// further key inputs, so ignore all inputs.
|
||||
this.viewDestroyed = true
|
||||
if (this.commitTimer) clearTimeout(this.commitTimer)
|
||||
|
||||
bus.$off('file-loaded', this.handleFileChange)
|
||||
bus.$off('file-changed', this.handleFileChange)
|
||||
bus.$off('dotu-select', this.handleSelectDoutu)
|
||||
bus.$off('selectAll', this.handleSelectAll)
|
||||
// Another tab was selected - only listen to get changes but don't set history or other things.
|
||||
handleFileChange ({ id, markdown, cursor }) {
|
||||
this.prepareTabSwitch()
|
||||
|
||||
const { editor } = this
|
||||
const { cursor, markdown } = this.getMarkdownAndCursor(editor)
|
||||
bus.$emit('file-changed', { id: this.tabId, markdown, cursor, renderCursor: true })
|
||||
if (typeof markdown === 'string') {
|
||||
editor.setValue(markdown)
|
||||
}
|
||||
// Cursor is null when loading a file or creating a new tab in source code mode.
|
||||
if (cursor) {
|
||||
const { anchor, focus } = cursor
|
||||
editor.setSelection(anchor, focus, { scroll: true }) // Scroll the focus into view.
|
||||
} else {
|
||||
setCursorAtLastLine(editor)
|
||||
}
|
||||
this.tabId = id
|
||||
},
|
||||
methods: {
|
||||
handleSelectDoutu (url) {
|
||||
const { editor } = this
|
||||
if (editor) {
|
||||
editor.replaceSelection(``)
|
||||
}
|
||||
},
|
||||
listenChange () {
|
||||
const { editor } = this
|
||||
editor.on('cursorActivity', cm => {
|
||||
const { cursor, markdown } = this.getMarkdownAndCursor(cm)
|
||||
const wordCount = getWordCount(markdown)
|
||||
if (this.commitTimer) clearTimeout(this.commitTimer)
|
||||
this.commitTimer = setTimeout(() => {
|
||||
// See "beforeDestroy" note
|
||||
if (!this.viewDestroyed) {
|
||||
if (this.tabId) {
|
||||
this.$store.dispatch('LISTEN_FOR_CONTENT_CHANGE', { id: this.tabId, markdown, wordCount, cursor })
|
||||
} else {
|
||||
// This may occur during tab switching but should not occur otherwise.
|
||||
console.warn(`LISTEN_FOR_CONTENT_CHANGE: Cannot commit changes because not tab id was set!`)
|
||||
}
|
||||
}
|
||||
}, 1000)
|
||||
})
|
||||
},
|
||||
// Another tab was selected - only listen to get changes but don't set history or other things.
|
||||
handleFileChange ({ id, markdown, cursor }) {
|
||||
this.prepareTabSwitch()
|
||||
// Get markdown and cursor from CodeMirror.
|
||||
getMarkdownAndCursor (cm) {
|
||||
let focus = cm.getCursor('head')
|
||||
let anchor = cm.getCursor('anchor')
|
||||
const markdown = cm.getValue()
|
||||
const adjCursor = cursor => {
|
||||
const line = cm.getLine(cursor.line)
|
||||
const preLine = cm.getLine(cursor.line - 1)
|
||||
const nextLine = cm.getLine(cursor.line + 1)
|
||||
return adjustCursor(cursor, preLine, line, nextLine)
|
||||
}
|
||||
focus = adjCursor(focus)
|
||||
anchor = adjCursor(anchor)
|
||||
|
||||
return { cursor: { focus, anchor }, markdown }
|
||||
},
|
||||
// Commit changes from old tab. Problem: tab was already switched, so commit changes with old tab id.
|
||||
prepareTabSwitch () {
|
||||
if (this.commitTimer) clearTimeout(this.commitTimer)
|
||||
if (this.tabId) {
|
||||
const { editor } = this
|
||||
if (typeof markdown === 'string') {
|
||||
editor.setValue(markdown)
|
||||
}
|
||||
// Cursor is null when loading a file or creating a new tab in source code mode.
|
||||
if (cursor) {
|
||||
const { anchor, focus } = cursor
|
||||
editor.setSelection(anchor, focus, { scroll: true }) // Scroll the focus into view.
|
||||
} else {
|
||||
setCursorAtLastLine(editor)
|
||||
}
|
||||
this.tabId = id
|
||||
},
|
||||
// Get markdown and cursor from CodeMirror.
|
||||
getMarkdownAndCursor (cm) {
|
||||
let focus = cm.getCursor('head')
|
||||
let anchor = cm.getCursor('anchor')
|
||||
const markdown = cm.getValue()
|
||||
const adjCursor = cursor => {
|
||||
const line = cm.getLine(cursor.line)
|
||||
const preLine = cm.getLine(cursor.line - 1)
|
||||
const nextLine = cm.getLine(cursor.line + 1)
|
||||
return adjustCursor(cursor, preLine, line, nextLine)
|
||||
}
|
||||
focus = adjCursor(focus)
|
||||
anchor = adjCursor(anchor)
|
||||
const { cursor, markdown } = this.getMarkdownAndCursor(editor)
|
||||
this.$store.dispatch('LISTEN_FOR_CONTENT_CHANGE', { id: this.tabId, markdown, cursor })
|
||||
this.tabId = null // invalidate tab id
|
||||
}
|
||||
},
|
||||
|
||||
return { cursor: { focus, anchor }, markdown }
|
||||
},
|
||||
// Commit changes from old tab. Problem: tab was already switched, so commit changes with old tab id.
|
||||
prepareTabSwitch () {
|
||||
if (this.commitTimer) clearTimeout(this.commitTimer)
|
||||
if (this.tabId) {
|
||||
const { editor } = this
|
||||
const { cursor, markdown } = this.getMarkdownAndCursor(editor)
|
||||
this.$store.dispatch('LISTEN_FOR_CONTENT_CHANGE', { id: this.tabId, markdown, cursor })
|
||||
this.tabId = null // invalidate tab id
|
||||
}
|
||||
},
|
||||
|
||||
handleSelectAll () {
|
||||
if (this.sourceCode && this.editor) {
|
||||
this.editor.execCommand('selectAll')
|
||||
}
|
||||
handleSelectAll () {
|
||||
if (this.sourceCode && this.editor) {
|
||||
this.editor.execCommand('selectAll')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
@ -42,100 +42,100 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import autoScroll from 'dom-autoscroller'
|
||||
import dragula from 'dragula'
|
||||
import { tabsMixins } from '../../mixins'
|
||||
import { mapState } from 'vuex'
|
||||
import autoScroll from 'dom-autoscroller'
|
||||
import dragula from 'dragula'
|
||||
import { tabsMixins } from '../../mixins'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
this.autoScroller = null
|
||||
this.drake = null
|
||||
return {}
|
||||
export default {
|
||||
data () {
|
||||
this.autoScroller = null
|
||||
this.drake = null
|
||||
return {}
|
||||
},
|
||||
mixins: [tabsMixins],
|
||||
computed: {
|
||||
...mapState({
|
||||
currentFile: state => state.editor.currentFile,
|
||||
tabs: state => state.editor.tabs,
|
||||
showSideBar: state => state.layout.showSideBar,
|
||||
sideBarWidth: state => state.layout.sideBarWidth
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
newFile () {
|
||||
this.$store.dispatch('NEW_UNTITLED_TAB', {})
|
||||
},
|
||||
mixins: [tabsMixins],
|
||||
computed: {
|
||||
...mapState({
|
||||
'currentFile': state => state.editor.currentFile,
|
||||
'tabs': state => state.editor.tabs,
|
||||
'showSideBar': state => state.layout.showSideBar,
|
||||
'sideBarWidth': state => state.layout.sideBarWidth
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
newFile () {
|
||||
this.$store.dispatch('NEW_UNTITLED_TAB', {})
|
||||
},
|
||||
handleTabScroll (event) {
|
||||
// Use mouse wheel value first but prioritize X value more (e.g. touchpad input).
|
||||
let delta = event.deltaY
|
||||
if (event.deltaX !== 0) {
|
||||
delta = event.deltaX
|
||||
handleTabScroll (event) {
|
||||
// Use mouse wheel value first but prioritize X value more (e.g. touchpad input).
|
||||
let delta = event.deltaY
|
||||
if (event.deltaX !== 0) {
|
||||
delta = event.deltaX
|
||||
}
|
||||
|
||||
const tabs = this.$refs.tabContainer
|
||||
const newLeft = Math.max(0, Math.min(tabs.scrollLeft + delta, tabs.scrollWidth))
|
||||
tabs.scrollLeft = newLeft
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.$nextTick(() => {
|
||||
const tabs = this.$refs.tabContainer
|
||||
|
||||
// Allow to scroll through the tabs by mouse wheel or touchpad.
|
||||
tabs.addEventListener('wheel', this.handleTabScroll)
|
||||
|
||||
// Allow tab drag and drop to reorder tabs.
|
||||
const drake = this.drake = dragula([this.$refs.tabDropContainer], {
|
||||
direction: 'horizontal',
|
||||
revertOnSpill: true,
|
||||
mirrorContainer: this.$refs.tabDropContainer,
|
||||
ignoreInputTextSelection: false
|
||||
}).on('drop', (el, target, source, sibling) => {
|
||||
// Current tab that was dropped and need to be reordered.
|
||||
const droppedId = el.getAttribute('data-id')
|
||||
// This should be the next tab (tab | ... | el | sibling | tab | ...) but may be
|
||||
// the mirror image or null (tab | ... | el | sibling or null) if last tab.
|
||||
const nextTabId = sibling && sibling.getAttribute('data-id')
|
||||
const isLastTab = !sibling || sibling.classList.contains('gu-mirror')
|
||||
if (!droppedId || (sibling && !nextTabId)) {
|
||||
throw new Error('Cannot reorder tabs: invalid tab id.')
|
||||
}
|
||||
|
||||
const tabs = this.$refs.tabContainer
|
||||
const newLeft = Math.max(0, Math.min(tabs.scrollLeft + delta, tabs.scrollWidth ))
|
||||
tabs.scrollLeft = newLeft
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.$nextTick(() => {
|
||||
const tabs = this.$refs.tabContainer
|
||||
|
||||
// Allow to scroll through the tabs by mouse wheel or touchpad.
|
||||
tabs.addEventListener('wheel', this.handleTabScroll)
|
||||
|
||||
// Allow tab drag and drop to reorder tabs.
|
||||
const drake = this.drake = dragula([ this.$refs.tabDropContainer ], {
|
||||
direction: 'horizontal',
|
||||
revertOnSpill: true,
|
||||
mirrorContainer: this.$refs.tabDropContainer,
|
||||
ignoreInputTextSelection: false
|
||||
}).on('drop', (el, target, source, sibling) => {
|
||||
// Current tab that was dropped and need to be reordered.
|
||||
const droppedId = el.getAttribute('data-id')
|
||||
// This should be the next tab (tab | ... | el | sibling | tab | ...) but may be
|
||||
// the mirror image or null (tab | ... | el | sibling or null) if last tab.
|
||||
const nextTabId = sibling && sibling.getAttribute('data-id')
|
||||
const isLastTab = !sibling || sibling.classList.contains('gu-mirror')
|
||||
if (!droppedId || (sibling && !nextTabId)) {
|
||||
throw new Error('Cannot reorder tabs: invalid tab id.')
|
||||
}
|
||||
|
||||
this.$store.dispatch('EXCHANGE_TABS_BY_ID', {
|
||||
fromId: droppedId,
|
||||
toId: isLastTab ? null : nextTabId
|
||||
})
|
||||
})
|
||||
|
||||
// TODO(perf): Create a copy of dom-autoscroller and just hook tabs-container to
|
||||
// improve performance. Currently autoScroll is triggered when the mouse is moved
|
||||
// in Mark Text window.
|
||||
|
||||
// Scroll when dragging a tab to the beginning or end of the tab container.
|
||||
this.autoScroller = autoScroll([ tabs ], {
|
||||
margin: 20,
|
||||
maxSpeed: 6,
|
||||
scrollWhenOutside: false,
|
||||
autoScroll: () => {
|
||||
return this.autoScroller.down && drake.dragging
|
||||
}
|
||||
this.$store.dispatch('EXCHANGE_TABS_BY_ID', {
|
||||
fromId: droppedId,
|
||||
toId: isLastTab ? null : nextTabId
|
||||
})
|
||||
})
|
||||
},
|
||||
beforeDestroy () {
|
||||
const tabs = this.$refs.tabContainer
|
||||
tabs.removeEventListener('wheel', this.handleTabScroll)
|
||||
|
||||
if (this.autoScroller) {
|
||||
// Force destroy
|
||||
this.autoScroller.destroy(true)
|
||||
}
|
||||
if (this.drake) {
|
||||
this.drake.destroy()
|
||||
}
|
||||
// TODO(perf): Create a copy of dom-autoscroller and just hook tabs-container to
|
||||
// improve performance. Currently autoScroll is triggered when the mouse is moved
|
||||
// in Mark Text window.
|
||||
|
||||
// Scroll when dragging a tab to the beginning or end of the tab container.
|
||||
this.autoScroller = autoScroll([tabs], {
|
||||
margin: 20,
|
||||
maxSpeed: 6,
|
||||
scrollWhenOutside: false,
|
||||
autoScroll: () => {
|
||||
return this.autoScroller.down && drake.dragging
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
beforeDestroy () {
|
||||
const tabs = this.$refs.tabContainer
|
||||
tabs.removeEventListener('wheel', this.handleTabScroll)
|
||||
|
||||
if (this.autoScroller) {
|
||||
// Force destroy
|
||||
this.autoScroller.destroy(true)
|
||||
}
|
||||
if (this.drake) {
|
||||
this.drake.destroy()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
@ -117,4 +117,3 @@ export default {
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
@ -14,19 +14,19 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ContentIcon from '@/assets/icons/undraw_content.svg'
|
||||
import ContentIcon from '@/assets/icons/undraw_content.svg'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
this.ContentIcon = ContentIcon
|
||||
return {}
|
||||
},
|
||||
methods: {
|
||||
newFile () {
|
||||
this.$store.dispatch('NEW_UNTITLED_TAB', {})
|
||||
}
|
||||
export default {
|
||||
data () {
|
||||
this.ContentIcon = ContentIcon
|
||||
return {}
|
||||
},
|
||||
methods: {
|
||||
newFile () {
|
||||
this.$store.dispatch('NEW_UNTITLED_TAB', {})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
@ -24,41 +24,41 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import bus from '../bus'
|
||||
import { mapState } from 'vuex'
|
||||
import bus from '../bus'
|
||||
import { mapState } from 'vuex'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
showRename: false,
|
||||
tempName: ''
|
||||
}
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
showRename: false,
|
||||
tempName: ''
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.$nextTick(() => {
|
||||
bus.$on('rename', this.handleRename)
|
||||
})
|
||||
},
|
||||
beforeDestroy () {
|
||||
bus.$off('rename', this.handleRename)
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
filename: state => state.editor.currentFile.filename
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
handleRename () {
|
||||
this.showRename = true
|
||||
this.tempName = this.filename
|
||||
this.$refs.search.focus()
|
||||
},
|
||||
created () {
|
||||
this.$nextTick(() => {
|
||||
bus.$on('rename', this.handleRename)
|
||||
})
|
||||
},
|
||||
beforeDestroy () {
|
||||
bus.$off('rename', this.handleRename)
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
filename: state => state.editor.currentFile.filename
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
handleRename () {
|
||||
this.showRename = true
|
||||
this.tempName = this.filename
|
||||
this.$refs.search.focus()
|
||||
},
|
||||
confirm () {
|
||||
this.$store.dispatch('RENAME', this.tempName)
|
||||
this.showRename = false
|
||||
}
|
||||
confirm () {
|
||||
this.$store.dispatch('RENAME', this.tempName)
|
||||
this.showRename = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
@ -102,121 +102,121 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import bus from '../bus'
|
||||
import { mapState } from 'vuex'
|
||||
import bus from '../bus'
|
||||
import { mapState } from 'vuex'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
showSearch: false,
|
||||
type: 'search',
|
||||
searchValue: '',
|
||||
replaceValue: '',
|
||||
caseSensitive: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
searchMatches: function (newValue, oldValue) {
|
||||
if (!newValue || !oldValue) return
|
||||
const { value } = newValue
|
||||
if (value && value !== oldValue.value) {
|
||||
this.searchValue = value
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
'searchMatches': state => state.editor.currentFile.searchMatches
|
||||
}),
|
||||
highlightIndex () {
|
||||
if (this.searchMatches) {
|
||||
return this.searchMatches.index
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
},
|
||||
highlightCount () {
|
||||
if (this.searchMatches) {
|
||||
return this.searchMatches.matches.length
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
bus.$on('find', this.listenFind)
|
||||
bus.$on('replace', this.listenReplace)
|
||||
bus.$on('findNext', this.listenFindNext)
|
||||
bus.$on('findPrev', this.listenFindPrev)
|
||||
document.addEventListener('click', this.docClick)
|
||||
document.addEventListener('keyup', this.docKeyup)
|
||||
},
|
||||
beforeDestroy () {
|
||||
bus.$off('find', this.listenFind)
|
||||
bus.$off('replace', this.listenReplace)
|
||||
bus.$off('findNext', this.listenFindNext)
|
||||
bus.$off('findPrev', this.listenFindPrev)
|
||||
document.removeEventListener('click', this.docClick)
|
||||
document.removeEventListener('keyup', this.docKeyup)
|
||||
},
|
||||
methods: {
|
||||
listenFind () {
|
||||
this.showSearch = true
|
||||
this.type = 'search'
|
||||
this.$nextTick(() => {
|
||||
this.$refs.search.focus()
|
||||
})
|
||||
},
|
||||
listenReplace () {
|
||||
this.showSearch = true
|
||||
this.type = 'replace'
|
||||
},
|
||||
listenFindNext () {
|
||||
this.find('next')
|
||||
},
|
||||
listenFindPrev () {
|
||||
this.find('prev')
|
||||
},
|
||||
docKeyup (event) {
|
||||
if (event.key === 'Escape') {
|
||||
this.emitSearch(true)
|
||||
}
|
||||
},
|
||||
docClick (isSelect) {
|
||||
if (!this.showSearch) return
|
||||
this.emitSearch()
|
||||
},
|
||||
emitSearch (selectHighlight = false) {
|
||||
this.showSearch = false
|
||||
const searchValue = this.searchValue = ''
|
||||
this.replaceValue = ''
|
||||
bus.$emit('searchValue', searchValue, { selectHighlight })
|
||||
},
|
||||
caseClick () {
|
||||
this.caseSensitive = !this.caseSensitive
|
||||
},
|
||||
typeClick () {
|
||||
this.type = this.type === 'search' ? 'replace' : 'search'
|
||||
},
|
||||
find (action) {
|
||||
bus.$emit('find', action)
|
||||
},
|
||||
search (event) {
|
||||
if (event.key === 'Escape') return
|
||||
if (event.key !== 'Enter') {
|
||||
const { caseSensitive } = this
|
||||
bus.$emit('searchValue', this.searchValue, { caseSensitive })
|
||||
} else {
|
||||
this.find('next')
|
||||
}
|
||||
},
|
||||
replace (isSingle = true) {
|
||||
const { caseSensitive, replaceValue } = this
|
||||
bus.$emit('replaceValue', replaceValue, { caseSensitive, isSingle })
|
||||
},
|
||||
noop () {}
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
showSearch: false,
|
||||
type: 'search',
|
||||
searchValue: '',
|
||||
replaceValue: '',
|
||||
caseSensitive: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
searchMatches: function (newValue, oldValue) {
|
||||
if (!newValue || !oldValue) return
|
||||
const { value } = newValue
|
||||
if (value && value !== oldValue.value) {
|
||||
this.searchValue = value
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
searchMatches: state => state.editor.currentFile.searchMatches
|
||||
}),
|
||||
highlightIndex () {
|
||||
if (this.searchMatches) {
|
||||
return this.searchMatches.index
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
},
|
||||
highlightCount () {
|
||||
if (this.searchMatches) {
|
||||
return this.searchMatches.matches.length
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
bus.$on('find', this.listenFind)
|
||||
bus.$on('replace', this.listenReplace)
|
||||
bus.$on('findNext', this.listenFindNext)
|
||||
bus.$on('findPrev', this.listenFindPrev)
|
||||
document.addEventListener('click', this.docClick)
|
||||
document.addEventListener('keyup', this.docKeyup)
|
||||
},
|
||||
beforeDestroy () {
|
||||
bus.$off('find', this.listenFind)
|
||||
bus.$off('replace', this.listenReplace)
|
||||
bus.$off('findNext', this.listenFindNext)
|
||||
bus.$off('findPrev', this.listenFindPrev)
|
||||
document.removeEventListener('click', this.docClick)
|
||||
document.removeEventListener('keyup', this.docKeyup)
|
||||
},
|
||||
methods: {
|
||||
listenFind () {
|
||||
this.showSearch = true
|
||||
this.type = 'search'
|
||||
this.$nextTick(() => {
|
||||
this.$refs.search.focus()
|
||||
})
|
||||
},
|
||||
listenReplace () {
|
||||
this.showSearch = true
|
||||
this.type = 'replace'
|
||||
},
|
||||
listenFindNext () {
|
||||
this.find('next')
|
||||
},
|
||||
listenFindPrev () {
|
||||
this.find('prev')
|
||||
},
|
||||
docKeyup (event) {
|
||||
if (event.key === 'Escape') {
|
||||
this.emitSearch(true)
|
||||
}
|
||||
},
|
||||
docClick (isSelect) {
|
||||
if (!this.showSearch) return
|
||||
this.emitSearch()
|
||||
},
|
||||
emitSearch (selectHighlight = false) {
|
||||
this.showSearch = false
|
||||
const searchValue = this.searchValue = ''
|
||||
this.replaceValue = ''
|
||||
bus.$emit('searchValue', searchValue, { selectHighlight })
|
||||
},
|
||||
caseClick () {
|
||||
this.caseSensitive = !this.caseSensitive
|
||||
},
|
||||
typeClick () {
|
||||
this.type = this.type === 'search' ? 'replace' : 'search'
|
||||
},
|
||||
find (action) {
|
||||
bus.$emit('find', action)
|
||||
},
|
||||
search (event) {
|
||||
if (event.key === 'Escape') return
|
||||
if (event.key !== 'Enter') {
|
||||
const { caseSensitive } = this
|
||||
bus.$emit('searchValue', this.searchValue, { caseSensitive })
|
||||
} else {
|
||||
this.find('next')
|
||||
}
|
||||
},
|
||||
replace (isSingle = true) {
|
||||
const { caseSensitive, replaceValue } = this
|
||||
bus.$emit('replaceValue', replaceValue, { caseSensitive, isSingle })
|
||||
},
|
||||
noop () {}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
@ -3,27 +3,27 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import fileIcons from 'muya/lib/ui/fileIcons'
|
||||
import fileIcons from 'muya/lib/ui/fileIcons'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
name: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: 'mock.md'
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
className () {
|
||||
let icon = fileIcons.getClassWithColor(this.name ? this.name : 'mock.md')
|
||||
if (!icon) {
|
||||
// Use fallback icon when the icon is unknown.
|
||||
icon = fileIcons.getClassWithColor('mock.md')
|
||||
}
|
||||
return icon.split(/\s/)
|
||||
export default {
|
||||
props: {
|
||||
name: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: 'mock.md'
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
className () {
|
||||
let icon = fileIcons.getClassWithColor(this.name ? this.name : 'mock.md')
|
||||
if (!icon) {
|
||||
// Use fallback icon when the icon is unknown.
|
||||
icon = fileIcons.getClassWithColor('mock.md')
|
||||
}
|
||||
return icon.split(/\s/)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user