Add custom classes select control to blocks menu
gitea/godo.js/pipeline/head There was a failure building this commit Details

This commit is contained in:
Corentin Sechet 2023-06-13 17:23:04 +02:00
parent b8f8eb2a08
commit 7874ebb0bc
5 changed files with 3700 additions and 2061 deletions

22
dist/index.html vendored
View File

@ -22,6 +22,20 @@
max-width: 60em;
margin: 0 auto;
}
.red {
padding: 1rem;
border: 1px solid red;
border-radius: 10px;
background: #FFCCCB;
}
.green {
padding: 1rem;
border: 1px solid green;
border-radius: 10px;
background: #90EE90;
}
</style>
</head>
@ -60,10 +74,14 @@
<h2>Full Godo</h2>
<p>p, h1 -&gt; h3, strong, em, ul</p>
<form action="">
<textarea class="textarea-for-godo-2" data-godo-schema="full">
<textarea
class="textarea-for-godo-2"
data-godo-schema="full"
data-godo-custom-classes='{"red": { "allowOn": "paragraph", "label": "Erreur"}, "green": { "allowOn": "paragraph", "label": "Info" } }'
>
<h1>titre</h1>
<h2>Sous-titre</h2>
<p>Paragraphe.</p>
<p>Paragraphe. <a href="http://sacripant.fr" class="pk-button">My website</a></p>
<ul>
<li>First Item</li>
<li>Second Item</li>

5639
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -18,8 +18,10 @@ export default {
},
],
plugins: [nodeResolve(), buble({
objectAssign: 'Object.assign',
transforms: {
forOf: false,
generator: false,
},
})],
}

View File

@ -1,15 +1,93 @@
import {DOMSerializer} from 'prosemirror-model'
export default (options) => ({
patchSchema (schemaSpec) {
addCustomClassesSupport(options, schemaSpec.nodes)
addCustomClassesSupport(options, schemaSpec.marks)
},
})
export default (options) => {
const customClasses = JSON.parse(options.customClasses || '{}')
function addCustomClassesSupport (options, specs) {
const customClasses = options.customClasses || {}
return {
patchSchema (schemaSpec) {
addCustomClassesSupport(customClasses, schemaSpec.nodes)
addCustomClassesSupport(customClasses, schemaSpec.marks)
},
blocksMenu () {
return {
selectClass: customClassMenu(customClasses),
}
},
}
}
function customClassMenu (customClasses) {
function filterAllowedClasses (classes, nodeOrMark) {
const result = []
for (const className of classes) {
const classSettings = customClasses[className]
const allowOn = classSettings['allowOn'] || []
if (allowOn.includes(nodeOrMark.type.name)) {
result.push(className)
}
}
return result
}
return function (view) {
let classSelect = document.createElement('select')
classSelect.addEventListener('change', e => {
e.preventDefault()
const cursor = view.state.selection.$cursor
const currentNode = cursor.parent
let selectedClasses = []
// First option is default style
if (classSelect.selectedIndex !== 0) {
selectedClasses = Array.from(classSelect.selectedOptions)
.map(option => option.value)
.filter(className => className !== undefined)
}
const newClasses = filterAllowedClasses(selectedClasses, currentNode)
const newAttrs = {...currentNode.attrs, classes: newClasses}
view.dispatch(
view.state.tr.setNodeMarkup(cursor.pos - cursor.parentOffset - 1, null, newAttrs, currentNode.marks),
)
})
return {
dom: classSelect,
update () {
classSelect.innerHTML = ''
classSelect.style.display = 'none'
const cursor = view.state.selection.$cursor
if (!cursor) {
return
}
const currentNode = cursor.parent
const currentNodeClasses = currentNode.attrs.classes || []
const defaultOption = document.createElement('option')
defaultOption.value = 0
defaultOption.text = 'Defaut'
defaultOption.selected = currentNodeClasses.length === 0
classSelect.add(defaultOption)
for (const className of filterAllowedClasses(Object.keys(customClasses), currentNode)) {
const classSettings = customClasses[className]
classSelect.style.display = null
const option = document.createElement('option')
option.value = className
option.text = classSettings['label'] || className
option.selected = currentNodeClasses.includes(className)
classSelect.add(option)
}
},
}
}
}
function addCustomClassesSupport (customClasses, specs) {
for (const specName in specs) {
const allowedClasses = Object.keys(customClasses).filter(className => {
const classSettings = customClasses[className]

View File

@ -13,6 +13,7 @@ import fontMarks from './components/font-marks.mjs'
import heading from './components/heading.mjs'
import link from './components/link.mjs'
import list from './components/list.mjs'
import customClasses from './components/custom-classes.mjs'
function menuPlugin (menu) {
return new Plugin({
@ -55,7 +56,7 @@ export default class Godo {
this.options = Object.assign(this.defaultOptions, options)
const componentsDefinitions = [base, fontMarks, link]
const componentsDefinitions = [base, fontMarks, link, customClasses]
if (this.options.schema === 'full') {
componentsDefinitions.push(heading, list)
}
@ -129,6 +130,7 @@ document.addEventListener('DOMContentLoaded', function () {
if (textarea.dataset.godoHeadingLevels) {
options.headingLevels = textarea.dataset.godoHeadingLevels
}
options.customClasses = textarea.dataset.godoCustomClasses
new Godo(textarea, options) // eslint-disable-line no-new
})
})