Image Node settings dialog fields
parent
8da183514e
commit
d4cb8bb5bb
|
|
@ -678,7 +678,7 @@
|
||||||
id="librecms-image-node-view-settings-dialog-"
|
id="librecms-image-node-view-settings-dialog-"
|
||||||
tabindex="-1">
|
tabindex="-1">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content">
|
<form action="#" class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h3 class="modal-title"
|
<h3 class="modal-title"
|
||||||
id="librecms-image-node-view-settings-dialog-title-">
|
id="librecms-image-node-view-settings-dialog-title-">
|
||||||
|
|
@ -692,7 +692,52 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
Image Node View Settings Dialog
|
<div class="form-group">
|
||||||
|
<label for="alttext">#{CmsAdminMessages['cms_editor.image_node_view.settings.dialog.alttext.label']}</label>
|
||||||
|
<input aria-describedby="alttext-help"
|
||||||
|
class="form-control"
|
||||||
|
id="alttext"
|
||||||
|
required="true"
|
||||||
|
type="text" />
|
||||||
|
<small class="form-text text-muted"
|
||||||
|
id="alttext-help">#{CmsAdminMessages['cms_editor.image_node_view.settings.dialog.alttext.help']}</small>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="size">#{CmsAdminMessages['cms_editor.image_node_view.settings.dialog.size.label']}</label>
|
||||||
|
<select aria-describedby="size-help"
|
||||||
|
class="custom-select"
|
||||||
|
id="size">
|
||||||
|
<option value="25">25%</option>
|
||||||
|
<option value="33">33%</option>
|
||||||
|
<option value="50">50%</option>
|
||||||
|
<option value="66">66%</option>
|
||||||
|
<option value="75">75%</option>
|
||||||
|
<option value="100">100%</option>
|
||||||
|
</select>
|
||||||
|
<small class="form-text text-muted"
|
||||||
|
id="size-help">#{CmsAdminMessages['cms_editor.image_node_view.settings.dialog.size.help']}</small>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="align">#{CmsAdminMessages['cms_editor.image_node_view.settings.dialog.align.label']}</label>
|
||||||
|
<select aria-describedby="align-help"
|
||||||
|
class="custom-select"
|
||||||
|
id="align">
|
||||||
|
<option value="floatleft">#{CmsAdminMessages['cms_editor.image_node_view.settings.dialog.align.floatleft']}</option>
|
||||||
|
<option value="center">#{CmsAdminMessages['cms_editor.image_node_view.settings.dialog.align.center']}</option>
|
||||||
|
<option value="floatright">#{CmsAdminMessages['cms_editor.image_node_view.settings.dialog.align.floatright']}</option>
|
||||||
|
</select>
|
||||||
|
<small class="form-text text-muted"
|
||||||
|
id="align-help">#{CmsAdminMessages['cms_editor.image_node_view.settings.dialog.align.help']}</small>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<input aria-describedby="fullsizeoverlay-help"
|
||||||
|
class="form-check-input"
|
||||||
|
id="fullsizeoverlay"
|
||||||
|
type="checkbox" />
|
||||||
|
<label for="fullsizeoverlay">#{CmsAdminMessages['cms_editor.image_node_view.settings.dialog.fullsizeoverlay.label']}</label>
|
||||||
|
<small class="form-text text-muted"
|
||||||
|
id="fullsizeoverlay-help">#{CmsAdminMessages['cms_editor.image_node_view.settings.dialog.fullsizeoverlay.help']}</small>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button class="btn btn-warning"
|
<button class="btn btn-warning"
|
||||||
|
|
@ -700,13 +745,13 @@
|
||||||
type="button">
|
type="button">
|
||||||
#{CmsAdminMessages['cms_editor.image_node_view.settings.dialog.close']}
|
#{CmsAdminMessages['cms_editor.image_node_view.settings.dialog.close']}
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-primary"
|
<button class="btn btn-primary image-settings-dialog-save"
|
||||||
data-dismiss="modal"
|
data-dismiss="modal"
|
||||||
type="button">
|
type="button">
|
||||||
#{CmsAdminMessages['cms_editor.image_node_view.settings.dialog.save']}
|
#{CmsAdminMessages['cms_editor.image_node_view.settings.dialog.save']}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ import TableRow from "@tiptap/extension-table-row";
|
||||||
import TableCell from "@tiptap/extension-table-cell";
|
import TableCell from "@tiptap/extension-table-cell";
|
||||||
import TableHeader from "@tiptap/extension-table-header";
|
import TableHeader from "@tiptap/extension-table-header";
|
||||||
|
|
||||||
|
import ImageNode from "./cms-editor/image-node";
|
||||||
|
|
||||||
const BUTTONS: CmsEditorButton[] = [
|
const BUTTONS: CmsEditorButton[] = [
|
||||||
{
|
{
|
||||||
selector: ".tiptap-emph",
|
selector: ".tiptap-emph",
|
||||||
|
|
@ -17,7 +19,13 @@ const BUTTONS: CmsEditorButton[] = [
|
||||||
return cmsEditor.getEditor().chain().focus().toggleItalic().run();
|
return cmsEditor.getEditor().chain().focus().toggleItalic().run();
|
||||||
},
|
},
|
||||||
can: (cmsEditor) => {
|
can: (cmsEditor) => {
|
||||||
return cmsEditor.getEditor().can().chain().focus().toggleItalic().run();
|
return cmsEditor
|
||||||
|
.getEditor()
|
||||||
|
.can()
|
||||||
|
.chain()
|
||||||
|
.focus()
|
||||||
|
.toggleItalic()
|
||||||
|
.run();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -26,7 +34,13 @@ const BUTTONS: CmsEditorButton[] = [
|
||||||
return cmsEditor.getEditor().chain().focus().toggleBold().run();
|
return cmsEditor.getEditor().chain().focus().toggleBold().run();
|
||||||
},
|
},
|
||||||
can: (cmsEditor) => {
|
can: (cmsEditor) => {
|
||||||
return cmsEditor.getEditor().can().chain().focus().toggleBold().run();
|
return cmsEditor
|
||||||
|
.getEditor()
|
||||||
|
.can()
|
||||||
|
.chain()
|
||||||
|
.focus()
|
||||||
|
.toggleBold()
|
||||||
|
.run();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -35,7 +49,13 @@ const BUTTONS: CmsEditorButton[] = [
|
||||||
return cmsEditor.getEditor().chain().focus().toggleCode().run();
|
return cmsEditor.getEditor().chain().focus().toggleCode().run();
|
||||||
},
|
},
|
||||||
can: (cmsEditor) => {
|
can: (cmsEditor) => {
|
||||||
return cmsEditor.getEditor().can().chain().focus().toggleCode().run();
|
return cmsEditor
|
||||||
|
.getEditor()
|
||||||
|
.can()
|
||||||
|
.chain()
|
||||||
|
.focus()
|
||||||
|
.toggleCode()
|
||||||
|
.run();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -44,13 +64,24 @@ const BUTTONS: CmsEditorButton[] = [
|
||||||
return cmsEditor.getEditor().chain().focus().toggleStrike().run();
|
return cmsEditor.getEditor().chain().focus().toggleStrike().run();
|
||||||
},
|
},
|
||||||
can: (cmsEditor) => {
|
can: (cmsEditor) => {
|
||||||
return cmsEditor.getEditor().can().chain().focus().toggleStrike().run();
|
return cmsEditor
|
||||||
|
.getEditor()
|
||||||
|
.can()
|
||||||
|
.chain()
|
||||||
|
.focus()
|
||||||
|
.toggleStrike()
|
||||||
|
.run();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: ".tiptap-subscript",
|
selector: ".tiptap-subscript",
|
||||||
command: (cmsEditor) => {
|
command: (cmsEditor) => {
|
||||||
return cmsEditor.getEditor().chain().focus().toggleSubscript().run();
|
return cmsEditor
|
||||||
|
.getEditor()
|
||||||
|
.chain()
|
||||||
|
.focus()
|
||||||
|
.toggleSubscript()
|
||||||
|
.run();
|
||||||
},
|
},
|
||||||
can: (cmsEditor) => {
|
can: (cmsEditor) => {
|
||||||
return cmsEditor
|
return cmsEditor
|
||||||
|
|
@ -65,7 +96,12 @@ const BUTTONS: CmsEditorButton[] = [
|
||||||
{
|
{
|
||||||
selector: ".tiptap-superscript",
|
selector: ".tiptap-superscript",
|
||||||
command: (cmsEditor) => {
|
command: (cmsEditor) => {
|
||||||
return cmsEditor.getEditor().chain().focus().toggleSuperscript().run();
|
return cmsEditor
|
||||||
|
.getEditor()
|
||||||
|
.chain()
|
||||||
|
.focus()
|
||||||
|
.toggleSuperscript()
|
||||||
|
.run();
|
||||||
},
|
},
|
||||||
can: (cmsEditor) => {
|
can: (cmsEditor) => {
|
||||||
return cmsEditor
|
return cmsEditor
|
||||||
|
|
@ -183,13 +219,24 @@ const BUTTONS: CmsEditorButton[] = [
|
||||||
return cmsEditor.getEditor().chain().focus().clearNodes().run();
|
return cmsEditor.getEditor().chain().focus().clearNodes().run();
|
||||||
},
|
},
|
||||||
can: (cmsEditor) => {
|
can: (cmsEditor) => {
|
||||||
return cmsEditor.getEditor().can().chain().focus().clearNodes().run();
|
return cmsEditor
|
||||||
|
.getEditor()
|
||||||
|
.can()
|
||||||
|
.chain()
|
||||||
|
.focus()
|
||||||
|
.clearNodes()
|
||||||
|
.run();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: ".tiptap-blockquote",
|
selector: ".tiptap-blockquote",
|
||||||
command: (cmsEditor) => {
|
command: (cmsEditor) => {
|
||||||
return cmsEditor.getEditor().chain().focus().toggleBlockquote().run();
|
return cmsEditor
|
||||||
|
.getEditor()
|
||||||
|
.chain()
|
||||||
|
.focus()
|
||||||
|
.toggleBlockquote()
|
||||||
|
.run();
|
||||||
},
|
},
|
||||||
can: (cmsEditor) => {
|
can: (cmsEditor) => {
|
||||||
return cmsEditor
|
return cmsEditor
|
||||||
|
|
@ -204,7 +251,12 @@ const BUTTONS: CmsEditorButton[] = [
|
||||||
{
|
{
|
||||||
selector: ".tiptap-codeblock",
|
selector: ".tiptap-codeblock",
|
||||||
command: (cmsEditor) => {
|
command: (cmsEditor) => {
|
||||||
return cmsEditor.getEditor().chain().focus().toggleCodeBlock().run();
|
return cmsEditor
|
||||||
|
.getEditor()
|
||||||
|
.chain()
|
||||||
|
.focus()
|
||||||
|
.toggleCodeBlock()
|
||||||
|
.run();
|
||||||
},
|
},
|
||||||
can: (cmsEditor) => {
|
can: (cmsEditor) => {
|
||||||
return cmsEditor
|
return cmsEditor
|
||||||
|
|
@ -219,7 +271,12 @@ const BUTTONS: CmsEditorButton[] = [
|
||||||
{
|
{
|
||||||
selector: ".tiptap-ul",
|
selector: ".tiptap-ul",
|
||||||
command: (cmsEditor) => {
|
command: (cmsEditor) => {
|
||||||
return cmsEditor.getEditor().chain().focus().toggleBulletList().run();
|
return cmsEditor
|
||||||
|
.getEditor()
|
||||||
|
.chain()
|
||||||
|
.focus()
|
||||||
|
.toggleBulletList()
|
||||||
|
.run();
|
||||||
},
|
},
|
||||||
can: (cmsEditor) => {
|
can: (cmsEditor) => {
|
||||||
return cmsEditor
|
return cmsEditor
|
||||||
|
|
@ -234,7 +291,12 @@ const BUTTONS: CmsEditorButton[] = [
|
||||||
{
|
{
|
||||||
selector: ".tiptap-ol",
|
selector: ".tiptap-ol",
|
||||||
command: (cmsEditor) => {
|
command: (cmsEditor) => {
|
||||||
return cmsEditor.getEditor().chain().focus().toggleOrderedList().run();
|
return cmsEditor
|
||||||
|
.getEditor()
|
||||||
|
.chain()
|
||||||
|
.focus()
|
||||||
|
.toggleOrderedList()
|
||||||
|
.run();
|
||||||
},
|
},
|
||||||
can: (cmsEditor) => {
|
can: (cmsEditor) => {
|
||||||
return cmsEditor
|
return cmsEditor
|
||||||
|
|
@ -252,7 +314,13 @@ const BUTTONS: CmsEditorButton[] = [
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
can: (cmsEditor) => {
|
can: (cmsEditor) => {
|
||||||
return cmsEditor.getEditor().can().chain().focus().insertTable().run();
|
return cmsEditor
|
||||||
|
.getEditor()
|
||||||
|
.can()
|
||||||
|
.chain()
|
||||||
|
.focus()
|
||||||
|
.insertTable()
|
||||||
|
.run();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -264,8 +332,12 @@ const BUTTONS: CmsEditorButton[] = [
|
||||||
if (!dialog) {
|
if (!dialog) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const rowsInput = dialog.querySelector("input#rows") as HTMLInputElement;
|
const rowsInput = dialog.querySelector(
|
||||||
const colsInput = dialog.querySelector("input#cols") as HTMLInputElement;
|
"input#rows"
|
||||||
|
) as HTMLInputElement;
|
||||||
|
const colsInput = dialog.querySelector(
|
||||||
|
"input#cols"
|
||||||
|
) as HTMLInputElement;
|
||||||
const headerRowInput = dialog.querySelector(
|
const headerRowInput = dialog.querySelector(
|
||||||
"input#headerRow"
|
"input#headerRow"
|
||||||
) as HTMLInputElement;
|
) as HTMLInputElement;
|
||||||
|
|
@ -301,7 +373,13 @@ const BUTTONS: CmsEditorButton[] = [
|
||||||
return cmsEditor.getEditor().chain().focus().addRowBefore().run();
|
return cmsEditor.getEditor().chain().focus().addRowBefore().run();
|
||||||
},
|
},
|
||||||
can: (cmsEditor) => {
|
can: (cmsEditor) => {
|
||||||
return cmsEditor.getEditor().can().chain().focus().addRowBefore().run();
|
return cmsEditor
|
||||||
|
.getEditor()
|
||||||
|
.can()
|
||||||
|
.chain()
|
||||||
|
.focus()
|
||||||
|
.addRowBefore()
|
||||||
|
.run();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -310,13 +388,24 @@ const BUTTONS: CmsEditorButton[] = [
|
||||||
return cmsEditor.getEditor().chain().focus().addRowAfter().run();
|
return cmsEditor.getEditor().chain().focus().addRowAfter().run();
|
||||||
},
|
},
|
||||||
can: (cmsEditor) => {
|
can: (cmsEditor) => {
|
||||||
return cmsEditor.getEditor().can().chain().focus().addRowAfter().run();
|
return cmsEditor
|
||||||
|
.getEditor()
|
||||||
|
.can()
|
||||||
|
.chain()
|
||||||
|
.focus()
|
||||||
|
.addRowAfter()
|
||||||
|
.run();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: ".tiptap-insert-table-column-before",
|
selector: ".tiptap-insert-table-column-before",
|
||||||
command: (cmsEditor) => {
|
command: (cmsEditor) => {
|
||||||
return cmsEditor.getEditor().chain().focus().addColumnBefore().run();
|
return cmsEditor
|
||||||
|
.getEditor()
|
||||||
|
.chain()
|
||||||
|
.focus()
|
||||||
|
.addColumnBefore()
|
||||||
|
.run();
|
||||||
},
|
},
|
||||||
can: (cmsEditor) => {
|
can: (cmsEditor) => {
|
||||||
return cmsEditor
|
return cmsEditor
|
||||||
|
|
@ -334,7 +423,13 @@ const BUTTONS: CmsEditorButton[] = [
|
||||||
return cmsEditor.getEditor().chain().focus().addColumnAfter().run();
|
return cmsEditor.getEditor().chain().focus().addColumnAfter().run();
|
||||||
},
|
},
|
||||||
can: (cmsEditor) => {
|
can: (cmsEditor) => {
|
||||||
return cmsEditor.getEditor().can().chain().focus().addColumnAfter().run();
|
return cmsEditor
|
||||||
|
.getEditor()
|
||||||
|
.can()
|
||||||
|
.chain()
|
||||||
|
.focus()
|
||||||
|
.addColumnAfter()
|
||||||
|
.run();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -343,7 +438,13 @@ const BUTTONS: CmsEditorButton[] = [
|
||||||
return cmsEditor.getEditor().chain().focus().deleteRow().run();
|
return cmsEditor.getEditor().chain().focus().deleteRow().run();
|
||||||
},
|
},
|
||||||
can: (cmsEditor) => {
|
can: (cmsEditor) => {
|
||||||
return cmsEditor.getEditor().can().chain().focus().deleteRow().run();
|
return cmsEditor
|
||||||
|
.getEditor()
|
||||||
|
.can()
|
||||||
|
.chain()
|
||||||
|
.focus()
|
||||||
|
.deleteRow()
|
||||||
|
.run();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -352,7 +453,13 @@ const BUTTONS: CmsEditorButton[] = [
|
||||||
return cmsEditor.getEditor().chain().focus().deleteColumn().run();
|
return cmsEditor.getEditor().chain().focus().deleteColumn().run();
|
||||||
},
|
},
|
||||||
can: (cmsEditor) => {
|
can: (cmsEditor) => {
|
||||||
return cmsEditor.getEditor().can().chain().focus().deleteColumn().run();
|
return cmsEditor
|
||||||
|
.getEditor()
|
||||||
|
.can()
|
||||||
|
.chain()
|
||||||
|
.focus()
|
||||||
|
.deleteColumn()
|
||||||
|
.run();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -361,13 +468,24 @@ const BUTTONS: CmsEditorButton[] = [
|
||||||
return cmsEditor.getEditor().chain().focus().deleteTable().run();
|
return cmsEditor.getEditor().chain().focus().deleteTable().run();
|
||||||
},
|
},
|
||||||
can: (cmsEditor) => {
|
can: (cmsEditor) => {
|
||||||
return cmsEditor.getEditor().can().chain().focus().deleteTable().run();
|
return cmsEditor
|
||||||
|
.getEditor()
|
||||||
|
.can()
|
||||||
|
.chain()
|
||||||
|
.focus()
|
||||||
|
.deleteTable()
|
||||||
|
.run();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: ".tiptap-toggle-table-header-row",
|
selector: ".tiptap-toggle-table-header-row",
|
||||||
command: (cmsEditor) => {
|
command: (cmsEditor) => {
|
||||||
return cmsEditor.getEditor().chain().focus().toggleHeaderRow().run();
|
return cmsEditor
|
||||||
|
.getEditor()
|
||||||
|
.chain()
|
||||||
|
.focus()
|
||||||
|
.toggleHeaderRow()
|
||||||
|
.run();
|
||||||
},
|
},
|
||||||
can: (cmsEditor) => {
|
can: (cmsEditor) => {
|
||||||
return cmsEditor
|
return cmsEditor
|
||||||
|
|
@ -382,7 +500,12 @@ const BUTTONS: CmsEditorButton[] = [
|
||||||
{
|
{
|
||||||
selector: ".tiptap-toggle-table-header-column",
|
selector: ".tiptap-toggle-table-header-column",
|
||||||
command: (cmsEditor) => {
|
command: (cmsEditor) => {
|
||||||
return cmsEditor.getEditor().chain().focus().toggleHeaderColumn().run();
|
return cmsEditor
|
||||||
|
.getEditor()
|
||||||
|
.chain()
|
||||||
|
.focus()
|
||||||
|
.toggleHeaderColumn()
|
||||||
|
.run();
|
||||||
},
|
},
|
||||||
can: (cmsEditor) => {
|
can: (cmsEditor) => {
|
||||||
return cmsEditor
|
return cmsEditor
|
||||||
|
|
@ -400,7 +523,13 @@ const BUTTONS: CmsEditorButton[] = [
|
||||||
return cmsEditor.getEditor().chain().focus().mergeCells().run();
|
return cmsEditor.getEditor().chain().focus().mergeCells().run();
|
||||||
},
|
},
|
||||||
can: (cmsEditor) => {
|
can: (cmsEditor) => {
|
||||||
return cmsEditor.getEditor().can().chain().focus().mergeCells().run();
|
return cmsEditor
|
||||||
|
.getEditor()
|
||||||
|
.can()
|
||||||
|
.chain()
|
||||||
|
.focus()
|
||||||
|
.mergeCells()
|
||||||
|
.run();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -409,13 +538,24 @@ const BUTTONS: CmsEditorButton[] = [
|
||||||
return cmsEditor.getEditor().chain().focus().splitCell().run();
|
return cmsEditor.getEditor().chain().focus().splitCell().run();
|
||||||
},
|
},
|
||||||
can: (cmsEditor) => {
|
can: (cmsEditor) => {
|
||||||
return cmsEditor.getEditor().can().chain().focus().splitCell().run();
|
return cmsEditor
|
||||||
|
.getEditor()
|
||||||
|
.can()
|
||||||
|
.chain()
|
||||||
|
.focus()
|
||||||
|
.splitCell()
|
||||||
|
.run();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: ".tiptap-insert-image",
|
selector: ".tiptap-insert-image",
|
||||||
command: (cmsEditor) => {
|
command: (cmsEditor) => {
|
||||||
return cmsEditor.getEditor().chain().focus().setLibreCmsImage().run();
|
return cmsEditor
|
||||||
|
.getEditor()
|
||||||
|
.chain()
|
||||||
|
.focus()
|
||||||
|
.setLibreCmsImage()
|
||||||
|
.run();
|
||||||
},
|
},
|
||||||
can: (cmsEditor) => {
|
can: (cmsEditor) => {
|
||||||
return cmsEditor
|
return cmsEditor
|
||||||
|
|
@ -444,166 +584,24 @@ const BUTTONS: CmsEditorButton[] = [
|
||||||
// }
|
// }
|
||||||
];
|
];
|
||||||
|
|
||||||
declare module "@tiptap/core" {
|
|
||||||
interface Commands<ReturnType> {
|
|
||||||
libreCmsImageNode: {
|
|
||||||
setLibreCmsImage: (attributes?: { language: string }) => ReturnType;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const ImageNode = Node.create({
|
|
||||||
name: "libreCmsImageNode",
|
|
||||||
|
|
||||||
content: "inline*",
|
|
||||||
|
|
||||||
marks: "",
|
|
||||||
|
|
||||||
group: "block",
|
|
||||||
|
|
||||||
code: false,
|
|
||||||
|
|
||||||
defining: true,
|
|
||||||
|
|
||||||
addAttributes() {
|
|
||||||
return {
|
|
||||||
altText: {
|
|
||||||
parseHTML: (element) => {
|
|
||||||
const imgElem = element.querySelector("img");
|
|
||||||
if (imgElem) {
|
|
||||||
return imgElem.alt;
|
|
||||||
} else {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
figCaption: {
|
|
||||||
parseHTML: (element) => {
|
|
||||||
const figCaptionElem = element.querySelector("figcaption");
|
|
||||||
if (figCaptionElem) {
|
|
||||||
return figCaptionElem.innerHTML;
|
|
||||||
} else {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
addCommands() {
|
|
||||||
return {
|
|
||||||
setLibreCmsImage:
|
|
||||||
(attributes) =>
|
|
||||||
({ commands }) => {
|
|
||||||
return commands.setNode("libreCmsImageNode", attributes);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
addNodeView() {
|
|
||||||
return ({
|
|
||||||
editor,
|
|
||||||
node,
|
|
||||||
getPos,
|
|
||||||
HTMLAttributes,
|
|
||||||
decorations,
|
|
||||||
extension,
|
|
||||||
}) => {
|
|
||||||
const templateNode = document.querySelector("#librecms-image-node-view");
|
|
||||||
if (!templateNode) {
|
|
||||||
const errorMsg = document.createElement("div");
|
|
||||||
errorMsg.classList.add("alert");
|
|
||||||
errorMsg.classList.add("alert-danger");
|
|
||||||
errorMsg.textContent = "Failed to create image node view.";
|
|
||||||
|
|
||||||
return errorMsg;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("Node: ");
|
|
||||||
console.dir(node);
|
|
||||||
|
|
||||||
console.log(`getPos =`);
|
|
||||||
console.dir(getPos);
|
|
||||||
|
|
||||||
console.log(`HTMLAttributes =`);
|
|
||||||
console.dir(HTMLAttributes);
|
|
||||||
|
|
||||||
console.log(`decorations = ${decorations}`);
|
|
||||||
console.dir(decorations);
|
|
||||||
|
|
||||||
console.log(`extension = ${extension}`);
|
|
||||||
console.dir(extension);
|
|
||||||
|
|
||||||
const template = templateNode as HTMLTemplateElement;
|
|
||||||
const nodeView = template.content.cloneNode(true) as HTMLElement;
|
|
||||||
const dialogId = `librecms-image-node-view-settings-dialog-${Math.floor(
|
|
||||||
Math.random() * 1000000000
|
|
||||||
)}`;
|
|
||||||
const dialogTitleId = `${dialogId}-title`;
|
|
||||||
const settingsButtonElem = nodeView.querySelector(
|
|
||||||
".image-settings-button"
|
|
||||||
);
|
|
||||||
if (settingsButtonElem) {
|
|
||||||
settingsButtonElem.setAttribute("data-target", `#${dialogId}`);
|
|
||||||
}
|
|
||||||
const settingsDialogElem = nodeView.querySelector(
|
|
||||||
".modal.image-settings-dialog"
|
|
||||||
);
|
|
||||||
if (settingsDialogElem) {
|
|
||||||
settingsDialogElem.id = dialogId;
|
|
||||||
settingsDialogElem.setAttribute("aria-labelledby", dialogTitleId);
|
|
||||||
|
|
||||||
const settingsDialogTitleElem =
|
|
||||||
settingsDialogElem.querySelector(".modal-title");
|
|
||||||
if (settingsDialogTitleElem) {
|
|
||||||
settingsDialogTitleElem.id = dialogTitleId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const figCaptionElem = nodeView.querySelector("figcaption");
|
|
||||||
if (node.attrs.figCaption !== "" && figCaptionElem) {
|
|
||||||
figCaptionElem.innerHTML = node.attrs.figCaption;
|
|
||||||
}
|
|
||||||
const dom = document.createElement("div");
|
|
||||||
dom.classList.add("librecms-image-node-view", "p-2");
|
|
||||||
dom.appendChild(nodeView);
|
|
||||||
|
|
||||||
return {
|
|
||||||
dom,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
parseHTML() {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
tag: "figure[data-type=librecms-image-node]",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
},
|
|
||||||
|
|
||||||
renderHTML({ HTMLAttributes }) {
|
|
||||||
return [
|
|
||||||
"figure",
|
|
||||||
mergeAttributes(HTMLAttributes, { "data-type": "librecms-image-node" }),
|
|
||||||
["img", { src: "/assets/remixicon/image-line.svg" }],
|
|
||||||
["figcaption"],
|
|
||||||
];
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
class CmsEditor {
|
class CmsEditor {
|
||||||
private editor: Editor;
|
private editor: Editor;
|
||||||
private editorElem: HTMLElement;
|
private editorElem: HTMLElement;
|
||||||
private saveUrl: string;
|
private saveUrl: string;
|
||||||
|
|
||||||
public constructor(editor: Editor, editorElem: HTMLElement, saveUrl: string) {
|
public constructor(
|
||||||
|
editor: Editor,
|
||||||
|
editorElem: HTMLElement,
|
||||||
|
saveUrl: string
|
||||||
|
) {
|
||||||
this.editor = editor;
|
this.editor = editor;
|
||||||
this.editorElem = editorElem;
|
this.editorElem = editorElem;
|
||||||
this.saveUrl = saveUrl;
|
this.saveUrl = saveUrl;
|
||||||
|
|
||||||
console.log("initializing editor buttons");
|
console.log("initializing editor buttons");
|
||||||
const buttonsElem = editorElem.querySelector(".cms-tiptap-editor-buttons");
|
const buttonsElem = editorElem.querySelector(
|
||||||
|
".cms-tiptap-editor-buttons"
|
||||||
|
);
|
||||||
if (buttonsElem) {
|
if (buttonsElem) {
|
||||||
for (const button of BUTTONS) {
|
for (const button of BUTTONS) {
|
||||||
const buttonElem = buttonsElem.querySelector(button.selector);
|
const buttonElem = buttonsElem.querySelector(button.selector);
|
||||||
|
|
@ -667,7 +665,10 @@ class CmsEditor {
|
||||||
});
|
});
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
} else {
|
} else {
|
||||||
this.showSaveFailedMessage(response.status, response.statusText);
|
this.showSaveFailedMessage(
|
||||||
|
response.status,
|
||||||
|
response.statusText
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.showSaveFailedErrMessage(error as string);
|
this.showSaveFailedErrMessage(error as string);
|
||||||
|
|
@ -761,7 +762,10 @@ class CmsEditorBuilder {
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
return await response.text();
|
return await response.text();
|
||||||
} else {
|
} else {
|
||||||
this.showLoadVariantFailedMessage(response.status, response.statusText);
|
this.showLoadVariantFailedMessage(
|
||||||
|
response.status,
|
||||||
|
response.statusText
|
||||||
|
);
|
||||||
throw `Failed to load variant. Status: ${response.status}, Status Text: ${response.statusText}`;
|
throw `Failed to load variant. Status: ${response.status}, Status Text: ${response.statusText}`;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,235 @@
|
||||||
|
import { Node, nodeInputRule, mergeAttributes } from "@tiptap/core";
|
||||||
|
|
||||||
|
declare module "@tiptap/core" {
|
||||||
|
interface Commands<ReturnType> {
|
||||||
|
libreCmsImageNode: {
|
||||||
|
setLibreCmsImage: (attributes?: { language: string }) => ReturnType;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ImageNode = Node.create({
|
||||||
|
name: "libreCmsImageNode",
|
||||||
|
|
||||||
|
content: "inline*",
|
||||||
|
|
||||||
|
marks: "",
|
||||||
|
|
||||||
|
group: "block",
|
||||||
|
|
||||||
|
code: false,
|
||||||
|
|
||||||
|
defining: true,
|
||||||
|
|
||||||
|
addAttributes() {
|
||||||
|
return {
|
||||||
|
align: {
|
||||||
|
parseHTML: (element) => {
|
||||||
|
if (element.hasAttribute("data-align")) {
|
||||||
|
return element.getAttribute("data-align");
|
||||||
|
} else {
|
||||||
|
return "center";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
altText: {
|
||||||
|
parseHTML: (element) => {
|
||||||
|
const imgElem = element.querySelector("img");
|
||||||
|
if (imgElem) {
|
||||||
|
return imgElem.alt;
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
figCaption: {
|
||||||
|
parseHTML: (element) => {
|
||||||
|
const figCaptionElem = element.querySelector("figcaption");
|
||||||
|
if (figCaptionElem) {
|
||||||
|
return figCaptionElem.innerHTML;
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fullSizeOverlay: {
|
||||||
|
parseHTML: (element) => {
|
||||||
|
if (element.hasAttribute("data-fullsizeoverlay")) {
|
||||||
|
return (
|
||||||
|
element.getAttribute("data-fullsizeoverlay") ===
|
||||||
|
"true"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
parseHTML: (element) => {
|
||||||
|
if (element.hasAttribute("data-size")) {
|
||||||
|
return element.getAttribute("data-size");
|
||||||
|
} else {
|
||||||
|
return "50";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
addCommands() {
|
||||||
|
return {
|
||||||
|
setLibreCmsImage:
|
||||||
|
(attributes) =>
|
||||||
|
({ commands }) => {
|
||||||
|
return commands.setNode("libreCmsImageNode", attributes);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
addNodeView() {
|
||||||
|
return ({
|
||||||
|
editor,
|
||||||
|
node,
|
||||||
|
getPos,
|
||||||
|
HTMLAttributes,
|
||||||
|
decorations,
|
||||||
|
extension,
|
||||||
|
}) => {
|
||||||
|
const templateNode = document.querySelector(
|
||||||
|
"#librecms-image-node-view"
|
||||||
|
);
|
||||||
|
if (!templateNode) {
|
||||||
|
const errorMsg = document.createElement("div");
|
||||||
|
errorMsg.classList.add("alert");
|
||||||
|
errorMsg.classList.add("alert-danger");
|
||||||
|
errorMsg.textContent = "Failed to create image node view.";
|
||||||
|
|
||||||
|
return errorMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
// console.log("Node: ");
|
||||||
|
// console.dir(node);
|
||||||
|
|
||||||
|
// console.log(`getPos =`);
|
||||||
|
// console.dir(getPos);
|
||||||
|
|
||||||
|
// console.log(`HTMLAttributes =`);
|
||||||
|
// console.dir(HTMLAttributes);
|
||||||
|
|
||||||
|
// console.log(`decorations = ${decorations}`);
|
||||||
|
// console.dir(decorations);
|
||||||
|
|
||||||
|
// console.log(`extension = ${extension}`);
|
||||||
|
// console.dir(extension);
|
||||||
|
|
||||||
|
const template = templateNode as HTMLTemplateElement;
|
||||||
|
const nodeView = template.content.cloneNode(true) as HTMLElement;
|
||||||
|
const dialogIdNr = Math.floor(Math.random() * 1000000000);
|
||||||
|
const dialogId = `librecms-image-node-view-settings-dialog-${dialogIdNr}`;
|
||||||
|
const dialogTitleId = `${dialogId}-title`;
|
||||||
|
const settingsButtonElem = nodeView.querySelector(
|
||||||
|
".image-settings-button"
|
||||||
|
);
|
||||||
|
if (settingsButtonElem) {
|
||||||
|
settingsButtonElem.setAttribute("data-target", `#${dialogId}`);
|
||||||
|
}
|
||||||
|
const settingsDialogElem = nodeView.querySelector(
|
||||||
|
".modal.image-settings-dialog"
|
||||||
|
);
|
||||||
|
if (settingsDialogElem) {
|
||||||
|
settingsDialogElem.id = dialogId;
|
||||||
|
settingsDialogElem.setAttribute(
|
||||||
|
"aria-labelledby",
|
||||||
|
dialogTitleId
|
||||||
|
);
|
||||||
|
|
||||||
|
const settingsDialogTitleElem =
|
||||||
|
settingsDialogElem.querySelector(".modal-title");
|
||||||
|
if (settingsDialogTitleElem) {
|
||||||
|
settingsDialogTitleElem.id = dialogTitleId;
|
||||||
|
}
|
||||||
|
|
||||||
|
const settingDialogIds =
|
||||||
|
settingsDialogElem.querySelectorAll("*[id]");
|
||||||
|
for (let i = 0; i < settingDialogIds.length; i++) {
|
||||||
|
const elemWithId = settingDialogIds.item(i);
|
||||||
|
elemWithId.id = `${elemWithId.id}-${dialogIdNr}`;
|
||||||
|
}
|
||||||
|
const settingDialogLabels =
|
||||||
|
settingsDialogElem.querySelectorAll("*[for]");
|
||||||
|
for (let i = 0; i < settingDialogLabels.length; i++) {
|
||||||
|
const label = settingDialogLabels.item(i);
|
||||||
|
label.id = `${label.id}-${dialogIdNr}`;
|
||||||
|
}
|
||||||
|
const describedElems = settingsDialogElem.querySelectorAll(
|
||||||
|
"*[aria-describedby]"
|
||||||
|
);
|
||||||
|
for (let i = 0; i < describedElems.length; i++) {
|
||||||
|
const describedElem = describedElems.item(i);
|
||||||
|
describedElem.id = `${describedElem.id}-${dialogIdNr}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const submitButton = settingsDialogElem.querySelector(
|
||||||
|
"button.image-settings-dialog-save"
|
||||||
|
);
|
||||||
|
|
||||||
|
const altTextInput = settingsDialogElem.querySelector(
|
||||||
|
`input#alttext-${dialogIdNr}`
|
||||||
|
);
|
||||||
|
const alignSelect = settingsDialogElem.querySelector(
|
||||||
|
`input#align-${dialogIdNr}`
|
||||||
|
);
|
||||||
|
|
||||||
|
// ToDo: Init inputs
|
||||||
|
|
||||||
|
if (submitButton) {
|
||||||
|
submitButton.addEventListener("click", (event) => {
|
||||||
|
// ToDo: Read values from inputs and update node.attrs
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const figCaptionElem = nodeView.querySelector("figcaption");
|
||||||
|
if (node.attrs.figCaption !== "" && figCaptionElem) {
|
||||||
|
figCaptionElem.innerHTML = node.attrs.figCaption;
|
||||||
|
}
|
||||||
|
const dom = document.createElement("div");
|
||||||
|
dom.classList.add("librecms-image-node-view", "p-2");
|
||||||
|
dom.appendChild(nodeView);
|
||||||
|
|
||||||
|
return {
|
||||||
|
dom,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
parseHTML() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
tag: "figure[data-type=librecms-image-node]",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
},
|
||||||
|
|
||||||
|
renderHTML({ node, HTMLAttributes }) {
|
||||||
|
console.log("node = ");
|
||||||
|
console.dir(node);
|
||||||
|
return [
|
||||||
|
"figure",
|
||||||
|
mergeAttributes(HTMLAttributes, {
|
||||||
|
"data-align": node.attrs.align,
|
||||||
|
"data-fullsizeoverlay": node.attrs.fullSizeOverlay,
|
||||||
|
"data-size": node.attrs.size,
|
||||||
|
"data-type": "librecms-image-node",
|
||||||
|
}),
|
||||||
|
[
|
||||||
|
"img",
|
||||||
|
{
|
||||||
|
alt: node.attrs.altText,
|
||||||
|
src: "/assets/remixicon/image-line.svg",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
["figcaption"],
|
||||||
|
];
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { ImageNode } from "./image-node";
|
||||||
|
|
||||||
|
export * from "./image-node";
|
||||||
|
|
||||||
|
export default ImageNode;
|
||||||
Loading…
Reference in New Issue