5
0
Fork 0
mirror of https://0xacab.org/sutty/sutty synced 2024-07-03 13:26:07 +00:00
This commit is contained in:
void 2019-11-20 00:35:58 -03:00
parent 1613589a41
commit 61b429b4f0
5 changed files with 177 additions and 15 deletions

View file

@ -242,18 +242,37 @@ svg {
}
}
.sutty-editor-prosemirror {
.sutty-editor-full {
$border-color: rgba(0, 0, 0, .2);
border-radius: 4px;
border: 1px solid rgba(0, 0, 0, 0.2);
padding: 5px 0;
max-height: 450px;
overflow-y: auto;
border: 1px solid $border-color;
background: var(--background);
.ProseMirror {
padding: 4px 10px;
line-height: 1.2;
outline: none;
word-wrap: break-word;
white-space: pre-wrap;
blockquote {
padding: .75rem 1rem;
border-left: 4px solid var(--color);
p { margin: 0; }
}
.sutty-editor-toolbar {
position: sticky;
top: 0;
padding: .5rem;
border-bottom: 1px solid $border-color;
border-radius: 4px 4px 0 0;
background: var(--background);
}
.sutty-editor-prosemirror {
padding: 5px 0;
max-height: 450px;
overflow-y: auto;
.ProseMirror {
padding: 4px 10px;
line-height: 1.2;
outline: none;
word-wrap: break-word;
white-space: pre-wrap;
}
}
}

View file

@ -18,6 +18,7 @@
import {EditorState} from "prosemirror-state"
import {EditorView} from "prosemirror-view"
import {Schema, DOMParser} from "prosemirror-model"
import {keymap} from "prosemirror-keymap"
// seleccionar cosas que no son texto
import {gapCursor} from "prosemirror-gapcursor"
@ -31,12 +32,76 @@ import {inputRules, wrappingInputRule, textblockTypeInputRule,
import {schema, defaultMarkdownParser,
defaultMarkdownSerializer} from "prosemirror-markdown"
import {toggleMark, setBlockType, wrapIn, baseKeymap} from "prosemirror-commands"
import {toggleWrap, toggleBlockType, toggleList,
updateMark, removeMark} from "tiptap-commands"
import { DirectUpload } from "@rails/activestorage"
const toggleBold = toggleMark(schema.marks.strong)
const toggleItalic = toggleMark(schema.marks.em)
const wrapInQuote = toggleWrap(schema.nodes.blockquote)
const toggleUl = toggleList(schema.nodes.bullet_list, schema.nodes.list_item)
const toggleOl = toggleList(schema.nodes.ordered_list, schema.nodes.list_item)
const generateHeadingToggle = level =>
toggleBlockType(
schema.nodes.heading,
schema.nodes.paragraph,
{ level: level },
)
const toggleH1 = generateHeadingToggle(1)
const toggleH2 = generateHeadingToggle(2)
const makeLink = (state, dispatch) => {
const {tr, selection, doc} = state
const type = schema.marks.link
const {from, to} = selection
const has = doc.rangeHasMark(from, to, type)
if (has) {
tr.removeMark(from, to, type)
} else {
console.log(tr.addMark(from, to, type.create({
href: window.prompt('elegir url', '//sutty.nl')
})))
}
return dispatch(tr)
}
console.log(schema)
class SuttyEditor {
constructor ({element, markdown}) {
constructor ({element, markdown, toolbar}) {
this.state = this.buildState(markdown)
this.view = this.buildView(element, this.state)
this.hooks(toolbar)
}
runCommand (command) {
return command(this.view.state, this.view.dispatch, this.view)
}
hooks (el) {
const setupBtn = (class_, action) => {
const btnEl = el.querySelector('.' + class_ + '-btn')
btnEl.type = 'button'
btnEl.addEventListener('click', e => {
action()
return false
})
}
setupBtn('bold', () => this.runCommand(toggleBold))
setupBtn('italic', () => this.runCommand(toggleItalic))
setupBtn('quote', () => this.runCommand(wrapInQuote))
setupBtn('link', () => this.runCommand(makeLink))
setupBtn('ul', () => this.runCommand(toggleUl))
setupBtn('ol', () => this.runCommand(toggleOl))
setupBtn('h1', () => this.runCommand(toggleH1))
setupBtn('h2', () => this.runCommand(toggleH2))
}
buildState (markdown) {
@ -47,6 +112,7 @@ class SuttyEditor {
} : {}),
plugins: [
gapCursor(),
keymap(baseKeymap),
inputRules({
rules: [
//emDash, // -- => —
@ -75,6 +141,11 @@ document.addEventListener('turbolinks:load', e => {
`.sutty-editor-content[data-sutty-identifier="${el.dataset.suttyIdentifier}"]`
)
// conseguir toolbar
const toolbarEl = document.querySelector(
`.sutty-editor-toolbar[data-sutty-identifier="${el.dataset.suttyIdentifier}"]`
)
// ocultarlo (no se oculta originalmente para usuaries noscript
textareaEl.style.display = 'none'
@ -82,6 +153,7 @@ document.addEventListener('turbolinks:load', e => {
const editor = new SuttyEditor({
element: el,
markdown: textareaEl.value,
toolbar: toolbarEl,
})
// hookear a la form para inyectar el contenido del editor al textarea oculto para que se mande

View file

@ -1,4 +1,15 @@
.sutty-editor.sutty-editor-prosemirror{ 'data-sutty-identifier': identifier }
.sutty-editor-full
.sutty-editor-toolbar{ 'data-sutty-identifier': identifier }
%button.bold-btn= "bold"
%button.italic-btn= "italic"
%button.quote-btn= "quote"
%button.ul-btn= "ul"
%button.ol-btn= "ol"
%button.link-btn= "link"
%button.img-btn= "image"
%button.h1-btn= "h1"
%button.h2-btn= "h2"
.sutty-editor.sutty-editor-prosemirror.content{ 'data-sutty-identifier': identifier }
%textarea.form-control.sutty-editor.sutty-editor-content{ rows: 8,
'data-sutty-identifier': identifier, name: name }
= markdown

View file

@ -6,13 +6,16 @@
"@rails/webpacker": "^4.0.7",
"commonmark": "^0.29.0",
"input-tag": "https://0xacab.org/sutty/input-tag.git",
"table-dragger": "https://0xacab.org/sutty/table-dragger.git",
"prosemirror-commands": "^1.0.8",
"prosemirror-gapcursor": "^1.0.4",
"prosemirror-inputrules": "^1.0.4",
"prosemirror-keymap": "^1.0.2",
"prosemirror-markdown": "^1.3.1",
"prosemirror-model": "^1.7.4",
"prosemirror-state": "^1.2.4",
"prosemirror-view": "^1.11.7",
"table-dragger": "https://0xacab.org/sutty/table-dragger.git",
"tiptap-commands": "^1.12.3",
"zepto": "^1.2.0"
},
"devDependencies": {

View file

@ -5597,6 +5597,15 @@ promise-inflight@^1.0.1:
resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM=
prosemirror-commands@^1.0.8:
version "1.0.8"
resolved "https://registry.yarnpkg.com/prosemirror-commands/-/prosemirror-commands-1.0.8.tgz#3b21e8b2f2e1c04ddb831b2d4055084b6d627bcc"
integrity sha512-P9QdkYYBHWsrJ1JztQuHgeZS7DPCcijQduOj9oxFiqK8Fm6eTsVHzU1IwiRBe+FlK7tyQaerhu/F5K8sqnZ1Cw==
dependencies:
prosemirror-model "^1.0.0"
prosemirror-state "^1.0.0"
prosemirror-transform "^1.0.0"
prosemirror-gapcursor@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/prosemirror-gapcursor/-/prosemirror-gapcursor-1.0.4.tgz#4ba663fb8511616e18ad222c904403cfbf6866dc"
@ -5615,7 +5624,7 @@ prosemirror-inputrules@^1.0.4:
prosemirror-state "^1.0.0"
prosemirror-transform "^1.0.0"
prosemirror-keymap@^1.0.0:
prosemirror-keymap@^1.0.0, prosemirror-keymap@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/prosemirror-keymap/-/prosemirror-keymap-1.0.2.tgz#e4e8b876a586ec6a170615fce19c4450f4075bef"
integrity sha512-aq3fBT3WMbwGNacUtMbS/mxd87hjJyjtUx5/h3q/P3FiVqHxmeA9snxQsZHYe0cWRziZePun8zw6kHFKLp/DAQ==
@ -5638,6 +5647,14 @@ prosemirror-model@^1.0.0, prosemirror-model@^1.1.0, prosemirror-model@^1.7.4:
dependencies:
orderedmap "^1.0.0"
prosemirror-schema-list@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/prosemirror-schema-list/-/prosemirror-schema-list-1.0.4.tgz#cbb11936e306aa45586af4279529ce61b52cfb6e"
integrity sha512-7Y0b6FIG6ATnCcDSLrZfU9yIfOG5Yad3DMNZ9W7GGfMSzdIl0aHExrsIUgviJZjovO2jtLJVbxWGjMR3OrTupA==
dependencies:
prosemirror-model "^1.0.0"
prosemirror-transform "^1.0.0"
prosemirror-state@^1.0.0, prosemirror-state@^1.2.4:
version "1.2.4"
resolved "https://registry.yarnpkg.com/prosemirror-state/-/prosemirror-state-1.2.4.tgz#aab932ebb33a0f27c256abce6fc20da8ca77ad5e"
@ -5646,6 +5663,17 @@ prosemirror-state@^1.0.0, prosemirror-state@^1.2.4:
prosemirror-model "^1.0.0"
prosemirror-transform "^1.0.0"
prosemirror-tables@^0.9.5:
version "0.9.5"
resolved "https://registry.yarnpkg.com/prosemirror-tables/-/prosemirror-tables-0.9.5.tgz#94d9881a46051e6fff3c51edffafa346da084def"
integrity sha512-RlAF/D7OvnDCOL8B6Qt6KuBkb0w3SedTdrou7wH7Nn2ml7+M5xUalW/h1f7dMD3wjsU47/Cn8zTbEkCDIpIggw==
dependencies:
prosemirror-keymap "^1.0.0"
prosemirror-model "^1.0.0"
prosemirror-state "^1.0.0"
prosemirror-transform "^1.0.0"
prosemirror-view "^1.0.0"
prosemirror-transform@^1.0.0, prosemirror-transform@^1.1.0:
version "1.1.5"
resolved "https://registry.yarnpkg.com/prosemirror-transform/-/prosemirror-transform-1.1.5.tgz#e50113d8004854eca1fa0711806bca53b1f1fad9"
@ -5653,6 +5681,11 @@ prosemirror-transform@^1.0.0, prosemirror-transform@^1.1.0:
dependencies:
prosemirror-model "^1.0.0"
prosemirror-utils@^0.9.6:
version "0.9.6"
resolved "https://registry.yarnpkg.com/prosemirror-utils/-/prosemirror-utils-0.9.6.tgz#3d97bd85897e3b535555867dc95a51399116a973"
integrity sha512-UC+j9hQQ1POYfMc5p7UFxBTptRiGPR7Kkmbl3jVvU8VgQbkI89tR/GK+3QYC8n+VvBZrtAoCrJItNhWSxX3slA==
prosemirror-view@^1.0.0, prosemirror-view@^1.11.7:
version "1.11.7"
resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.11.7.tgz#537020acab43e18d51e18717fb1f39466317ce21"
@ -6795,6 +6828,30 @@ timsort@^0.3.0:
resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4"
integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=
tiptap-commands@^1.12.3:
version "1.12.3"
resolved "https://registry.yarnpkg.com/tiptap-commands/-/tiptap-commands-1.12.3.tgz#604767878073e6344d1daf7a376fd89fc62e4742"
integrity sha512-Dck51lePBwuHmkvkJ6+8V3DbInxAhZwtS2mPvVwz74pDUIcy17tCFw1eHUN50JoXIAci7acuxPKO/weVO1JAyw==
dependencies:
prosemirror-commands "^1.0.8"
prosemirror-inputrules "^1.0.4"
prosemirror-model "^1.7.4"
prosemirror-schema-list "^1.0.4"
prosemirror-state "^1.2.4"
prosemirror-tables "^0.9.5"
prosemirror-utils "^0.9.6"
tiptap-utils "^1.8.2"
tiptap-utils@^1.8.2:
version "1.8.2"
resolved "https://registry.yarnpkg.com/tiptap-utils/-/tiptap-utils-1.8.2.tgz#f07a2053c6ac9fbbb4f02e0844b326d0e6c8b7fb"
integrity sha512-pyx+3p4fICGM7JU1mcsnRx5jXvLrCL8Nm/9yjeWEZXpAC85L/btY0eFo2Oz4+dKg39+1EGNHheodujx3ngw4lQ==
dependencies:
prosemirror-model "^1.7.4"
prosemirror-state "^1.2.4"
prosemirror-tables "^0.9.5"
prosemirror-utils "^0.9.6"
to-arraybuffer@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"