mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-12-12 13:33:46 +08:00
260 lines
9.0 KiB
TypeScript
260 lines
9.0 KiB
TypeScript
import {
|
|
EditorFormDefinition,
|
|
EditorFormField,
|
|
EditorFormTabs,
|
|
EditorSelectFormFieldDefinition
|
|
} from "../../framework/forms";
|
|
import {EditorUiContext} from "../../framework/core";
|
|
import {$createNodeSelection, $createTextNode, $getSelection, $insertNodes, $setSelection} from "lexical";
|
|
import {$isImageNode, ImageNode} from "../../../nodes/image";
|
|
import {$createLinkNode, $isLinkNode, LinkNode} from "@lexical/link";
|
|
import {$createMediaNodeFromHtml, $createMediaNodeFromSrc, $isMediaNode, MediaNode} from "../../../nodes/media";
|
|
import {$insertNodeToNearestRoot} from "@lexical/utils";
|
|
import {$getNodeFromSelection, getLastSelection} from "../../../utils/selection";
|
|
import {EditorFormModal} from "../../framework/modals";
|
|
import {EditorActionField} from "../../framework/blocks/action-field";
|
|
import {EditorButton} from "../../framework/buttons";
|
|
import {showImageManager} from "../../../utils/images";
|
|
import searchImageIcon from "@icons/editor/image-search.svg";
|
|
import searchIcon from "@icons/search.svg";
|
|
import {showLinkSelector} from "../../../utils/links";
|
|
import {LinkField} from "../../framework/blocks/link-field";
|
|
import {insertOrUpdateLink} from "../../../utils/formats";
|
|
|
|
export function $showImageForm(image: ImageNode, context: EditorUiContext) {
|
|
const imageModal: EditorFormModal = context.manager.createModal('image');
|
|
const height = image.getHeight();
|
|
const width = image.getWidth();
|
|
|
|
const formData = {
|
|
src: image.getSrc(),
|
|
alt: image.getAltText(),
|
|
height: height === 0 ? '' : String(height),
|
|
width: width === 0 ? '' : String(width),
|
|
};
|
|
|
|
imageModal.show(formData);
|
|
}
|
|
|
|
export const image: EditorFormDefinition = {
|
|
submitText: 'Apply',
|
|
async action(formData, context: EditorUiContext) {
|
|
context.editor.update(() => {
|
|
const selection = getLastSelection(context.editor);
|
|
const selectedImage = $getNodeFromSelection(selection, $isImageNode);
|
|
if ($isImageNode(selectedImage)) {
|
|
selectedImage.setSrc(formData.get('src')?.toString() || '');
|
|
selectedImage.setAltText(formData.get('alt')?.toString() || '');
|
|
|
|
selectedImage.setWidth(Number(formData.get('width')?.toString() || '0'));
|
|
selectedImage.setHeight(Number(formData.get('height')?.toString() || '0'));
|
|
}
|
|
});
|
|
return true;
|
|
},
|
|
fields: [
|
|
{
|
|
build() {
|
|
return new EditorActionField(
|
|
new EditorFormField({
|
|
label: 'Source',
|
|
name: 'src',
|
|
type: 'text',
|
|
}),
|
|
new EditorButton({
|
|
label: 'Browse files',
|
|
icon: searchImageIcon,
|
|
action(context: EditorUiContext) {
|
|
showImageManager((image) => {
|
|
const modal = context.manager.getActiveModal('image');
|
|
if (modal) {
|
|
modal.getForm().setValues({
|
|
src: image.thumbs?.display || image.url,
|
|
alt: image.name,
|
|
});
|
|
}
|
|
});
|
|
}
|
|
}),
|
|
);
|
|
},
|
|
},
|
|
{
|
|
label: 'Alternative description',
|
|
name: 'alt',
|
|
type: 'text',
|
|
},
|
|
{
|
|
label: 'Width',
|
|
name: 'width',
|
|
type: 'text',
|
|
},
|
|
{
|
|
label: 'Height',
|
|
name: 'height',
|
|
type: 'text',
|
|
},
|
|
],
|
|
};
|
|
|
|
export function $showLinkForm(link: LinkNode|null, context: EditorUiContext) {
|
|
const linkModal = context.manager.createModal('link');
|
|
|
|
let formDefaults = {};
|
|
if (link) {
|
|
formDefaults = {
|
|
url: link.getURL(),
|
|
text: link.getTextContent(),
|
|
title: link.getTitle(),
|
|
target: link.getTarget(),
|
|
}
|
|
|
|
context.editor.update(() => {
|
|
const selection = $createNodeSelection();
|
|
selection.add(link.getKey());
|
|
$setSelection(selection);
|
|
});
|
|
}
|
|
|
|
linkModal.show(formDefaults);
|
|
}
|
|
|
|
export const link: EditorFormDefinition = {
|
|
submitText: 'Apply',
|
|
async action(formData, context: EditorUiContext) {
|
|
insertOrUpdateLink(context.editor, {
|
|
url: formData.get('url')?.toString() || '',
|
|
title: formData.get('title')?.toString() || '',
|
|
target: formData.get('target')?.toString() || '',
|
|
text: formData.get('text')?.toString() || '',
|
|
});
|
|
return true;
|
|
},
|
|
fields: [
|
|
{
|
|
build() {
|
|
return new EditorActionField(
|
|
new LinkField(new EditorFormField({
|
|
label: 'URL',
|
|
name: 'url',
|
|
type: 'text',
|
|
})),
|
|
new EditorButton({
|
|
label: 'Browse links',
|
|
icon: searchIcon,
|
|
action(context: EditorUiContext) {
|
|
showLinkSelector(entity => {
|
|
const modal = context.manager.getActiveModal('link');
|
|
if (modal) {
|
|
modal.getForm().setValues({
|
|
url: entity.link,
|
|
text: entity.name,
|
|
title: entity.name,
|
|
});
|
|
}
|
|
});
|
|
}
|
|
}),
|
|
);
|
|
},
|
|
},
|
|
{
|
|
label: 'Text to display',
|
|
name: 'text',
|
|
type: 'text',
|
|
},
|
|
{
|
|
label: 'Title',
|
|
name: 'title',
|
|
type: 'text',
|
|
},
|
|
{
|
|
label: 'Open link in...',
|
|
name: 'target',
|
|
type: 'select',
|
|
valuesByLabel: {
|
|
'Current window': '',
|
|
'New window': '_blank',
|
|
}
|
|
} as EditorSelectFormFieldDefinition,
|
|
],
|
|
};
|
|
|
|
export const media: EditorFormDefinition = {
|
|
submitText: 'Save',
|
|
async action(formData, context: EditorUiContext) {
|
|
const selectedNode: MediaNode|null = await (new Promise((res, rej) => {
|
|
context.editor.getEditorState().read(() => {
|
|
const node = $getNodeFromSelection($getSelection(), $isMediaNode);
|
|
res(node as MediaNode|null);
|
|
});
|
|
}));
|
|
|
|
const embedCode = (formData.get('embed') || '').toString().trim();
|
|
if (embedCode) {
|
|
context.editor.update(() => {
|
|
const node = $createMediaNodeFromHtml(embedCode);
|
|
if (selectedNode && node) {
|
|
selectedNode.replace(node)
|
|
} else if (node) {
|
|
$insertNodeToNearestRoot(node);
|
|
}
|
|
});
|
|
|
|
return true;
|
|
}
|
|
|
|
context.editor.update(() => {
|
|
const src = (formData.get('src') || '').toString().trim();
|
|
const height = (formData.get('height') || '').toString().trim();
|
|
const width = (formData.get('width') || '').toString().trim();
|
|
|
|
const updateNode = selectedNode || $createMediaNodeFromSrc(src);
|
|
updateNode.setSrc(src);
|
|
updateNode.setWidthAndHeight(width, height);
|
|
if (!selectedNode) {
|
|
$insertNodeToNearestRoot(updateNode);
|
|
}
|
|
});
|
|
|
|
return true;
|
|
},
|
|
fields: [
|
|
{
|
|
build() {
|
|
return new EditorFormTabs([
|
|
{
|
|
label: 'General',
|
|
contents: [
|
|
{
|
|
label: 'Source',
|
|
name: 'src',
|
|
type: 'text',
|
|
},
|
|
{
|
|
label: 'Width',
|
|
name: 'width',
|
|
type: 'text',
|
|
},
|
|
{
|
|
label: 'Height',
|
|
name: 'height',
|
|
type: 'text',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
label: 'Embed',
|
|
contents: [
|
|
{
|
|
label: 'Paste your embed code below:',
|
|
name: 'embed',
|
|
type: 'textarea',
|
|
},
|
|
],
|
|
}
|
|
])
|
|
}
|
|
},
|
|
],
|
|
}; |