mirror of
https://0xacab.org/sutty/sutty
synced 2024-11-17 05:46:23 +00:00
toolbar
This commit is contained in:
parent
1613589a41
commit
61b429b4f0
5 changed files with 177 additions and 15 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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": {
|
||||
|
|
59
yarn.lock
59
yarn.lock
|
@ -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"
|
||||
|
|
Loading…
Reference in a new issue