aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.vscode/launch.json2
-rw-r--r--src/client/documents/Documents.ts6
-rw-r--r--src/client/util/DictationManager.ts3
-rw-r--r--src/client/util/Import & Export/ImageUtils.ts12
-rw-r--r--src/client/util/RichTextRules.ts2
-rw-r--r--src/client/util/request-image-size.js2
-rw-r--r--src/client/views/DocumentDecorations.tsx2
-rw-r--r--src/client/views/PreviewCursor.tsx6
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx2
-rw-r--r--src/client/views/collections/CollectionStackingViewFieldColumn.tsx2
-rw-r--r--src/client/views/collections/CollectionSubView.tsx15
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx2
-rw-r--r--src/client/views/collections/CollectionView.tsx2
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx2
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx2
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx8
-rw-r--r--src/client/views/nodes/DocumentContentsView.tsx7
-rw-r--r--src/client/views/nodes/DocumentView.tsx8
-rw-r--r--src/client/views/nodes/FormattedTextBox.tsx8
-rw-r--r--src/client/views/nodes/ImageBox.tsx52
-rw-r--r--src/new_fields/util.ts7
-rw-r--r--src/scraping/buxton/scraper.py2
-rw-r--r--src/server/ApiManagers/UploadManager.ts3
-rw-r--r--src/server/DashUploadUtils.ts88
-rw-r--r--src/server/RouteManager.ts2
-rw-r--r--src/server/authentication/models/current_user_utils.ts6
26 files changed, 136 insertions, 117 deletions
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 77e139dbd..829f8f492 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -52,7 +52,7 @@
"request": "attach",
"name": "Typescript Server",
"protocol": "inspector",
- "port": 9230,
+ "port": 9229,
"localRoot": "${workspaceFolder}",
"remoteRoot": "${workspaceFolder}"
},
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index c0f0e0552..58aec6173 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -56,6 +56,7 @@ const requestImageSize = require('../util/request-image-size');
const path = require('path');
export interface DocumentOptions {
+ _autoHeight?: boolean;
_panX?: number;
_panY?: number;
_width?: number;
@@ -103,7 +104,6 @@ export interface DocumentOptions {
sectionFilter?: string; // field key used to determine headings for sections in stacking and masonry views
schemaColumns?: List<SchemaHeaderField>;
dockingConfig?: string;
- autoHeight?: boolean;
annotationOn?: Doc;
removeDropProperties?: List<string>; // list of properties that should be removed from a document when it is dropped. e.g., a creator button may be forceActive to allow it be dragged, but the forceActive property can be removed from the dropped document
dbDoc?: Doc;
@@ -333,7 +333,7 @@ export namespace Docs {
*/
export namespace Create {
- const delegateKeys = ["x", "y", "_width", "_height", "_panX", "_panY", "_viewType", "_nativeWidth", "_nativeHeight", "_dropAction", "_annotationOn", "_chromeStatus", "_forceActive", "_fitWidth", "_LODdisable"];
+ const delegateKeys = ["x", "y", "_width", "_height", "_panX", "_panY", "_viewType", "_nativeWidth", "_nativeHeight", "_dropAction", "_annotationOn", "_chromeStatus", "_forceActive", "_autoHeight", "_fitWidth", "_LODdisable"];
/**
* This function receives the relevant document prototype and uses
@@ -703,7 +703,7 @@ export namespace Docs {
created = Docs.Create.StackingDocument(DocListCast(field), resolved);
layout = CollectionView.LayoutString;
} else {
- created = Docs.Create.TextDocument({ ...{ _width: 200, _height: 25, autoHeight: true }, ...resolved });
+ created = Docs.Create.TextDocument({ ...{ _width: 200, _height: 25, _autoHeight: true }, ...resolved });
layout = FormattedTextBox.LayoutString;
}
created.layout = layout?.(fieldKey);
diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts
index a99e3bc4f..fa7f63965 100644
--- a/src/client/util/DictationManager.ts
+++ b/src/client/util/DictationManager.ts
@@ -332,8 +332,7 @@ export namespace DictationManager {
["new outline", {
action: (target: DocumentView) => {
- const newBox = Docs.Create.TextDocument({ _width: 400, _height: 200, title: "My Outline" });
- newBox.autoHeight = true;
+ const newBox = Docs.Create.TextDocument({ _width: 400, _height: 200, title: "My Outline", _autoHeight: true });
const proto = newBox.proto!;
const prompt = "Press alt + r to start dictating here...";
const head = 3;
diff --git a/src/client/util/Import & Export/ImageUtils.ts b/src/client/util/Import & Export/ImageUtils.ts
index 6a9486f83..2f4db0e17 100644
--- a/src/client/util/Import & Export/ImageUtils.ts
+++ b/src/client/util/Import & Export/ImageUtils.ts
@@ -14,9 +14,17 @@ export namespace ImageUtils {
return false;
}
const source = field.url.href;
- const response = await Networking.PostToServer("/inspectImage", { source });
- const { error, data } = response.exifData;
+ const {
+ contentSize,
+ nativeWidth,
+ nativeHeight,
+ exifData: { error, data }
+ } = await Networking.PostToServer("/inspectImage", { source });
document.exif = error || Docs.Get.DocumentHierarchyFromJson(data);
+ const proto = Doc.GetProto(document);
+ proto.nativeWidth = nativeWidth;
+ proto.nativeHeight = nativeHeight;
+ proto.contentSize = contentSize;
return data !== undefined;
};
diff --git a/src/client/util/RichTextRules.ts b/src/client/util/RichTextRules.ts
index fb22e0d18..02b7502d8 100644
--- a/src/client/util/RichTextRules.ts
+++ b/src/client/util/RichTextRules.ts
@@ -196,7 +196,7 @@ export const inpRules = {
new InputRule(
new RegExp(/%#$/),
(state, match, start, end) => {
- const target = Docs.Create.TextDocument({ _width: 75, _height: 35, backgroundColor: "yellow", annotationOn: FormattedTextBox.FocusedBox!.dataDoc, autoHeight: true, fontSize: 9, title: "inline comment" });
+ const target = Docs.Create.TextDocument({ _width: 75, _height: 35, backgroundColor: "yellow", annotationOn: FormattedTextBox.FocusedBox!.dataDoc, _autoHeight: true, fontSize: 9, title: "inline comment" });
const node = (state.doc.resolve(start) as any).nodeAfter;
const newNode = schema.nodes.dashComment.create({ docid: target[Id] });
const dashDoc = schema.nodes.dashDoc.create({ width: 75, height: 35, title: "dashDoc", docid: target[Id], float: "right" });
diff --git a/src/client/util/request-image-size.js b/src/client/util/request-image-size.js
index 27605d167..beb030635 100644
--- a/src/client/util/request-image-size.js
+++ b/src/client/util/request-image-size.js
@@ -38,7 +38,7 @@ module.exports = function requestImageSize(options) {
return reject(new HttpError(res.statusCode, res.statusMessage));
}
- let buffer = new Buffer([]);
+ let buffer = new Buffer.from([]);
let size;
let imageSizeError;
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 095b9b17c..8b0f34bdf 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -493,7 +493,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
} else {
dW && (layoutDoc._width = actualdW);
dH && (layoutDoc._height = actualdH);
- dH && layoutDoc.autoHeight && (layoutDoc.autoHeight = false);
+ dH && layoutDoc._autoHeight && (layoutDoc._autoHeight = false);
}
}
}));
diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx
index 831d9ca0b..7993e951e 100644
--- a/src/client/views/PreviewCursor.tsx
+++ b/src/client/views/PreviewCursor.tsx
@@ -42,7 +42,7 @@ export class PreviewCursor extends React.Component<{}> {
if (re.test(e.clipboardData.getData("text/plain"))) {
const url = e.clipboardData.getData("text/plain");
return PreviewCursor._addDocument(Docs.Create.WebDocument(url, {
- title: url, width: 500, height: 300,
+ title: url, _width: 500, _height: 300,
// nativeWidth: 300, nativeHeight: 472.5,
x: newPoint[0], y: newPoint[1]
}));
@@ -50,9 +50,9 @@ export class PreviewCursor extends React.Component<{}> {
// creates text document
return PreviewCursor._addLiveTextDoc(Docs.Create.TextDocument({
- width: 500,
+ _width: 500,
limitHeight: 400,
- autoHeight: true,
+ _autoHeight: true,
x: newPoint[0],
y: newPoint[1],
title: "-pasted text-"
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 372db5fee..55fba2d11 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -104,7 +104,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
componentDidMount() {
super.componentDidMount();
this._heightDisposer = reaction(() => {
- if (this.props.Document.autoHeight) {
+ if (this.props.Document._autoHeight) {
const sectionsList = Array.from(this.Sections.size ? this.Sections.values() : [this.filteredChildren]);
if (this.isStackingView) {
const res = this.props.ContentScaling() * sectionsList.reduce((maxHght, s) => {
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 249d3de68..0960b0e96 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -152,7 +152,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
}
this._createAliasSelected = false;
const key = StrCast(this.props.parent.props.Document.sectionFilter);
- const newDoc = Docs.Create.TextDocument({ _height: 18, _width: 200, documentText: "@@@" + value, title: value, autoHeight: true });
+ const newDoc = Docs.Create.TextDocument({ _height: 18, _width: 200, documentText: "@@@" + value, title: value, _autoHeight: true });
newDoc[key] = this.getValue(this.props.heading);
const maxHeading = this.props.docList.reduce((maxHeading, doc) => NumCast(doc.heading) > maxHeading ? NumCast(doc.heading) : maxHeading, 0);
const heading = maxHeading === 0 || this.props.docList.length === 0 ? 1 : maxHeading === 1 ? 2 : 3;
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 7b42c6166..e2bcbda9c 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -310,12 +310,19 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
formData.append('file', file);
const dropFileName = file ? file.name : "-empty-";
promises.push(Networking.PostFormDataToServer("/upload", formData).then(results => {
- results.map(action(({ clientAccessPath }: any) => {
- const full = { ...options, _width: 300, title: dropFileName };
+ results.map(action((result: any) => {
+ const { clientAccessPath, nativeWidth, nativeHeight, contentSize } = result;
+ const full = { ...options, width: 300, title: dropFileName };
const pathname = Utils.prepend(clientAccessPath);
Docs.Get.DocumentFromType(type, pathname, full).then(doc => {
- doc && (Doc.GetProto(doc).fileUpload = basename(pathname).replace("upload_", "").replace(/\.[a-z0-9]*$/, ""));
- doc && this.props.addDocument(doc);
+ if (doc) {
+ const proto = Doc.GetProto(doc);
+ proto.fileUpload = basename(pathname).replace("upload_", "").replace(/\.[a-z0-9]*$/, "");
+ nativeWidth && (proto["data-nativeWidth"] = nativeWidth);
+ nativeHeight && (proto["data-nativeHeight"] = nativeHeight);
+ contentSize && (proto.contentSize = contentSize);
+ this.props.addDocument(doc);
+ }
});
}));
}));
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 92317b317..6c6e6b449 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -638,7 +638,7 @@ export class CollectionTreeView extends CollectionSubView(Document) {
const detailedLayout = Docs.Create.StackingDocument([
ImageDocument(fallbackImg, { title: "activeHero" }),
MulticolumnDocument([], { title: "data", _height: 100, onChildClick: ScriptField.MakeFunction(`containingCollection.resolvedDataDoc.activeHero = copyField(this.data)`, { containingCollection: Doc.name }) }),
- TextDocument({ title: "short_description", autoHeight: true }),
+ TextDocument({ title: "short_description", _autoHeight: true }),
...["year", "company", "degrees_of_freedom"].map(key => TextDocument({ title: key, _height: 30 }))
], { _chromeStatus: "disabled", title: "detailed layout stack" });
detailedLayout.isTemplateDoc = makeTemplate(detailedLayout);
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 715094bf5..338d74ca7 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -214,7 +214,7 @@ export class CollectionView extends Touchable<FieldViewProps> {
subItems.push({
description: "Stacking (AutoHeight)", event: () => {
this.props.Document._viewType = CollectionViewType.Stacking;
- this.props.Document.autoHeight = true;
+ this.props.Document._autoHeight = true;
}, icon: "ellipsis-v"
});
subItems.push({ description: "Staff", event: () => this.props.Document._viewType = CollectionViewType.Staff, icon: "music" });
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
index 8bf56338b..09ee3255d 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
@@ -82,7 +82,7 @@ export function computePivotLayout(poolData: ObservableMap<string, any>, pivotDo
let hgt = layoutDoc._nativeWidth ? (NumCast(layoutDoc._nativeHeight) / NumCast(layoutDoc._nativeWidth)) * pivotAxisWidth : pivotAxisWidth;
if (hgt > pivotAxisWidth) {
hgt = pivotAxisWidth;
- wid = layoutDoc.nativeHeight ? (NumCast(layoutDoc._nativeWidth) / NumCast(layoutDoc._nativeHeight)) * pivotAxisWidth : pivotAxisWidth;
+ wid = layoutDoc._nativeHeight ? (NumCast(layoutDoc._nativeWidth) / NumCast(layoutDoc._nativeHeight)) * pivotAxisWidth : pivotAxisWidth;
}
docMap.set(doc, {
x: x + xCount * pivotAxisWidth * expander + (pivotAxisWidth - wid) / 2 + (val.length < numCols ? (numCols - val.length) * pivotAxisWidth / 2 : 0),
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index cd99c02fe..7aa9d4922 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -921,7 +921,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
description: "Add Note ...",
subitems: DocListCast((CurrentUserUtils.UserDocument.noteTypes as Doc).data).map((note, i) => ({
description: (i + 1) + ": " + StrCast(note.title),
- event: (args: { x: number, y: number }) => this.addLiveTextBox(Docs.Create.TextDocument({ _width: 200, _height: 100, x: this.getTransform().transformPoint(args.x, args.y)[0], y: this.getTransform().transformPoint(args.x, args.y)[1], autoHeight: true, layout: note, title: StrCast(note.title) })),
+ event: (args: { x: number, y: number }) => this.addLiveTextBox(Docs.Create.TextDocument({ _width: 200, _height: 100, x: this.getTransform().transformPoint(args.x, args.y)[0], y: this.getTransform().transformPoint(args.x, args.y)[1], _autoHeight: true, layout: note, title: StrCast(note.title) })),
icon: "eye"
})) as ContextMenuProps[],
icon: "eye"
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 0e02d1ef2..741712b6e 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -101,10 +101,10 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
});
} else if (!e.ctrlKey) {
this.props.addLiveTextDocument(
- Docs.Create.TextDocument({ _width: 200, _height: 100, x: x, y: y, autoHeight: true, title: "-typed text-" }));
+ Docs.Create.TextDocument({ _width: 200, _height: 100, x: x, y: y, _autoHeight: true, title: "-typed text-" }));
} else if (e.keyCode > 48 && e.keyCode <= 57) {
const notes = DocListCast((CurrentUserUtils.UserDocument.noteTypes as Doc).data);
- const text = Docs.Create.TextDocument({ _width: 200, _height: 100, x: x, y: y, autoHeight: true, title: "-typed text-" });
+ const text = Docs.Create.TextDocument({ _width: 200, _height: 100, x: x, y: y, _autoHeight: true, title: "-typed text-" });
text.layout = notes[(e.keyCode - 49) % notes.length];
this.props.addLiveTextDocument(text);
}
@@ -374,14 +374,14 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
return d;
});
newCollection._chromeStatus = "disabled";
- const summary = Docs.Create.TextDocument({ x: bounds.left, y: bounds.top, _width: 300, _height: 100, autoHeight: true, backgroundColor: "#e2ad32" /* yellow */, title: "-summary-" });
+ const summary = Docs.Create.TextDocument({ x: bounds.left, y: bounds.top, _width: 300, _height: 100, _autoHeight: true, backgroundColor: "#e2ad32" /* yellow */, title: "-summary-" });
Doc.GetProto(summary).summarizedDocs = new List<Doc>([newCollection]);
newCollection.x = bounds.left + bounds.width;
Doc.GetProto(newCollection).summaryDoc = summary;
Doc.GetProto(newCollection).title = ComputedField.MakeFunction(`summaryTitle(this);`);
if (e instanceof KeyboardEvent ? e.key === "s" : true) { // summary is wrapped in an expand/collapse container that also contains the summarized documents in a free form view.
const container = Docs.Create.FreeformDocument([summary, newCollection], {
- x: bounds.left, y: bounds.top, _width: 300, _height: 200, autoHeight: true,
+ x: bounds.left, y: bounds.top, _width: 300, _height: 200, _autoHeight: true,
_viewType: CollectionViewType.Stacking, _chromeStatus: "disabled", title: "-summary-"
});
Doc.GetProto(summary).maximizeLocation = "inPlace"; // or "onRight"
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 42cf7cca3..0b01e6471 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -75,12 +75,13 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
if (this.props.DataDoc === undefined && typeof Doc.LayoutField(this.props.Document) !== "string") {
// if there is no dataDoc (ie, we're not rendering a template layout), but this document has a layout document (not a layout string),
// then we render the layout document as a template and use this document as the data context for the template layout.
- return this.props.Document;
+ const proto = Doc.GetProto(this.props.Document);
+ return proto instanceof Promise ? undefined : proto;
}
- return this.props.DataDoc;
+ return this.props.DataDoc instanceof Promise ? undefined : this.props.DataDoc;
}
get layoutDoc() {
- return Doc.expandTemplateLayout(Doc.Layout(this.props.Document), this.props.Document);
+ return Doc.Layout(this.props.Document);
}
CreateBindings(): JsxBindings {
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 120bc4fd1..c8b1f9794 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -427,7 +427,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
} else {
dW && (layoutDoc._width = actualdW);
dH && (layoutDoc._height = actualdH);
- dH && layoutDoc.autoHeight && (layoutDoc.autoHeight = false);
+ dH && layoutDoc._autoHeight && (layoutDoc._autoHeight = false);
}
}
e.stopPropagation();
@@ -548,7 +548,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
fieldTemplate.backgroundColor = doc.backgroundColor;
fieldTemplate.heading = 1;
- fieldTemplate.autoHeight = true;
+ fieldTemplate._autoHeight = true;
const docTemplate = Docs.Create.FreeformDocument([fieldTemplate], { title: customName + "(" + doc.title + ")", isTemplateDoc: true, _width: _width + 20, _height: Math.max(100, _height + 45) });
@@ -621,7 +621,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
@undoBatch
@action
freezeNativeDimensions = (): void => {
- this.layoutDoc.autoHeight = this.layoutDoc.autoHeight = false;
+ this.layoutDoc._autoHeight = false;
this.layoutDoc.ignoreAspect = !this.layoutDoc.ignoreAspect;
if (!this.layoutDoc.ignoreAspect && !this.layoutDoc._nativeWidth) {
this.layoutDoc._nativeWidth = this.props.PanelWidth();
@@ -740,7 +740,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
layoutItems.push({ description: "Make View of Metadata Field", event: () => Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.DataDoc!), icon: "concierge-bell" });
}
layoutItems.push({ description: `${this.Document._chromeStatus !== "disabled" ? "Hide" : "Show"} Chrome`, event: () => this.Document._chromeStatus = (this.Document._chromeStatus !== "disabled" ? "disabled" : "enabled"), icon: "project-diagram" });
- layoutItems.push({ description: `${this.Document.autoHeight ? "Variable Height" : "Auto Height"}`, event: () => this.layoutDoc.autoHeight = !this.layoutDoc.autoHeight, icon: "plus" });
+ layoutItems.push({ description: `${this.Document._autoHeight ? "Variable Height" : "Auto Height"}`, event: () => this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight, icon: "plus" });
layoutItems.push({ description: this.Document.ignoreAspect || !this.Document._nativeWidth || !this.Document._nativeHeight ? "Freeze" : "Unfreeze", event: this.freezeNativeDimensions, icon: "snowflake" });
layoutItems.push({ description: this.Document.lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.Document.lockedPosition) ? "unlock" : "lock" });
layoutItems.push({ description: this.Document.lockedTransform ? "Unlock Transform" : "Lock Transform", event: this.toggleLockTransform, icon: BoolCast(this.Document.lockedTransform) ? "unlock" : "lock" });
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index ef92ddf2e..46000a03d 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -530,7 +530,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
);
this._heightReactionDisposer = reaction(
- () => [this.layoutDoc[WidthSym](), this.layoutDoc.autoHeight],
+ () => [this.layoutDoc[WidthSym](), this.layoutDoc._autoHeight],
() => this.tryUpdateHeight()
);
@@ -1051,12 +1051,12 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
@action
tryUpdateHeight(limitHeight?: number) {
let scrollHeight = this._ref.current?.scrollHeight;
- if (!this.layoutDoc.animateToPos && this.layoutDoc.autoHeight && scrollHeight &&
+ if (!this.layoutDoc.animateToPos && this.layoutDoc._autoHeight && scrollHeight &&
getComputedStyle(this._ref.current!.parentElement!).top === "0px") { // if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation
if (limitHeight && scrollHeight > limitHeight) {
scrollHeight = limitHeight;
this.layoutDoc.limitHeight = undefined;
- this.layoutDoc.autoHeight = false;
+ this.layoutDoc._autoHeight = false;
}
const nh = this.Document.isTemplateForField ? 0 : NumCast(this.dataDoc._nativeHeight, 0);
const dh = NumCast(this.layoutDoc._height, 0);
@@ -1084,7 +1084,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
return (
<div className={`formattedTextBox-cont`} ref={this._ref}
style={{
- height: this.layoutDoc.autoHeight ? "max-content" : undefined,
+ height: this.layoutDoc._autoHeight ? "max-content" : undefined,
background: this.props.hideOnLeave ? "rgba(0,0,0 ,0.4)" : undefined,
opacity: this.props.hideOnLeave ? (this._entered ? 1 : 0.1) : 1,
color: this.props.hideOnLeave ? "white" : "inherit",
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index b6874961e..03753e9d3 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -27,6 +27,7 @@ import { documentSchema } from '../../../new_fields/documentSchemas';
import { Id } from '../../../new_fields/FieldSymbols';
import { TraceMobx } from '../../../new_fields/util';
import { SelectionManager } from '../../util/SelectionManager';
+import { cache } from 'sharp';
const requestImageSize = require('../../util/request-image-size');
const path = require('path');
const { Howl } = require('howler');
@@ -212,33 +213,34 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
}
_curSuffix = "_m";
- _resized = "";
resize = (imgPath: string) => {
- // if (!this.dataDoc[this.props.fieldKey + "-nativeHeight"])
- // {
- requestImageSize(imgPath)
- .then((size: any) => {
+ const cachedNativeSize = {
+ width: NumCast(this.Document[this.props.fieldKey + "-nativeWidth"]),
+ height: NumCast(this.Document[this.props.fieldKey + "-nativeHeight"])
+ };
+ const cachedImgPath = this.dataDoc[this.props.fieldKey + "-imgPath"];
+ if (!cachedNativeSize.width || !cachedNativeSize.height || imgPath !== cachedImgPath) {
+ (!this.layoutDoc.isTemplateDoc || this.dataDoc !== this.layoutDoc) && requestImageSize(imgPath).then((inquiredSize: any) => {
const rotation = NumCast(this.dataDoc[this.props.fieldKey + "-rotation"]) % 180;
- const realsize = rotation === 90 || rotation === 270 ? { height: size.width, width: size.height } : size;
- const aspect = realsize.height / realsize.width;
- if (this.Document._width && (Math.abs(1 - NumCast(this.Document._height) / NumCast(this.Document._width) / (realsize.height / realsize.width)) > 0.1)) {
- setTimeout(action(() => {
- if (this.paths[NumCast(this.props.Document.curPage)] === imgPath && (!this.layoutDoc.isTemplateDoc || this.dataDoc !== this.layoutDoc)) {
- this._resized = imgPath;
- this.Document._height = this.Document[WidthSym]() * aspect;
- this.dataDoc[this.props.fieldKey + "-nativeHeight"] = this.Document._nativeHeight = realsize.height;
- this.dataDoc[this.props.fieldKey + "-nativeWidth"] = this.Document._nativeWidth = realsize.width;
- }
- }), 0);
- } else this._resized = imgPath;
+ const rotatedNativeSize = rotation === 90 || rotation === 270 ? { height: inquiredSize.width, width: inquiredSize.height } : inquiredSize;
+ const rotatedAspect = rotatedNativeSize.height / rotatedNativeSize.width;
+ const docAspect = this.Document[HeightSym]() / this.Document[WidthSym]();
+ setTimeout(action(() => {
+ if (this.Document[WidthSym]() && (!cachedNativeSize.width || !cachedNativeSize.height || Math.abs(1 - docAspect / rotatedAspect) > 0.1)) {
+ this.Document._height = this.Document[WidthSym]() * rotatedAspect;
+ this.dataDoc[this.props.fieldKey + "-nativeWidth"] = this.Document._nativeWidth = rotatedNativeSize.width;
+ this.dataDoc[this.props.fieldKey + "-nativeHeight"] = this.Document._nativeHeight = rotatedNativeSize.height;
+ }
+ this.dataDoc[this.props.fieldKey + "-imgPath"] = imgPath;
+ }), 0);
})
- .catch((err: any) => console.log(err));
- // } else {
- // setTimeout(() => {
- // this.Document._nativeHeight = NumCast(this.dataDoc[this.props.fieldKey + "-nativeHeight"]);
- // this.Document._nativeWidth = NumCast(this.dataDoc[this.props.fieldKey + "-nativeWidth"]);
- // }, 0);
- // }
+ .catch((err: any) => console.log(err));
+ } else if (this.Document._nativeHeight !== cachedNativeSize.width || this.Document._nativeWidth !== cachedNativeSize.height) {
+ setTimeout(() => {
+ this.Document._nativeWidth = cachedNativeSize.width;
+ this.Document._nativeHeight = cachedNativeSize.height;
+ }, 0);
+ }
}
@action
@@ -309,7 +311,7 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
const aspect = (rotation % 180) ? this.Document[HeightSym]() / this.Document[WidthSym]() : 1;
const shift = (rotation % 180) ? (nativeHeight - nativeWidth / aspect) / 2 : 0;
- !this.Document.ignoreAspect && this._resized !== srcpath && this.resize(srcpath);
+ !this.Document.ignoreAspect && this.resize(srcpath);
return <div className="imageBox-cont" key={this.props.Document[Id]} ref={this.createDropTarget} onContextMenu={this.specificContextMenu}>
<div className="imageBox-fader" >
diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts
index 7d093b6ea..2cedda7a6 100644
--- a/src/new_fields/util.ts
+++ b/src/new_fields/util.ts
@@ -101,7 +101,7 @@ export function makeEditable() {
}
let layoutProps = ["panX", "panY", "width", "height", "nativeWidth", "nativeHeight", "fitWidth", "fitToBox",
- "LODdisable", "dropAction", "chromeStatus", "viewType", "gridGap", "xMargin", "yMargin"];
+ "LODdisable", "dropAction", "chromeStatus", "viewType", "gridGap", "xMargin", "yMargin", "autoHeight"];
export function setter(target: any, in_prop: string | symbol | number, value: any, receiver: any): boolean {
let prop = in_prop;
if (typeof prop === "string" && prop !== "__id" && prop !== "__fields" &&
@@ -110,7 +110,7 @@ export function setter(target: any, in_prop: string | symbol | number, value: an
console.log(prop + " is deprecated - switch to _" + prop);
prop = "_" + prop;
}
- const resolvedLayout = getFieldImpl(target, getFieldImpl(target, "layoutKey", receiver), receiver); // + "-" + (prop as string).substring(1);
+ const resolvedLayout = getFieldImpl(target, getFieldImpl(target, "layoutKey", receiver), receiver);
if (resolvedLayout instanceof Doc) {
resolvedLayout[prop] = value;
return true;
@@ -127,11 +127,10 @@ export function getter(target: any, in_prop: string | symbol | number, receiver:
console.log(prop + " is deprecated - switch to _" + prop);
prop = "_" + prop;
}
- const resolvedLayout = getFieldImpl(target, getFieldImpl(target, "layoutKey", receiver), receiver); // + "-" + (prop as string).substring(1);
+ const resolvedLayout = getFieldImpl(target, getFieldImpl(target, "layoutKey", receiver), receiver);
if (resolvedLayout instanceof Doc) {
return resolvedLayout[prop];
}
- // prop = getFieldImpl(target, "layoutKey", receiver) + "-" + (prop as string).substring(1);
}
if (prop === "then") {//If we're being awaited
return undefined;
diff --git a/src/scraping/buxton/scraper.py b/src/scraping/buxton/scraper.py
index f16bbfd14..16b248ae7 100644
--- a/src/scraping/buxton/scraper.py
+++ b/src/scraping/buxton/scraper.py
@@ -161,7 +161,7 @@ def write_text_doc(content):
"__type": "date"
},
"isPrototype": True,
- "autoHeight": True,
+ "_autoHeight": True,
"page": -1,
"nativeHeight": 200,
"height": 200,
diff --git a/src/server/ApiManagers/UploadManager.ts b/src/server/ApiManagers/UploadManager.ts
index 74f45ae62..583eaa59b 100644
--- a/src/server/ApiManagers/UploadManager.ts
+++ b/src/server/ApiManagers/UploadManager.ts
@@ -169,8 +169,7 @@ export default class UploadManager extends ApiManager {
secureHandler: async ({ req, res }) => {
const { source } = req.body;
if (typeof source === "string") {
- const { serverAccessPaths } = await DashUploadUtils.UploadImage(source);
- return res.send(await DashUploadUtils.InspectImage(serverAccessPaths[SizeSuffix.Original]));
+ return res.send(await DashUploadUtils.InspectImage(source));
}
res.send({});
}
diff --git a/src/server/DashUploadUtils.ts b/src/server/DashUploadUtils.ts
index d9d985ca5..b826b4882 100644
--- a/src/server/DashUploadUtils.ts
+++ b/src/server/DashUploadUtils.ts
@@ -1,4 +1,4 @@
-import * as fs from 'fs';
+import { unlinkSync, createWriteStream, readFileSync, rename } from 'fs';
import { Utils } from '../Utils';
import * as path from 'path';
import * as sharp from 'sharp';
@@ -12,8 +12,9 @@ import { basename } from "path";
import { createIfNotExists } from './ActionUtilities';
import { ParsedPDF } from "../server/PdfTypes";
const parse = require('pdf-parse');
-import { Directory, serverPathToFile, clientPathToFile } from './ApiManagers/UploadManager';
+import { Directory, serverPathToFile, clientPathToFile, pathToDirectory } from './ApiManagers/UploadManager';
import { red } from 'colors';
+const requestImageSize = require("../client/util/request-image-size");
export enum SizeSuffix {
Small = "_s",
@@ -27,6 +28,10 @@ export function InjectSize(filename: string, size: SizeSuffix) {
return filename.substring(0, filename.length - extension.length) + size + extension;
}
+function isLocal() {
+ return /Dash-Web[\\\/]src[\\\/]server[\\\/]public[\\\/](.*)/;
+}
+
export namespace DashUploadUtils {
export interface Size {
@@ -92,12 +97,12 @@ export namespace DashUploadUtils {
}
async function UploadPdf(absolutePath: string) {
- const dataBuffer = fs.readFileSync(absolutePath);
+ const dataBuffer = readFileSync(absolutePath);
const result: ParsedPDF = await parse(dataBuffer);
const parsedName = basename(absolutePath);
await new Promise<void>((resolve, reject) => {
const textFilename = `${parsedName.substring(0, parsedName.length - 4)}.txt`;
- const writeStream = fs.createWriteStream(serverPathToFile(Directory.text, textFilename));
+ const writeStream = createWriteStream(serverPathToFile(Directory.text, textFilename));
writeStream.write(result.text, error => error ? reject(error) : resolve());
});
return MoveParsedFile(absolutePath, Directory.pdfs);
@@ -134,12 +139,13 @@ export namespace DashUploadUtils {
};
export interface InspectionResults {
- isLocal: boolean;
- stream: any;
- normalizedUrl: string;
+ source: string;
+ requestable: string;
exifData: EnrichedExifData;
- contentSize?: number;
- contentType?: string;
+ contentSize: number;
+ contentType: string;
+ nativeWidth: number;
+ nativeHeight: number;
}
export interface EnrichedExifData {
@@ -152,6 +158,12 @@ export namespace DashUploadUtils {
return Promise.all(pending);
}
+ export interface RequestedImageSize {
+ width: number;
+ height: number;
+ type: string;
+ }
+
/**
* Based on the url's classification as local or remote, gleans
* as much information as possible about the specified image
@@ -159,24 +171,28 @@ export namespace DashUploadUtils {
* @param source is the path or url to the image in question
*/
export const InspectImage = async (source: string): Promise<InspectionResults> => {
- const { isLocal, stream, normalized: normalizedUrl } = classify(source);
- const exifData = await parseExifData(source);
+ let resolvedUrl: string;
+ const matches = isLocal().exec(source);
+ if (matches === null) {
+ resolvedUrl = source;
+ } else {
+ resolvedUrl = `http://localhost:1050/${matches[1].split("\\").join("/")}`;
+ }
+ const exifData = await parseExifData(resolvedUrl);
const results = {
exifData,
- isLocal,
- stream,
- normalizedUrl
+ requestable: resolvedUrl
};
- // stop here if local, since request.head() can't handle local paths, only urls on the web
- if (isLocal) {
- return results;
- }
const { headers } = (await new Promise<any>((resolve, reject) => {
- request.head(source, (error, res) => error ? reject(error) : resolve(res));
- }));
+ request.head(resolvedUrl, (error, res) => error ? reject(error) : resolve(res));
+ }).catch(error => console.error(error)));
+ const { width: nativeWidth, height: nativeHeight }: RequestedImageSize = await requestImageSize(resolvedUrl);
return {
+ source,
contentSize: parseInt(headers[size]),
contentType: headers[type],
+ nativeWidth,
+ nativeHeight,
...results
};
};
@@ -185,22 +201,20 @@ export namespace DashUploadUtils {
return new Promise<{ clientAccessPath: Opt<string> }>(resolve => {
const filename = basename(absolutePath);
const destinationPath = serverPathToFile(destination, filename);
- fs.rename(absolutePath, destinationPath, error => {
+ rename(absolutePath, destinationPath, error => {
resolve({ clientAccessPath: error ? undefined : clientPathToFile(destination, filename) });
});
});
}
export const UploadInspectedImage = async (metadata: InspectionResults, filename?: string, format?: string, prefix = ""): Promise<ImageUploadInformation> => {
- const { isLocal, stream, normalizedUrl, contentSize, contentType, exifData } = metadata;
- const resolved = filename || generate(prefix, normalizedUrl);
- const extension = format || sanitizeExtension(normalizedUrl || resolved);
+ const { requestable, source, ...remaining } = metadata;
+ const resolved = filename || generate(prefix, requestable);
+ const extension = format || sanitizeExtension(requestable || resolved);
const information: ImageUploadInformation = {
clientAccessPath: clientPathToFile(Directory.images, resolved),
serverAccessPaths: {},
- exifData,
- contentSize,
- contentType,
+ ...remaining
};
const { pngs, jpgs } = AcceptibleMedia;
return new Promise<ImageUploadInformation>(async (resolve, reject) => {
@@ -220,32 +234,22 @@ export namespace DashUploadUtils {
await new Promise<void>(resolve => {
const filename = InjectSize(resolved, suffix);
information.serverAccessPaths[suffix] = serverPathToFile(Directory.images, filename);
- stream(normalizedUrl).pipe(resizer).pipe(fs.createWriteStream(serverPathToFile(Directory.images, filename)))
+ request(requestable).pipe(resizer).pipe(createWriteStream(serverPathToFile(Directory.images, filename)))
.on('close', resolve)
.on('error', reject);
});
}
- if (isLocal) {
- await new Promise<boolean>(resolve => {
- fs.unlink(normalizedUrl, error => resolve(error === null));
- });
+ if (isLocal().test(source)) {
+ unlinkSync(source);
}
resolve(information);
});
};
- const classify = (url: string) => {
- const isLocal = /Dash-Web(\\|\/)src(\\|\/)server(\\|\/)public(\\|\/)files/g.test(url);
- return {
- isLocal,
- stream: isLocal ? fs.createReadStream : request,
- normalized: isLocal ? path.normalize(url) : url
- };
- };
-
const parseExifData = async (source: string): Promise<EnrichedExifData> => {
+ const image = await request.get(source, { encoding: null });
return new Promise<EnrichedExifData>(resolve => {
- new ExifImage(source, (error, data) => {
+ new ExifImage({ image }, (error, data) => {
let reason: Opt<string> = undefined;
if (error) {
reason = (error as any).code;
diff --git a/src/server/RouteManager.ts b/src/server/RouteManager.ts
index 6bc75ca21..63e957cd1 100644
--- a/src/server/RouteManager.ts
+++ b/src/server/RouteManager.ts
@@ -180,7 +180,7 @@ export const STATUS = {
};
export function _error(res: Response, message: string, error?: any) {
- console.error(message);
+ console.error(message, error);
res.statusMessage = message;
res.status(STATUS.EXECUTION_ERROR).send(error);
}
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index 361cf9216..818a30e9f 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -130,7 +130,7 @@ export class CurrentUserUtils {
static setupThumbDoc(userDoc: Doc) {
if (!userDoc.thumbDoc) {
userDoc.thumbDoc = Docs.Create.LinearDocument(CurrentUserUtils.setupThumbButtons(userDoc), {
- _width: 100, _height: 50, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", title: "buttons", autoHeight: true, _yMargin: 5, isExpanded: true, backgroundColor: "white"
+ _width: 100, _height: 50, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", title: "buttons", _autoHeight: true, _yMargin: 5, isExpanded: true, backgroundColor: "white"
});
}
return userDoc.thumbDoc;
@@ -138,7 +138,7 @@ export class CurrentUserUtils {
static setupMobileDoc(userDoc: Doc) {
return userDoc.activeMoble ?? Docs.Create.MasonryDocument(CurrentUserUtils.setupMobileButtons(userDoc), {
- columnWidth: 100, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", title: "buttons", autoHeight: true, _yMargin: 5
+ columnWidth: 100, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", title: "buttons", _autoHeight: true, _yMargin: 5
});
}
@@ -146,7 +146,7 @@ export class CurrentUserUtils {
static setupToolsPanel(sidebarContainer: Doc, doc: Doc) {
// setup a masonry view of all he creators
const dragCreators = Docs.Create.MasonryDocument(CurrentUserUtils.setupCreatorButtons(doc), {
- _width: 500, autoHeight: true, columnWidth: 35, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", title: "buttons",
+ _width: 500, _autoHeight: true, columnWidth: 35, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", title: "buttons",
dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), _yMargin: 5
});
// setup a color picker