aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/nodes')
-rw-r--r--src/client/views/nodes/ImageBox.scss42
-rw-r--r--src/client/views/nodes/ImageBox.tsx34
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx63
-rw-r--r--src/client/views/nodes/formattedText/RichTextRules.ts3
-rw-r--r--src/client/views/nodes/imageEditor/imageMeshTool/imageMeshToolButton.tsx15
5 files changed, 98 insertions, 59 deletions
diff --git a/src/client/views/nodes/ImageBox.scss b/src/client/views/nodes/ImageBox.scss
index 9fc20ffd4..ac1a6ece9 100644
--- a/src/client/views/nodes/ImageBox.scss
+++ b/src/client/views/nodes/ImageBox.scss
@@ -106,7 +106,7 @@
height: 100%;
img {
object-fit: contain;
- height: 100%;
+ height: fit-content;
}
.imageBox-fadeBlocker,
@@ -249,27 +249,29 @@
background: white;
padding: 20px;
border-radius: 8px;
- box-shadow: 0 4px 12px rgba(0,0,0,0.2);
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
z-index: 10000;
-
- h3 { margin-top: 0; }
-
+
+ h3 {
+ margin-top: 0;
+ }
+
input {
- width: 300px;
- padding: 8px;
- margin-bottom: 10px;
+ width: 300px;
+ padding: 8px;
+ margin-bottom: 10px;
}
-
+
.buttons {
- display: flex;
- justify-content: flex-end;
- gap: 10px;
-
- .generate-btn {
- background: #0078d4;
- color: white;
- border: none;
- padding: 8px 16px;
- }
+ display: flex;
+ justify-content: flex-end;
+ gap: 10px;
+
+ .generate-btn {
+ background: #0078d4;
+ color: white;
+ border: none;
+ padding: 8px 16px;
+ }
}
- } \ No newline at end of file
+}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 999d7089b..31a135fa7 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -170,13 +170,10 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
},
{ fireImmediately: true }
);
- this._disposers.outpainting = reaction(
- () => this.Document?._needsOutpainting,
- needsOutpainting => {
- if (needsOutpainting && this.Document?._outpaintingResize) {
- this.processOutpainting();
- }
- }
+ this._disposers.outpaint = reaction(
+ () => this.Document[this.fieldKey + '_outpaintOriginalWidth'] !== undefined && !SnappingManager.ShiftKey,
+ complete => complete && this.openOutpaintPrompt(),
+ { fireImmediately: true }
);
}
@@ -212,7 +209,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
drop = undoable(
action((e: Event, de: DragManager.DropEvent) => {
- if (de.complete.docDragData && this._props.rejectDrop?.(de, this.DocumentView?.())) {
+ if (de.complete.docDragData && !this._props.rejectDrop?.(de, this.DocumentView?.())) {
let added: boolean | undefined;
const hitDropTarget = (ele: HTMLElement, dropTarget: HTMLDivElement | null): boolean => {
if (!ele) return false;
@@ -306,7 +303,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
const anchy = NumCast(cropping.y);
const anchw = NumCast(cropping._width);
const anchh = NumCast(cropping._height);
- const viewScale = NumCast(this.dataDoc[this.fieldKey + '_nativeHeight']) / anchh;
+ const viewScale = NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']) / anchw;
cropping.x = NumCast(this.Document.x) + NumCast(this.layoutDoc._width);
cropping.y = NumCast(this.Document.y);
cropping.onClick = undefined;
@@ -380,13 +377,8 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
const field = Cast(this.dataDoc[this.fieldKey], ImageField);
if (!field) return;
- const origWidth = NumCast(this.Document._outpaintingOriginalWidth);
- const origHeight = NumCast(this.Document._outpaintingOriginalHeight);
-
- if (!origWidth || !origHeight) {
- console.error('Original dimensions (_outpaintingOriginalWidth/_outpaintingOriginalHeight) not set. Ensure resizeViewForOutpainting was called first.');
- return;
- }
+ const origWidth = NumCast(this.Document[this.fieldKey + '_outpaintOriginalWidth']);
+ const origHeight = NumCast(this.Document[this.fieldKey + '_outpaintOriginalHeight']);
// Set flag that outpainting is in progress
this._outpaintingInProgress = true;
@@ -421,7 +413,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
const response = await Networking.PostToServer('/outpaintImage', {
imageUrl: currentPath,
prompt: customPrompt,
- originalDimensions: { width: origWidth, height: origHeight },
+ originalDimensions: { width: Math.min(newWidth, origWidth), height: Math.min(newHeight, origHeight) },
newDimensions: { width: newWidth, height: newHeight },
});
@@ -452,6 +444,8 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
this.Document.$ai = true;
this.Document.$ai_outpainted = true;
this.Document.$ai_outpaint_prompt = customPrompt;
+ this.Document[this.fieldKey + '_outpaintOriginalWidth'] = undefined;
+ this.Document[this.fieldKey + '_outpaintOriginalHeight'] = undefined;
} else {
this.Document._width = origWidth;
this.Document._height = origHeight;
@@ -471,11 +465,9 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
}
};
- processOutpainting = () => this.openOutpaintPrompt();
-
componentUI = () =>
!this._showOutpaintPrompt ? null : (
- <div className="imageBox-regenerate-dialog" style={{ backgroundColor: SettingsManager.userBackgroundColor, color: SettingsManager.userColor }}>
+ <div key="imageBox-componentui" className="imageBox-regenerate-dialog" style={{ backgroundColor: SettingsManager.userBackgroundColor, color: SettingsManager.userColor }}>
<h3>Outpaint Image</h3>
<EditableText
placeholder="Enter a prompt for extending the image:"
@@ -732,7 +724,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
ref={action((r: HTMLImageElement | null) => (this.imageRef = r))}
key="paths"
src={srcpath}
- style={{ transform, transformOrigin }}
+ style={{ transform, transformOrigin, height: this.Document[this.fieldKey + '_outpaintOriginalWidth'] !== undefined ? '100%' : undefined }}
onError={action(e => (this._error = e.toString()))}
draggable={false}
width={nativeWidth}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 9897a0062..d6fa3172d 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1149,7 +1149,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
// Since we also monitor all component height changes, this will update the document's height.
resetNativeHeight = action((scrollHeight: number) => {
this.layoutDoc['_' + this.fieldKey + '_height'] = scrollHeight;
- if (!this.layoutDoc.isTemplateForField) this.layoutDoc._nativeHeight = scrollHeight;
+ if (!this.layoutDoc.isTemplateForField && NumCast(this.layoutDoc._nativeHeight)) this.layoutDoc._nativeHeight = scrollHeight;
});
addPlugin = (plugin: Plugin) => {
@@ -1344,8 +1344,62 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
return text;
};
- handlePaste = (view: EditorView, event: Event /* , slice: Slice */): boolean => {
- const pdfAnchorId = (event as ClipboardEvent).clipboardData?.getData('dash/pdfAnchor');
+ handlePaste = (view: EditorView, event: ClipboardEvent /* , slice: Slice */): boolean => {
+ return this.doPaste(view, event.clipboardData);
+ };
+ doPaste = (view: EditorView, data: DataTransfer | null) => {
+ const html = data?.getData('text/html');
+ const pdfAnchorId = data?.getData('dash/pdfAnchor');
+ if (html && !pdfAnchorId) {
+ const replaceDivsWithParagraphs = (expr: string) => {
+ // Create a temporary DOM container
+ const container = document.createElement('div');
+ container.innerHTML = expr;
+
+ // Recursive function to process all divs
+ function processDivs(node: HTMLElement) {
+ // Get all div elements in the current node (live collection)
+ const divs = node.getElementsByTagName('div');
+
+ // We need to convert to array because we'll be modifying the DOM
+ const divsArray = Array.from(divs);
+
+ for (const div of divsArray) {
+ // Create replacement paragraph
+ const p = document.createElement('p');
+
+ // Copy all attributes
+ for (const attr of div.attributes) {
+ p.setAttribute(attr.name, attr.value);
+ }
+
+ // Move all child nodes
+ while (div.firstChild) {
+ p.appendChild(div.firstChild);
+ }
+
+ // Replace the div with the paragraph
+ div.parentNode?.replaceChild(p, div);
+
+ // Process any nested divs that were moved into the new paragraph
+ processDivs(p);
+ }
+ }
+
+ // Start processing from the container
+ processDivs(container);
+
+ return container.innerHTML;
+ };
+ const fixedHTML = replaceDivsWithParagraphs(html);
+ // .replace(/<div\b([^>]*)>(.*?)<\/div>/g, '<p$1>$2</p>'); // prettier-ignore
+ this._inDrop = true;
+ view.pasteHTML(html.split('<p').length < 2 ? fixedHTML : html);
+ this._inDrop = false;
+
+ return true;
+ }
+
return !!(pdfAnchorId && this.addPdfReference(pdfAnchorId));
};
@@ -1485,9 +1539,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
}
if (this._props.isContentActive()) this.prepareForTyping();
if (this.EditorView && FormattedTextBox.PasteOnLoad) {
- const pdfAnchorId = FormattedTextBox.PasteOnLoad.clipboardData?.getData('dash/pdfAnchor');
+ this.doPaste(this.EditorView, FormattedTextBox.PasteOnLoad.clipboardData);
FormattedTextBox.PasteOnLoad = undefined;
- pdfAnchorId && this.addPdfReference(pdfAnchorId);
}
if (this._props.autoFocus) setTimeout(() => this.EditorView!.focus()); // not sure why setTimeout is needed but editing dashFieldView's doesn't work without it.
}
diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts
index 26ccf6931..f26a75fe4 100644
--- a/src/client/views/nodes/formattedText/RichTextRules.ts
+++ b/src/client/views/nodes/formattedText/RichTextRules.ts
@@ -349,7 +349,8 @@ export class RichTextRules {
let count = 0; // ignore first return value which will be the notation that chat is pending a result
Doc.SetField(this.Document, '', match[2], false, (gptval: FieldResult) => {
if (count) {
- const tr = this.TextBox.EditorView?.state.tr.insertText(' ' + (gptval as string));
+ this.TextBox.EditorView?.pasteText(' ' + (gptval as string), undefined);
+ const tr = this.TextBox.EditorView?.state.tr; //.insertText(' ' + (gptval as string));
tr && this.TextBox.EditorView?.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(end + 2), tr.doc.resolve(end + 2 + (gptval as string).length))));
RichTextMenu.Instance?.elideSelection(this.TextBox.EditorView?.state, true);
}
diff --git a/src/client/views/nodes/imageEditor/imageMeshTool/imageMeshToolButton.tsx b/src/client/views/nodes/imageEditor/imageMeshTool/imageMeshToolButton.tsx
index c02a1eb94..e580c7070 100644
--- a/src/client/views/nodes/imageEditor/imageMeshTool/imageMeshToolButton.tsx
+++ b/src/client/views/nodes/imageEditor/imageMeshTool/imageMeshToolButton.tsx
@@ -13,20 +13,11 @@ interface ButtonContainerProps {
btnText: string;
imageWidth: number;
imageHeight: number;
- gridXSize: number; // X subdivisions
- gridYSize: number; // Y subdivisions
+ gridXSize: number; // X subdivisions
+ gridYSize: number; // Y subdivisions
}
-export function MeshTransformButton({
- loading,
- onClick,
- onReset,
- btnText,
- imageWidth,
- imageHeight,
- gridXSize,
- gridYSize
-}: ButtonContainerProps) {
+export function MeshTransformButton({ loading, onClick, onReset, btnText, imageWidth, imageHeight, gridXSize, gridYSize }: ButtonContainerProps) {
const [showGrid, setShowGrid] = React.useState(false);
const [isGridInteractive, setIsGridInteractive] = React.useState(false); // Controls the dragging of control points
const imageRef = React.useRef<HTMLImageElement>(null); // Reference to the image element