aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/views/MainOverlayTextBox.tsx6
-rw-r--r--src/client/views/MetadataEntryMenu.tsx2
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx2
-rw-r--r--src/client/views/collections/CollectionSchemaCells.tsx3
-rw-r--r--src/client/views/collections/CollectionStackingView.scss1
-rw-r--r--src/client/views/collections/CollectionStackingViewFieldColumn.tsx4
-rw-r--r--src/client/views/nodes/DocumentView.tsx16
-rw-r--r--src/client/views/nodes/FieldView.tsx2
-rw-r--r--src/client/views/nodes/FormattedTextBox.tsx4
-rw-r--r--src/client/views/nodes/ImageBox.tsx8
-rw-r--r--src/client/views/nodes/KeyValueBox.tsx2
-rw-r--r--src/client/views/nodes/KeyValuePair.tsx8
-rw-r--r--src/client/views/nodes/PDFBox.tsx14
-rw-r--r--src/new_fields/Doc.ts3
-rw-r--r--src/server/index.ts18
15 files changed, 60 insertions, 33 deletions
diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx
index 126efd11c..8e2d7be85 100644
--- a/src/client/views/MainOverlayTextBox.tsx
+++ b/src/client/views/MainOverlayTextBox.tsx
@@ -4,7 +4,7 @@ import "normalize.css";
import * as React from 'react';
import { Doc } from '../../new_fields/Doc';
import { BoolCast } from '../../new_fields/Types';
-import { emptyFunction, returnTrue, returnZero, Utils } from '../../Utils';
+import { emptyFunction, returnTrue, returnZero, Utils, returnOne } from '../../Utils';
import { DragManager } from '../util/DragManager';
import { Transform } from '../util/Transform';
import { CollectionDockingView } from './collections/CollectionDockingView';
@@ -29,6 +29,7 @@ export class MainOverlayTextBox extends React.Component<MainOverlayTextBoxProps>
private _outerdiv: HTMLElement | null = null;
private _textBox: FormattedTextBox | undefined;
private _tooltip?: HTMLElement;
+ ChromeHeight?: () => number;
@observable public TextDoc?: Doc;
@observable public TextDataDoc?: Doc;
@@ -49,6 +50,7 @@ export class MainOverlayTextBox extends React.Component<MainOverlayTextBoxProps>
(box?: FormattedTextBox) => {
this._textBox = box;
if (box) {
+ this.ChromeHeight = box.props.ChromeHeight;
this.TextDoc = box.props.Document;
this.TextDataDoc = box.props.DataDoc;
let xf = () => {
@@ -140,7 +142,7 @@ export class MainOverlayTextBox extends React.Component<MainOverlayTextBoxProps>
Document={FormattedTextBox.InputBoxOverlay.props.Document}
DataDoc={FormattedTextBox.InputBoxOverlay.props.DataDoc}
isSelected={returnTrue} select={emptyFunction} renderDepth={0} selectOnLoad={true}
- ContainingCollectionView={undefined} whenActiveChanged={emptyFunction} active={returnTrue}
+ ContainingCollectionView={undefined} whenActiveChanged={emptyFunction} active={returnTrue} ContentScaling={returnOne}
ScreenToLocalTransform={this._textXf} PanelWidth={returnZero} PanelHeight={returnZero} focus={emptyFunction} addDocTab={this.addDocTab} outer_div={(tooltip: HTMLElement) => { this._tooltip = tooltip; this.updateTooltip(); }} />
</div>
</div>
diff --git a/src/client/views/MetadataEntryMenu.tsx b/src/client/views/MetadataEntryMenu.tsx
index 652e0e91a..36c240dd8 100644
--- a/src/client/views/MetadataEntryMenu.tsx
+++ b/src/client/views/MetadataEntryMenu.tsx
@@ -5,6 +5,7 @@ import { observable, action, runInAction, trace } from 'mobx';
import { KeyValueBox } from './nodes/KeyValueBox';
import { Doc, Field } from '../../new_fields/Doc';
import * as Autosuggest from 'react-autosuggest';
+import { undoBatch } from '../util/UndoManager';
export type DocLike = Doc | Doc[] | Promise<Doc> | Promise<Doc[]>;
export interface MetadataEntryProps {
@@ -74,6 +75,7 @@ export class MetadataEntryMenu extends React.Component<MetadataEntryProps>{
this.userModified = e.target.value.trim() !== "";
}
+ @undoBatch
@action
onValueKeyDown = async (e: React.KeyboardEvent) => {
if (e.key === "Enter") {
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 1859ebee7..d7b5262b1 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -561,7 +561,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
}
return Transform.Identity();
}
- get previewPanelCenteringOffset() { return this.nativeWidth && !BoolCast(this._document!.ignoreAspect) ? (this._panelWidth - this.nativeWidth() * this.contentScaling()) / 2 : 0; }
+ get previewPanelCenteringOffset() { return this.nativeWidth && !BoolCast(this._document!.ignoreAspect) ? (this._panelWidth - this.nativeWidth()) / 2 : 0; }
addDocTab = (doc: Doc, dataDoc: Doc | undefined, location: string) => {
if (doc.dockingConfig) {
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index 194765880..fdf0896ac 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -115,7 +115,7 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
}
}
- private dropRef = (ele: HTMLElement) => {
+ private dropRef = (ele: HTMLElement | null) => {
this._dropDisposer && this._dropDisposer();
if (ele) {
this._dropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.drop.bind(this) } });
@@ -154,6 +154,7 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
PanelHeight: returnZero,
PanelWidth: returnZero,
addDocTab: this.props.addDocTab,
+ ContentScaling: returnOne
};
let field = props.Document[props.fieldKey];
diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss
index 004b57eff..2bb36c825 100644
--- a/src/client/views/collections/CollectionStackingView.scss
+++ b/src/client/views/collections/CollectionStackingView.scss
@@ -74,6 +74,7 @@
transform-origin: top left;
grid-column-end: span 1;
height: 100%;
+ margin: auto;
}
.collectionStackingView-sectionHeader {
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 71c4d9f0c..b5dbc1a22 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -239,7 +239,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
};
let headingView = this.props.headingObject ?
<div key={heading} className="collectionStackingView-sectionHeader" ref={this._headerRef}
- style={{ width: (style.columnWidth) / (uniqueHeadings.length + (this.props.parent.props.CollectionView.props.Document.chromeStatus !== 'disabled' ? 1 : 0)) }}>
+ style={{ width: (style.columnWidth) / ((uniqueHeadings.length + (this.props.parent.props.CollectionView.props.Document.chromeStatus !== 'disabled' ? 1 : 0)) || 1) }}>
{/* the default bucket (no key value) has a tooltip that describes what it is.
Further, it does not have a color and cannot be deleted. */}
<div className="collectionStackingView-sectionHeader-subCont" onPointerDown={this.headerDown}
@@ -261,7 +261,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
</div> : (null);
for (let i = 0; i < cols; i++) templatecols += `${style.columnWidth}px `;
return (
- <div key={heading} style={{ width: `${100 / (uniqueHeadings.length + (this.props.parent.props.CollectionView.props.Document.chromeStatus !== 'disabled' ? 1 : 0))}%`, background: this._background }}
+ <div key={heading} style={{ width: `${100 / ((uniqueHeadings.length + (this.props.parent.props.CollectionView.props.Document.chromeStatus !== 'disabled' ? 1 : 0)) || 1)}%`, background: this._background }}
ref={this.createColumnDropRef} onPointerEnter={this.pointerEntered} onPointerLeave={this.pointerLeave}>
{headingView}
<div key={`${heading}-stack`} className={`collectionStackingView-masonry${singleColumn ? "Single" : "Grid"}`}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index f101222ae..9f0945c6b 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -99,6 +99,7 @@ export interface DocumentViewProps {
zoomToScale: (scale: number) => void;
getScale: () => number;
animateBetweenIcon?: (iconPos: number[], startTime: number, maximizing: boolean) => void;
+ ChromeHeight?: () => number;
}
const schema = createSchema({
@@ -644,6 +645,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
@computed get nativeHeight() { return this.Document.nativeHeight || 0; }
@computed get contents() {
return (<DocumentContentsView {...this.props}
+ ChromeHeight={this.chromeHeight}
isSelected={this.isSelected} select={this.select}
selectOnLoad={this.props.selectOnLoad}
layoutKey={"layout"}
@@ -651,6 +653,12 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
DataDoc={this.dataDoc} />);
}
+ chromeHeight = () => {
+ let showOverlays = this.props.showOverlays ? this.props.showOverlays(this.layoutDoc) : undefined;
+ let showTitle = showOverlays && "title" in showOverlays ? showOverlays.title : StrCast(this.layoutDoc.showTitle);
+ return showTitle ? 25 : 0;
+ }
+
get layoutDoc() {
// if this document's layout field contains a document (ie, a rendering template), then we will use that
// to determine the render JSX string, otherwise the layout field should directly contain a JSX layout string.
@@ -666,8 +674,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
var nativeWidth = this.nativeWidth > 0 && !BoolCast(this.props.Document.ignoreAspect) ? `${this.nativeWidth}px` : "100%";
var nativeHeight = BoolCast(this.props.Document.ignoreAspect) ? this.props.PanelHeight() / this.props.ContentScaling() : this.nativeHeight > 0 ? `${this.nativeHeight}px` : "100%";
let showOverlays = this.props.showOverlays ? this.props.showOverlays(this.layoutDoc) : undefined;
- let showTitle = showOverlays && showOverlays.title !== "undefined" ? showOverlays.title : StrCast(this.layoutDoc.showTitle);
- let showCaption = showOverlays && showOverlays.caption !== "undefined" ? showOverlays.caption : StrCast(this.layoutDoc.showCaption);
+ let showTitle = showOverlays && "title" in showOverlays ? showOverlays.title : StrCast(this.layoutDoc.showTitle);
+ let showCaption = showOverlays && "caption" in showOverlays ? showOverlays.caption : StrCast(this.layoutDoc.showCaption);
let templates = Cast(this.layoutDoc.templates, listSpec("string"));
if (!showOverlays && templates instanceof List) {
templates.map(str => {
@@ -716,11 +724,11 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
transformOrigin: "top left", transform: `scale(${1 / this.props.ContentScaling()})`
}}>
<EditableView
- contents={this.layoutDoc[showTitle]}
+ contents={(this.layoutDoc.isTemplate || !this.dataDoc ? this.layoutDoc : this.dataDoc)[showTitle]}
display={"block"}
height={72}
fontSize={12}
- GetValue={() => StrCast(this.layoutDoc[showTitle!])}
+ GetValue={() => StrCast((this.layoutDoc.isTemplate || !this.dataDoc ? this.layoutDoc : this.dataDoc)[showTitle!])}
SetValue={(value: string) => (Doc.GetProto(this.layoutDoc)[showTitle!] = value) ? true : true}
/>
</div>
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index ffaee8042..da54ecc3a 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -48,6 +48,8 @@ export interface FieldViewProps {
PanelHeight: () => number;
setVideoBox?: (player: VideoBox) => void;
setPdfBox?: (player: PDFBox) => void;
+ ContentScaling: () => number;
+ ChromeHeight?: () => number;
}
@observer
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index f019868aa..0f51ca2ce 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -35,6 +35,7 @@ import "./FormattedTextBox.scss";
import React = require("react");
import { DateField } from '../../../new_fields/DateField';
import { Utils } from '../../../Utils';
+import { MainOverlayTextBox } from '../MainOverlayTextBox';
library.add(faEdit);
library.add(faSmile, faTextHeight);
@@ -557,7 +558,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
let nh = NumCast(this.dataDoc.nativeHeight, 0);
let dh = NumCast(this.props.Document.height, 0);
let sh = scrBounds.height;
- this.props.Document.height = nh ? dh / nh * sh : sh;
+ const ChromeHeight = MainOverlayTextBox.Instance.ChromeHeight;
+ this.props.Document.height = (nh ? dh / nh * sh : sh) + (ChromeHeight ? ChromeHeight() : 0);
this.dataDoc.nativeHeight = nh ? sh : undefined;
}
}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 29a76b0c8..d4e0eaf98 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -96,7 +96,11 @@ export class ImageBox extends DocComponent<FieldViewProps, ImageDocument>(ImageD
this.props.Document.width = drop.width;
this.props.Document.height = drop.height;
Doc.GetProto(this.props.Document).type = DocumentType.TEMPLATE;
- this.props.Document.layout = temp;
+ if (this.props.DataDoc && this.props.DataDoc.layout === this.props.Document) {
+ this.props.DataDoc.layout = temp;
+ } else {
+ this.props.Document.layout = temp;
+ }
e.stopPropagation();
} else if (de.mods === "AltKey" && /*this.dataDoc !== this.props.Document &&*/ drop.data instanceof ImageField) {
Doc.GetProto(this.dataDoc)[this.props.fieldKey] = new ImageField(drop.data.url);
@@ -287,7 +291,7 @@ export class ImageBox extends DocComponent<FieldViewProps, ImageDocument>(ImageD
let aspect = size.height / size.width;
let rotation = NumCast(this.dataDoc.rotation) % 180;
if (rotation === 90 || rotation === 270) aspect = 1 / aspect;
- if (Math.abs(layoutdoc[HeightSym]() / layoutdoc[WidthSym]() - aspect) > 0.01) {
+ if (Math.abs(NumCast(layoutdoc.height) - size.height) > 1 || Math.abs(NumCast(layoutdoc.width) - size.width) > 1) {
setTimeout(action(() => {
layoutdoc.height = layoutdoc[WidthSym]() * aspect;
layoutdoc.nativeHeight = size.height;
diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index e8075d076..f10079169 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -21,6 +21,7 @@ import { ImageField } from "../../../new_fields/URLField";
import { SelectionManager } from "../../util/SelectionManager";
import { listSpec } from "../../../new_fields/Schema";
import { CollectionViewType } from "../collections/CollectionBaseView";
+import { undoBatch } from "../../util/UndoManager";
export type KVPScript = {
script: CompiledScript;
@@ -90,6 +91,7 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
return false;
}
+ @undoBatch
public static SetField(doc: Doc, key: string, value: string) {
const script = this.CompileKVPScript(value);
if (!script) return false;
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index 064f3edcc..3775f0f47 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -1,7 +1,7 @@
import { action, observable } from 'mobx';
import { observer } from "mobx-react";
import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app
-import { emptyFunction, returnFalse, returnZero, returnTrue } from '../../../Utils';
+import { emptyFunction, returnFalse, returnZero, returnTrue, returnOne } from '../../../Utils';
import { CompileScript, CompiledScript, ScriptOptions } from "../../util/Scripting";
import { Transform } from '../../util/Transform';
import { EditableView } from "../EditableView";
@@ -16,6 +16,7 @@ import { DragManager, SetupDrag } from '../../util/DragManager';
import { ContextMenu } from '../ContextMenu';
import { Docs } from '../../documents/Documents';
import { CollectionDockingView } from '../collections/CollectionDockingView';
+import { undoBatch } from '../../util/UndoManager';
// Represents one row in a key value plane
@@ -70,6 +71,7 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
PanelWidth: returnZero,
PanelHeight: returnZero,
addDocTab: returnZero,
+ ContentScaling: returnOne
};
let contents = <FieldView {...props} />;
// let fieldKey = Object.keys(props.Document).indexOf(props.fieldKey) !== -1 ? props.fieldKey : "(" + props.fieldKey + ")";
@@ -91,12 +93,12 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
<tr className={this.props.rowStyle} onPointerEnter={action(() => this.isPointerOver = true)} onPointerLeave={action(() => this.isPointerOver = false)}>
<td className="keyValuePair-td-key" style={{ width: `${this.props.keyWidth}%` }}>
<div className="keyValuePair-td-key-container">
- <button style={hover} className="keyValuePair-td-key-delete" onClick={() => {
+ <button style={hover} className="keyValuePair-td-key-delete" onClick={undoBatch(() => {
if (Object.keys(props.Document).indexOf(props.fieldKey) !== -1) {
props.Document[props.fieldKey] = undefined;
}
else props.Document.proto![props.fieldKey] = undefined;
- }}>
+ })}>
X
</button>
<input
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 4973340df..fa072aecf 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -69,24 +69,10 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
componentDidMount() {
if (this.props.setPdfBox) this.props.setPdfBox(this);
-
- document.removeEventListener("copy", this.copy);
- document.addEventListener("copy", this.copy);
}
componentWillUnmount() {
this._reactionDisposer && this._reactionDisposer();
- document.removeEventListener("copy", this.copy);
- }
-
- private copy = (e: ClipboardEvent) => {
- if (this.props.active()) {
- if (e.clipboardData) {
- e.clipboardData.setData("text/plain", text);
- e.clipboardData.setData("dash/pdfOrigin", this.props.Document[Id]);
- e.preventDefault();
- }
- }
}
public GetPage() {
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index da4f459e2..59314783b 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -12,6 +12,7 @@ import { scriptingGlobal } from "../client/util/Scripting";
import { List } from "./List";
import { DocumentType } from "../client/documents/Documents";
import { ComputedField } from "./ScriptField";
+import { PrefetchProxy } from "./Proxy";
export namespace Field {
export function toKeyValueString(doc: Doc, key: string): string {
@@ -348,7 +349,7 @@ export namespace Doc {
while (proto && !Doc.IsPrototype(proto)) {
proto = proto.proto;
}
- (proto ? proto : doc)[fieldKey + "_ext"] = docExtensionForField;
+ (proto ? proto : doc)[fieldKey + "_ext"] = new PrefetchProxy(docExtensionForField);
}, 0);
} else if (doc instanceof Doc) { // backward compatibility -- add fields for docs that don't have them already
docExtensionForField.extendsDoc === undefined && setTimeout(() => docExtensionForField.extendsDoc = doc, 0);
diff --git a/src/server/index.ts b/src/server/index.ts
index 40c0e7981..adf218be6 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -437,8 +437,22 @@ app.post(RouteStore.forgot, postForgot);
app.get(RouteStore.reset, getReset);
app.post(RouteStore.reset, postReset);
-app.use(RouteStore.corsProxy, (req, res) =>
- req.pipe(request(decodeURIComponent(req.url.substring(1)))).pipe(res));
+const headerCharRegex = /[^\t\x20-\x7e\x80-\xff]/;
+app.use(RouteStore.corsProxy, (req, res) => {
+ req.pipe(request(decodeURIComponent(req.url.substring(1)))).on("response", res => {
+ const headers = Object.keys(res.headers);
+ headers.forEach(headerName => {
+ const header = res.headers[headerName];
+ if (Array.isArray(header)) {
+ res.headers[headerName] = header.filter(h => !headerCharRegex.test(h));
+ } else if (header) {
+ if (headerCharRegex.test(header as any)) {
+ delete res.headers[headerName];
+ }
+ }
+ });
+ }).pipe(res);
+});
app.get(RouteStore.delete, (req, res) => {
if (release) {