mirror of
https://github.com/writefreely/writefreely
synced 2024-11-10 11:24:13 +00:00
add prosemirror build environment
This commit is contained in:
parent
172a6dba25
commit
f1f5dbb128
7 changed files with 7260 additions and 0 deletions
8
prose/.babelrc.js
Normal file
8
prose/.babelrc.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
module.exports = {
|
||||
"presets": [
|
||||
["@babel/env", {
|
||||
"modules": false
|
||||
}]
|
||||
],
|
||||
"plugins": ["@babel/plugin-syntax-dynamic-import"]
|
||||
}
|
1147
prose/dist/prose.bundle.js
vendored
Normal file
1147
prose/dist/prose.bundle.js
vendored
Normal file
File diff suppressed because one or more lines are too long
5840
prose/package-lock.json
generated
Normal file
5840
prose/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
29
prose/package.json
Normal file
29
prose/package.json
Normal file
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"name": "prose",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "prose.js",
|
||||
"dependencies": {
|
||||
"babel-core": "^6.26.3",
|
||||
"babel-preset-es2015": "^6.24.1",
|
||||
"prosemirror-example-setup": "^1.1.2",
|
||||
"prosemirror-markdown": "^1.4.4",
|
||||
"prosemirror-model": "^1.9.1",
|
||||
"prosemirror-state": "^1.3.2",
|
||||
"prosemirror-view": "^1.14.2",
|
||||
"webpack": "^4.42.0",
|
||||
"webpack-cli": "^3.3.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.8.7",
|
||||
"@babel/preset-env": "^7.8.7",
|
||||
"babel-loader": "^8.0.6"
|
||||
},
|
||||
"scripts": {
|
||||
"develop": "webpack --mode development --watch",
|
||||
"build": "webpack --mode production"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
10
prose/prose.html
Normal file
10
prose/prose.html
Normal file
|
@ -0,0 +1,10 @@
|
|||
<link rel="stylesheet" href="../static/css/prose.css" />
|
||||
<div id="editor" style="margin-bottom: 0"></div>
|
||||
<!-- <div style="text-align: center"> -->
|
||||
<!-- <label style="border-right: 1px solid silver"> -->
|
||||
<!-- Markdown <input type=radio name=inputformat value=markdown> </label> -->
|
||||
<!-- <label> <input type=radio name=inputformat value=prosemirror checked> WYSIWYM</label> -->
|
||||
<!-- </div> -->
|
||||
|
||||
<div style="display: none"><textarea id="content">This is a comment written in [Markdown](http://commonmark.org). *You* may know the syntax for inserting a link, but does your whole audience? So you can give people the **choice** to use a more familiar, discoverable interface.</textarea></div>
|
||||
<script src="dist/prose.bundle.js"></script>
|
201
prose/prose.js
Normal file
201
prose/prose.js
Normal file
|
@ -0,0 +1,201 @@
|
|||
// class MarkdownView {
|
||||
// constructor(target, content) {
|
||||
// this.textarea = target.appendChild(document.createElement("textarea"))
|
||||
// this.textarea.value = content
|
||||
// }
|
||||
|
||||
// get content() { return this.textarea.value }
|
||||
// focus() { this.textarea.focus() }
|
||||
// destroy() { this.textarea.remove() }
|
||||
// }
|
||||
|
||||
import {Schema} from "prosemirror-model"
|
||||
import {EditorView} from "prosemirror-view"
|
||||
import {EditorState, Plugin} from "prosemirror-state"
|
||||
import {defaultMarkdownParser,
|
||||
defaultMarkdownSerializer} from "prosemirror-markdown"
|
||||
import {exampleSetup} from "prosemirror-example-setup"
|
||||
|
||||
// TODO: maybe don't need to use our own schema but waiting to figure out
|
||||
// line break issues
|
||||
const schema = new Schema({
|
||||
nodes: {
|
||||
doc: {
|
||||
content: "block+"
|
||||
},
|
||||
|
||||
paragraph: {
|
||||
content: "inline*",
|
||||
group: "block",
|
||||
parseDOM: [{tag: "p"}],
|
||||
toDOM() { return ["p", 0] }
|
||||
},
|
||||
|
||||
blockquote: {
|
||||
content: "block+",
|
||||
group: "block",
|
||||
parseDOM: [{tag: "blockquote"}],
|
||||
toDOM() { return ["blockquote", 0] }
|
||||
},
|
||||
|
||||
horizontal_rule: {
|
||||
group: "block",
|
||||
parseDOM: [{tag: "hr"}],
|
||||
toDOM() { return ["div", ["hr"]] }
|
||||
},
|
||||
|
||||
heading: {
|
||||
attrs: {level: {default: 1}},
|
||||
content: "inline*",
|
||||
group: "block",
|
||||
defining: true,
|
||||
parseDOM: [{tag: "h1", attrs: {level: 1}},
|
||||
{tag: "h2", attrs: {level: 2}},
|
||||
{tag: "h3", attrs: {level: 3}},
|
||||
{tag: "h4", attrs: {level: 4}},
|
||||
{tag: "h5", attrs: {level: 5}},
|
||||
{tag: "h6", attrs: {level: 6}}],
|
||||
toDOM(node) { return ["h" + node.attrs.level, 0] }
|
||||
},
|
||||
|
||||
code_block: {
|
||||
content: "text*",
|
||||
group: "block",
|
||||
code: true,
|
||||
defining: true,
|
||||
marks: "",
|
||||
attrs: {params: {default: ""}},
|
||||
parseDOM: [{tag: "pre", preserveWhitespace: "full", getAttrs: node => (
|
||||
{params: node.getAttribute("data-params") || ""}
|
||||
)}],
|
||||
toDOM(node) { return ["pre", node.attrs.params ? {"data-params": node.attrs.params} : {}, ["code", 0]] }
|
||||
},
|
||||
|
||||
ordered_list: {
|
||||
content: "list_item+",
|
||||
group: "block",
|
||||
attrs: {order: {default: 1}, tight: {default: false}},
|
||||
parseDOM: [{tag: "ol", getAttrs(dom) {
|
||||
return {order: dom.hasAttribute("start") ? +dom.getAttribute("start") : 1,
|
||||
tight: dom.hasAttribute("data-tight")}
|
||||
}}],
|
||||
toDOM(node) {
|
||||
return ["ol", {start: node.attrs.order == 1 ? null : node.attrs.order,
|
||||
"data-tight": node.attrs.tight ? "true" : null}, 0]
|
||||
}
|
||||
},
|
||||
|
||||
bullet_list: {
|
||||
content: "list_item+",
|
||||
group: "block",
|
||||
attrs: {tight: {default: false}},
|
||||
parseDOM: [{tag: "ul", getAttrs: dom => ({tight: dom.hasAttribute("data-tight")})}],
|
||||
toDOM(node) { return ["ul", {"data-tight": node.attrs.tight ? "true" : null}, 0] }
|
||||
},
|
||||
|
||||
list_item: {
|
||||
content: "paragraph block*",
|
||||
defining: true,
|
||||
parseDOM: [{tag: "li"}],
|
||||
toDOM() { return ["li", 0] }
|
||||
},
|
||||
|
||||
text: {
|
||||
group: "inline"
|
||||
},
|
||||
|
||||
image: {
|
||||
inline: true,
|
||||
attrs: {
|
||||
src: {},
|
||||
alt: {default: null},
|
||||
title: {default: null}
|
||||
},
|
||||
group: "inline",
|
||||
draggable: true,
|
||||
parseDOM: [{tag: "img[src]", getAttrs(dom) {
|
||||
return {
|
||||
src: dom.getAttribute("src"),
|
||||
title: dom.getAttribute("title"),
|
||||
alt: dom.getAttribute("alt")
|
||||
}
|
||||
}}],
|
||||
toDOM(node) { return ["img", node.attrs] }
|
||||
},
|
||||
|
||||
hard_break: {
|
||||
inline: true,
|
||||
group: "inline",
|
||||
selectable: false,
|
||||
parseDOM: [{tag: "br"}],
|
||||
toDOM() { return ["br"] }
|
||||
}
|
||||
},
|
||||
|
||||
marks: {
|
||||
em: {
|
||||
parseDOM: [{tag: "i"}, {tag: "em"},
|
||||
{style: "font-style", getAttrs: value => value == "italic" && null}],
|
||||
toDOM() { return ["em"] }
|
||||
},
|
||||
|
||||
strong: {
|
||||
parseDOM: [{tag: "b"}, {tag: "strong"},
|
||||
{style: "font-weight", getAttrs: value => /^(bold(er)?|[5-9]\d{2,})$/.test(value) && null}],
|
||||
toDOM() { return ["strong"] }
|
||||
},
|
||||
|
||||
link: {
|
||||
attrs: {
|
||||
href: {},
|
||||
title: {default: null}
|
||||
},
|
||||
inclusive: false,
|
||||
parseDOM: [{tag: "a[href]", getAttrs(dom) {
|
||||
return {href: dom.getAttribute("href"), title: dom.getAttribute("title")}
|
||||
}}],
|
||||
toDOM(node) { return ["a", node.attrs] }
|
||||
},
|
||||
|
||||
code: {
|
||||
parseDOM: [{tag: "code"}],
|
||||
toDOM() { return ["code"] }
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
class ProseMirrorView {
|
||||
constructor(target, content) {
|
||||
this.view = new EditorView(target, {
|
||||
state: EditorState.create({
|
||||
doc: defaultMarkdownParser.parse(content),
|
||||
plugins: exampleSetup({schema})
|
||||
}), dispatchTransaction(transaction) {
|
||||
document.querySelector('#content').innerText = defaultMarkdownSerializer.serialize(transaction.doc)
|
||||
let newState = this.state.apply(transaction)
|
||||
this.updateState(newState)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
get content() {
|
||||
return defaultMarkdownSerializer.serialize(this.view.state.doc)
|
||||
}
|
||||
focus() { this.view.focus() }
|
||||
destroy() { this.view.destroy() }
|
||||
}
|
||||
|
||||
let place = document.querySelector("#editor")
|
||||
let view = new ProseMirrorView(place, document.querySelector('#content').value)
|
||||
|
||||
// document.querySelectorAll("input[type=radio]").forEach(button => {
|
||||
// button.addEventListener("change", () => {
|
||||
// if (!button.checked) return
|
||||
// let View = button.value == "markdown" ? MarkdownView : ProseMirrorView
|
||||
// if (view instanceof View) return
|
||||
// let content = view.content
|
||||
// view.destroy()
|
||||
// view = new View(place, content)
|
||||
// view.focus()
|
||||
// })
|
||||
// })
|
25
prose/webpack.config.js
Normal file
25
prose/webpack.config.js
Normal file
|
@ -0,0 +1,25 @@
|
|||
const path = require('path')
|
||||
|
||||
module.exports = {
|
||||
entry: {
|
||||
entry: __dirname + '/prose.js'
|
||||
},
|
||||
output: {
|
||||
filename: 'prose.bundle.js',
|
||||
path: path.resolve(__dirname, 'dist')
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
exclude: /(nodue_modules|bower_components)/,
|
||||
use: {
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
presets: ['@babel/preset-env']
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue