I’ve been tinkering with creating some Writer Marks that require a dialog to add attributes to the resulting HTML. I’ve got as far as successfully defining the attributes, opening a custom dialog to enter values for each of the attributes but am stuck on actually getting them to save back to the Writer field itself.
Hoping someone might be able to point me in the right direction (or correct anything I’ve just flat out done wrong) because I’ve had no luck digging through the documentation and anything else that might be helpful.
Here’s a quick breakdown of the plugin code as it stands:
index.php
<?php
use Kirby\Cms\App as Kirby;
Kirby::plugin('scottboms/writer-span', [
'name' => 'Span',
'author' => 'Scott Boms',
'version' => '1.0.0',
'options' => [
// Define any plugin options here if needed
],
'translations' => [
'en' => [
'writer.spanAttribute' => 'Add span with attributes',
]
]
]);
src/index.js
import SpanDialog from "./components/SpanDialog.vue";
// Register the main plugin
window.panel.plugin("scottboms/writer-span", {
components: {
"writer-span-dialog": SpanDialog,
},
writerMarks: {
span: {
get button() {
return {
icon: 'code',
label: 'Add Span'
}
},
commands() {
return {
span: () => {
console.log("Opening dialog with component: writer-span-dialog");
window.panel.dialog.open({
component: "writer-span-dialog",
props: {
editor: this.editor,
value: {
// default values that appear automatically
// if any text is entered here
class: "",
title: ""
}
}
});
}
};
},
insertSpan: (attrs = {}) => {
console.log('insertSpan called with attrs:', attrs);
const { selection } = this.editor.state;
// Check if the selection is empty and the span mark is not active
if (
selection.empty &&
this.editor.activeMarks.includes("span") === false
) {
console.log('Inserting text:', attrs.class);
this.editor.insertText(attrs.class, true);
}
// Apply the attributes if class or title is present
if (attrs.class || attrs.title) {
console.log('Applying span mark with attrs:', attrs);
return this.editor.chain().focus().toggleMark('span', attrs).run();
} else {
console.log('No attributes to apply');
}
},
removeSpan: () => {
console.log('removeSpan called');
return this.editor.chain().focus().unsetMark('span').run();
},
toggleSpan: (attrs = {}) => {
if (attrs.class?.length > 0) {
this.editor.command("insertSpan", attrs);
} else {
this.editor.command("removeSpan");
}
},
get defaults() {
console.log('defaults');
return {
class: null,
title: null
}
},
get name() {
return 'span';
},
get schema() {
return {
parseDOM: [{
tag: 'span',
getAttrs: (dom) => ({
class: dom.getAttribute('class'),
title: dom.getAttribute('title')
})
}],
toDOM: (node) => {
return ['span', {
class: node.attrs.class || null,
title: node.attrs.title || null
}, 0];
}
}
},
plugins() {
return [
{
props: {
handleClick: (view, pos, event) => {
const attrs = this.editor.getMarkAttrs("span");
if(
attrs.class &&
attrs.title
) {
event.stopPropagation();
window.open(attrs.class, attrs.title);
}
}
}
}
];
}
}
}
});
src/components/SpanDialog.vue
<template>
<k-dialog
class="writer-span-dialog"
ref="dialog"
:visible="true"
:submit-button="true"
:cancel-button="true"
size="medium"
@submit="submit"
@cancel="$emit('cancel')">
<k-form
:fields="fields"
v-bind="$props"
:value="values"
@input="handleInput"
@cancel="$emit('cancel')"
@submit="submit" />
</k-dialog>
</template>
<script>
console.log('span dialog loaded...');
export default {
name: "writer-span-dialog",
props: {
editor: {
type: Object,
required: true
},
value: {
type: Object,
default: () => ({
class: "",
title: ""
})
}
},
data() {
return {
values: this.value,
fields: {
class: {
label: "Class",
type: "text",
placeholder: "Enter one or more CSS classes"
},
title: {
label: "Title",
type: "text",
placeholder: "Enter a title"
}
}
};
},
methods: {
openDialog() {
if (this.$refs.dialog) {
this.$refs.dialog.showDialog();
}
},
closeDialog() {
if (this.$refs.dialog) {
this.$refs.dialog.close();
}
},
mounted() {
this.openDialog();
},
handleInput(values) {
console.log('Form input values:', values);
this.values = values;
this.$emit('input', values);
},
submit() {
console.log('Submit button clicked with values:', this.values);
if (this.values.class || this.values.title) {
console.log('Submitting values:', this.values);
this.editor.command("insertSpan", {
class: this.values.class || null,
title: this.values.title || null
});
}
this.closeDialog();
},
}
};
</script>