mirror of
https://github.com/marktext/marktext.git
synced 2025-05-02 18:51:55 +08:00
Support multiple lines math input (#294)
* change another way to render math * open\save\edit multiple lines math block * rewrite header label style * inline code style update * update dark theme style * update change log * typo error * update webpack to v4 * update license * fix unexpected to delete math preview block * fix cursor error when change mode
This commit is contained in:
parent
1a7a3d5c06
commit
16bb1de82e
@ -51,7 +51,7 @@ function startRenderer () {
|
|||||||
compiler.plugin('compilation', compilation => {
|
compiler.plugin('compilation', compilation => {
|
||||||
compilation.plugin('html-webpack-plugin-after-emit', (data, cb) => {
|
compilation.plugin('html-webpack-plugin-after-emit', (data, cb) => {
|
||||||
hotMiddleware.publish({ action: 'reload' })
|
hotMiddleware.publish({ action: 'reload' })
|
||||||
cb()
|
cb && cb()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -5,10 +5,10 @@ process.env.BABEL_ENV = 'main'
|
|||||||
const path = require('path')
|
const path = require('path')
|
||||||
const { dependencies } = require('../package.json')
|
const { dependencies } = require('../package.json')
|
||||||
const webpack = require('webpack')
|
const webpack = require('webpack')
|
||||||
|
const proMode = process.env.NODE_ENV === 'production'
|
||||||
|
|
||||||
const BabiliWebpackPlugin = require('babili-webpack-plugin')
|
const mainConfig = {
|
||||||
|
mode: 'development',
|
||||||
let mainConfig = {
|
|
||||||
entry: {
|
entry: {
|
||||||
main: path.join(__dirname, '../src/main/index.js')
|
main: path.join(__dirname, '../src/main/index.js')
|
||||||
},
|
},
|
||||||
@ -40,8 +40,8 @@ let mainConfig = {
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
node: {
|
node: {
|
||||||
__dirname: process.env.NODE_ENV !== 'production',
|
__dirname: !proMode,
|
||||||
__filename: process.env.NODE_ENV !== 'production'
|
__filename: !proMode
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
filename: '[name].js',
|
filename: '[name].js',
|
||||||
@ -60,7 +60,7 @@ let mainConfig = {
|
|||||||
/**
|
/**
|
||||||
* Adjust mainConfig for development settings
|
* Adjust mainConfig for development settings
|
||||||
*/
|
*/
|
||||||
if (process.env.NODE_ENV !== 'production') {
|
if (!proMode) {
|
||||||
mainConfig.plugins.push(
|
mainConfig.plugins.push(
|
||||||
new webpack.DefinePlugin({
|
new webpack.DefinePlugin({
|
||||||
'__static': `"${path.join(__dirname, '../static').replace(/\\/g, '\\\\')}"`
|
'__static': `"${path.join(__dirname, '../static').replace(/\\/g, '\\\\')}"`
|
||||||
@ -71,12 +71,10 @@ if (process.env.NODE_ENV !== 'production') {
|
|||||||
/**
|
/**
|
||||||
* Adjust mainConfig for production settings
|
* Adjust mainConfig for production settings
|
||||||
*/
|
*/
|
||||||
if (process.env.NODE_ENV === 'production') {
|
if (proMode) {
|
||||||
|
mainConfig.mode = 'production'
|
||||||
mainConfig.plugins.push(
|
mainConfig.plugins.push(
|
||||||
new BabiliWebpackPlugin(),
|
// new BabiliWebpackPlugin()
|
||||||
new webpack.DefinePlugin({
|
|
||||||
'process.env.NODE_ENV': '"production"'
|
|
||||||
})
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,14 +3,14 @@
|
|||||||
process.env.BABEL_ENV = 'renderer'
|
process.env.BABEL_ENV = 'renderer'
|
||||||
|
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const { dependencies } = require('../package.json')
|
|
||||||
const webpack = require('webpack')
|
const webpack = require('webpack')
|
||||||
|
|
||||||
const BabiliWebpackPlugin = require('babili-webpack-plugin')
|
|
||||||
const CopyWebpackPlugin = require('copy-webpack-plugin')
|
const CopyWebpackPlugin = require('copy-webpack-plugin')
|
||||||
const ExtractTextPlugin = require('extract-text-webpack-plugin')
|
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
||||||
|
const VueLoaderPlugin = require('vue-loader/lib/plugin')
|
||||||
|
|
||||||
|
const { dependencies } = require('../package.json')
|
||||||
|
const proMode = process.env.NODE_ENV === 'production'
|
||||||
/**
|
/**
|
||||||
* List of node_modules to include in webpack bundle
|
* List of node_modules to include in webpack bundle
|
||||||
*
|
*
|
||||||
@ -18,9 +18,10 @@ const HtmlWebpackPlugin = require('html-webpack-plugin')
|
|||||||
* that provide pure *.vue files that need compiling
|
* that provide pure *.vue files that need compiling
|
||||||
* https://simulatedgreg.gitbooks.io/electron-vue/content/en/webpack-configurations.html#white-listing-externals
|
* https://simulatedgreg.gitbooks.io/electron-vue/content/en/webpack-configurations.html#white-listing-externals
|
||||||
*/
|
*/
|
||||||
let whiteListedModules = ['vue']
|
const whiteListedModules = ['vue']
|
||||||
|
|
||||||
let rendererConfig = {
|
const rendererConfig = {
|
||||||
|
mode: 'development',
|
||||||
devtool: '#cheap-module-eval-source-map',
|
devtool: '#cheap-module-eval-source-map',
|
||||||
entry: {
|
entry: {
|
||||||
renderer: path.join(__dirname, '../src/renderer/main.js')
|
renderer: path.join(__dirname, '../src/renderer/main.js')
|
||||||
@ -43,10 +44,10 @@ let rendererConfig = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.css$/,
|
test: /\.css$/,
|
||||||
use: ExtractTextPlugin.extract({
|
use: [
|
||||||
fallback: 'style-loader',
|
proMode ? MiniCssExtractPlugin.loader : 'style-loader',
|
||||||
use: 'css-loader'
|
"css-loader"
|
||||||
})
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.html$/,
|
test: /\.html$/,
|
||||||
@ -64,14 +65,7 @@ let rendererConfig = {
|
|||||||
{
|
{
|
||||||
test: /\.vue$/,
|
test: /\.vue$/,
|
||||||
use: {
|
use: {
|
||||||
loader: 'vue-loader',
|
loader: 'vue-loader'
|
||||||
options: {
|
|
||||||
extractCSS: process.env.NODE_ENV === 'production',
|
|
||||||
loaders: {
|
|
||||||
sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax=1',
|
|
||||||
scss: 'vue-style-loader!css-loader!sass-loader'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -109,7 +103,6 @@ let rendererConfig = {
|
|||||||
__filename: process.env.NODE_ENV !== 'production'
|
__filename: process.env.NODE_ENV !== 'production'
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new ExtractTextPlugin('styles.css'),
|
|
||||||
new HtmlWebpackPlugin({
|
new HtmlWebpackPlugin({
|
||||||
filename: 'index.html',
|
filename: 'index.html',
|
||||||
template: path.resolve(__dirname, '../src/index.ejs'),
|
template: path.resolve(__dirname, '../src/index.ejs'),
|
||||||
@ -123,7 +116,8 @@ let rendererConfig = {
|
|||||||
: false
|
: false
|
||||||
}),
|
}),
|
||||||
new webpack.HotModuleReplacementPlugin(),
|
new webpack.HotModuleReplacementPlugin(),
|
||||||
new webpack.NoEmitOnErrorsPlugin()
|
new webpack.NoEmitOnErrorsPlugin(),
|
||||||
|
new VueLoaderPlugin()
|
||||||
],
|
],
|
||||||
output: {
|
output: {
|
||||||
filename: '[name].js',
|
filename: '[name].js',
|
||||||
@ -154,11 +148,16 @@ if (process.env.NODE_ENV !== 'production') {
|
|||||||
/**
|
/**
|
||||||
* Adjust rendererConfig for production settings
|
* Adjust rendererConfig for production settings
|
||||||
*/
|
*/
|
||||||
if (process.env.NODE_ENV === 'production') {
|
if (proMode) {
|
||||||
rendererConfig.devtool = ''
|
rendererConfig.devtool = ''
|
||||||
|
rendererConfig.mode = 'production'
|
||||||
rendererConfig.plugins.push(
|
rendererConfig.plugins.push(
|
||||||
new BabiliWebpackPlugin(),
|
new MiniCssExtractPlugin({
|
||||||
|
// Options similar to the same options in webpackOptions.output
|
||||||
|
// both options are optional
|
||||||
|
filename: '[name].[hash].css',
|
||||||
|
chunkFilename: '[id].[hash].css'
|
||||||
|
}),
|
||||||
new CopyWebpackPlugin([
|
new CopyWebpackPlugin([
|
||||||
{
|
{
|
||||||
from: path.join(__dirname, '../static'),
|
from: path.join(__dirname, '../static'),
|
||||||
@ -170,9 +169,6 @@ if (process.env.NODE_ENV === 'production') {
|
|||||||
to: path.join(__dirname, '../dist/electron/codemirror/mode/[name]/[name].js')
|
to: path.join(__dirname, '../dist/electron/codemirror/mode/[name]/[name].js')
|
||||||
}
|
}
|
||||||
]),
|
]),
|
||||||
new webpack.DefinePlugin({
|
|
||||||
'process.env.NODE_ENV': '"production"'
|
|
||||||
}),
|
|
||||||
new webpack.LoaderOptionsPlugin({
|
new webpack.LoaderOptionsPlugin({
|
||||||
minimize: true
|
minimize: true
|
||||||
})
|
})
|
||||||
|
@ -5,12 +5,15 @@ process.env.BABEL_ENV = 'web'
|
|||||||
const path = require('path')
|
const path = require('path')
|
||||||
const webpack = require('webpack')
|
const webpack = require('webpack')
|
||||||
|
|
||||||
const BabiliWebpackPlugin = require('babili-webpack-plugin')
|
|
||||||
const CopyWebpackPlugin = require('copy-webpack-plugin')
|
const CopyWebpackPlugin = require('copy-webpack-plugin')
|
||||||
const ExtractTextPlugin = require('extract-text-webpack-plugin')
|
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
||||||
|
const VueLoaderPlugin = require('vue-loader/lib/plugin')
|
||||||
|
|
||||||
let webConfig = {
|
const proMode = process.env.NODE_ENV === 'production'
|
||||||
|
|
||||||
|
const webConfig = {
|
||||||
|
mode: 'development',
|
||||||
devtool: '#cheap-module-eval-source-map',
|
devtool: '#cheap-module-eval-source-map',
|
||||||
entry: {
|
entry: {
|
||||||
web: path.join(__dirname, '../src/renderer/main.js')
|
web: path.join(__dirname, '../src/renderer/main.js')
|
||||||
@ -30,10 +33,10 @@ let webConfig = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.css$/,
|
test: /\.css$/,
|
||||||
use: ExtractTextPlugin.extract({
|
use: [
|
||||||
fallback: 'style-loader',
|
proMode ? MiniCssExtractPlugin.loader : 'style-loader',
|
||||||
use: 'css-loader'
|
"css-loader"
|
||||||
})
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.html$/,
|
test: /\.html$/,
|
||||||
@ -48,14 +51,7 @@ let webConfig = {
|
|||||||
{
|
{
|
||||||
test: /\.vue$/,
|
test: /\.vue$/,
|
||||||
use: {
|
use: {
|
||||||
loader: 'vue-loader',
|
loader: 'vue-loader'
|
||||||
options: {
|
|
||||||
extractCSS: true,
|
|
||||||
loaders: {
|
|
||||||
sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax=1',
|
|
||||||
scss: 'vue-style-loader!css-loader!sass-loader'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -81,7 +77,6 @@ let webConfig = {
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new ExtractTextPlugin('styles.css'),
|
|
||||||
new HtmlWebpackPlugin({
|
new HtmlWebpackPlugin({
|
||||||
filename: 'index.html',
|
filename: 'index.html',
|
||||||
template: path.resolve(__dirname, '../src/index.ejs'),
|
template: path.resolve(__dirname, '../src/index.ejs'),
|
||||||
@ -96,7 +91,8 @@ let webConfig = {
|
|||||||
'process.env.IS_WEB': 'true'
|
'process.env.IS_WEB': 'true'
|
||||||
}),
|
}),
|
||||||
new webpack.HotModuleReplacementPlugin(),
|
new webpack.HotModuleReplacementPlugin(),
|
||||||
new webpack.NoEmitOnErrorsPlugin()
|
new webpack.NoEmitOnErrorsPlugin(),
|
||||||
|
new VueLoaderPlugin()
|
||||||
],
|
],
|
||||||
output: {
|
output: {
|
||||||
filename: '[name].js',
|
filename: '[name].js',
|
||||||
@ -115,11 +111,17 @@ let webConfig = {
|
|||||||
/**
|
/**
|
||||||
* Adjust webConfig for production settings
|
* Adjust webConfig for production settings
|
||||||
*/
|
*/
|
||||||
if (process.env.NODE_ENV === 'production') {
|
if (proMode) {
|
||||||
webConfig.devtool = ''
|
webConfig.devtool = ''
|
||||||
|
webConfig.mode ='production'
|
||||||
|
|
||||||
webConfig.plugins.push(
|
webConfig.plugins.push(
|
||||||
new BabiliWebpackPlugin(),
|
new MiniCssExtractPlugin({
|
||||||
|
// Options similar to the same options in webpackOptions.output
|
||||||
|
// both options are optional
|
||||||
|
filename: '[name].[hash].css',
|
||||||
|
chunkFilename: '[id].[hash].css'
|
||||||
|
}),
|
||||||
new CopyWebpackPlugin([
|
new CopyWebpackPlugin([
|
||||||
{
|
{
|
||||||
from: path.join(__dirname, '../static'),
|
from: path.join(__dirname, '../static'),
|
||||||
@ -127,9 +129,6 @@ if (process.env.NODE_ENV === 'production') {
|
|||||||
ignore: ['.*']
|
ignore: ['.*']
|
||||||
}
|
}
|
||||||
]),
|
]),
|
||||||
new webpack.DefinePlugin({
|
|
||||||
'process.env.NODE_ENV': '"production"'
|
|
||||||
}),
|
|
||||||
new webpack.LoaderOptionsPlugin({
|
new webpack.LoaderOptionsPlugin({
|
||||||
minimize: true
|
minimize: true
|
||||||
})
|
})
|
||||||
|
3
.github/CHANGELOG.md
vendored
3
.github/CHANGELOG.md
vendored
@ -1,4 +1,4 @@
|
|||||||
### 0.11.37
|
### 0.11.38
|
||||||
|
|
||||||
**:cactus:Feature**
|
**:cactus:Feature**
|
||||||
|
|
||||||
@ -11,6 +11,7 @@
|
|||||||
- feature: Support `setext` heading but the default heading style is `atx`
|
- feature: Support `setext` heading but the default heading style is `atx`
|
||||||
- feature: User list item marker setting in preference file.
|
- feature: User list item marker setting in preference file.
|
||||||
- feature: Select text from selected table (cell) only if you press Ctrl+A
|
- feature: Select text from selected table (cell) only if you press Ctrl+A
|
||||||
|
- feature: Support Multiple lines math #242
|
||||||
|
|
||||||
**:butterfly:Optimization**
|
**:butterfly:Optimization**
|
||||||
|
|
||||||
|
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2017-2018 Jocs
|
Copyright (c) 2017-Present Jocs
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
!macro customUnInstall
|
|
||||||
MessageBox MB_YESNO "Do you want to delete user settings?" /SD IDNO IDNO SkipRemoval
|
|
||||||
SetShellVarContext current
|
|
||||||
RMDir /r "$APPDATA\marktext"
|
|
||||||
SkipRemoval:
|
|
||||||
!macroend
|
|
0
dist/electron/.gitkeep
vendored
0
dist/electron/.gitkeep
vendored
0
dist/web/.gitkeep
vendored
0
dist/web/.gitkeep
vendored
5543
package-lock.json
generated
5543
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
90
package.json
90
package.json
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "marktext",
|
"name": "marktext",
|
||||||
"version": "0.10.21",
|
"version": "0.10.21",
|
||||||
"author": "Jocs <luoran1988@126.com>",
|
"author": "Jocs <ransixi@gmail.com>",
|
||||||
"description": "Next generation markdown editor",
|
"description": "Next generation markdown editor",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "./dist/electron/main.js",
|
"main": "./dist/electron/main.js",
|
||||||
@ -105,61 +105,59 @@
|
|||||||
"codemirror": "^5.36.0",
|
"codemirror": "^5.36.0",
|
||||||
"css-tree": "^1.0.0-alpha.28",
|
"css-tree": "^1.0.0-alpha.28",
|
||||||
"dompurify": "^1.0.3",
|
"dompurify": "^1.0.3",
|
||||||
"electron-window-state": "^4.1.1",
|
"element-ui": "^2.3.9",
|
||||||
"element-ui": "^2.3.3",
|
|
||||||
"file-icons-js": "^1.0.3",
|
"file-icons-js": "^1.0.3",
|
||||||
"fs-extra": "^5.0.0",
|
"fs-extra": "^6.0.1",
|
||||||
"fuzzaldrin": "^2.1.0",
|
"fuzzaldrin": "^2.1.0",
|
||||||
"html-tags": "^2.0.0",
|
"html-tags": "^2.0.0",
|
||||||
"katex": "^0.9.0",
|
"katex": "^0.10.0-alpha",
|
||||||
"mousetrap": "^1.6.1",
|
"mousetrap": "^1.6.1",
|
||||||
"parse5": "^4.0.0",
|
"parse5": "^5.0.0",
|
||||||
"snabbdom": "^0.7.1",
|
"snabbdom": "^0.7.1",
|
||||||
"snabbdom-to-html": "^5.1.1",
|
"snabbdom-to-html": "^5.1.1",
|
||||||
"snabbdom-virtualize": "^0.7.0",
|
"snabbdom-virtualize": "^0.7.0",
|
||||||
"turndown": "^4.0.1",
|
"turndown": "^4.0.2",
|
||||||
"turndown-plugin-gfm": "^1.0.1",
|
"turndown-plugin-gfm": "^1.0.2",
|
||||||
"vue": "^2.5.16",
|
"vue": "^2.5.16",
|
||||||
"vue-electron": "^1.0.6",
|
"vue-electron": "^1.0.6",
|
||||||
"vuex": "^2.3.1"
|
"vuex": "^3.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-core": "^6.26.3",
|
"babel-core": "^6.26.3",
|
||||||
"babel-eslint": "^7.2.3",
|
"babel-eslint": "^8.2.3",
|
||||||
"babel-loader": "^7.1.1",
|
"babel-loader": "^7.1.4",
|
||||||
"babel-plugin-component": "^1.1.0",
|
"babel-plugin-component": "^1.1.1",
|
||||||
"babel-plugin-istanbul": "^4.1.6",
|
"babel-plugin-istanbul": "^4.1.6",
|
||||||
"babel-plugin-transform-runtime": "^6.23.0",
|
"babel-plugin-transform-runtime": "^6.23.0",
|
||||||
"babel-preset-env": "^1.6.0",
|
"babel-preset-env": "^1.7.0",
|
||||||
"babel-preset-stage-0": "^6.24.1",
|
"babel-preset-stage-0": "^6.24.1",
|
||||||
"babel-register": "^6.24.1",
|
"babel-register": "^6.26.0",
|
||||||
"babili-webpack-plugin": "^0.1.2",
|
"cfonts": "^2.1.2",
|
||||||
"cfonts": "^1.2.0",
|
|
||||||
"chai": "^4.0.0",
|
"chai": "^4.0.0",
|
||||||
"chalk": "^2.1.0",
|
"chalk": "^2.4.1",
|
||||||
"copy-webpack-plugin": "^4.0.1",
|
"copy-webpack-plugin": "^4.5.1",
|
||||||
"cross-env": "^5.0.5",
|
"cross-env": "^5.1.6",
|
||||||
"css-loader": "^0.28.4",
|
"css-loader": "^0.28.11",
|
||||||
"del": "^3.0.0",
|
"del": "^3.0.0",
|
||||||
"devtron": "^1.4.0",
|
"devtron": "^1.4.0",
|
||||||
"electron": "^2.0.2",
|
"electron": "^2.0.2",
|
||||||
"electron-builder": "^20.14.7",
|
"electron-builder": "^20.14.7",
|
||||||
"electron-debug": "^1.5.0",
|
"electron-debug": "^1.5.0",
|
||||||
"electron-devtools-installer": "^2.2.0",
|
"electron-devtools-installer": "^2.2.4",
|
||||||
"electron-updater": "^2.21.8",
|
"electron-updater": "^2.21.10",
|
||||||
|
"electron-window-state": "^4.1.1",
|
||||||
"eslint": "^4.19.1",
|
"eslint": "^4.19.1",
|
||||||
"eslint-config-standard": "^10.2.1",
|
"eslint-config-standard": "^11.0.0",
|
||||||
"eslint-friendly-formatter": "^3.0.0",
|
"eslint-friendly-formatter": "^4.0.1",
|
||||||
"eslint-loader": "^1.9.0",
|
"eslint-loader": "^2.0.0",
|
||||||
"eslint-plugin-html": "^3.1.1",
|
"eslint-plugin-html": "^4.0.3",
|
||||||
"eslint-plugin-import": "^2.10.0",
|
"eslint-plugin-import": "^2.12.0",
|
||||||
"eslint-plugin-node": "^5.1.1",
|
"eslint-plugin-node": "^6.0.1",
|
||||||
"eslint-plugin-promise": "^3.5.0",
|
"eslint-plugin-promise": "^3.8.0",
|
||||||
"eslint-plugin-standard": "^3.0.1",
|
"eslint-plugin-standard": "^3.1.0",
|
||||||
"extract-text-webpack-plugin": "^3.0.0",
|
"file-loader": "^1.1.11",
|
||||||
"file-loader": "^0.11.2",
|
"html-webpack-plugin": "^3.2.0",
|
||||||
"html-webpack-plugin": "^2.30.1",
|
"inject-loader": "^4.0.1",
|
||||||
"inject-loader": "^3.0.0",
|
|
||||||
"karma": "^1.3.0",
|
"karma": "^1.3.0",
|
||||||
"karma-chai": "^0.1.0",
|
"karma-chai": "^0.1.0",
|
||||||
"karma-coverage": "^1.1.1",
|
"karma-coverage": "^1.1.1",
|
||||||
@ -168,20 +166,22 @@
|
|||||||
"karma-sourcemap-loader": "^0.3.7",
|
"karma-sourcemap-loader": "^0.3.7",
|
||||||
"karma-spec-reporter": "^0.0.31",
|
"karma-spec-reporter": "^0.0.31",
|
||||||
"karma-webpack": "^2.0.1",
|
"karma-webpack": "^2.0.1",
|
||||||
|
"mini-css-extract-plugin": "^0.4.0",
|
||||||
"mocha": "^3.0.2",
|
"mocha": "^3.0.2",
|
||||||
"multispinner": "^0.2.1",
|
"multispinner": "^0.2.1",
|
||||||
"node-loader": "^0.6.0",
|
"node-loader": "^0.6.0",
|
||||||
"require-dir": "^0.3.0",
|
"require-dir": "^1.0.0",
|
||||||
"spectron": "^3.7.1",
|
"spectron": "^3.8.0",
|
||||||
"style-loader": "^0.18.2",
|
"style-loader": "^0.21.0",
|
||||||
"url-loader": "^0.5.9",
|
"url-loader": "^1.0.1",
|
||||||
"vue-html-loader": "^1.2.4",
|
"vue-html-loader": "^1.2.4",
|
||||||
"vue-loader": "^14.2.2",
|
"vue-loader": "^15.2.0",
|
||||||
"vue-style-loader": "^3.0.1",
|
"vue-style-loader": "^4.1.0",
|
||||||
"vue-template-compiler": "^2.4.2",
|
"vue-template-compiler": "^2.5.16",
|
||||||
"webpack": "^3.5.2",
|
"webpack": "^4.8.3",
|
||||||
"webpack-dev-server": "^2.7.1",
|
"webpack-cli": "^2.1.4",
|
||||||
"webpack-hot-middleware": "^2.22.0",
|
"webpack-dev-server": "^3.1.4",
|
||||||
"webpack-merge": "^4.1.0"
|
"webpack-hot-middleware": "^2.22.2",
|
||||||
|
"webpack-merge": "^4.1.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,10 @@ import { generateKeyHash, genUpper2LowerKeyHash, getLongUniqueId } from './utils
|
|||||||
import htmlTags from 'html-tags'
|
import htmlTags from 'html-tags'
|
||||||
import voidHtmlTags from 'html-tags/void'
|
import voidHtmlTags from 'html-tags/void'
|
||||||
|
|
||||||
export const UNDO_DEPTH = 100
|
|
||||||
// [0.25, 0.5, 1, 2, 4, 8] <—?—> [256M, 500M/768M, 1G/1000M, 2G, 4G, 8G]
|
// [0.25, 0.5, 1, 2, 4, 8] <—?—> [256M, 500M/768M, 1G/1000M, 2G, 4G, 8G]
|
||||||
export const DEVICE_MEMORY = navigator.deviceMemory // Get the divice memory number
|
// Electron 2.0.2 not support yet! So give a default value 4
|
||||||
|
export const DEVICE_MEMORY = navigator.deviceMemory || 4 // Get the divice memory number(Chrome >= 63)
|
||||||
|
export const UNDO_DEPTH = DEVICE_MEMORY >= 4 ? 100 : 50
|
||||||
export const HAS_TEXT_BLOCK_REG = /^(h\d|span|th|td|hr|pre)/i
|
export const HAS_TEXT_BLOCK_REG = /^(h\d|span|th|td|hr|pre)/i
|
||||||
export const VOID_HTML_TAGS = voidHtmlTags
|
export const VOID_HTML_TAGS = voidHtmlTags
|
||||||
export const HTML_TAGS = htmlTags
|
export const HTML_TAGS = htmlTags
|
||||||
@ -80,6 +81,7 @@ export const CLASS_OR_ID = genUpper2LowerKeyHash([
|
|||||||
'AG_HTML_ESCAPE',
|
'AG_HTML_ESCAPE',
|
||||||
'AG_FRONT_MATTER',
|
'AG_FRONT_MATTER',
|
||||||
'AG_FRONT_MATTER_LINE',
|
'AG_FRONT_MATTER_LINE',
|
||||||
|
'AG_MULTIPLE_MATH_LINE',
|
||||||
'AG_CODEMIRROR_BLOCK',
|
'AG_CODEMIRROR_BLOCK',
|
||||||
'AG_SHOW_PREVIEW',
|
'AG_SHOW_PREVIEW',
|
||||||
'AG_HTML_PREVIEW',
|
'AG_HTML_PREVIEW',
|
||||||
@ -113,7 +115,11 @@ export const CLASS_OR_ID = genUpper2LowerKeyHash([
|
|||||||
'AG_MATH_TEXT',
|
'AG_MATH_TEXT',
|
||||||
'AG_MATH_RENDER',
|
'AG_MATH_RENDER',
|
||||||
'AG_MATH_ERROR',
|
'AG_MATH_ERROR',
|
||||||
|
'AG_MATH_EMPTY',
|
||||||
'AG_MATH_MARKER',
|
'AG_MATH_MARKER',
|
||||||
|
'AG_MATH_PREVIEW',
|
||||||
|
'AG_MULTIPLE_MATH_BLOCK',
|
||||||
|
'AG_MULTIPLE_MATH',
|
||||||
'AG_LOOSE_LIST_ITEM',
|
'AG_LOOSE_LIST_ITEM',
|
||||||
'AG_TIGHT_LIST_ITEM',
|
'AG_TIGHT_LIST_ITEM',
|
||||||
'AG_HTML_TAG',
|
'AG_HTML_TAG',
|
||||||
|
@ -89,7 +89,7 @@ const arrowCtrl = ContentState => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (block.type === 'pre' && block.functionType !== 'frontmatter') {
|
if (block.type === 'pre' && /code|html/.test(block.functionType)) {
|
||||||
// handle cursor in code block. the case at firstline or lastline.
|
// handle cursor in code block. the case at firstline or lastline.
|
||||||
const cm = this.codeBlocks.get(id)
|
const cm = this.codeBlocks.get(id)
|
||||||
const anchorBlock = block.functionType === 'html' ? this.getParent(this.getParent(block)) : block
|
const anchorBlock = block.functionType === 'html' ? this.getParent(this.getParent(block)) : block
|
||||||
@ -205,8 +205,8 @@ const arrowCtrl = ContentState => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(preBlock && preBlock.type === 'pre' && preBlock.functionType !== 'frontmatter' && event.key === EVENT_KEYS.ArrowUp) ||
|
(preBlock && preBlock.type === 'pre' && /code|html/.test(preBlock.functionType) && event.key === EVENT_KEYS.ArrowUp) ||
|
||||||
(preBlock && preBlock.type === 'pre' && preBlock.functionType !== 'frontmatter' && event.key === EVENT_KEYS.ArrowLeft && left === 0)
|
(preBlock && preBlock.type === 'pre' && /code|html/.test(preBlock.functionType) && event.key === EVENT_KEYS.ArrowLeft && left === 0)
|
||||||
) {
|
) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
@ -222,8 +222,8 @@ const arrowCtrl = ContentState => {
|
|||||||
|
|
||||||
return this.partialRender()
|
return this.partialRender()
|
||||||
} else if (
|
} else if (
|
||||||
(nextBlock && nextBlock.type === 'pre' && nextBlock.functionType !== 'frontmatter' && event.key === EVENT_KEYS.ArrowDown) ||
|
(nextBlock && nextBlock.type === 'pre' && /code|html/.test(nextBlock.functionType) && event.key === EVENT_KEYS.ArrowDown) ||
|
||||||
(nextBlock && nextBlock.type === 'pre' && nextBlock.functionType !== 'frontmatter' && event.key === EVENT_KEYS.ArrowRight && right === 0)
|
(nextBlock && nextBlock.type === 'pre' && /code|html/.test(nextBlock.functionType) && event.key === EVENT_KEYS.ArrowRight && right === 0)
|
||||||
) {
|
) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
|
@ -104,6 +104,7 @@ const backspaceCtrl = ContentState => {
|
|||||||
const { start, end } = selection.getCursorRange()
|
const { start, end } = selection.getCursorRange()
|
||||||
const startBlock = this.getBlock(start.key)
|
const startBlock = this.getBlock(start.key)
|
||||||
const endBlock = this.getBlock(end.key)
|
const endBlock = this.getBlock(end.key)
|
||||||
|
|
||||||
// fix: #67 problem 1
|
// fix: #67 problem 1
|
||||||
if (startBlock.icon) return event.preventDefault()
|
if (startBlock.icon) return event.preventDefault()
|
||||||
// fix: unexpect remove all editor html. #67 problem 4
|
// fix: unexpect remove all editor html. #67 problem 4
|
||||||
@ -131,11 +132,11 @@ const backspaceCtrl = ContentState => {
|
|||||||
if (start.key !== end.key) {
|
if (start.key !== end.key) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
const { key, offset } = start
|
const { key, offset } = start
|
||||||
const startRemainText = startBlock.type === 'pre' && startBlock.functionType !== 'frontmatter'
|
const startRemainText = startBlock.type === 'pre' && /code|html/.test(startBlock.functionType)
|
||||||
? startBlock.text.substring(0, offset - 1)
|
? startBlock.text.substring(0, offset - 1)
|
||||||
: startBlock.text.substring(0, offset)
|
: startBlock.text.substring(0, offset)
|
||||||
|
|
||||||
const endRemainText = endBlock.type === 'pre' && endBlock.functionType !== 'frontmatter'
|
const endRemainText = endBlock.type === 'pre' && /code|html/.test(endBlock.functionType)
|
||||||
? endBlock.text.substring(end.offset - 1)
|
? endBlock.text.substring(end.offset - 1)
|
||||||
: endBlock.text.substring(end.offset)
|
: endBlock.text.substring(end.offset)
|
||||||
|
|
||||||
@ -183,7 +184,7 @@ const backspaceCtrl = ContentState => {
|
|||||||
return tHeadHasContent || tBodyHasContent
|
return tHeadHasContent || tBodyHasContent
|
||||||
}
|
}
|
||||||
|
|
||||||
if (block.type === 'pre' && block.functionType !== 'frontmatter') {
|
if (block.type === 'pre' && /code|html/.test(block.functionType)) {
|
||||||
const cm = this.codeBlocks.get(id)
|
const cm = this.codeBlocks.get(id)
|
||||||
// if event.preventDefault(), you can not use backspace in language input.
|
// if event.preventDefault(), you can not use backspace in language input.
|
||||||
if (isCursorAtBegin(cm) && onlyHaveOneLine(cm)) {
|
if (isCursorAtBegin(cm) && onlyHaveOneLine(cm)) {
|
||||||
@ -204,9 +205,10 @@ const backspaceCtrl = ContentState => {
|
|||||||
this.partialRender()
|
this.partialRender()
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
block.type === 'span' && block.functionType === 'frontmatter' &&
|
block.type === 'span' && /frontmatter|multiplemath/.test(block.functionType) &&
|
||||||
left === 0 && !preBlock
|
left === 0 && !block.preSibling
|
||||||
) {
|
) {
|
||||||
|
const isMathLine = block.functionType === 'multiplemath'
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
const { key } = block
|
const { key } = block
|
||||||
@ -216,6 +218,9 @@ const backspaceCtrl = ContentState => {
|
|||||||
delete line.functionType
|
delete line.functionType
|
||||||
this.appendChild(pBlock, line)
|
this.appendChild(pBlock, line)
|
||||||
}
|
}
|
||||||
|
if (isMathLine) {
|
||||||
|
parent = this.getParent(parent)
|
||||||
|
}
|
||||||
this.insertBefore(pBlock, parent)
|
this.insertBefore(pBlock, parent)
|
||||||
this.removeBlock(parent)
|
this.removeBlock(parent)
|
||||||
|
|
||||||
@ -326,7 +331,7 @@ const backspaceCtrl = ContentState => {
|
|||||||
const { text } = block
|
const { text } = block
|
||||||
const key = preBlock.key
|
const key = preBlock.key
|
||||||
const offset = preBlock.text.length
|
const offset = preBlock.text.length
|
||||||
if (preBlock.type === 'pre' && preBlock.functionType !== 'frontmatter') {
|
if (preBlock.type === 'pre' && /code|html/.test(preBlock.functionType)) {
|
||||||
const cm = this.codeBlocks.get(key)
|
const cm = this.codeBlocks.get(key)
|
||||||
const value = cm.getValue() + text
|
const value = cm.getValue() + text
|
||||||
cm.setValue(value)
|
cm.setValue(value)
|
||||||
|
@ -52,7 +52,7 @@ const copyCutCtrl = ContentState => {
|
|||||||
$(
|
$(
|
||||||
`.${CLASS_OR_ID['AG_REMOVE']}, .${CLASS_OR_ID['AG_TOOL_BAR']},
|
`.${CLASS_OR_ID['AG_REMOVE']}, .${CLASS_OR_ID['AG_TOOL_BAR']},
|
||||||
.${CLASS_OR_ID['AG_MATH_RENDER']}, .${CLASS_OR_ID['AG_HTML_PREVIEW']},
|
.${CLASS_OR_ID['AG_MATH_RENDER']}, .${CLASS_OR_ID['AG_HTML_PREVIEW']},
|
||||||
.${CLASS_OR_ID['AG_COPY_REMOVE']}`
|
.${CLASS_OR_ID['AG_MATH_PREVIEW']}, .${CLASS_OR_ID['AG_COPY_REMOVE']}`
|
||||||
).remove()
|
).remove()
|
||||||
$(`.${CLASS_OR_ID['AG_EMOJI_MARKER']}`).text(':')
|
$(`.${CLASS_OR_ID['AG_EMOJI_MARKER']}`).text(':')
|
||||||
$(`.${CLASS_OR_ID['AG_NOTEXT_LINK']}`).empty()
|
$(`.${CLASS_OR_ID['AG_NOTEXT_LINK']}`).empty()
|
||||||
@ -102,6 +102,18 @@ const copyCutCtrl = ContentState => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const mathBlock = $(`figure.ag-multiple-math-block`)
|
||||||
|
if (mathBlock.length > 0) {
|
||||||
|
mathBlock.each((i, hb) => {
|
||||||
|
const ele = $(hb)
|
||||||
|
const id = ele.attr('id')
|
||||||
|
const { math } = this.getBlock(id).children[1]
|
||||||
|
const pre = $('<pre class="multiple-math"></pre>')
|
||||||
|
pre.text(math)
|
||||||
|
ele.replaceWith(pre)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
event.clipboardData.setData('text/html', $('body').html())
|
event.clipboardData.setData('text/html', $('body').html())
|
||||||
event.clipboardData.setData('text/plain', text)
|
event.clipboardData.setData('text/plain', text)
|
||||||
}
|
}
|
||||||
|
@ -150,7 +150,7 @@ const enterCtrl = ContentState => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
// handle cursor in code block
|
// handle cursor in code block
|
||||||
if (block.type === 'pre' && block.functionType !== 'frontmatter') {
|
if (block.type === 'pre' && block.functionType === 'code') {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,15 +197,13 @@ const enterCtrl = ContentState => {
|
|||||||
// only cursor in `line block` can create `soft line break` and `hard line break`
|
// only cursor in `line block` can create `soft line break` and `hard line break`
|
||||||
if (
|
if (
|
||||||
(event.shiftKey && block.type === 'span') ||
|
(event.shiftKey && block.type === 'span') ||
|
||||||
(block.type === 'span' && block.functionType === 'frontmatter')
|
(block.type === 'span' && /frontmatter|multiplemath/.test(block.functionType))
|
||||||
) {
|
) {
|
||||||
const { text } = block
|
const { text } = block
|
||||||
const newLineText = text.substring(start.offset)
|
const newLineText = text.substring(start.offset)
|
||||||
block.text = text.substring(0, start.offset)
|
block.text = text.substring(0, start.offset)
|
||||||
const newLine = this.createBlock('span', newLineText)
|
const newLine = this.createBlock('span', newLineText)
|
||||||
if (block.functionType === 'frontmatter') {
|
newLine.functionType = block.functionType
|
||||||
newLine.functionType = 'frontmatter'
|
|
||||||
}
|
|
||||||
this.insertAfter(newLine, block)
|
this.insertAfter(newLine, block)
|
||||||
const { key } = newLine
|
const { key } = newLine
|
||||||
const offset = 0
|
const offset = 0
|
||||||
@ -374,6 +372,7 @@ const enterCtrl = ContentState => {
|
|||||||
const blockNeedFocus = this.codeBlockUpdate(preParagraphBlock)
|
const blockNeedFocus = this.codeBlockUpdate(preParagraphBlock)
|
||||||
let tableNeedFocus = this.tableBlockUpdate(preParagraphBlock)
|
let tableNeedFocus = this.tableBlockUpdate(preParagraphBlock)
|
||||||
let htmlNeedFocus = this.updateHtmlBlock(preParagraphBlock)
|
let htmlNeedFocus = this.updateHtmlBlock(preParagraphBlock)
|
||||||
|
let mathNeedFocus = this.updateMathBlock(preParagraphBlock)
|
||||||
let cursorBlock
|
let cursorBlock
|
||||||
|
|
||||||
switch (true) {
|
switch (true) {
|
||||||
@ -386,6 +385,9 @@ const enterCtrl = ContentState => {
|
|||||||
case !!htmlNeedFocus:
|
case !!htmlNeedFocus:
|
||||||
cursorBlock = htmlNeedFocus
|
cursorBlock = htmlNeedFocus
|
||||||
break
|
break
|
||||||
|
case !!mathNeedFocus:
|
||||||
|
cursorBlock = mathNeedFocus
|
||||||
|
break
|
||||||
default:
|
default:
|
||||||
cursorBlock = newBlock
|
cursorBlock = newBlock
|
||||||
break
|
break
|
||||||
|
@ -8,8 +8,7 @@ const DOMPurify = createDOMPurify(window)
|
|||||||
|
|
||||||
const htmlBlock = ContentState => {
|
const htmlBlock = ContentState => {
|
||||||
ContentState.prototype.createToolBar = function (tools, toolBarType) {
|
ContentState.prototype.createToolBar = function (tools, toolBarType) {
|
||||||
const toolBar = this.createBlock('div')
|
const toolBar = this.createBlock('div', '', false)
|
||||||
toolBar.editable = false
|
|
||||||
toolBar.toolBarType = toolBarType
|
toolBar.toolBarType = toolBarType
|
||||||
const ul = this.createBlock('ul')
|
const ul = this.createBlock('ul')
|
||||||
|
|
||||||
@ -28,8 +27,7 @@ const htmlBlock = ContentState => {
|
|||||||
ContentState.prototype.createCodeInHtml = function (code, selection) {
|
ContentState.prototype.createCodeInHtml = function (code, selection) {
|
||||||
const codeContainer = this.createBlock('div')
|
const codeContainer = this.createBlock('div')
|
||||||
codeContainer.functionType = 'html'
|
codeContainer.functionType = 'html'
|
||||||
const preview = this.createBlock('div')
|
const preview = this.createBlock('div', '', false)
|
||||||
preview.editable = false
|
|
||||||
preview.htmlContent = DOMPurify.sanitize(escapeInBlockHtml(code), DOMPURIFY_CONFIG)
|
preview.htmlContent = DOMPurify.sanitize(escapeInBlockHtml(code), DOMPURIFY_CONFIG)
|
||||||
preview.functionType = 'preview'
|
preview.functionType = 'preview'
|
||||||
const codePre = this.createBlock('pre')
|
const codePre = this.createBlock('pre')
|
||||||
|
@ -51,7 +51,6 @@ class ContentState {
|
|||||||
this.blocks = [ this.createBlockP() ]
|
this.blocks = [ this.createBlockP() ]
|
||||||
this.stateRender = new StateRender(eventCenter)
|
this.stateRender = new StateRender(eventCenter)
|
||||||
this.codeBlocks = new Map()
|
this.codeBlocks = new Map()
|
||||||
this.loadMathMap = new Map()
|
|
||||||
this.renderRange = [ null, null ]
|
this.renderRange = [ null, null ]
|
||||||
this.currentCursor = null
|
this.currentCursor = null
|
||||||
this.prevCursor = null
|
this.prevCursor = null
|
||||||
@ -122,7 +121,7 @@ class ContentState {
|
|||||||
setCursor () {
|
setCursor () {
|
||||||
const { start: { key } } = this.cursor
|
const { start: { key } } = this.cursor
|
||||||
const block = this.getBlock(key)
|
const block = this.getBlock(key)
|
||||||
if (block.type === 'pre' && block.functionType !== 'frontmatter') {
|
if (block.type === 'pre' && /code|html/.test(block.functionType)) {
|
||||||
const cm = this.codeBlocks.get(key)
|
const cm = this.codeBlocks.get(key)
|
||||||
const { selection } = block
|
const { selection } = block
|
||||||
if (selection) {
|
if (selection) {
|
||||||
@ -156,7 +155,6 @@ class ContentState {
|
|||||||
this.setNextRenderRange()
|
this.setNextRenderRange()
|
||||||
this.stateRender.render(blocks, cursor, activeBlocks, matches)
|
this.stateRender.render(blocks, cursor, activeBlocks, matches)
|
||||||
this.pre2CodeMirror(isRenderCursor)
|
this.pre2CodeMirror(isRenderCursor)
|
||||||
this.renderMath()
|
|
||||||
if (isRenderCursor) this.setCursor()
|
if (isRenderCursor) this.setCursor()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,7 +173,6 @@ class ContentState {
|
|||||||
this.setNextRenderRange()
|
this.setNextRenderRange()
|
||||||
this.stateRender.partialRender(needRenderBlocks, cursor, activeBlocks, matches, startKey, endKey)
|
this.stateRender.partialRender(needRenderBlocks, cursor, activeBlocks, matches, startKey, endKey)
|
||||||
this.pre2CodeMirror(true, [...new Set([cursorOutMostBlock, ...needRenderBlocks])])
|
this.pre2CodeMirror(true, [...new Set([cursorOutMostBlock, ...needRenderBlocks])])
|
||||||
this.renderMath([...new Set([cursorOutMostBlock, ...needRenderBlocks])])
|
|
||||||
this.setCursor()
|
this.setCursor()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,12 +180,13 @@ class ContentState {
|
|||||||
* A block in Aganippe present a paragraph(block syntax in GFM) or a line in paragraph.
|
* A block in Aganippe present a paragraph(block syntax in GFM) or a line in paragraph.
|
||||||
* a line block must in a `p block` or `pre block(frontmatter)` and `p block`'s children must be line blocks.
|
* a line block must in a `p block` or `pre block(frontmatter)` and `p block`'s children must be line blocks.
|
||||||
*/
|
*/
|
||||||
createBlock (type = 'span', text = '') { // span type means it is a line block.
|
createBlock (type = 'span', text = '', editable = true) { // span type means it is a line block.
|
||||||
const key = getUniqueId()
|
const key = getUniqueId()
|
||||||
return {
|
return {
|
||||||
key,
|
key,
|
||||||
type,
|
type,
|
||||||
text,
|
text,
|
||||||
|
editable,
|
||||||
parent: null,
|
parent: null,
|
||||||
preSibling: null,
|
preSibling: null,
|
||||||
nextSibling: null,
|
nextSibling: null,
|
||||||
@ -310,7 +308,7 @@ class ContentState {
|
|||||||
if (children.length) {
|
if (children.length) {
|
||||||
children.forEach(child => this.removeTextOrBlock(child))
|
children.forEach(child => this.removeTextOrBlock(child))
|
||||||
}
|
}
|
||||||
} else {
|
} else if (block.editable) {
|
||||||
this.removeBlock(block)
|
this.removeBlock(block)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -365,8 +363,8 @@ class ContentState {
|
|||||||
if (!afterEnd) {
|
if (!afterEnd) {
|
||||||
const parent = this.getParent(after)
|
const parent = this.getParent(after)
|
||||||
if (parent) {
|
if (parent) {
|
||||||
const isOnlyChild = this.isOnlyChild(after)
|
const removeAfter = isRemoveAfter && this.isOnlyEditableChild(after)
|
||||||
this.removeBlocks(before, parent, isOnlyChild, true)
|
this.removeBlocks(before, parent, removeAfter, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isRemoveAfter) {
|
if (isRemoveAfter) {
|
||||||
@ -505,6 +503,13 @@ class ContentState {
|
|||||||
return !block.nextSibling && !block.preSibling
|
return !block.nextSibling && !block.preSibling
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isOnlyEditableChild (block) {
|
||||||
|
if (block.editable === false) return false
|
||||||
|
const parent = this.getParent(block)
|
||||||
|
if (!parent) throw new Error('isOnlyEditableChild method only apply for child block')
|
||||||
|
return parent.children.filter(child => child.editable).length === 1
|
||||||
|
}
|
||||||
|
|
||||||
getLastChild (block) {
|
getLastChild (block) {
|
||||||
if (block) {
|
if (block) {
|
||||||
const len = block.children.length
|
const len = block.children.length
|
||||||
|
@ -1,40 +1,69 @@
|
|||||||
import katex from 'katex'
|
// import { CLASS_OR_ID } from '../config'
|
||||||
import { CLASS_OR_ID } from '../config'
|
const LINE_BREAKS_REG = /\n/
|
||||||
|
|
||||||
import 'katex/dist/katex.min.css'
|
|
||||||
|
|
||||||
const mathCtrl = ContentState => {
|
const mathCtrl = ContentState => {
|
||||||
ContentState.prototype.renderMath = function (blocks) {
|
ContentState.prototype.createMathBlock = function (value = '') {
|
||||||
let selector = ''
|
const FUNCTION_TYPE = 'multiplemath'
|
||||||
|
const mathBlock = this.createBlock('figure')
|
||||||
if (blocks) {
|
const textArea = this.createBlock('pre')
|
||||||
selector = blocks.map(block => `#${block.key} .${CLASS_OR_ID['AG_MATH_RENDER']}`).join(', ')
|
const mathPreview = this.createBlock('div', '', false)
|
||||||
|
if (typeof value === 'string' && value) {
|
||||||
|
const lines = value.replace(/^\s+/, '').split(LINE_BREAKS_REG).map(line => this.createBlock('span', line))
|
||||||
|
for (const line of lines) {
|
||||||
|
line.functionType = FUNCTION_TYPE
|
||||||
|
this.appendChild(textArea, line)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
selector = `.${CLASS_OR_ID['AG_MATH_RENDER']}`
|
const emptyLine = this.createBlock('span')
|
||||||
|
emptyLine.functionType = FUNCTION_TYPE
|
||||||
|
this.appendChild(textArea, emptyLine)
|
||||||
}
|
}
|
||||||
|
|
||||||
const mathEles = document.querySelectorAll(selector)
|
mathBlock.functionType = textArea.functionType = mathPreview.functionType = FUNCTION_TYPE
|
||||||
const { loadMathMap } = this
|
mathPreview.math = value
|
||||||
for (const math of mathEles) {
|
this.appendChild(mathBlock, textArea)
|
||||||
const content = math.getAttribute('data-math')
|
this.appendChild(mathBlock, mathPreview)
|
||||||
const type = math.getAttribute('data-type')
|
return mathBlock
|
||||||
const displayMode = type === 'display_math'
|
}
|
||||||
const key = `${content}_${type}`
|
|
||||||
if (loadMathMap.has(key)) {
|
ContentState.prototype.initMathBlock = function (block) { // p block
|
||||||
math.innerHTML = loadMathMap.get(key)
|
const FUNCTION_TYPE = 'multiplemath'
|
||||||
continue
|
const textArea = this.createBlock('pre')
|
||||||
}
|
const emptyLine = this.createBlock('span')
|
||||||
try {
|
textArea.functionType = emptyLine.functionType = FUNCTION_TYPE
|
||||||
const html = katex.renderToString(content, {
|
this.appendChild(textArea, emptyLine)
|
||||||
displayMode
|
block.type = 'figure'
|
||||||
})
|
block.functionType = FUNCTION_TYPE
|
||||||
loadMathMap.set(key, html)
|
block.children = []
|
||||||
math.innerHTML = html
|
|
||||||
} catch (err) {
|
const mathPreview = this.createBlock('div', '', false)
|
||||||
math.innerHTML = 'Invalid'
|
mathPreview.math = ''
|
||||||
math.classList.add(CLASS_OR_ID['AG_MATH_ERROR'])
|
mathPreview.functionType = FUNCTION_TYPE
|
||||||
}
|
|
||||||
|
this.appendChild(block, textArea)
|
||||||
|
this.appendChild(block, mathPreview)
|
||||||
|
return emptyLine
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentState.prototype.handleMathBlockClick = function (mathFigure) {
|
||||||
|
const { id } = mathFigure
|
||||||
|
const mathBlock = this.getBlock(id)
|
||||||
|
const textAreaBlock = mathBlock.children[0]
|
||||||
|
const firstLine = textAreaBlock.children[0]
|
||||||
|
const { key } = firstLine
|
||||||
|
const offset = 0
|
||||||
|
this.cursor = {
|
||||||
|
start: { key, offset },
|
||||||
|
end: { key, offset }
|
||||||
}
|
}
|
||||||
|
this.partialRender()
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentState.prototype.updateMathBlock = function (block) {
|
||||||
|
const { type } = block
|
||||||
|
if (type !== 'p') return false
|
||||||
|
const { text } = block.children[0]
|
||||||
|
return text.trim() === '$$' ? this.initMathBlock(block) : false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,6 +318,27 @@ const paragraphCtrl = ContentState => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ContentState.prototype.insertMathBlock = function () {
|
||||||
|
const { start, end } = selection.getCursorRange()
|
||||||
|
if (start.key !== end.key) return
|
||||||
|
let block = this.getBlock(start.key)
|
||||||
|
if (block.type === 'span') {
|
||||||
|
block = this.getParent(block)
|
||||||
|
}
|
||||||
|
const mathBlock = this.createMathBlock()
|
||||||
|
this.insertAfter(mathBlock, block)
|
||||||
|
if (block.type === 'p' && block.children.length === 1 && !block.children[0].text) {
|
||||||
|
this.removeBlock(block)
|
||||||
|
}
|
||||||
|
const cursorBlock = mathBlock.children[0].children[0]
|
||||||
|
const { key } = cursorBlock
|
||||||
|
const offset = 0
|
||||||
|
this.cursor = {
|
||||||
|
start: { key, offset },
|
||||||
|
end: { key, offset }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ContentState.prototype.updateParagraph = function (paraType) {
|
ContentState.prototype.updateParagraph = function (paraType) {
|
||||||
const { start, end } = selection.getCursorRange()
|
const { start, end } = selection.getCursorRange()
|
||||||
const block = this.getBlock(start.key)
|
const block = this.getBlock(start.key)
|
||||||
@ -346,6 +367,10 @@ const paragraphCtrl = ContentState => {
|
|||||||
this.handleQuoteMenu()
|
this.handleQuoteMenu()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
case 'mathblock': {
|
||||||
|
this.insertMathBlock()
|
||||||
|
break
|
||||||
|
}
|
||||||
case 'heading 1':
|
case 'heading 1':
|
||||||
case 'heading 2':
|
case 'heading 2':
|
||||||
case 'heading 3':
|
case 'heading 3':
|
||||||
|
@ -131,10 +131,15 @@ const pasteCtrl = ContentState => {
|
|||||||
throw new Error('unknown paste type')
|
throw new Error('unknown paste type')
|
||||||
}
|
}
|
||||||
// step 3: set cursor and render
|
// step 3: set cursor and render
|
||||||
const cursorBlock = this.getBlock(key)
|
let cursorBlock = this.getBlock(key)
|
||||||
if (!cursorBlock) {
|
if (!cursorBlock) {
|
||||||
key = startBlock.key
|
key = startBlock.key
|
||||||
offset = startBlock.text.length - cacheText.length
|
offset = startBlock.text.length - cacheText.length
|
||||||
|
cursorBlock = startBlock
|
||||||
|
}
|
||||||
|
// TODO @Jocs duplicate with codes in updateCtrl.js
|
||||||
|
if (cursorBlock && cursorBlock.type === 'span' && cursorBlock.functionType === 'multiplemath') {
|
||||||
|
this.updateMathContent(cursorBlock)
|
||||||
}
|
}
|
||||||
this.cursor = {
|
this.cursor = {
|
||||||
start: {
|
start: {
|
||||||
|
@ -284,6 +284,13 @@ const updateCtrl = ContentState => {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ContentState.prototype.updateMathContent = function (block) {
|
||||||
|
const preBlock = this.getParent(block)
|
||||||
|
const mathPreview = this.getNextSibling(preBlock)
|
||||||
|
const math = preBlock.children.map(line => line.text).join('\n')
|
||||||
|
mathPreview.math = math
|
||||||
|
}
|
||||||
|
|
||||||
ContentState.prototype.updateState = function (event) {
|
ContentState.prototype.updateState = function (event) {
|
||||||
const { floatBox } = this
|
const { floatBox } = this
|
||||||
const { start, end } = selection.getCursorRange()
|
const { start, end } = selection.getCursorRange()
|
||||||
@ -314,7 +321,7 @@ const updateCtrl = ContentState => {
|
|||||||
this.removeBlocks(startBlock, endBlock)
|
this.removeBlocks(startBlock, endBlock)
|
||||||
// there still has little bug, when the oldstart block is `pre`, the input value will be ignored.
|
// there still has little bug, when the oldstart block is `pre`, the input value will be ignored.
|
||||||
// and act as `backspace`
|
// and act as `backspace`
|
||||||
if (startBlock.type === 'pre' && startBlock.functionType !== 'frontmatter') {
|
if (startBlock.type === 'pre' && /code|html/.test(startBlock.functionType)) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
const startRemainText = startBlock.type === 'pre'
|
const startRemainText = startBlock.type === 'pre'
|
||||||
? startBlock.text.substring(0, oldStart.offset - 1)
|
? startBlock.text.substring(0, oldStart.offset - 1)
|
||||||
@ -379,7 +386,7 @@ const updateCtrl = ContentState => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (block && block.type === 'pre' && block.functionType !== 'frontmatter') {
|
if (block && block.type === 'pre' && /code|html/.test(block.functionType)) {
|
||||||
if (block.key !== oldKey) {
|
if (block.key !== oldKey) {
|
||||||
this.cursor = lastCursor = { start, end }
|
this.cursor = lastCursor = { start, end }
|
||||||
if (event.type === 'click' && oldKey) {
|
if (event.type === 'click' && oldKey) {
|
||||||
@ -388,6 +395,7 @@ const updateCtrl = ContentState => {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// auto pair
|
// auto pair
|
||||||
if (block && block.text !== text) {
|
if (block && block.text !== text) {
|
||||||
const BRACKET_HASH = {
|
const BRACKET_HASH = {
|
||||||
@ -423,13 +431,16 @@ const updateCtrl = ContentState => {
|
|||||||
block.text = text
|
block.text = text
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (block && block.type === 'span' && block.functionType === 'multiplemath') {
|
||||||
|
this.updateMathContent(block)
|
||||||
|
}
|
||||||
|
|
||||||
if (oldKey !== key || oldStart.offset !== start.offset || oldEnd.offset !== end.offset) {
|
if (oldKey !== key || oldStart.offset !== start.offset || oldEnd.offset !== end.offset) {
|
||||||
needRender = true
|
needRender = true
|
||||||
}
|
}
|
||||||
this.cursor = lastCursor = { start, end }
|
this.cursor = lastCursor = { start, end }
|
||||||
const checkMarkedUpdate = this.checkNeedRender(block)
|
const checkMarkedUpdate = this.checkNeedRender(block)
|
||||||
const inlineUpdatedBlock = this.isCollapse() && block.functionType !== 'frontmatter' && this.checkInlineUpdate(block)
|
const inlineUpdatedBlock = this.isCollapse() && !/frontmatter|multiplemath/.test(block.functionType) && this.checkInlineUpdate(block)
|
||||||
|
|
||||||
if (checkMarkedUpdate || inlineUpdatedBlock || needRender) {
|
if (checkMarkedUpdate || inlineUpdatedBlock || needRender) {
|
||||||
this.partialRender()
|
this.partialRender()
|
||||||
}
|
}
|
||||||
|
@ -10,12 +10,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
h1.ag-active::before,
|
#ag-editor-id > h1.ag-active::before,
|
||||||
h2.ag-active::before,
|
#ag-editor-id > h2.ag-active::before,
|
||||||
h3.ag-active::before,
|
#ag-editor-id > h3.ag-active::before,
|
||||||
h4.ag-active::before,
|
#ag-editor-id > h4.ag-active::before,
|
||||||
h5.ag-active::before,
|
#ag-editor-id > h5.ag-active::before,
|
||||||
h6.ag-active::before {
|
#ag-editor-id > h6.ag-active::before {
|
||||||
content: attr(data-head);
|
content: attr(data-head);
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
@ -25,12 +25,10 @@ h6.ag-active::before {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: -25px;
|
left: -25px;
|
||||||
border: 1px solid #C0C4CC;
|
font-size: 14px;
|
||||||
border-radius: 3px;
|
|
||||||
font-size: 12px;
|
|
||||||
color: #C0C4CC;
|
color: #C0C4CC;
|
||||||
transform: scale(.7);
|
font-weight: 400;
|
||||||
font-weight: 100;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ag-paragraph:empty::after,
|
.ag-paragraph:empty::after,
|
||||||
@ -43,6 +41,10 @@ h6.ag-active::before {
|
|||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ag-gray {
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
|
||||||
/* .ag-soft-line-break::after {
|
/* .ag-soft-line-break::after {
|
||||||
content: '↓';
|
content: '↓';
|
||||||
opacity: .5;
|
opacity: .5;
|
||||||
@ -58,6 +60,7 @@ h6.ag-active::before {
|
|||||||
color: #303133;
|
color: #303133;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
figure pre.ag-multiple-math,
|
||||||
div.ag-function-html pre.ag-html-block {
|
div.ag-function-html pre.ag-html-block {
|
||||||
width: 0;
|
width: 0;
|
||||||
height: 0;
|
height: 0;
|
||||||
@ -67,7 +70,8 @@ div.ag-function-html pre.ag-html-block {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.ag-function-html.ag-active pre.ag-html-block {
|
div.ag-function-html.ag-active pre.ag-html-block,
|
||||||
|
figure.ag-active pre.ag-multiple-math {
|
||||||
position: static;
|
position: static;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: auto;
|
height: auto;
|
||||||
@ -101,37 +105,38 @@ span.ag-html-tag {
|
|||||||
span.ag-math {
|
span.ag-math {
|
||||||
position: relative;
|
position: relative;
|
||||||
color: purple;
|
color: purple;
|
||||||
letter-spacing: 0.1em;
|
font-family: monospace;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: bottom;
|
vertical-align: bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ag-math > .ag-math-render {
|
.ag-math > .ag-math-render {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
background: rgb(79, 79, 79);
|
padding: .5rem;
|
||||||
padding: .3em 1em;
|
background: #fff;
|
||||||
border-radius: 5px;
|
border: 1px solid #ebeef5;
|
||||||
color: #fff;
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .1);
|
||||||
|
color: #333;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 30px;
|
top: 30px;
|
||||||
left: 0;
|
left: 0;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ag-math > .ag-math-error {
|
div.ag-math-empty {
|
||||||
color: rgba(242, 134, 94, .7);
|
color: #999;
|
||||||
|
font-size: 14px;
|
||||||
|
font-style: italic;
|
||||||
|
font-family: monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ag-math > .ag-math-render::before {
|
div.ag-math-error,
|
||||||
content: '';
|
span.ag-math > .ag-math-render.ag-math-error {
|
||||||
width: 10px;
|
color: #e6a23c;
|
||||||
height: 10px;
|
font-size: 14px;
|
||||||
display: inline-block;
|
font-style: italic;
|
||||||
position: absolute;
|
font-family: monospace;
|
||||||
transform: rotate(45deg) translateX(-50%);
|
|
||||||
background: rgb(79, 79, 79);
|
|
||||||
left: 10px;
|
|
||||||
top: -1px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.ag-math > .ag-math-render .katex-display {
|
.ag-math > .ag-math-render .katex-display {
|
||||||
@ -151,9 +156,11 @@ span.ag-math {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.ag-hide.ag-math > .ag-math-render {
|
.ag-hide.ag-math > .ag-math-render {
|
||||||
|
padding: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: 0;
|
border: none;
|
||||||
|
box-shadow: none;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,7 +171,7 @@ span.ag-math {
|
|||||||
figure {
|
figure {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
margin-top: 25px;
|
margin: 1rem 0;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
.ag-tool-bar {
|
.ag-tool-bar {
|
||||||
@ -221,29 +228,18 @@ figure.ag-active .ag-tool-bar {
|
|||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
figure[data-role=HTML] {
|
figure.ag-active[data-role=HTML]::before {
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
figure.ag-active[data-role=HTML]::before,
|
|
||||||
pre.ag-active[data-role=YAML]::before {
|
|
||||||
content: attr(data-role);
|
content: attr(data-role);
|
||||||
width: auto;
|
|
||||||
padding: 0 .3rem;
|
|
||||||
letter-spacing: .1rem;
|
|
||||||
height: 20px;
|
height: 20px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
line-height: 22px;
|
|
||||||
display: block;
|
display: block;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: -45px;
|
left: -45px;
|
||||||
border: 1px solid #C0C4CC;
|
|
||||||
border-radius: 3px;
|
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #C0C4CC;
|
color: #C0C4CC;
|
||||||
transform: scale(.7);
|
font-weight: 400;
|
||||||
font-weight: 300;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
table {
|
table {
|
||||||
@ -340,12 +336,17 @@ p:not(.ag-active)[data-role="hr"] * {
|
|||||||
color: transparent;
|
color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pre.ag-multiple-math,
|
||||||
pre.ag-front-matter {
|
pre.ag-front-matter {
|
||||||
position: relative;
|
position: relative;
|
||||||
background: #f7f7f7;
|
background: #f6f8fa;
|
||||||
padding: 1rem;
|
padding: .5rem;
|
||||||
border: 5px;
|
border: 5px;
|
||||||
font-size: 15px;
|
font-size: 14px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
pre.ag-front-matter {
|
||||||
|
margin: 1rem 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
span.ag-front-matter-line:first-of-type:empty::after {
|
span.ag-front-matter-line:first-of-type:empty::after {
|
||||||
@ -353,6 +354,11 @@ span.ag-front-matter-line:first-of-type:empty::after {
|
|||||||
color: #999;
|
color: #999;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
span.ag-multiple-math-line:first-of-type:empty::after {
|
||||||
|
content: 'Input Mathematical Formula...';
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
figure,
|
figure,
|
||||||
pre.ag-html-block,
|
pre.ag-html-block,
|
||||||
div.ag-function-html,
|
div.ag-function-html,
|
||||||
@ -365,22 +371,70 @@ pre.ag-code-block {
|
|||||||
|
|
||||||
pre.ag-code-block {
|
pre.ag-code-block {
|
||||||
margin: 1rem 0;
|
margin: 1rem 0;
|
||||||
|
padding: 0 .5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre.ag-active.ag-front-matter::before,
|
||||||
|
pre.ag-active.ag-front-matter::after {
|
||||||
|
content: '---';
|
||||||
|
}
|
||||||
|
|
||||||
|
pre.ag-active.ag-multiple-math::before,
|
||||||
|
pre.ag-active.ag-multiple-math::after {
|
||||||
|
content: '$$';
|
||||||
}
|
}
|
||||||
|
|
||||||
pre.ag-active.ag-code-block::before,
|
pre.ag-active.ag-code-block::before,
|
||||||
pre.ag-active.ag-code-block::after {
|
pre.ag-active.ag-code-block::after {
|
||||||
content: '```';
|
content: '```';
|
||||||
|
}
|
||||||
|
|
||||||
|
pre.ag-active.ag-front-matter::before,
|
||||||
|
pre.ag-active.ag-front-matter::after,
|
||||||
|
pre.ag-active.ag-code-block::before,
|
||||||
|
pre.ag-active.ag-code-block::after,
|
||||||
|
pre.ag-active.ag-multiple-math::before,
|
||||||
|
pre.ag-active.ag-multiple-math::after {
|
||||||
color: #909399;
|
color: #909399;
|
||||||
|
font-family: monospace;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pre.ag-active.ag-front-matter::before,
|
||||||
|
pre.ag-active.ag-multiple-math::before,
|
||||||
pre.ag-active.ag-code-block::before {
|
pre.ag-active.ag-code-block::before {
|
||||||
top: -20px;
|
top: -20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pre.ag-active.ag-front-matter::after,
|
||||||
|
pre.ag-active.ag-multiple-math::after,
|
||||||
pre.ag-active.ag-code-block::after {
|
pre.ag-active.ag-code-block::after {
|
||||||
bottom: -25px;
|
bottom: -23px;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.ag-multiple-math-line {
|
||||||
|
color: purple;
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
figure div.ag-math-preview {
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
figure.ag-active div.ag-math-preview {
|
||||||
|
position: absolute;
|
||||||
|
top: calc(100% + 8px);
|
||||||
|
left: 50%;
|
||||||
|
width: auto;
|
||||||
|
z-index: 1;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
padding: .5rem;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #ebeef5;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .1);
|
||||||
}
|
}
|
||||||
|
|
||||||
div.ag-html-preview {
|
div.ag-html-preview {
|
||||||
|
@ -80,6 +80,7 @@ class Aganippe {
|
|||||||
this.dispatchTableToolBar()
|
this.dispatchTableToolBar()
|
||||||
this.dispatchCodeBlockClick()
|
this.dispatchCodeBlockClick()
|
||||||
this.htmlPreviewClick()
|
this.htmlPreviewClick()
|
||||||
|
this.mathPreviewClick()
|
||||||
|
|
||||||
contentState.listenForPathChange()
|
contentState.listenForPathChange()
|
||||||
|
|
||||||
@ -429,6 +430,21 @@ class Aganippe {
|
|||||||
eventCenter.attachDOMEvent(container, 'click', handler)
|
eventCenter.attachDOMEvent(container, 'click', handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mathPreviewClick () {
|
||||||
|
const { eventCenter, container } = this
|
||||||
|
const handler = event => {
|
||||||
|
const target = event.target
|
||||||
|
const mathFigure = isInElement(target, 'ag-multiple-math-block')
|
||||||
|
if (mathFigure && !mathFigure.classList.contains(CLASS_OR_ID['AG_ACTIVE'])) {
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopPropagation()
|
||||||
|
this.contentState.handleMathBlockClick(mathFigure)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eventCenter.attachDOMEvent(container, 'click', handler)
|
||||||
|
}
|
||||||
|
|
||||||
listItemCheckBoxClick () {
|
listItemCheckBoxClick () {
|
||||||
const { container, eventCenter } = this
|
const { container, eventCenter } = this
|
||||||
const handler = event => {
|
const handler = event => {
|
||||||
|
@ -29,7 +29,8 @@ var block = {
|
|||||||
table: noop,
|
table: noop,
|
||||||
paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
|
paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
|
||||||
text: /^[^\n]+/,
|
text: /^[^\n]+/,
|
||||||
frontmatter: /^---\n([\s\S]+?)---(?:\n+|$)/
|
frontmatter: /^---\n([\s\S]+?)---(?:\n+|$)/,
|
||||||
|
multiplemath: /^\$\$\n([\s\S]+?)\n\$\$(?:\n+|$)/
|
||||||
};
|
};
|
||||||
|
|
||||||
block.checkbox = /^\[([ x])\] +/;
|
block.checkbox = /^\[([ x])\] +/;
|
||||||
@ -195,16 +196,25 @@ Lexer.prototype.token = function(src, top, bq) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// multiple line math
|
||||||
|
if (cap = this.rules.multiplemath.exec(src)) {
|
||||||
|
src = src.substring(cap[0].length)
|
||||||
|
this.tokens.push({
|
||||||
|
type: 'multiplemath',
|
||||||
|
text: cap[1]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// fences (gfm)
|
// fences (gfm)
|
||||||
if (cap = this.rules.fences.exec(src)) {
|
if (cap = this.rules.fences.exec(src)) {
|
||||||
src = src.substring(cap[0].length);
|
src = src.substring(cap[0].length)
|
||||||
this.tokens.push({
|
this.tokens.push({
|
||||||
type: 'code',
|
type: 'code',
|
||||||
codeBlockStyle: 'fenced',
|
codeBlockStyle: 'fenced',
|
||||||
lang: cap[2],
|
lang: cap[2],
|
||||||
text: cap[3]
|
text: cap[3]
|
||||||
});
|
})
|
||||||
continue;
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// heading
|
// heading
|
||||||
@ -822,6 +832,10 @@ Renderer.prototype.frontmatter = function (text) {
|
|||||||
return `<pre class="front-matter">\n${text}</pre>\n`
|
return `<pre class="front-matter">\n${text}</pre>\n`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Renderer.prototype.multiplemath = function (text) {
|
||||||
|
return `<pre class="multiple-math">\n${text}</pre>\n`
|
||||||
|
}
|
||||||
|
|
||||||
Renderer.prototype.code = function (code, lang, escaped, codeBlockStyle) {
|
Renderer.prototype.code = function (code, lang, escaped, codeBlockStyle) {
|
||||||
if (this.options.highlight) {
|
if (this.options.highlight) {
|
||||||
var out = this.options.highlight(code, lang);
|
var out = this.options.highlight(code, lang);
|
||||||
@ -1073,13 +1087,17 @@ Parser.prototype.tok = function() {
|
|||||||
return this.renderer.hr()
|
return this.renderer.hr()
|
||||||
}
|
}
|
||||||
case 'heading': {
|
case 'heading': {
|
||||||
return this.renderer.heading(
|
return this.renderer.heading(
|
||||||
this.inline.output(this.token.text),
|
this.inline.output(this.token.text),
|
||||||
this.token.depth,
|
this.token.depth,
|
||||||
this.token.text,
|
this.token.text,
|
||||||
this.token.headingStyle
|
this.token.headingStyle
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
case 'multiplemath': {
|
||||||
|
const { text } = this.token
|
||||||
|
return this.renderer.multiplemath(text)
|
||||||
|
}
|
||||||
case 'code':
|
case 'code':
|
||||||
{
|
{
|
||||||
const { codeBlockStyle, text, lang, escaped } = this.token
|
const { codeBlockStyle, text, lang, escaped } = this.token
|
||||||
|
@ -101,7 +101,7 @@ const tokenizerFac = (src, beginRules, inlineRules, pos = 0, top) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (beginRules && pos === 0) {
|
if (beginRules && pos === 0) {
|
||||||
const beginR = ['header', 'hr', 'code_fense', 'display_math']
|
const beginR = ['header', 'hr', 'code_fense', 'display_math', 'multiple_math']
|
||||||
|
|
||||||
for (const ruleName of beginR) {
|
for (const ruleName of beginR) {
|
||||||
const to = beginRules[ruleName].exec(src)
|
const to = beginRules[ruleName].exec(src)
|
||||||
@ -488,6 +488,7 @@ export const generator = tokens => {
|
|||||||
result += token.escapeCharacter
|
result += token.escapeCharacter
|
||||||
break
|
break
|
||||||
case 'tail_header':
|
case 'tail_header':
|
||||||
|
case 'multiple_math':
|
||||||
result += token.marker
|
result += token.marker
|
||||||
break
|
break
|
||||||
case 'hard_line_break':
|
case 'hard_line_break':
|
||||||
|
@ -9,6 +9,7 @@ class StateRender {
|
|||||||
constructor (eventCenter) {
|
constructor (eventCenter) {
|
||||||
this.eventCenter = eventCenter
|
this.eventCenter = eventCenter
|
||||||
this.loadImageMap = new Map()
|
this.loadImageMap = new Map()
|
||||||
|
this.loadMathMap = new Map()
|
||||||
this.tokenCache = new Map()
|
this.tokenCache = new Map()
|
||||||
this.container = null
|
this.container = null
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,9 @@ export default function renderContainerBlock (block, cursor, activeBlocks, match
|
|||||||
if (block.functionType === 'html') { // HTML Block
|
if (block.functionType === 'html') { // HTML Block
|
||||||
Object.assign(data.dataset, { role: block.functionType.toUpperCase() })
|
Object.assign(data.dataset, { role: block.functionType.toUpperCase() })
|
||||||
}
|
}
|
||||||
|
if (block.functionType === 'multiplemath') {
|
||||||
|
selector += `.${CLASS_OR_ID['AG_MULTIPLE_MATH_BLOCK']}`
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// hanle list block
|
// hanle list block
|
||||||
if (/ul|ol/.test(block.type) && block.listType) {
|
if (/ul|ol/.test(block.type) && block.listType) {
|
||||||
@ -72,9 +75,11 @@ export default function renderContainerBlock (block, cursor, activeBlocks, match
|
|||||||
if (block.type === 'ol') {
|
if (block.type === 'ol') {
|
||||||
Object.assign(data.attrs, { start: block.start })
|
Object.assign(data.attrs, { start: block.start })
|
||||||
}
|
}
|
||||||
if (block.type === 'pre' && block.functionType === 'frontmatter') {
|
if (block.type === 'pre' && /frontmatter|multiplemath/.test(block.functionType)) {
|
||||||
Object.assign(data.dataset, { role: 'YAML' })
|
const role = block.functionType === 'frontmatter' ? 'YAML' : 'MATH'
|
||||||
selector += `.${CLASS_OR_ID['AG_FRONT_MATTER']}`
|
const className = block.functionType === 'frontmatter' ? CLASS_OR_ID['AG_FRONT_MATTER'] : CLASS_OR_ID['AG_MULTIPLE_MATH']
|
||||||
|
Object.assign(data.dataset, { role })
|
||||||
|
selector += `.${className}`
|
||||||
}
|
}
|
||||||
|
|
||||||
return h(selector, data, block.children.map(child => this.renderBlock(child, cursor, activeBlocks, matches, useCache)))
|
return h(selector, data, block.children.map(child => this.renderBlock(child, cursor, activeBlocks, matches, useCache)))
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import katex from 'katex'
|
||||||
import { CLASS_OR_ID, DEVICE_MEMORY } from '../../../config'
|
import { CLASS_OR_ID, DEVICE_MEMORY } from '../../../config'
|
||||||
import { tokenizer } from '../../parse'
|
import { tokenizer } from '../../parse'
|
||||||
import { snakeToCamel } from '../../../utils'
|
import { snakeToCamel } from '../../../utils'
|
||||||
@ -9,13 +10,26 @@ const PRE_BLOCK_HASH = {
|
|||||||
'frontmatter': `.${CLASS_OR_ID['AG_FRONT_MATTER']}`
|
'frontmatter': `.${CLASS_OR_ID['AG_FRONT_MATTER']}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export default function renderLeafBlock (block, cursor, activeBlocks, matches, useCache = false) {
|
export default function renderLeafBlock (block, cursor, activeBlocks, matches, useCache = false) {
|
||||||
|
const { loadMathMap } = this
|
||||||
let selector = this.getSelector(block, cursor, activeBlocks)
|
let selector = this.getSelector(block, cursor, activeBlocks)
|
||||||
// highlight search key in block
|
// highlight search key in block
|
||||||
const highlights = matches.filter(m => m.key === block.key)
|
const highlights = matches.filter(m => m.key === block.key)
|
||||||
const { text, type, headingStyle, align, htmlContent, icon, checked, key, lang, functionType, codeBlockStyle } = block
|
const {
|
||||||
|
text,
|
||||||
|
type,
|
||||||
|
headingStyle,
|
||||||
|
align,
|
||||||
|
htmlContent,
|
||||||
|
icon,
|
||||||
|
checked,
|
||||||
|
key,
|
||||||
|
lang,
|
||||||
|
functionType,
|
||||||
|
codeBlockStyle,
|
||||||
|
math,
|
||||||
|
editable
|
||||||
|
} = block
|
||||||
const data = {
|
const data = {
|
||||||
attrs: {},
|
attrs: {},
|
||||||
dataset: {}
|
dataset: {}
|
||||||
@ -33,16 +47,41 @@ export default function renderLeafBlock (block, cursor, activeBlocks, matches, u
|
|||||||
children = tokens.reduce((acc, token) => [...acc, ...this[snakeToCamel(token.type)](h, cursor, block, token)], [])
|
children = tokens.reduce((acc, token) => [...acc, ...this[snakeToCamel(token.type)](h, cursor, block, token)], [])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (editable === false) {
|
||||||
|
Object.assign(data.attrs, {
|
||||||
|
contenteditable: 'false'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if (/th|td/.test(type) && align) {
|
if (/th|td/.test(type) && align) {
|
||||||
Object.assign(data.attrs, {
|
Object.assign(data.attrs, {
|
||||||
style: `text-align:${align}`
|
style: `text-align:${align}`
|
||||||
})
|
})
|
||||||
} else if (type === 'div' && htmlContent !== undefined) {
|
} else if (type === 'div') {
|
||||||
selector += `.${CLASS_OR_ID['AG_HTML_PREVIEW']}`
|
if (typeof htmlContent === 'string') {
|
||||||
Object.assign(data.attrs, {
|
selector += `.${CLASS_OR_ID['AG_HTML_PREVIEW']}`
|
||||||
contenteditable: 'false'
|
children = htmlToVNode(htmlContent)
|
||||||
})
|
} else if (typeof math === 'string') {
|
||||||
children = htmlToVNode(htmlContent)
|
const key = `${math}_display_math`
|
||||||
|
selector += `.${CLASS_OR_ID['AG_MATH_PREVIEW']}`
|
||||||
|
if (math === '') {
|
||||||
|
children = '< Empty Mathematical Formula >'
|
||||||
|
selector += `.${CLASS_OR_ID['AG_MATH_EMPTY']}`
|
||||||
|
} else if (loadMathMap.has(key)) {
|
||||||
|
children = loadMathMap.get(key)
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
const html = katex.renderToString(math, {
|
||||||
|
displayMode: true
|
||||||
|
})
|
||||||
|
children = htmlToVNode(html)
|
||||||
|
loadMathMap.set(key, children)
|
||||||
|
} catch (err) {
|
||||||
|
children = '< Invalid Mathematical Formula >'
|
||||||
|
selector += `.${CLASS_OR_ID['AG_MATH_ERROR']}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (type === 'svg' && icon) {
|
} else if (type === 'svg' && icon) {
|
||||||
selector += '.icon'
|
selector += '.icon'
|
||||||
Object.assign(data.attrs, {
|
Object.assign(data.attrs, {
|
||||||
@ -98,12 +137,17 @@ export default function renderLeafBlock (block, cursor, activeBlocks, matches, u
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (functionType !== 'frontmatter') {
|
if (/code|html/.test(functionType)) {
|
||||||
// do not set it to '' (empty string)
|
// do not set it to '' (empty string)
|
||||||
children = []
|
children = []
|
||||||
}
|
}
|
||||||
} else if (type === 'span' && functionType === 'frontmatter') {
|
} else if (type === 'span' && /frontmatter|multiplemath/.test(functionType)) {
|
||||||
selector += `.${CLASS_OR_ID['AG_FRONT_MATTER_LINE']}`
|
if (functionType === 'frontmatter') {
|
||||||
|
selector += `.${CLASS_OR_ID['AG_FRONT_MATTER_LINE']}`
|
||||||
|
}
|
||||||
|
if (functionType === 'multiplemath') {
|
||||||
|
selector += `.${CLASS_OR_ID['AG_MULTIPLE_MATH_LINE']}`
|
||||||
|
}
|
||||||
children = text
|
children = text
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
|
import katex from 'katex'
|
||||||
import { CLASS_OR_ID } from '../../../config'
|
import { CLASS_OR_ID } from '../../../config'
|
||||||
|
import { htmlToVNode } from '../snabbdom'
|
||||||
|
|
||||||
|
import 'katex/dist/katex.min.css'
|
||||||
|
|
||||||
export default function displayMath (h, cursor, block, token, outerClass) {
|
export default function displayMath (h, cursor, block, token, outerClass) {
|
||||||
const className = this.getClassName(outerClass, block, token, cursor)
|
const className = this.getClassName(outerClass, block, token, cursor)
|
||||||
@ -11,14 +15,34 @@ export default function displayMath (h, cursor, block, token, outerClass) {
|
|||||||
|
|
||||||
const { content: math, type } = token
|
const { content: math, type } = token
|
||||||
|
|
||||||
|
const { loadMathMap } = this
|
||||||
|
|
||||||
|
const displayMode = type === 'display_math'
|
||||||
|
const key = `${math}_${type}`
|
||||||
|
let mathVnode = null
|
||||||
|
let previewSelector = `span.${CLASS_OR_ID['AG_MATH_RENDER']}`
|
||||||
|
if (loadMathMap.has(key)) {
|
||||||
|
mathVnode = loadMathMap.get(key)
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
const html = katex.renderToString(math, {
|
||||||
|
displayMode
|
||||||
|
})
|
||||||
|
mathVnode = htmlToVNode(html)
|
||||||
|
loadMathMap.set(key, mathVnode)
|
||||||
|
} catch (err) {
|
||||||
|
mathVnode = '< Invalid Mathematical Formula >'
|
||||||
|
previewSelector += `.${CLASS_OR_ID['AG_MATH_ERROR']}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
h(`span.${className}.${CLASS_OR_ID['AG_MATH_MARKER']}`, startMarker),
|
h(`span.${className}.${CLASS_OR_ID['AG_MATH_MARKER']}`, startMarker),
|
||||||
h(`span.${className}.${CLASS_OR_ID['AG_MATH']}`, [
|
h(`span.${className}.${CLASS_OR_ID['AG_MATH']}`, [
|
||||||
h(`span.${CLASS_OR_ID['AG_MATH_TEXT']}`, content),
|
h(`span.${CLASS_OR_ID['AG_MATH_TEXT']}`, content),
|
||||||
h(`span.${CLASS_OR_ID['AG_MATH_RENDER']}`, {
|
h(previewSelector, {
|
||||||
dataset: { math, type },
|
|
||||||
attrs: { contenteditable: 'false' }
|
attrs: { contenteditable: 'false' }
|
||||||
}, 'Loading')
|
}, mathVnode)
|
||||||
]),
|
]),
|
||||||
h(`span.${className}.${CLASS_OR_ID['AG_MATH_MARKER']}`, endMarker)
|
h(`span.${className}.${CLASS_OR_ID['AG_MATH_MARKER']}`, endMarker)
|
||||||
]
|
]
|
||||||
|
@ -23,6 +23,7 @@ import del from './del'
|
|||||||
import em from './em'
|
import em from './em'
|
||||||
import strong from './strong'
|
import strong from './strong'
|
||||||
import htmlEscape from './htmlEscape'
|
import htmlEscape from './htmlEscape'
|
||||||
|
import multipleMath from './multipleMath'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
backlashInToken,
|
backlashInToken,
|
||||||
@ -49,5 +50,6 @@ export default {
|
|||||||
del,
|
del,
|
||||||
em,
|
em,
|
||||||
strong,
|
strong,
|
||||||
htmlEscape
|
htmlEscape,
|
||||||
|
multipleMath
|
||||||
}
|
}
|
||||||
|
9
src/editor/parser/render/renderInlines/multipleMath.js
Normal file
9
src/editor/parser/render/renderInlines/multipleMath.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { CLASS_OR_ID } from '../../../config'
|
||||||
|
|
||||||
|
export default function multipleMath (h, cursor, block, token, outerClass) {
|
||||||
|
const { start, end } = token.range
|
||||||
|
const content = this.highlight(h, block, start, end, token)
|
||||||
|
return [
|
||||||
|
h(`span.${CLASS_OR_ID['AG_GRAY']}.${CLASS_OR_ID['AG_REMOVE']}`, content)
|
||||||
|
]
|
||||||
|
}
|
@ -5,7 +5,8 @@ export const beginRules = {
|
|||||||
'hr': /^(\*{3,}$|^\-{3,}$|^\_{3,}$)/,
|
'hr': /^(\*{3,}$|^\-{3,}$|^\_{3,}$)/,
|
||||||
'code_fense': /^(`{3,})([^`]*)$/,
|
'code_fense': /^(`{3,})([^`]*)$/,
|
||||||
'header': /(^\s{0,3}#{1,6}(\s{1,}|$))/,
|
'header': /(^\s{0,3}#{1,6}(\s{1,}|$))/,
|
||||||
'display_math': /^(\$\$)([^\$]*?[^\$\\])(\\*)\1$/
|
'display_math': /^(\$\$)([^\$]*?[^\$\\])(\\*)\1$/,
|
||||||
|
'multiple_math': /^(\$\$)$/
|
||||||
}
|
}
|
||||||
|
|
||||||
export const inlineRules = {
|
export const inlineRules = {
|
||||||
|
@ -55,6 +55,8 @@ class ExportMarkdown {
|
|||||||
result.push(this.normalizeTable(table, indent))
|
result.push(this.normalizeTable(table, indent))
|
||||||
} else if (block.functionType === 'html') {
|
} else if (block.functionType === 'html') {
|
||||||
result.push(this.normalizeHTML(block, indent))
|
result.push(this.normalizeHTML(block, indent))
|
||||||
|
} else if (block.functionType === 'multiplemath') {
|
||||||
|
result.push(this.normalizeMultipleMath(block, indent))
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
|
||||||
@ -159,6 +161,16 @@ class ExportMarkdown {
|
|||||||
return result.join('')
|
return result.join('')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
normalizeMultipleMath (block, /* figure */ indent) {
|
||||||
|
const result = []
|
||||||
|
result.push('$$\n')
|
||||||
|
for (const line of block.children[0].children) {
|
||||||
|
result.push(`${line.text}\n`)
|
||||||
|
}
|
||||||
|
result.push('$$\n')
|
||||||
|
return result.join('')
|
||||||
|
}
|
||||||
|
|
||||||
normalizeCodeBlock (block, indent) {
|
normalizeCodeBlock (block, indent) {
|
||||||
const result = []
|
const result = []
|
||||||
const textList = block.text.split(LINE_BREAKS)
|
const textList = block.text.split(LINE_BREAKS)
|
||||||
|
@ -65,12 +65,15 @@ const importRegister = ContentState => {
|
|||||||
return { lang, codeBlockStyle }
|
return { lang, codeBlockStyle }
|
||||||
}
|
}
|
||||||
|
|
||||||
const isFrontMatter = node => {
|
const getPreFunctionType = node => {
|
||||||
|
let type = 'code'
|
||||||
const classAttr = node.attrs.filter(attr => attr.name === 'class')[0]
|
const classAttr = node.attrs.filter(attr => attr.name === 'class')[0]
|
||||||
if (classAttr && classAttr.value) {
|
if (classAttr && classAttr.value) {
|
||||||
return /front-matter/.test(classAttr.value)
|
const { value } = classAttr
|
||||||
|
if (/front-matter/.test(value)) type = 'frontmatter'
|
||||||
|
if (/multiple-math/.test(value)) type = 'multiplemath'
|
||||||
}
|
}
|
||||||
return false
|
return type
|
||||||
}
|
}
|
||||||
|
|
||||||
const getRowColumnCount = childNodes => {
|
const getRowColumnCount = childNodes => {
|
||||||
@ -219,17 +222,20 @@ const importRegister = ContentState => {
|
|||||||
break
|
break
|
||||||
|
|
||||||
case 'pre':
|
case 'pre':
|
||||||
const frontMatter = isFrontMatter(child)
|
const functionType = getPreFunctionType(child)
|
||||||
if (frontMatter) {
|
if (functionType === 'frontmatter') {
|
||||||
value = child.childNodes[0].value
|
value = child.childNodes[0].value
|
||||||
block = this.createBlock('pre')
|
block = this.createBlock('pre')
|
||||||
const lines = value.replace(/^\s+/, '').split(LINE_BREAKS_REG).map(line => this.createBlock('span', line))
|
const lines = value.replace(/^\s+/, '').split(LINE_BREAKS_REG).map(line => this.createBlock('span', line))
|
||||||
for (const line of lines) {
|
for (const line of lines) {
|
||||||
line.functionType = 'frontmatter'
|
line.functionType = functionType
|
||||||
this.appendChild(block, line)
|
this.appendChild(block, line)
|
||||||
}
|
}
|
||||||
block.functionType = 'frontmatter'
|
block.functionType = functionType
|
||||||
} else {
|
} else if (functionType === 'multiplemath') {
|
||||||
|
value = child.childNodes[0].value
|
||||||
|
block = this.createMathBlock(value)
|
||||||
|
} else if (functionType === 'code') {
|
||||||
const codeNode = child.childNodes[0]
|
const codeNode = child.childNodes[0]
|
||||||
const { lang, codeBlockStyle } = getLangAndType(codeNode)
|
const { lang, codeBlockStyle } = getLangAndType(codeNode)
|
||||||
value = codeNode.childNodes[0].value
|
value = codeNode.childNodes[0].value
|
||||||
@ -343,19 +349,29 @@ const importRegister = ContentState => {
|
|||||||
// set cursor
|
// set cursor
|
||||||
const travel = blocks => {
|
const travel = blocks => {
|
||||||
for (const block of blocks) {
|
for (const block of blocks) {
|
||||||
const { key, text, children } = block
|
const { key, text, children, editable, type, functionType } = block
|
||||||
if (text) {
|
if (text) {
|
||||||
const offset = text.indexOf(CURSOR_DNA)
|
const offset = text.indexOf(CURSOR_DNA)
|
||||||
if (offset > -1) {
|
if (offset > -1) {
|
||||||
block.text = text.substring(0, offset) + text.substring(offset + CURSOR_DNA.length)
|
block.text = text.substring(0, offset) + text.substring(offset + CURSOR_DNA.length)
|
||||||
this.cursor = {
|
if (editable) {
|
||||||
start: { key, offset },
|
this.cursor = {
|
||||||
end: { key, offset }
|
start: { key, offset },
|
||||||
|
end: { key, offset }
|
||||||
|
}
|
||||||
|
// handle cursor in Math block, need to remove `CURSOR_DNA` in preview block
|
||||||
|
if (type === 'span' && functionType === 'multiplemath') {
|
||||||
|
const mathPreview = this.getNextSibling(this.getParent(block))
|
||||||
|
const { math } = mathPreview
|
||||||
|
const offset = math.indexOf(CURSOR_DNA)
|
||||||
|
if (offset > -1) {
|
||||||
|
mathPreview.math = math.substring(0, offset) + math.substring(offset + CURSOR_DNA.length)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
} else if (children.length) {
|
||||||
if (children.length) {
|
|
||||||
travel(children)
|
travel(children)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,16 @@ export const usePluginAddRules = turndownService => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// handle multiple lines math
|
||||||
|
turndownService.addRule('multiplemath', {
|
||||||
|
filter (node, options) {
|
||||||
|
return node.nodeName === 'PRE' && node.classList.contains('multiple-math')
|
||||||
|
},
|
||||||
|
replacement (content, node, options) {
|
||||||
|
return `$$\n${content}\n$$`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// handle `soft line break` and `hard line break`
|
// handle `soft line break` and `hard line break`
|
||||||
// add `LINE_BREAK` to the end of soft line break and hard line break.
|
// add `LINE_BREAK` to the end of soft line break and hard line break.
|
||||||
turndownService.addRule('lineBreak', {
|
turndownService.addRule('lineBreak', {
|
||||||
|
@ -68,6 +68,14 @@ const setCheckedMenuItem = affiliation => {
|
|||||||
return item.id === 'frontMatterMenuItem'
|
return item.id === 'frontMatterMenuItem'
|
||||||
} else if (b.functionType === 'code') {
|
} else if (b.functionType === 'code') {
|
||||||
return item.id === 'codeFencesMenuItem'
|
return item.id === 'codeFencesMenuItem'
|
||||||
|
} else if (b.functionType === 'html') {
|
||||||
|
return false
|
||||||
|
} else if (b.functionType === 'multiplemath') {
|
||||||
|
return item.id === 'mathBlockMenuItem'
|
||||||
|
}
|
||||||
|
} else if (b.type === 'figure' && b.functionType) {
|
||||||
|
if (b.functionType === 'table') {
|
||||||
|
return item.id === 'tableMenuItem'
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return b.type === MENU_ID_MAP[item.id]
|
return b.type === MENU_ID_MAP[item.id]
|
||||||
@ -90,10 +98,15 @@ ipcMain.on('AGANI::selection-change', (e, { start, end, affiliation }) => {
|
|||||||
setCheckedMenuItem(affiliation)
|
setCheckedMenuItem(affiliation)
|
||||||
// handle disable
|
// handle disable
|
||||||
setParagraphMenuItemStatus(true)
|
setParagraphMenuItemStatus(true)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(/th|td/.test(start.type) && /th|td/.test(end.type)) ||
|
(/th|td/.test(start.type) && /th|td/.test(end.type)) ||
|
||||||
(start.type === 'span' && start.block.functionType === 'frontmatter') ||
|
(start.type === 'span' && start.block.functionType === 'frontmatter') ||
|
||||||
(end.type === 'span' && end.block.functionType === 'frontmatter')
|
(end.type === 'span' && end.block.functionType === 'frontmatter') ||
|
||||||
|
(start.type === 'span' && start.block.functionType === 'multiplemath') ||
|
||||||
|
(end.type === 'span' && end.block.functionType === 'multiplemath') ||
|
||||||
|
(start.type === 'pre' && start.block.functionType === 'html') ||
|
||||||
|
(end.type === 'pre' && end.block.functionType === 'html')
|
||||||
) {
|
) {
|
||||||
setParagraphMenuItemStatus(false)
|
setParagraphMenuItemStatus(false)
|
||||||
} else if (start.key !== end.key) {
|
} else if (start.key !== end.key) {
|
||||||
|
@ -7,9 +7,6 @@
|
|||||||
|
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
|
|
||||||
// Set environment for development
|
|
||||||
process.env.NODE_ENV = 'development'
|
|
||||||
|
|
||||||
// Install `electron-debug` with `devtron`
|
// Install `electron-debug` with `devtron`
|
||||||
require('electron-debug')({ showDevTools: false })
|
require('electron-debug')({ showDevTools: false })
|
||||||
|
|
||||||
|
@ -93,6 +93,14 @@ export default {
|
|||||||
click (menuItem, browserWindow) {
|
click (menuItem, browserWindow) {
|
||||||
actions.paragraph(browserWindow, 'blockquote')
|
actions.paragraph(browserWindow, 'blockquote')
|
||||||
}
|
}
|
||||||
|
}, {
|
||||||
|
id: 'mathBlockMenuItem',
|
||||||
|
label: 'Math Block',
|
||||||
|
type: 'checkbox',
|
||||||
|
accelerator: 'Alt+CmdOrCtrl+M',
|
||||||
|
click (menuItem, browserWindow) {
|
||||||
|
actions.paragraph(browserWindow, 'mathblock')
|
||||||
|
}
|
||||||
}, {
|
}, {
|
||||||
type: 'separator'
|
type: 'separator'
|
||||||
}, {
|
}, {
|
||||||
|
@ -67,9 +67,9 @@
|
|||||||
|
|
||||||
const STANDAR_Y = 320
|
const STANDAR_Y = 320
|
||||||
const PARAGRAPH_CMD = [
|
const PARAGRAPH_CMD = [
|
||||||
'ul-bullet', 'ul-task', 'ol-order', 'pre', 'blockquote', 'heading 1', 'heading 2', 'heading 3',
|
'ul-bullet', 'ul-task', 'ol-order', 'pre', 'blockquote', 'mathblock', 'heading 1', 'heading 2',
|
||||||
'heading 4', 'heading 5', 'heading 6', 'upgrade heading', 'degrade heading', 'paragraph', 'hr',
|
'heading 3', 'heading 4', 'heading 5', 'heading 6', 'upgrade heading', 'degrade heading',
|
||||||
'loose-list-item', 'front-matter'
|
'paragraph', 'hr', 'loose-list-item', 'front-matter'
|
||||||
]
|
]
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -109,8 +109,8 @@ export const adjustCursor = (cursor, preline, line, nextline) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Need to adjust the cursor when cursor in the first or last line of code block.
|
// Need to adjust the cursor when cursor in the first or last line of code/math block.
|
||||||
if (/```[\S]*/.test(line)) {
|
if (/```[\S]*/.test(line) || /^\$\$$/.test(line)) {
|
||||||
if (typeof nextline === 'string' && /\S/.test(nextline)) {
|
if (typeof nextline === 'string' && /\S/.test(nextline)) {
|
||||||
newCursor.line += 1
|
newCursor.line += 1
|
||||||
newCursor.ch = 0
|
newCursor.ch = 0
|
||||||
|
@ -372,10 +372,30 @@ code {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ag-editor-id pre.ag-html-block {
|
#ag-editor-id pre.ag-html-block {
|
||||||
padding: .4rem 1rem;
|
padding: 0 .5rem;
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ag-editor-id pre.ag-front-matter {
|
||||||
|
background: transparent;
|
||||||
|
border-bottom: 1px dashed #efefef;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ag-editor-id pre.ag-multiple-math {
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid #909399;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ag-editor-id span.ag-math-text,
|
||||||
|
#ag-editor-id pre.ag-multiple-math span.ag-multiple-math-line {
|
||||||
|
color: lightsalmon;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ag-editor-id div.ag-math-preview {
|
||||||
|
background: #303133;
|
||||||
|
border-color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
#ag-editor-id pre.ag-code-block,
|
#ag-editor-id pre.ag-code-block,
|
||||||
#ag-editor-id pre.ag-html-block {
|
#ag-editor-id pre.ag-html-block {
|
||||||
font-size: 90%;
|
font-size: 90%;
|
||||||
|
@ -48,7 +48,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.ag-gray {
|
.ag-gray {
|
||||||
color: #E4E7ED;
|
color: #C0C4CC;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -317,12 +317,13 @@ tt {
|
|||||||
|
|
||||||
/* custom add */
|
/* custom add */
|
||||||
code {
|
code {
|
||||||
|
padding: 0.2em 0.4em;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 85%;
|
||||||
|
background-color: rgba(27,31,35,0.05);
|
||||||
|
border-radius: 3px;
|
||||||
border: none;
|
border: none;
|
||||||
padding: 2px 4px;
|
color: #24292e;
|
||||||
font-size: 90%;
|
|
||||||
color: #c7254e;
|
|
||||||
background-color: #f9f2f4;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
|
font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -355,12 +356,12 @@ code {
|
|||||||
|
|
||||||
#ag-editor-id pre.ag-html-block {
|
#ag-editor-id pre.ag-html-block {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
padding: .4rem 1rem;
|
padding: 0 .5rem;
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ag-editor-id pre.ag-active.ag-html-block {
|
#ag-editor-id pre.ag-active.ag-html-block {
|
||||||
background: #F2F6FC;
|
background: #f6f8fa;
|
||||||
}
|
}
|
||||||
|
|
||||||
p:not(.ag-active)[data-role="hr"]::before {
|
p:not(.ag-active)[data-role="hr"]::before {
|
||||||
|
Loading…
Reference in New Issue
Block a user