aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/documents/Documents.ts6
-rw-r--r--src/client/views/MainOverlayTextBox.tsx7
-rw-r--r--src/client/views/Templates.tsx4
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx125
-rw-r--r--src/client/views/collections/CollectionSubView.tsx2
-rw-r--r--src/client/views/nodes/CollectionFreeFormDocumentView.tsx6
-rw-r--r--src/client/views/nodes/DocumentContentsView.tsx1
-rw-r--r--src/client/views/nodes/DocumentView.tsx5
-rw-r--r--src/client/views/nodes/FormattedTextBox.tsx21
9 files changed, 107 insertions, 70 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 4bc0df31f..9bf62196f 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -26,7 +26,7 @@ import { OmitKeys } from "../../Utils";
import { ImageField, VideoField, AudioField, PdfField, WebField } from "../../new_fields/URLField";
import { HtmlField } from "../../new_fields/HtmlField";
import { List } from "../../new_fields/List";
-import { Cast } from "../../new_fields/Types";
+import { Cast, NumCast } from "../../new_fields/Types";
import { IconField } from "../../new_fields/IconField";
import { listSpec } from "../../new_fields/Schema";
import { DocServer } from "../DocServer";
@@ -221,10 +221,12 @@ export namespace Docs {
let inst = CreateInstance(imageProto, new ImageField(new URL(url)), options);
requestImageSize(window.origin + RouteStore.corsProxy + "/" + url)
.then((size: any) => {
+ let aspect = size.height / size.width;
if (!inst.proto!.nativeWidth) {
inst.proto!.nativeWidth = size.width;
}
- inst.proto!.nativeHeight = Number(inst.proto!.nativeWidth!) * size.height / size.width;
+ inst.proto!.nativeHeight = Number(inst.proto!.nativeWidth!) * aspect;
+ inst.proto!.height = NumCast(inst.proto!.width) * aspect;
})
.catch((err: any) => console.log(err));
return inst;
diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx
index 9be408049..6e8e6f8ce 100644
--- a/src/client/views/MainOverlayTextBox.tsx
+++ b/src/client/views/MainOverlayTextBox.tsx
@@ -17,6 +17,7 @@ export class MainOverlayTextBox extends React.Component<MainOverlayTextBoxProps>
@observable _textXf: () => Transform = () => Transform.Identity();
private _textFieldKey: string = "data";
private _textColor: string | null = null;
+ private _textHideOnLeave?: boolean;
private _textTargetDiv: HTMLDivElement | undefined;
private _textProxyDiv: React.RefObject<HTMLDivElement>;
@@ -39,9 +40,9 @@ export class MainOverlayTextBox extends React.Component<MainOverlayTextBoxProps>
this._textFieldKey = textFieldKey!;
this._textXf = tx ? tx : () => Transform.Identity();
this._textTargetDiv = div;
+ this._textHideOnLeave = FormattedTextBox.InputBoxOverlay && FormattedTextBox.InputBoxOverlay.props.hideOnLeave;
if (div) {
- if (div.parentElement && div.parentElement instanceof HTMLDivElement && div.parentElement.id === "screenSpace") this._textXf = () => Transform.Identity();
- this._textColor = div.style.color;
+ this._textColor = (getComputedStyle(div) as any).color;
div.style.color = "transparent";
}
}
@@ -88,7 +89,7 @@ export class MainOverlayTextBox extends React.Component<MainOverlayTextBoxProps>
return <div className="mainOverlayTextBox-textInput" style={{ transform: `translate(${textRect.left}px, ${textRect.top}px) scale(${1 / s},${1 / s})`, width: "auto", height: "auto" }} >
<div className="mainOverlayTextBox-textInput" onPointerDown={this.textBoxDown} ref={this._textProxyDiv} onScroll={this.textScroll}
style={{ width: `${textRect.width * s}px`, height: `${textRect.height * s}px` }}>
- <FormattedTextBox fieldKey={this._textFieldKey} isOverlay={true} Document={FormattedTextBox.InputBoxOverlay.props.Document} isSelected={returnTrue} select={emptyFunction} isTopMost={true}
+ <FormattedTextBox fieldKey={this._textFieldKey} hideOnLeave={this._textHideOnLeave} isOverlay={true} Document={FormattedTextBox.InputBoxOverlay.props.Document} isSelected={returnTrue} select={emptyFunction} isTopMost={true}
selectOnLoad={true} ContainingCollectionView={undefined} whenActiveChanged={emptyFunction} active={returnTrue}
ScreenToLocalTransform={this._textXf} PanelWidth={returnZero} PanelHeight={returnZero} focus={emptyFunction} addDocTab={emptyFunction} />
</div>
diff --git a/src/client/views/Templates.tsx b/src/client/views/Templates.tsx
index 303f3f3b8..0cd367bcb 100644
--- a/src/client/views/Templates.tsx
+++ b/src/client/views/Templates.tsx
@@ -42,8 +42,8 @@ export namespace Templates {
export const Caption = new Template("Caption", TemplatePosition.OutterBottom,
`<div>
<div style="height:100%; width:100%;position:absolute;">{layout}</div>
- <div id="screenSpace" style="top: 100%; font-size:14px; background:yellow; width:100%; position:absolute">
- <FormattedTextBox {...props} fieldKey={"caption"} />
+ <div style="bottom: 0; font-size:14px; width:100%; position:absolute">
+ <FormattedTextBox {...props} fieldKey={"caption"} hideOnLeave={"true"} />
</div>
</div>` );
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index a29648d5b..425eecebb 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -4,9 +4,9 @@ import { CollectionSubView, CollectionViewProps, SubCollectionViewProps } from "
import { Doc, WidthSym, HeightSym, DocListCast } from "../../../new_fields/Doc";
import { DocumentView } from "../nodes/DocumentView";
import { Transform } from "../../util/Transform";
-import { emptyFunction, returnOne } from "../../../Utils";
+import { emptyFunction, returnOne, Utils } from "../../../Utils";
import "./CollectionStackingView.scss";
-import { action, reaction } from "mobx";
+import { action, reaction, trace, computed } from "mobx";
import { StrCast, NumCast } from "../../../new_fields/Types";
import { Id } from "../../../new_fields/FieldSymbols";
@@ -14,20 +14,13 @@ import { Id } from "../../../new_fields/FieldSymbols";
@observer
export class CollectionStackingView extends CollectionSubView(doc => doc) {
- getPreviewTransform = (): Transform => this.props.ScreenToLocalTransform();
+
+ get gridGap() { return 10; }
+ get gridSize() { return 20; }
+ get itemWidth() { return NumCast(this.props.Document.itemWidth, 250); }
constructor(props: SubCollectionViewProps) {
super(props);
- // reaction(() => [this.props.PanelHeight() + this.props.PanelWidth(),
- // (this.props.ContainingCollectionView && this.props.ContainingCollectionView.props.Document[this.props.ContainingCollectionView.props.fieldKey])], () => {
- // if (this.props.ContainingCollectionView) {
- // let allItems = DocListCast(this.props.ContainingCollectionView.props.Document[this.props.ContainingCollectionView.props.fieldKey]);
- // for (let x = 0; x < allItems.length; x++) {
- // resizeGridItem(allItems[x]);
- // }
- // }
- // }
- // );
}
@action
@@ -36,57 +29,79 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
addDocument(doc);
return true;
}
+ getDocTransform(doc: Doc, dref: HTMLDivElement) {
+ let { scale, translateX, translateY } = Utils.GetScreenTransform(dref);
+ let outerXf = Utils.GetScreenTransform(this.masonryGridRef!);
+ let offset = this.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY);
+ return this.props.ScreenToLocalTransform().translate(offset[0], offset[1]).scale(NumCast(doc.width, 1) / this.itemWidth);
+ }
+ masonryGridRef: HTMLDivElement | null = null;
+ createRef = (ele: HTMLDivElement | null) => {
+ this.masonryGridRef = ele;
+ this.createDropTarget(ele!);
+ }
+ @computed
+ get children() {
+ return this.childDocs.map(d => {
+ let colSpan = Math.ceil((this.itemWidth + this.gridGap) / (this.gridSize + this.gridGap));
+ let rowSpan = Math.ceil((this.itemWidth / d[WidthSym]() * d[HeightSym]() + this.gridGap) / (this.gridSize + this.gridGap));
+ let dref = React.createRef<HTMLDivElement>();
+ let dxf = () => this.getDocTransform(d, dref.current!);
+ return (<div className="colletionStackingView-masonryDoc"
+ key={d[Id]}
+ ref={dref}
+ style={{
+ transformOrigin: "top left",
+ gridRowEnd: `span ${rowSpan}`,
+ gridColumnEnd: `span ${colSpan}`,
+ transform: `scale(${this.itemWidth / NumCast(d.nativeWidth, 1)}, ${this.itemWidth / NumCast(d.nativeWidth, 1)})`
+ }} >
+ <DocumentView key={d[Id]} Document={d}
+ addDocument={this.props.addDocument}
+ removeDocument={this.props.removeDocument}
+ moveDocument={this.moveDocument}
+ ContainingCollectionView={this.props.CollectionView}
+ isTopMost={false}
+ ScreenToLocalTransform={dxf}
+ focus={emptyFunction}
+ ContentScaling={returnOne}
+ PanelWidth={d[WidthSym]}
+ PanelHeight={d[HeightSym]}
+ selectOnLoad={false}
+ parentActive={this.props.active}
+ addDocTab={this.props.addDocTab}
+ bringToFront={emptyFunction}
+ toggleMinimized={emptyFunction}
+ whenActiveChanged={this.props.whenActiveChanged} />
+ </div>);
+ })
+ }
+ onClick = (e: React.MouseEvent) => {
+ if (this.props.active()) {
+ let rect = (this.masonryGridRef!.firstChild! as HTMLElement).getBoundingClientRect();
+ if (e.clientX < rect.left || e.clientX > rect.right || e.clientY > rect.bottom) this.props.select(false);
+ e.stopPropagation();
+ }
+ }
render() {
- const docs = this.childDocs;
- let gridGap = 10;
- let gridSize = 20;
- let itemWidth = NumCast(this.props.Document.itemWidth, 250);
let leftMargin = 20;
let topMargin = 20;
- let itemCols = Math.ceil(itemWidth / (gridSize + gridGap));
- let cells = Math.floor((this.props.PanelWidth() - leftMargin) / (itemCols * (gridSize + gridGap)));
+ let itemCols = Math.ceil(this.itemWidth / (this.gridSize + this.gridGap));
+ let cells = Math.floor((this.props.PanelWidth() - leftMargin) / (itemCols * (this.gridSize + this.gridGap)));
return (
- <div className="collectionStackingView" ref={this.createDropTarget} onWheel={(e: React.WheelEvent) => e.stopPropagation()}>
+ <div className="collectionStackingView" ref={this.createRef} onClick={this.onClick} onWheel={(e: React.WheelEvent) => e.stopPropagation()}>
<div className="collectionStackingview-masonryGrid"
style={{
padding: `${topMargin}px 0px 0px ${leftMargin}px`,
- width: `${cells * itemCols * (gridSize + gridGap) + leftMargin}`,
- margin: "auto", position: "relative",
- gridGap: gridGap,
- gridTemplateColumns: `repeat(auto-fill, minmax(${gridSize}px,1fr))`,
- gridAutoRows: `${gridSize}px`
+ width: `${cells * itemCols * (this.gridSize + this.gridGap) + leftMargin}`,
+ height: "auto",
+ marginLeft: "auto", marginRight: "auto", position: "relative",
+ gridGap: this.gridGap,
+ gridTemplateColumns: `repeat(auto-fill, minmax(${this.gridSize}px,1fr))`,
+ gridAutoRows: `${this.gridSize}px`
}}
>
- {docs.map(d => {
- let colSpan = Math.ceil((itemWidth + gridGap) / (gridSize + gridGap));
- let rowSpan = Math.ceil((itemWidth / d[WidthSym]() * d[HeightSym]() + gridGap) / (gridSize + gridGap));
- return (<div className="mycontent" id={StrCast(d.title, "")}
- key={d[Id]}
- style={{
- transformOrigin: "top left",
- gridRowEnd: `span ${rowSpan}`,
- gridColumnEnd: `span ${colSpan}`,
- transform: `scale(${itemWidth / NumCast(d.nativeWidth, 1)}, ${itemWidth / NumCast(d.nativeWidth, 1)})`
- }} >
- <DocumentView Document={d}
- addDocument={this.props.addDocument}
- removeDocument={this.props.removeDocument}
- moveDocument={this.moveDocument}
- ContainingCollectionView={this.props.CollectionView}
- isTopMost={false}
- ScreenToLocalTransform={this.getPreviewTransform}
- focus={emptyFunction}
- ContentScaling={returnOne}
- PanelWidth={d[WidthSym]}
- PanelHeight={d[HeightSym]}
- selectOnLoad={false}
- parentActive={this.props.active}
- addDocTab={this.props.addDocTab}
- bringToFront={emptyFunction}
- toggleMinimized={emptyFunction}
- whenActiveChanged={this.props.active} />
- </div>);
- })}
+ {this.children}
</div>
</div>
);
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index c4e72b23a..fe9e12640 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -212,7 +212,7 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
}).then(async (res: Response) => {
(await res.json()).map(action((file: any) => {
let path = window.location.origin + file;
- let docPromise = this.getDocumentFromType(type, path, { ...options, nativeWidth: 600, width: 300, title: dropFileName });
+ let docPromise = this.getDocumentFromType(type, path, { ...options, nativeWidth: 300, width: 300, title: dropFileName });
docPromise.then(doc => doc && this.props.addDocument(doc));
}));
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 66d91f9c2..04e0a91f8 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -256,9 +256,6 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
}
}
- onPointerEnter = (e: React.PointerEvent): void => { this.props.Document.libraryBrush = true; };
- onPointerLeave = (e: React.PointerEvent): void => { this.props.Document.libraryBrush = false; };
-
borderRounding = () => {
let br = NumCast(this.props.Document.borderRounding);
return br >= 0 ? br :
@@ -283,8 +280,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
return (
<div className="collectionFreeFormDocumentView-container" ref={this._mainCont}
- onPointerDown={this.onPointerDown}
- onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave} onPointerOver={this.onPointerEnter}
+ onPointerDown={this.onPointerDown} onPointerOver={this.onPointerEnter}
onClick={this.onClick}
style={{
outlineColor: "maroon",
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 52a9582d2..02396c3af 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -44,6 +44,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
isSelected: () => boolean,
select: (ctrl: boolean) => void,
layoutKey: string,
+ hideOnLeave?: boolean
}> {
@computed get layout(): string {
const layout = Cast(this.props.Document[this.props.layoutKey], "string");
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 01c4d82fb..ed5862660 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -343,6 +343,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
}
}
+ onPointerEnter = (e: React.PointerEvent): void => { this.props.Document.libraryBrush = true; };
+ onPointerLeave = (e: React.PointerEvent): void => { this.props.Document.libraryBrush = false; };
+
isSelected = () => SelectionManager.IsSelected(this);
select = (ctrlPressed: boolean) => SelectionManager.SelectDoc(this, ctrlPressed);
@@ -366,6 +369,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
transform: `scale(${scaling}, ${scaling})`
}}
onDrop={this.onDrop} onContextMenu={this.onContextMenu} onPointerDown={this.onPointerDown} onClick={this.onClick}
+
+ onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave}
>
{this.contents}
</div>
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 5afef221c..5b74c2e7e 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -50,8 +50,9 @@ library.add(faSmile);
// this will edit the document and assign the new value to that field.
//]
-export interface FormattedTextBoxOverlay {
+export interface FormattedTextBoxProps {
isOverlay?: boolean;
+ hideOnLeave?: boolean;
}
const richTextSchema = createSchema({
@@ -62,7 +63,7 @@ type RichTextDocument = makeInterface<[typeof richTextSchema]>;
const RichTextDocument = makeInterface(richTextSchema);
@observer
-export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTextBoxOverlay), RichTextDocument>(RichTextDocument) {
+export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTextBoxProps), RichTextDocument>(RichTextDocument) {
public static LayoutString(fieldStr: string = "data") {
return FieldView.LayoutString(FormattedTextBox, fieldStr);
}
@@ -357,6 +358,17 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
this._undoTyping = UndoManager.StartBatch("undoTyping");
}
}
+
+ @observable
+ _entered = false;
+ @action
+ onPointerEnter = (e: React.PointerEvent) => {
+ this._entered = true;
+ }
+ @action
+ onPointerLeave = (e: React.PointerEvent) => {
+ this._entered = false;
+ }
render() {
let style = this.props.isOverlay ? "scroll" : "hidden";
let rounded = NumCast(this.props.Document.borderRounding) < 0 ? "-rounded" : "";
@@ -364,6 +376,9 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
return (
<div className={`formattedTextBox-cont-${style}`} ref={this._ref}
style={{
+ background: this.props.hideOnLeave ? "rgba(0,0,0,0.4)" : undefined,
+ opacity: this.props.hideOnLeave ? (this._entered || this.props.isSelected() || this.props.Document.libraryBrush ? 1 : 0.1) : 1,
+ color: this.props.hideOnLeave ? "white" : "initial",
pointerEvents: interactive ? "all" : "none",
}}
// onKeyDown={this.onKeyPress}
@@ -377,6 +392,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
onContextMenu={this.specificContextMenu}
// tfs: do we need this event handler
onWheel={this.onPointerWheel}
+ onPointerEnter={this.onPointerEnter}
+ onPointerLeave={this.onPointerLeave}
>
<div className={`formattedTextBox-inner${rounded}`} style={{ whiteSpace: "pre-wrap", pointerEvents: this.props.Document.isButton && !this.props.isSelected() ? "none" : "all" }} ref={this._proseRef} />
</div>