aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/documents/Documents.ts2
-rw-r--r--src/client/views/DocumentButtonBar.tsx2
-rw-r--r--src/client/views/DocumentDecorations.tsx107
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx2
-rw-r--r--src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx3
-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
-rw-r--r--src/client/views/pdf/PDFViewer.tsx1
-rw-r--r--src/client/views/search/FaceRecognitionHandler.tsx2
-rw-r--r--src/client/views/smartdraw/SmartDrawHandler.tsx1
-rw-r--r--src/server/ApiManagers/FireflyManager.ts40
14 files changed, 156 insertions, 161 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index e694419a4..a4a668085 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -535,8 +535,6 @@ export class DocumentOptions {
* The list of embedded Doc instances in each Scrapbook slot
*/
scrapbookContents?: List<Doc>;
-
- _outpaintingMetadata?: STRt = new StrInfo('serialized JSON metadata needed for image outpainting', false);
}
export const DocOptions = new DocumentOptions();
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index 8a850467a..bc669fc4e 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -507,7 +507,7 @@ export class DocumentButtonBar extends ObservableReactComponent<{ views: () => (
)}
{DocumentLinksButton.StartLink && DocumentLinksButton.StartLink !== doc ? <div className="documentButtonBar-button">{this.endLinkButton} </div> : null}
- <div className="documentButtonBar-button">{this.templateButton}</div>
+ {Doc.noviceMode ? null : <div className="documentButtonBar-button">{this.templateButton}</div>}
{!DocumentView.Selected().some(v => v.allLinks.length) ? null : <div className="documentButtonBar-button">{this.followLinkButton}</div>}
<div className="documentButtonBar-button">{this.pinButton}</div>
<div className="documentButtonBar-button">{this.recordButton}</div>
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 3f11a4713..ab665e984 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -445,6 +445,12 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
@action
onPointerDown = (e: React.PointerEvent): void => {
SnappingManager.SetIsResizing(DocumentView.Selected().lastElement()?.Document[Id]); // turns off pointer events on things like youtube videos and web pages so that dragging doesn't get "stuck" when cursor moves over them
+ DocumentView.Selected()
+ .filter(dv => e.shiftKey && dv.ComponentView instanceof ImageBox)
+ .forEach(dv => {
+ dv.Document[dv.ComponentView!.fieldKey + '_outpaintOriginalWidth'] = NumCast(dv.Document._width);
+ dv.Document[dv.ComponentView!.fieldKey + '_outpaintOriginalHeight'] = NumCast(dv.Document._height);
+ });
setupMoveUpEvents(this, e, this.onPointerMove, this.onPointerUp, emptyFunction);
e.stopPropagation();
const id = (this._resizeHdlId = e.currentTarget.className);
@@ -484,50 +490,32 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
const dragHdl = this._resizeHdlId.split(' ')[0].replace('documentDecorations-', '').replace('Resizer', '');
const thisPt = // do snapping of drag point
- fixedAspect && (dragHdl === 'bottomRight' || dragHdl === 'topLeft')
+ fixedAspect && (dragHdl === 'bottomRight' || dragHdl === 'topLeft') && e.ctrlKey
? DragManager.snapDragAspect(this.projectDragToAspect(e, first, fixedAspect), fixedAspect)
: DragManager.snapDrag(e, -this._offset.x, -this._offset.y, this._offset.x, this._offset.y);
const { scale, refPt } = this.getResizeVals(thisPt, dragHdl);
!this._interactionLock &&
- runInAction(async () => {
+ runInAction(() => {
// resize selected docs if we're not in the middle of a resize (ie, throttle input events to frame rate)
this._interactionLock = true;
this._snapPt = thisPt;
- // Special handling for shift+click (outpainting mode)
- if (e.shiftKey && DocumentView.Selected().some(dv => dv.ComponentView instanceof ImageBox)) {
- DocumentView.Selected().forEach(docView => {
- if (docView.ComponentView instanceof ImageBox) {
- // Set flag for outpainting mode
- docView.Document._outpaintingResize = true;
+ const outpainted = e.shiftKey ? DocumentView.Selected().filter(dv => dv.ComponentView instanceof ImageBox) : [];
+ const notOutpainted = e.shiftKey ? DocumentView.Selected().filter(dv => !outpainted.includes(dv)) : DocumentView.Selected();
- // Adjust only the document dimensions without scaling internal content
- this.resizeViewForOutpainting(docView, refPt, scale, { dragHdl, shiftKey: e.shiftKey });
- } else {
- // Handle regular resize for non-image components
- e.ctrlKey && !Doc.NativeHeight(docView.Document) && docView.toggleNativeDimensions();
- const hasFixedAspect = this.hasFixedAspect(docView.Document);
- const scaleAspect = { x: scale.x === 1 && hasFixedAspect ? scale.y : scale.x, y: scale.x !== 1 && hasFixedAspect ? scale.x : scale.y };
- this.resizeView(docView, refPt, scaleAspect, { dragHdl, ctrlKey: e.ctrlKey });
- }
- });
- } else {
- // Regular resize behavior (existing code)
- e.ctrlKey && DocumentView.Selected().forEach(docView => !Doc.NativeHeight(docView.Document) && docView.toggleNativeDimensions());
- const hasFixedAspect = DocumentView.Selected()
- .map(dv => dv.Document)
- .some(this.hasFixedAspect);
- const scaleAspect = { x: scale.x === 1 && hasFixedAspect ? scale.y : scale.x, y: scale.x !== 1 && hasFixedAspect ? scale.x : scale.y };
- DocumentView.Selected().forEach(docView => this.resizeView(docView, refPt, scaleAspect, { dragHdl, ctrlKey: e.ctrlKey }));
- }
+ // Special handling for shift-drag resize (outpainting of Images by resizing without scaling content - fill in with firefly GAI)
+ e.shiftKey && outpainted.forEach(dv => this.resizeViewForOutpainting(dv, refPt, scale, { dragHdl, shiftKey: e.shiftKey }));
- await new Promise<void>(res => {
- setTimeout(() => {
- res((this._interactionLock = undefined));
- });
- });
+ // Special handling for not outpainted Docs when ctrl-resizing (setup native dimesions for modification)
+ e.ctrlKey && notOutpainted.forEach(docView => !Doc.NativeHeight(docView.Document) && docView.toggleNativeDimensions());
+
+ const hasFixedAspect = notOutpainted.map(dv => dv.Document).some(this.hasFixedAspect);
+ const scaleAspect = { x: scale.x === 1 && hasFixedAspect ? scale.y : scale.x, y: scale.x !== 1 && hasFixedAspect ? scale.x : scale.y };
+ notOutpainted.forEach(docView => this.resizeView(docView, refPt, scaleAspect, { dragHdl, freezeNativeDims: e.ctrlKey }));
+
+ new Promise<void>(res => setTimeout(() => res((this._interactionLock = undefined))));
});
return false;
@@ -545,11 +533,6 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
return;
}
- if (!doc._outpaintingOriginalWidth || !doc._outpaintingOriginalHeight) {
- doc._outpaintingOriginalWidth = NumCast(doc._width);
- doc._outpaintingOriginalHeight = NumCast(doc._height);
- }
-
// Calculate new boundary dimensions
const originalWidth = NumCast(doc._width);
const originalHeight = NumCast(doc._height);
@@ -564,41 +547,14 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
const { deltaX, deltaY } = this.realignRefPt(doc, refCent, originalWidth, originalHeight);
doc.x = NumCast(doc.x) + deltaX;
doc.y = NumCast(doc.y) + deltaY;
-
doc._layout_modificationDate = new DateField();
-
- // Trigger outpainting
- doc._needsOutpainting = true;
-
- // Store metadata needed for outpainting
- doc._outpaintingMetadata = JSON.stringify({
- originalWidth: doc._outpaintingOriginalWidth,
- originalHeight: doc._outpaintingOriginalHeight,
- newWidth,
- newHeight,
- scaleX: scale.x,
- scaleY: scale.y,
- anchorHandle: opts.dragHdl,
- });
};
@action
- onPointerUp = (): void => {
+ onPointerUp = () => {
SnappingManager.SetIsResizing(undefined);
SnappingManager.clearSnapLines();
- // Check if any outpainting needs to be processed
- DocumentView.Selected().forEach(view => {
- if (view.Document._needsOutpainting && view.ComponentView instanceof ImageBox) {
- // Trigger outpainting process in the ImageBox component
- (view.ComponentView as ImageBox).processOutpainting();
-
- // Clear flags
- view.Document._needsOutpainting = false;
- view.Document._outpaintingResize = false;
- }
- });
-
this._resizeHdlId = '';
this._resizeUndo?.end();
@@ -647,7 +603,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
//
// resize a single DocumentView about the specified reference point, possibly setting/updating the native dimensions of the Doc
//
- resizeView = (docView: DocumentView, refPt: number[], scale: { x: number; y: number }, opts: { dragHdl: string; ctrlKey: boolean }) => {
+ resizeView = (docView: DocumentView, refPt: number[], scale: { x: number; y: number }, opts: { dragHdl: string; freezeNativeDims: boolean }) => {
const doc = docView.Document;
if (doc.isGroup) {
DocListCast(doc.data)
@@ -660,25 +616,24 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
const [nwidth, nheight] = [docView.nativeWidth, docView.nativeHeight];
const [initWidth, initHeight] = [NumCast(doc._width, 1), NumCast(doc._height)];
- const modifyNativeDim =
- (opts.ctrlKey && doc._layout_nativeDimEditable) || // e.g., PDF or web page
- (doc._layout_reflowHorizontal && opts.dragHdl !== 'bottom' && opts.dragHdl !== 'top') || // eg rtf or some web pages
- (doc._layout_reflowVertical && (opts.dragHdl === 'bottom' || opts.dragHdl === 'top' || opts.ctrlKey)); // eg rtf, web, pdf
- if (nwidth && nheight && !modifyNativeDim) {
- // eg., dragging right resizer on PDF -- enforce native dimensions because not expliclty overridden with ctrl or bottom resize drag
+ const cornerReflow = !opts.freezeNativeDims && doc._layout_reflowHorizontal && doc._layout_reflowVertical && ['topLeft', 'topRight', 'bottomLeft', 'bottomRight'].includes(opts.dragHdl);
+ const horizontalReflow = !opts.freezeNativeDims && doc._layout_reflowHorizontal && ['left', 'right'].includes(opts.dragHdl); // eg rtf or some web pages
+ const verticalReflow = !opts.freezeNativeDims && doc._layout_reflowVertical && ['bottom', 'top'].includes(opts.dragHdl); // eg rtf, web, pdf
+ // preserve aspect ratio if Doc has a native ize and drag won't cause reflow (eg, ctrl-dragging a Doc's corner doesn't allow reflow, or dragging right side of a PDF which isn't horizontally reflowable)
+ if (nwidth && nheight && !cornerReflow && !horizontalReflow && !verticalReflow) {
scale.x === 1 ? (scale.x = scale.y) : (scale.y = scale.x);
}
- if (['right', 'left', 'bottomRight'].includes(opts.dragHdl) && modifyNativeDim && Doc.NativeWidth(doc)) {
+ if ((horizontalReflow || cornerReflow) && Doc.NativeWidth(doc)) {
const setData = Doc.NativeWidth(doc[DocData]) === doc.nativeWidth;
- doc.nativeWidth = scale.x * Doc.NativeWidth(doc);
+ doc._nativeWidth = scale.x * Doc.NativeWidth(doc);
if (setData) Doc.SetNativeWidth(doc[DocData], NumCast(doc.nativeWidth));
if (doc._layout_reflowVertical && !NumCast(doc.nativeHeight)) {
doc._nativeHeight = (initHeight / initWidth) * nwidth; // initializes the nativeHeight for a PDF
}
}
- if (['bottom', 'top', 'bottomRight'].includes(opts.dragHdl) && modifyNativeDim && Doc.NativeHeight(doc)) {
- const setData = Doc.NativeHeight(doc[DocData]) === doc.nativeHeight && (!doc.layout_reflowVertical || opts.ctrlKey);
+ if ((verticalReflow || cornerReflow) && Doc.NativeHeight(doc)) {
+ const setData = Doc.NativeHeight(doc[DocData]) === doc.nativeHeight && !doc.layout_reflowVertical;
doc._nativeHeight = scale.y * Doc.NativeHeight(doc);
if (setData) Doc.SetNativeHeight(doc[DocData], NumCast(doc._nativeHeight));
}
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index ea6259a32..13c3eb72f 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -443,7 +443,7 @@ export class CollectionDockingView extends CollectionSubView() {
window.addEventListener('mouseup', this.onPointerUp);
if (!htmlTarget.closest('*.lm_content') && (htmlTarget.closest('*.lm_tab') || htmlTarget.closest('*.lm_stack'))) {
const className = typeof htmlTarget.className === 'string' ? htmlTarget.className : '';
- if (className.includes('lm_maximise')) {
+ if (className.includes('lm_maximise') || className.includes('lm_close_tab')) {
// this._flush = UndoManager.StartBatch('tab maximize');
} else {
const tabTarget = (e.target as HTMLElement)?.parentElement?.className.includes('lm_tab') ? (e.target as HTMLElement).parentElement : (e.target as HTMLElement);
diff --git a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx
index ad05a798b..624c85beb 100644
--- a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx
+++ b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx
@@ -24,6 +24,7 @@ import { FaceRecognitionHandler } from '../../search/FaceRecognitionHandler';
import { CollectionStackingView } from '../CollectionStackingView';
import './FaceCollectionBox.scss';
import { MarqueeOptionsMenu } from './MarqueeOptionsMenu';
+import { returnEmptyDocViewList } from '../../StyleProvider';
/**
* This code is used to render the sidebar collection of unique recognized faces, where each
@@ -268,6 +269,8 @@ export class FaceCollectionBox extends ViewBoxBaseComponent<FieldViewProps>() {
{...this._props} //
styleProvider={this.stackingStyleProvider}
Document={Doc.ActiveDashboard}
+ DocumentView={undefined}
+ docViewPath={returnEmptyDocViewList}
fieldKey="myUniqueFaces"
moveDocument={this.moveDocument}
addDocument={this.addDocument}
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
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 041fc0de7..fc2567fbc 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -146,6 +146,7 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> {
e.clipboardData.setData('dash/pdfAnchor', anchor[DocData][Id]);
}
e.preventDefault();
+ e.stopPropagation();
}
};
diff --git a/src/client/views/search/FaceRecognitionHandler.tsx b/src/client/views/search/FaceRecognitionHandler.tsx
index cb837e3ab..3ad5bc844 100644
--- a/src/client/views/search/FaceRecognitionHandler.tsx
+++ b/src/client/views/search/FaceRecognitionHandler.tsx
@@ -43,7 +43,7 @@ export class FaceRecognitionHandler {
* Loads an image
*/
private static loadImage = (imgUrl: ImageField): Promise<HTMLImageElement> => {
- const [name, type] = ImageCastToNameType(imgUrl.url.href);
+ const [name, type] = ImageCastToNameType(imgUrl);
const imageURL = `${name}_o.${type}`;
return new Promise((resolve, reject) => {
diff --git a/src/client/views/smartdraw/SmartDrawHandler.tsx b/src/client/views/smartdraw/SmartDrawHandler.tsx
index 2283ef965..4f0cd3978 100644
--- a/src/client/views/smartdraw/SmartDrawHandler.tsx
+++ b/src/client/views/smartdraw/SmartDrawHandler.tsx
@@ -576,6 +576,7 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
type="text"
autoFocus
value={this._userInput}
+ onPointerDown={e => e.stopPropagation()}
onChange={action(e => this._canInteract && (this._userInput = e.target.value))}
placeholder="Enter item to draw"
onKeyDown={this.handleKeyPress}
diff --git a/src/server/ApiManagers/FireflyManager.ts b/src/server/ApiManagers/FireflyManager.ts
index 0b19f66e0..1b8a85a5c 100644
--- a/src/server/ApiManagers/FireflyManager.ts
+++ b/src/server/ApiManagers/FireflyManager.ts
@@ -86,25 +86,23 @@ export default class FireflyManager extends ApiManager {
.then(link => resolve(link.result.link))
.catch(linkErr => reject(new Error('Failed to get temporary link: ' + linkErr.message)))
)
- .catch(uploadErr => reject(new Error('Failed to upload file to Dropbox: ' + uploadErr.message)));
+ .catch(uploadErr => {
+ if (user?.dropboxRefresh) {
+ console.log('Attempting to refresh Dropbox token for user:', user.email);
+ this.refreshDropboxToken(user)
+ .then(token => {
+ if (!token) return reject(new Error('Failed to refresh Dropbox token.' + user.email));
- uploadToDropbox(dbx).catch(e => {
- if (user?.dropboxRefresh) {
- console.log('Attempting to refresh Dropbox token for user:', user.email);
- this.refreshDropboxToken(user)
- .then(token => {
- if (!token) {
- return reject(new Error('Failed to refresh Dropbox token.' + user.email));
- }
+ const dbxNew = new Dropbox({ accessToken: token });
+ uploadToDropbox(dbxNew).catch(finalErr => reject(new Error('Failed to refresh Dropbox token:' + finalErr.message)));
+ })
+ .catch(refreshErr => reject(new Error('Failed to refresh Dropbox token: ' + refreshErr.message)));
+ } else {
+ reject(new Error('Dropbox error: ' + uploadErr.message));
+ }
+ });
- const dbxNew = new Dropbox({ accessToken: token });
- uploadToDropbox(dbxNew).catch(finalErr => reject(new Error('Failed to refresh Dropbox token:' + finalErr.message)));
- })
- .catch(refreshErr => reject(new Error('Failed to refresh Dropbox token: ' + refreshErr.message)));
- } else {
- reject(new Error('Dropbox error: ' + e.message));
- }
- });
+ uploadToDropbox(dbx);
});
});
@@ -345,10 +343,10 @@ export default class FireflyManager extends ApiManager {
numVariations: 1,
placement: {
inset: {
- left: 0,
- top: 0,
- right: Math.round(req.body.newDimensions.width - req.body.originalDimensions.width),
- bottom: Math.round(req.body.newDimensions.height - req.body.originalDimensions.height),
+ left: Math.round((req.body.newDimensions.width - req.body.originalDimensions.width) / 2),
+ top: Math.round((req.body.newDimensions.height - req.body.originalDimensions.height) / 2),
+ right: Math.round((req.body.newDimensions.width - req.body.originalDimensions.width) / 2),
+ bottom: Math.round((req.body.newDimensions.height - req.body.originalDimensions.height) / 2),
},
alignment: {
horizontal: 'center',