aboutsummaryrefslogtreecommitdiff
path: root/src/client/views
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views')
-rw-r--r--src/client/views/DocComponent.tsx5
-rw-r--r--src/client/views/DocumentButtonBar.tsx4
-rw-r--r--src/client/views/DocumentDecorations.scss12
-rw-r--r--src/client/views/DocumentDecorations.tsx33
-rw-r--r--src/client/views/MainView.tsx1
-rw-r--r--src/client/views/ScriptBox.tsx46
-rw-r--r--src/client/views/TemplateMenu.tsx12
-rw-r--r--src/client/views/collections/CollectionCarouselView.scss20
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx53
-rw-r--r--src/client/views/collections/CollectionStackingViewFieldColumn.tsx6
-rw-r--r--src/client/views/collections/CollectionSubView.tsx14
-rw-r--r--src/client/views/collections/CollectionTimeView.scss18
-rw-r--r--src/client/views/collections/CollectionTimeView.tsx113
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx29
-rw-r--r--src/client/views/collections/CollectionView.tsx21
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx21
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx85
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx42
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx22
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss2
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMultirowView.scss2
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx2
-rw-r--r--src/client/views/nodes/ContentFittingDocumentView.tsx6
-rw-r--r--src/client/views/nodes/DocumentContentsView.tsx9
-rw-r--r--src/client/views/nodes/DocumentView.scss1
-rw-r--r--src/client/views/nodes/DocumentView.tsx85
-rw-r--r--src/client/views/nodes/FieldView.tsx9
-rw-r--r--src/client/views/nodes/FormattedTextBox.tsx22
-rw-r--r--src/client/views/nodes/IconBox.scss23
-rw-r--r--src/client/views/nodes/IconBox.tsx93
-rw-r--r--src/client/views/nodes/ImageBox.tsx9
-rw-r--r--src/client/views/nodes/KeyValueBox.scss4
-rw-r--r--src/client/views/nodes/PresBox.scss8
-rw-r--r--src/client/views/nodes/PresBox.tsx140
-rw-r--r--src/client/views/nodes/SliderBox-components.tsx256
-rw-r--r--src/client/views/nodes/SliderBox-tooltip.css33
-rw-r--r--src/client/views/nodes/SliderBox.scss8
-rw-r--r--src/client/views/nodes/SliderBox.tsx130
-rw-r--r--src/client/views/nodes/VideoBox.tsx3
-rw-r--r--src/client/views/nodes/WebBox.tsx3
-rw-r--r--src/client/views/pdf/PDFViewer.tsx3
-rw-r--r--src/client/views/presentationview/PresElementBox.tsx90
42 files changed, 923 insertions, 575 deletions
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index ce48e1215..0bf944f22 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -1,4 +1,4 @@
-import { Doc } from '../../new_fields/Doc';
+import { Doc, Opt } from '../../new_fields/Doc';
import { Touchable } from './Touchable';
import { computed, action, observable } from 'mobx';
import { Cast } from '../../new_fields/Types';
@@ -11,12 +11,13 @@ import { PositionDocument } from '../../new_fields/documentSchemas';
/// DocComponent returns a generic React base class used by views that don't have any data extensions (e.g.,CollectionFreeFormDocumentView, DocumentView, ButtonBox)
interface DocComponentProps {
Document: Doc;
+ LayoutDoc?: () => Opt<Doc>;
}
export function DocComponent<P extends DocComponentProps, T>(schemaCtor: (doc: Doc) => T) {
class Component extends Touchable<P> {
//TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then
@computed get Document(): T { return schemaCtor(this.props.Document); }
- @computed get layoutDoc() { return PositionDocument(Doc.Layout(this.props.Document)); }
+ @computed get layoutDoc() { return PositionDocument(Doc.Layout(this.props.Document, this.props.LayoutDoc?.())); }
}
return Component;
}
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index d6029dbe5..ee850922a 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -24,6 +24,7 @@ import React = require("react");
import { DragManager } from '../util/DragManager';
import { MetadataEntryMenu } from './MetadataEntryMenu';
import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils';
+import GoogleAuthenticationManager from '../apis/GoogleAuthenticationManager';
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
@@ -162,7 +163,8 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView |
title={`${published ? "Push" : "Publish"} to Google Docs`}
className="documentButtonBar-linker"
style={{ animation }}
- onClick={() => {
+ onClick={async () => {
+ await GoogleAuthenticationManager.Instance.fetchOrGenerateAccessToken();
!published && runInAction(() => this.isAnimatingPulse = true);
DocumentButtonBar.hasPushedHack = false;
targetDoc[Pushes] = NumCast(targetDoc[Pushes]) + 1;
diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss
index 32346165d..d57b1456a 100644
--- a/src/client/views/DocumentDecorations.scss
+++ b/src/client/views/DocumentDecorations.scss
@@ -98,6 +98,18 @@ $linkGap : 3px;
pointer-events: auto;
overflow: hidden;
text-align: center;
+ display:inline-block;
+ }
+ .publishBox {
+ width: 20px;
+ height: 22px;
+ grid-column-start: 3;
+ grid-column-end: 4;
+ pointer-events: all;
+ background: darkgray;
+ display: inline-block;
+ position: absolute;
+ right: 0;
}
}
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 4ec1659cc..7359835c5 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -1,5 +1,5 @@
import { IconProp, library } from '@fortawesome/fontawesome-svg-core';
-import { faArrowAltCircleDown, faArrowAltCircleUp, faCheckCircle, faCloudUploadAlt, faLink, faShare, faStopCircle, faSyncAlt, faTag, faTimes } from '@fortawesome/free-solid-svg-icons';
+import { faCaretUp, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote, faTextHeight, faArrowAltCircleDown, faArrowAltCircleUp, faCheckCircle, faCloudUploadAlt, faLink, faShare, faStopCircle, faSyncAlt, faTag, faTimes } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { action, computed, observable, reaction } from "mobx";
import { observer } from "mobx-react";
@@ -18,12 +18,17 @@ import { undoBatch, UndoManager } from "../util/UndoManager";
import { DocumentButtonBar } from './DocumentButtonBar';
import './DocumentDecorations.scss';
import { DocumentView } from "./nodes/DocumentView";
-import { IconBox } from "./nodes/IconBox";
import React = require("react");
+import { Id } from '../../new_fields/FieldSymbols';
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
+library.add(faCaretUp);
+library.add(faObjectGroup);
+library.add(faStickyNote);
+library.add(faFilePdf);
+library.add(faFilm, faTextHeight);
library.add(faLink);
library.add(faTag);
library.add(faTimes);
@@ -482,6 +487,15 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
this.TextBar = ele;
}
}
+ public static DocumentIcon(layout: string) {
+ const button = layout.indexOf("PDFBox") !== -1 ? faFilePdf :
+ layout.indexOf("ImageBox") !== -1 ? faImage :
+ layout.indexOf("Formatted") !== -1 ? faStickyNote :
+ layout.indexOf("Video") !== -1 ? faFilm :
+ layout.indexOf("Collection") !== -1 ? faObjectGroup :
+ faCaretUp;
+ return <FontAwesomeIcon icon={button} className="documentView-minimizedIcon" />;
+ }
render() {
const bounds = this.Bounds;
const seldoc = SelectionManager.SelectedDocuments().length ? SelectionManager.SelectedDocuments()[0] : undefined;
@@ -491,7 +505,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
const minimizeIcon = (
<div className="documentDecorations-minimizeButton" onPointerDown={this.onMinimizeDown}>
{/* Currently, this is set to be enabled if there is no ink selected. It might be interesting to think about minimizing ink if it's useful? -syip2*/}
- {SelectionManager.SelectedDocuments().length === 1 ? IconBox.DocumentIcon(StrCast(SelectionManager.SelectedDocuments()[0].props.Document.layout, "...")) : "..."}
+ {SelectionManager.SelectedDocuments().length === 1 ? DocumentDecorations.DocumentIcon(StrCast(SelectionManager.SelectedDocuments()[0].props.Document.layout, "...")) : "..."}
</div>);
bounds.x = Math.max(0, bounds.x - this._resizeBorderWidth / 2) + this._resizeBorderWidth / 2;
@@ -524,8 +538,17 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
}}>
{minimizeIcon}
- {this._edtingTitle ?
- <input ref={this._keyinput} className="title" type="text" name="dynbox" value={this._accumulatedTitle} onBlur={e => this.titleBlur(true)} onChange={this.titleChanged} onKeyPress={this.titleEntered} /> :
+ {this._edtingTitle ? <>
+ <input ref={this._keyinput} className="title" type="text" name="dynbox" value={this._accumulatedTitle} style={{ width: "calc(100% - 20px)" }}
+ onBlur={e => this.titleBlur(true)} onChange={this.titleChanged} onKeyPress={this.titleEntered} />
+ <div className="publishBox" title="make document referenceable by its title"
+ onPointerDown={e => {
+ const promoteDoc = SelectionManager.SelectedDocuments()[0];
+ DocUtils.Publish(promoteDoc.props.Document, this._accumulatedTitle, promoteDoc.props.addDocument, promoteDoc.props.removeDocument);
+ }}>
+ <FontAwesomeIcon size="lg" color={SelectionManager.SelectedDocuments()[0].props.Document.title === SelectionManager.SelectedDocuments()[0].props.Document[Id] ? "green" : undefined} icon="sticky-note"></FontAwesomeIcon>
+ </div>
+ </> :
<div className="title" onPointerDown={this.onTitleDown} ><span>{`${this.selectionTitle}`}</span></div>}
<div className="documentDecorations-closeButton" title="Close Document" onPointerDown={this.onCloseDown}>
<FontAwesomeIcon className="documentdecorations-times" icon={faTimes} size="lg" />
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index a9e81093a..401a4b15c 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -493,7 +493,6 @@ export class MainView extends React.Component {
fieldKey={"data"}
annotationsKey={""}
select={emptyFunction}
- chromeCollapsed={true}
active={returnFalse}
isSelected={returnFalse}
moveDocument={this.moveButtonDoc}
diff --git a/src/client/views/ScriptBox.tsx b/src/client/views/ScriptBox.tsx
index d24256886..cc5d7640e 100644
--- a/src/client/views/ScriptBox.tsx
+++ b/src/client/views/ScriptBox.tsx
@@ -93,29 +93,33 @@ export class ScriptBox extends React.Component<ScriptBoxProps> {
const params: string[] = [];
const setParams = (p: string[]) => params.splice(0, params.length, ...p);
const scriptingBox = <ScriptBox initialText={originalText} setParams={setParams} onCancel={overlayDisposer} onSave={(text, onError) => {
- const script = CompileScript(text, {
- params: { this: Doc.name, ...contextParams },
- typecheck: false,
- editable: true,
- transformer: DocumentIconContainer.getTransformer()
- });
- if (!script.compiled) {
- onError(script.errors.map(error => error.messageText).join("\n"));
- return;
- }
+ if (!text) {
+ doc[fieldKey] = undefined;
+ } else {
+ const script = CompileScript(text, {
+ params: { this: Doc.name, ...contextParams },
+ typecheck: false,
+ editable: true,
+ transformer: DocumentIconContainer.getTransformer()
+ });
+ if (!script.compiled) {
+ onError(script.errors.map(error => error.messageText).join("\n"));
+ return;
+ }
- const div = document.createElement("div");
- div.style.width = "90";
- div.style.height = "20";
- div.style.background = "gray";
- div.style.position = "absolute";
- div.style.display = "inline-block";
- div.style.transform = `translate(${clientX}px, ${clientY}px)`;
- div.innerHTML = "button";
- params.length && DragManager.StartButtonDrag([div], text, doc.title + "-instance", {}, params, (button: Doc) => { }, clientX, clientY);
+ const div = document.createElement("div");
+ div.style.width = "90";
+ div.style.height = "20";
+ div.style.background = "gray";
+ div.style.position = "absolute";
+ div.style.display = "inline-block";
+ div.style.transform = `translate(${clientX}px, ${clientY}px)`;
+ div.innerHTML = "button";
+ params.length && DragManager.StartButtonDrag([div], text, doc.title + "-instance", {}, params, (button: Doc) => { }, clientX, clientY);
- doc[fieldKey] = new ScriptField(script);
- overlayDisposer();
+ doc[fieldKey] = new ScriptField(script);
+ overlayDisposer();
+ }
}} showDocumentIcons />;
overlayDisposer = OverlayView.Instance.addWindow(scriptingBox, { x: 400, y: 200, width: 500, height: 400, title: title });
}
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index f61eb9cd0..c9c6af054 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -4,14 +4,11 @@ import { SelectionManager } from "../util/SelectionManager";
import { undoBatch } from "../util/UndoManager";
import './TemplateMenu.scss';
import { DocumentView } from "./nodes/DocumentView";
-import { Template, Templates } from "./Templates";
+import { Template } from "./Templates";
import React = require("react");
import { Doc, DocListCast } from "../../new_fields/Doc";
import { StrCast, Cast } from "../../new_fields/Types";
import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils";
-const higflyout = require("@hig/flyout");
-export const { anchorPoints } = higflyout;
-export const Flyout = higflyout.default;
@observer
class TemplateToggle extends React.Component<{ template: Template, checked: boolean, toggle: (event: React.ChangeEvent<HTMLInputElement>, template: Template) => void }> {
@@ -48,6 +45,8 @@ export interface TemplateMenuProps {
@observer
export class TemplateMenu extends React.Component<TemplateMenuProps> {
+ _addedKeys = new ObservableSet();
+ _customRef = React.createRef<HTMLInputElement>();
@observable private _hidden: boolean = true;
toggleLayout = (e: React.ChangeEvent<HTMLInputElement>, layout: string): void => {
@@ -62,7 +61,6 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
DocumentView.FloatDoc(topDocView, ex, ey);
}
-
@undoBatch
@action
toggleTemplate = (event: React.ChangeEvent<HTMLInputElement>, template: Template): void => {
@@ -83,7 +81,7 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
toggleChrome = (): void => {
this.props.docViews.map(dv => {
const layout = Doc.Layout(dv.Document);
- layout._chromeStatus = (layout._chromeStatus !== "disabled" ? "disabled" : "enabled");
+ layout._chromeStatus = (layout._chromeStatus !== "disabled" ? "disabled" : StrCast(layout._replacedChrome, "enabled"));
});
}
@@ -105,8 +103,6 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
});
}
- _addedKeys = new ObservableSet();
- _customRef = React.createRef<HTMLInputElement>();
render() {
const layout = Doc.Layout(this.props.docViews[0].Document);
const templateMenu: Array<JSX.Element> = [];
diff --git a/src/client/views/collections/CollectionCarouselView.scss b/src/client/views/collections/CollectionCarouselView.scss
index 4815f1a59..ad369bbff 100644
--- a/src/client/views/collections/CollectionCarouselView.scss
+++ b/src/client/views/collections/CollectionCarouselView.scss
@@ -14,27 +14,23 @@
width: 100%;
}
}
-.carouselView-back {
+.carouselView-back, .carouselView-fwd {
position: absolute;
display: flex;
- left: 0;
top: 50%;
width: 30;
height: 30;
- background: lightgray;
align-items: center;
border-radius: 5px;
justify-content: center;
+ background : rgba(255, 255, 255, 0.46);
}
-.carouselView-fwd {
- position: absolute;
- display: flex;
+.carouselView-fwd {
right: 0;
- top: 50%;
- width: 30;
- height: 30;
+}
+.carouselView-back {
+ left: 0;
+}
+.carouselView-back:hover, .carouselView-fwd:hover {
background: lightgray;
- align-items: center;
- border-radius: 5px;
- justify-content: center;
} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index d772ace23..d21ae32bc 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -4,25 +4,25 @@ import { CursorProperty } from "csstype";
import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
import Switch from 'rc-switch';
-import { Doc, HeightSym, WidthSym, DataSym } from "../../../new_fields/Doc";
+import { Doc, HeightSym, WidthSym } from "../../../new_fields/Doc";
import { Id } from "../../../new_fields/FieldSymbols";
import { List } from "../../../new_fields/List";
import { listSpec } from "../../../new_fields/Schema";
import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField";
-import { BoolCast, Cast, NumCast, StrCast, ScriptCast } from "../../../new_fields/Types";
-import { emptyFunction, Utils } from "../../../Utils";
+import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../new_fields/Types";
+import { TraceMobx } from "../../../new_fields/util";
+import { Utils } from "../../../Utils";
import { DragManager } from "../../util/DragManager";
import { Transform } from "../../util/Transform";
import { undoBatch } from "../../util/UndoManager";
+import { ContextMenu } from "../ContextMenu";
+import { ContextMenuProps } from "../ContextMenuItem";
import { EditableView } from "../EditableView";
import { ContentFittingDocumentView } from "../nodes/ContentFittingDocumentView";
+import { CollectionMasonryViewFieldRow } from "./CollectionMasonryViewFieldRow";
import "./CollectionStackingView.scss";
import { CollectionStackingViewFieldColumn } from "./CollectionStackingViewFieldColumn";
import { CollectionSubView } from "./CollectionSubView";
-import { ContextMenu } from "../ContextMenu";
-import { ContextMenuProps } from "../ContextMenuItem";
-import { CollectionMasonryViewFieldRow } from "./CollectionMasonryViewFieldRow";
-import { TraceMobx } from "../../../new_fields/util";
import { CollectionViewType } from "./CollectionView";
@observer
@@ -55,7 +55,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
this._docXfs.length = 0;
return docs.map((d, i) => {
const height = () => this.getDocHeight(d);
- const width = () => this.widthScale * Math.min(d._nativeWidth && !d.ignoreAspect && !this.props.Document.fillColumn ? d[WidthSym]() : Number.MAX_VALUE, this.columnWidth / this.numGroupColumns);
+ const width = () => this.getDocWidth(d);
const dref = React.createRef<HTMLDivElement>();
const dxf = () => this.getDocTransform(d, dref.current!);
this._docXfs.push({ dxf: dxf, width: width, height: height });
@@ -154,11 +154,12 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
@computed get onClickHandler() { return ScriptCast(this.Document.onChildClick); }
getDisplayDoc(doc: Doc, dataDoc: Doc | undefined, dxf: () => Transform, width: () => number) {
- const layoutDoc = Doc.Layout(doc);
+ const layoutDoc = Doc.Layout(doc, this.props.childLayoutTemplate?.());
const height = () => this.getDocHeight(doc);
return <ContentFittingDocumentView
Document={doc}
DataDocument={dataDoc}
+ LayoutDoc={this.props.childLayoutTemplate}
LibraryPath={this.props.LibraryPath}
renderDepth={this.props.renderDepth + 1}
fitToBox={this.props.fitToBox}
@@ -178,19 +179,26 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
pinToPres={this.props.pinToPres}>
</ContentFittingDocumentView>;
}
+
+ getDocWidth(d?: Doc) {
+ if (!d) return 0;
+ const layoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.());
+ const nw = NumCast(layoutDoc._nativeWidth);
+ return Math.min(nw && !d.ignoreAspect && !this.props.Document.fillColumn ? d[WidthSym]() : Number.MAX_VALUE, this.columnWidth / this.numGroupColumns);
+ }
getDocHeight(d?: Doc) {
if (!d) return 0;
- const layoutDoc = Doc.Layout(d);
+ let layoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.());
const nw = NumCast(layoutDoc._nativeWidth);
const nh = NumCast(layoutDoc._nativeHeight);
let wid = this.columnWidth / (this.isStackingView ? this.numGroupColumns : 1);
if (!layoutDoc.ignoreAspect && !layoutDoc._fitWidth && nw && nh) {
const aspect = nw && nh ? nh / nw : 1;
- if (!(d._nativeWidth && !layoutDoc.ignoreAspect && this.props.Document.fillColumn)) wid = Math.min(layoutDoc[WidthSym](), wid);
+ if (!(!layoutDoc.ignoreAspect && this.props.Document.fillColumn)) wid = Math.min(layoutDoc[WidthSym](), wid);
return wid * aspect;
}
- return layoutDoc._fitWidth ? !layoutDoc._nativeHeight ? this.props.PanelHeight() - 2 * this.yMargin :
- Math.min(wid * NumCast(layoutDoc.scrollHeight, NumCast(layoutDoc._nativeHeight)) / NumCast(layoutDoc._nativeWidth, 1), this.props.PanelHeight() - 2 * this.yMargin) : layoutDoc[HeightSym]();
+ return layoutDoc._fitWidth ? !nh ? this.props.PanelHeight() - 2 * this.yMargin :
+ Math.min(wid * NumCast(layoutDoc.scrollHeight, nh) / (nw || 1), this.props.PanelHeight() - 2 * this.yMargin) : layoutDoc[HeightSym]();
}
columnDividerDown = (e: React.PointerEvent) => {
@@ -376,16 +384,9 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
}
return sections.map(section => this.isStackingView ? this.sectionStacking(section[0], section[1]) : this.sectionMasonry(section[0], section[1]));
}
- @computed get contentScale() {
- const heightExtra = this.heightPercent > 1 ? this.heightPercent : 1;
- return Math.min(this.props.Document[WidthSym]() / this.props.PanelWidth(), heightExtra * this.props.Document[HeightSym]() / this.props.PanelHeight());
- }
- @computed get widthScale() {
- return this.heightPercent < 1 ? Math.max(1, this.contentScale) : 1;
- }
- @computed get heightPercent() {
- return this.props.PanelHeight() / this.layoutDoc[HeightSym]();
- }
+
+ @computed get scaling() { return !this.props.Document._nativeWidth ? 1 : this.props.PanelHeight() / NumCast(this.props.Document._nativeHeight); }
+
render() {
TraceMobx();
const editableViewProps = {
@@ -399,9 +400,9 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
ref={this.createRef}
style={{
overflowY: this.props.active() ? "auto" : "hidden",
- transform: `scale(${Math.min(1, this.heightPercent)})`,
- height: `${100 * Math.max(1, this.contentScale)}%`,
- width: `${100 * this.widthScale}%`,
+ transform: `scale(${this.scaling}`,
+ height: `${1 / this.scaling * 100}%`,
+ width: `${1 / this.scaling * 100}%`,
transformOrigin: "top left",
}}
onScroll={action((e: React.UIEvent<HTMLDivElement>) => this._scroll = e.currentTarget.scrollTop)}
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 21982f1ca..3fc05c6b7 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -285,8 +285,10 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
description: ":" + fieldKey, event: () => {
const created = Docs.Create.CarouselDocument([], { _width: 400, _height: 200, title: fieldKey });
if (created) {
- if (this.props.parent.Document.isTemplateDoc) {
- Doc.MakeMetadataFieldTemplate(created, this.props.parent.props.Document);
+ const container = this.props.parent.Document.resolvedDataDoc ? Doc.GetProto(this.props.parent.Document) : this.props.parent.Document;
+ if (container.isTemplateDoc) {
+ Doc.MakeMetadataFieldTemplate(created, container);
+ return Doc.AddDocToList(container, Doc.LayoutFieldKey(container), created);
}
return this.props.parent.props.addDocument(created);
}
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 62b9e8380..20941493f 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -1,7 +1,7 @@
import { action, computed, IReactionDisposer, reaction, trace } from "mobx";
import * as rp from 'request-promise';
import CursorField from "../../../new_fields/CursorField";
-import { Doc, DocListCast, Opt } from "../../../new_fields/Doc";
+import { Doc, DocListCast, Opt, WidthSym, HeightSym } from "../../../new_fields/Doc";
import { Id } from "../../../new_fields/FieldSymbols";
import { List } from "../../../new_fields/List";
import { listSpec } from "../../../new_fields/Schema";
@@ -33,7 +33,6 @@ export interface CollectionViewProps extends FieldViewProps {
PanelWidth: () => number;
PanelHeight: () => number;
VisibleHeight?: () => number;
- chromeCollapsed: boolean;
setPreviewCursor?: (func: (x: number, y: number, drag: boolean) => void) => void;
fieldKey: string;
}
@@ -167,6 +166,9 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
return true;
}
let added = false;
+ if (this.props.Document._freezeOnDrop) {
+ de.complete.docDragData?.droppedDocuments.forEach(drop => Doc.freezeNativeDimensions(drop, drop[WidthSym](), drop[HeightSym]()));
+ }
if (docDragData.dropAction || docDragData.userDropAction) {
added = docDragData.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d) || added, false);
} else if (docDragData.moveDocument) {
@@ -230,8 +232,8 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
const split = img.split("src=\"")[1].split("\"")[0];
let source = split;
if (split.startsWith("data:image") && split.includes("base64")) {
- const [{ clientAccessPath }] = await Networking.PostToServer("/uploadRemoteImage", { sources: [split] });
- source = Utils.prepend(clientAccessPath);
+ const [{ accessPaths }] = await Networking.PostToServer("/uploadRemoteImage", { sources: [split] });
+ source = Utils.prepend(accessPaths.agnostic.client);
}
const doc = Docs.Create.ImageDocument(source, { ...options, _width: 300 });
ImageUtils.ExtractExif(doc);
@@ -310,9 +312,9 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
const dropFileName = file ? file.name : "-empty-";
promises.push(Networking.PostFormDataToServer("/uploadFormData", formData).then(results => {
results.map(action((result: any) => {
- const { clientAccessPath, nativeWidth, nativeHeight, contentSize } = result;
+ const { accessPaths, nativeWidth, nativeHeight, contentSize } = result;
const full = { ...options, _width: 300, title: dropFileName };
- const pathname = Utils.prepend(clientAccessPath);
+ const pathname = Utils.prepend(accessPaths.agnostic.client);
Docs.Get.DocumentFromType(type, pathname, full).then(doc => {
if (doc) {
const proto = Doc.GetProto(doc);
diff --git a/src/client/views/collections/CollectionTimeView.scss b/src/client/views/collections/CollectionTimeView.scss
index a5ce73a92..2dffb3ea0 100644
--- a/src/client/views/collections/CollectionTimeView.scss
+++ b/src/client/views/collections/CollectionTimeView.scss
@@ -1,21 +1,26 @@
-.collectionTimeView, .collectionTimeView-pivot {
+.collectionTimeView,
+.collectionTimeView-pivot {
display: flex;
flex-direction: row;
position: absolute;
height: 100%;
width: 100%;
overflow: hidden;
+
.collectionTimeView-backBtn {
background: green;
display: inline;
margin-right: 20px;
}
+
.collectionFreeform-customText {
text-align: left;
}
+
.collectionFreeform-customDiv {
position: absolute;
}
+
.collectionTimeView-thumb {
position: absolute;
width: 30px;
@@ -28,19 +33,21 @@
border-radius: 9px;
opacity: 0.25;
}
+
.collectionTimeView-thumb-min {
- margin-left:25%;
+ margin-left: 25%;
}
+
.collectionTimeView-thumb-max {
- margin-left:75%;
+ margin-left: 75%;
}
+
.collectionTimeView-thumb-mid {
- margin-left:50%;
+ margin-left: 50%;
}
.collectionTimeView-flyout {
width: 400px;
- height: 300px;
display: inline-block;
.collectionTimeView-flyout-item {
@@ -119,6 +126,7 @@
left: -10px;
}
}
+
.collectionTimeView-pivot {
.collectionFreeform-customText {
text-align: center;
diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx
index 4983acbc2..50e297f0b 100644
--- a/src/client/views/collections/CollectionTimeView.tsx
+++ b/src/client/views/collections/CollectionTimeView.tsx
@@ -1,27 +1,29 @@
import { faEdit } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { action, computed, observable, trace, runInAction } from "mobx";
+import { action, computed, observable, runInAction, trace } from "mobx";
import { observer } from "mobx-react";
-import { Set } from "typescript-collections";
-import { Doc, DocListCast, Field } from "../../../new_fields/Doc";
+import { Doc, DocListCast, Field, WidthSym, HeightSym } from "../../../new_fields/Doc";
import { List } from "../../../new_fields/List";
+import { ObjectField } from "../../../new_fields/ObjectField";
import { RichTextField } from "../../../new_fields/RichTextField";
import { listSpec } from "../../../new_fields/Schema";
import { ComputedField, ScriptField } from "../../../new_fields/ScriptField";
import { Cast, NumCast, StrCast } from "../../../new_fields/Types";
import { Docs } from "../../documents/Documents";
+import { DocumentType } from "../../documents/DocumentTypes";
import { Scripting } from "../../util/Scripting";
import { ContextMenu } from "../ContextMenu";
import { ContextMenuProps } from "../ContextMenuItem";
import { EditableView } from "../EditableView";
-import { anchorPoints, Flyout } from "../TemplateMenu";
import { ViewDefBounds } from "./collectionFreeForm/CollectionFreeFormLayoutEngines";
import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView";
import { CollectionSubView } from "./CollectionSubView";
import "./CollectionTimeView.scss";
-import React = require("react");
import { CollectionTreeView } from "./CollectionTreeView";
-import { ObjectField } from "../../../new_fields/ObjectField";
+const higflyout = require("@hig/flyout");
+export const { anchorPoints } = higflyout;
+export const Flyout = higflyout.default;
+import React = require("react");
@observer
export class CollectionTimeView extends CollectionSubView(doc => doc) {
@@ -29,11 +31,12 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
@observable _layoutEngine = "pivot";
componentDidMount() {
+ this.props.Document._freezeOnDrop = true;
const childDetailed = this.props.Document.childDetailed; // bcz: needs to be here to make sure the childDetailed layout template has been loaded when the first item is clicked;
if (!this.props.Document._facetCollection) {
- const facetCollection = Docs.Create.TreeDocument([], { title: "facetFilters", _yMargin: 0, treeViewHideTitle: true });
+ const facetCollection = Docs.Create.TreeDocument([], { title: "facetFilters", _yMargin: 0, treeViewHideTitle: true, treeViewHideHeaderFields: true });
facetCollection.target = this.props.Document;
- this.props.Document.excludeFields = new List<string>(["_facetCollection", "_docFilter"]);
+ this.props.Document.excludeFields = new List<string>(["_facetCollection", "_docFilters"]);
const scriptText = "setDocFilter(containingTreeView.target, heading, this.title, checked)";
const childText = "const alias = getAlias(this); Doc.ApplyTemplateTo(containingCollection.childDetailed, alias, 'layout_detailView'); alias.dropAction='alias'; alias.removeDropProperties=new List<string>(['dropAction']); useRightSplit(alias, shiftKey); ";
@@ -43,7 +46,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
this.props.Document._fitToBox = true;
}
if (!this.props.Document.onViewDefClick) {
- this.props.Document.onViewDefDivClick = ScriptField.MakeScript("pivotColumnClick(this,payload)", { payload: "any" })
+ this.props.Document.onViewDefDivClick = ScriptField.MakeScript("pivotColumnClick(this,payload)", { payload: "any" });
}
}
@@ -54,7 +57,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
const facets = new Set<string>();
this.childDocs.forEach(child => Object.keys(Doc.GetProto(child)).forEach(key => facets.add(key)));
Doc.AreProtosEqual(this.dataDoc, this.props.Document) && this.childDocs.forEach(child => Object.keys(child).forEach(key => facets.add(key)));
- return facets.toArray();
+ return Array.from(facets);
}
/**
@@ -66,19 +69,58 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
const found = DocListCast(facetCollection.data).findIndex(doc => doc.title === facetHeader);
if (found !== -1) {
(facetCollection.data as List<Doc>).splice(found, 1);
- const docFilter = Cast(this.props.Document._docFilter, listSpec("string"));
+ const docFilter = Cast(this.props.Document._docFilters, listSpec("string"));
if (docFilter) {
let index: number;
while ((index = docFilter.findIndex(item => item === facetHeader)) !== -1) {
docFilter.splice(index, 3);
}
}
+ const docRangeFilters = Cast(this.props.Document._docRangeFilters, listSpec("string"));
+ if (docRangeFilters) {
+ let index: number;
+ while ((index = docRangeFilters.findIndex(item => item === facetHeader)) !== -1) {
+ docRangeFilters.splice(index, 3);
+ }
+ }
} else {
- const newFacet = Docs.Create.TreeDocument([], { title: facetHeader, treeViewOpen: true, isFacetFilter: true });
- const capturedVariables = { layoutDoc: this.props.Document, dataDoc: this.dataDoc };
- const params = { layoutDoc: Doc.name, dataDoc: Doc.name, };
- newFacet.data = ComputedField.MakeFunction(`readFacetData(layoutDoc, dataDoc, "${this.props.fieldKey}", "${facetHeader}")`, params, capturedVariables);
- Doc.AddDocToList(facetCollection, "data", newFacet);
+ const allCollectionDocs = DocListCast(this.dataDoc[this.props.fieldKey]);
+ const facetValues = Array.from(allCollectionDocs.reduce((set, child) =>
+ set.add(Field.toString(child[facetHeader] as Field)), new Set<string>()));
+
+ let nonNumbers = 0;
+ let minVal = Number.MAX_VALUE, maxVal = -Number.MAX_VALUE;
+ facetValues.map(val => {
+ const num = Number(val);
+ if (Number.isNaN(num)) {
+ nonNumbers++;
+ } else {
+ minVal = Math.min(num, minVal);
+ maxVal = Math.max(num, maxVal);
+ }
+ });
+ if (nonNumbers / allCollectionDocs.length < .1) {
+ const ranged = Doc.readDocRangeFilter(this.props.Document, facetHeader);
+ const newFacet = Docs.Create.SliderDocument({ title: facetHeader });
+ Doc.GetProto(newFacet).type = DocumentType.COL; // forces item to show an open/close button instead ofa checkbox
+ newFacet.treeViewExpandedView = "layout";
+ newFacet.treeViewOpen = true;
+ newFacet._sliderMin = ranged === undefined ? minVal : ranged[0];
+ newFacet._sliderMax = ranged === undefined ? maxVal : ranged[1];
+ newFacet._sliderMinThumb = minVal;
+ newFacet._sliderMaxThumb = maxVal;
+ newFacet.target = this.props.Document;
+ const scriptText = `setDocFilterRange(this.target, "${facetHeader}", range)`;
+ newFacet.onThumbChanged = ScriptField.MakeScript(scriptText, { this: Doc.name, range: "number" });
+
+ Doc.AddDocToList(facetCollection, "data", newFacet);
+ } else {
+ const newFacet = Docs.Create.TreeDocument([], { title: facetHeader, treeViewOpen: true, isFacetFilter: true });
+ const capturedVariables = { layoutDoc: this.props.Document, dataDoc: this.dataDoc };
+ const params = { layoutDoc: Doc.name, dataDoc: Doc.name, };
+ newFacet.data = ComputedField.MakeFunction(`readFacetData(layoutDoc, dataDoc, "${this.props.fieldKey}", "${facetHeader}")`, params, capturedVariables);
+ Doc.AddDocToList(facetCollection, "data", newFacet);
+ }
}
}
}
@@ -120,9 +162,9 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
pair.layout[fieldKey] instanceof RichTextField ||
typeof (pair.layout[fieldKey]) === "number" ||
typeof (pair.layout[fieldKey]) === "string").map(fieldKey => keySet.add(fieldKey)));
- keySet.toArray().map(fieldKey =>
+ Array.from(keySet).map(fieldKey =>
docItems.push({ description: ":" + fieldKey, event: () => this.props.Document._pivotField = fieldKey, icon: "compress-arrows-alt" }));
- docItems.push({ description: ":(null)", event: () => this.props.Document._pivotField = undefined, icon: "compress-arrows-alt" })
+ docItems.push({ description: ":(null)", event: () => this.props.Document._pivotField = undefined, icon: "compress-arrows-alt" });
ContextMenu.Instance.addItem({ description: "Pivot Fields ...", subitems: docItems, icon: "eye" });
const pt = this.props.ScreenToLocalTransform().inverse().transformPoint(x, y);
ContextMenu.Instance.displayMenu(x, y, ":");
@@ -148,6 +190,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
const minReq = NumCast(this.props.Document[this.props.fieldKey + "-timelineMinReq"], NumCast(this.props.Document[this.props.fieldKey + "-timelineMin"], 0));
const maxReq = NumCast(this.props.Document[this.props.fieldKey + "-timelineMaxReq"], NumCast(this.props.Document[this.props.fieldKey + "-timelineMax"], 10));
this.props.Document[this.props.fieldKey + "-timelineMinReq"] = minReq + (maxReq - minReq) * delta / this.props.PanelWidth();
+ this.props.Document[this.props.fieldKey + "-timelineSpan"] = undefined;
}
onMinUp = (e: PointerEvent) => {
document.removeEventListener("pointermove", this.onMinMove);
@@ -170,6 +213,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
const minReq = NumCast(this.props.Document[this.props.fieldKey + "-timelineMinReq"], NumCast(this.props.Document[this.props.fieldKey + "-timelineMin"], 0));
const maxReq = NumCast(this.props.Document[this.props.fieldKey + "-timelineMaxReq"], NumCast(this.props.Document[this.props.fieldKey + "-timelineMax"], 10));
this.props.Document[this.props.fieldKey + "-timelineMaxReq"] = maxReq + (maxReq - minReq) * delta / this.props.PanelWidth();
+ this.props.Document[this.props.fieldKey + "-timelineSpan"] = undefined;
}
onMaxUp = (e: PointerEvent) => {
document.removeEventListener("pointermove", this.onMaxMove);
@@ -209,7 +253,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
trace();
const facetCollection = Cast(this.props.Document?._facetCollection, Doc, null);
const flyout = (
- <div className="collectionTimeView-flyout" style={{ width: `${this._facetWidth}` }}>
+ <div className="collectionTimeView-flyout" style={{ width: `${this._facetWidth}`, height: this.props.PanelHeight() - 30, display: "block" }} onWheel={e => e.stopPropagation()}>
{this._allFacets.map(facet => <label className="collectionTimeView-flyout-item" key={`${facet}`} onClick={e => this.facetClick(facet)}>
<input type="checkbox" onChange={e => { }} checked={DocListCast((this.props.Document._facetCollection as Doc)?.data).some(d => d.title === facet)} />
<span className="checkmark" />
@@ -227,7 +271,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
</Flyout>
</div>
<div className="collectionTimeView-tree" key="tree">
- <CollectionTreeView {...this.props} Document={facetCollection} />
+ <CollectionTreeView {...this.props} PanelWidth={() => this._facetWidth} Document={facetCollection} />
</div>
</div>;
}
@@ -240,9 +284,9 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
const layoutItems: ContextMenuProps[] = [];
const doc = this.props.Document;
- layoutItems.push({ description: "Force Timeline", event: () => { doc._forceRenderEngine = "timeline" }, icon: "compress-arrows-alt" });
- layoutItems.push({ description: "Force Pivot", event: () => { doc._forceRenderEngine = "pivot" }, icon: "compress-arrows-alt" });
- layoutItems.push({ description: "Auto Time/Pivot layout", event: () => { doc._forceRenderEngine = undefined }, icon: "compress-arrows-alt" });
+ layoutItems.push({ description: "Force Timeline", event: () => { doc._forceRenderEngine = "timeline"; }, icon: "compress-arrows-alt" });
+ layoutItems.push({ description: "Force Pivot", event: () => { doc._forceRenderEngine = "pivot"; }, icon: "compress-arrows-alt" });
+ layoutItems.push({ description: "Auto Time/Pivot layout", event: () => { doc._forceRenderEngine = undefined; }, icon: "compress-arrows-alt" });
layoutItems.push({ description: "Sync with presentation", event: () => CollectionTimeView.SyncTimelineToPresentation(doc), icon: "compress-arrows-alt" });
ContextMenu.Instance.addItem({ description: "Pivot/Time Options ...", subitems: layoutItems, icon: "eye" });
@@ -289,14 +333,16 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
<div className={"collectionTimeView" + (doTimeline ? "" : "-pivot")} onContextMenu={this.specificMenu}
style={{ height: `calc(100% - ${this.props.Document._chromeStatus === "enabled" ? 51 : 0}px)` }}>
<div className={"pivotKeyEntry"}>
- <button className="collectionTimeView-backBtn" style={{ width: 50, height: 20, background: "green" }}
+ <button className="collectionTimeView-backBtn"
onClick={action(() => {
- let pfilterIndex = NumCast(this.props.Document._pfilterIndex);
- if (pfilterIndex > 0) {
- this.props.Document._docFilter = ObjectField.MakeCopy(this.props.Document["_pfilter" + --pfilterIndex] as ObjectField);
- this.props.Document._pfilterIndex = pfilterIndex;
+ let prevFilterIndex = NumCast(this.props.Document._prevFilterIndex);
+ if (prevFilterIndex > 0) {
+ prevFilterIndex--;
+ this.props.Document._docFilters = ObjectField.MakeCopy(this.props.Document["_prevDocFilter" + prevFilterIndex] as ObjectField);
+ this.props.Document._docRangeFilters = ObjectField.MakeCopy(this.props.Document["_prevDocRangeFilters" + prevFilterIndex] as ObjectField);
+ this.props.Document._prevFilterIndex = prevFilterIndex;
} else {
- this.props.Document._docFilter = new List([]);
+ this.props.Document._docFilters = new List([]);
}
})}>
back
@@ -320,11 +366,12 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
}
Scripting.addGlobal(function pivotColumnClick(pivotDoc: Doc, bounds: ViewDefBounds) {
- let pfilterIndex = NumCast(pivotDoc._pfilterIndex);
- pivotDoc["_pfilter" + pfilterIndex] = ObjectField.MakeCopy(pivotDoc._docFilter as ObjectField);
- pivotDoc._pfilterIndex = ++pfilterIndex;
+ let prevFilterIndex = NumCast(pivotDoc._prevFilterIndex);
+ pivotDoc["_prevDocFilter" + prevFilterIndex] = ObjectField.MakeCopy(pivotDoc._docFilters as ObjectField);
+ pivotDoc["_prevDocRangeFilters" + prevFilterIndex] = ObjectField.MakeCopy(pivotDoc._docRangeFilters as ObjectField);
+ pivotDoc._prevFilterIndex = ++prevFilterIndex;
runInAction(() => {
- pivotDoc._docFilter = new List();
+ pivotDoc._docFilters = new List();
(bounds.payload as string[]).map(filterVal =>
Doc.setDocFilter(pivotDoc, StrCast(pivotDoc._pivotField), filterVal, "check"));
});
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 001064b30..be2947dff 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -60,7 +60,7 @@ export interface TreeViewProps {
treeViewId: Doc;
parentKey: string;
active: (outsideReaction?: boolean) => boolean;
- hideHeaderFields: () => boolean;
+ treeViewHideHeaderFields: () => boolean;
preventTreeViewOpen: boolean;
renderedIds: string[];
onCheckedClick?: ScriptField;
@@ -292,7 +292,7 @@ class TreeView extends React.Component<TreeViewProps> {
contentElement = TreeView.GetChildElements(contents instanceof Doc ? [contents] :
DocListCast(contents), this.props.treeViewId, doc, undefined, key, this.props.containingCollection, this.props.prevSibling, addDoc, remDoc, this.move,
this.props.dropAction, this.props.addDocTab, this.props.pinToPres, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active,
- this.props.panelWidth, this.props.ChromeHeight, this.props.renderDepth, this.props.hideHeaderFields, this.props.preventTreeViewOpen,
+ this.props.panelWidth, this.props.ChromeHeight, this.props.renderDepth, this.props.treeViewHideHeaderFields, this.props.preventTreeViewOpen,
[...this.props.renderedIds, doc[Id]], this.props.libraryPath, this.props.onCheckedClick);
} else {
contentElement = <EditableView
@@ -335,7 +335,7 @@ class TreeView extends React.Component<TreeViewProps> {
TreeView.GetChildElements(docs, this.props.treeViewId, Doc.Layout(this.props.document),
this.templateDataDoc, expandKey, this.props.containingCollection, this.props.prevSibling, addDoc, remDoc, this.move,
this.props.dropAction, this.props.addDocTab, this.props.pinToPres, this.props.ScreenToLocalTransform,
- this.props.outerXf, this.props.active, this.props.panelWidth, this.props.ChromeHeight, this.props.renderDepth, this.props.hideHeaderFields, this.props.preventTreeViewOpen,
+ this.props.outerXf, this.props.active, this.props.panelWidth, this.props.ChromeHeight, this.props.renderDepth, this.props.treeViewHideHeaderFields, this.props.preventTreeViewOpen,
[...this.props.renderedIds, this.props.document[Id]], this.props.libraryPath, this.props.onCheckedClick)}
</ul >;
} else if (this.treeViewExpandedView === "fields") {
@@ -425,7 +425,7 @@ class TreeView extends React.Component<TreeViewProps> {
}} >
{this.editableView("title")}
</div >
- {this.props.hideHeaderFields() ? (null) : headerElements}
+ {this.props.treeViewHideHeaderFields() ? (null) : headerElements}
{openRight}
</>;
}
@@ -464,7 +464,7 @@ class TreeView extends React.Component<TreeViewProps> {
panelWidth: () => number,
ChromeHeight: undefined | (() => number),
renderDepth: number,
- hideHeaderFields: () => boolean,
+ treeViewHideHeaderFields: () => boolean,
preventTreeViewOpen: boolean,
renderedIds: string[],
libraryPath: Doc[] | undefined,
@@ -574,7 +574,7 @@ class TreeView extends React.Component<TreeViewProps> {
outerXf={outerXf}
parentKey={key}
active={active}
- hideHeaderFields={hideHeaderFields}
+ treeViewHideHeaderFields={treeViewHideHeaderFields}
preventTreeViewOpen={preventTreeViewOpen}
renderedIds={renderedIds} />;
});
@@ -625,7 +625,7 @@ export class CollectionTreeView extends CollectionSubView(Document) {
} else {
const layoutItems: ContextMenuProps[] = [];
layoutItems.push({ description: (this.props.Document.preventTreeViewOpen ? "Persist" : "Abandon") + "Treeview State", event: () => this.props.Document.preventTreeViewOpen = !this.props.Document.preventTreeViewOpen, icon: "paint-brush" });
- layoutItems.push({ description: (this.props.Document.hideHeaderFields ? "Show" : "Hide") + " Header Fields", event: () => this.props.Document.hideHeaderFields = !this.props.Document.hideHeaderFields, icon: "paint-brush" });
+ layoutItems.push({ description: (this.props.Document.treeViewHideHeaderFields ? "Show" : "Hide") + " Header Fields", event: () => this.props.Document.treeViewHideHeaderFields = !this.props.Document.treeViewHideHeaderFields, icon: "paint-brush" });
layoutItems.push({ description: (this.props.Document.treeViewHideTitle ? "Show" : "Hide") + " Title", event: () => this.props.Document.treeViewHideTitle = !this.props.Document.treeViewHideTitle, icon: "paint-brush" });
ContextMenu.Instance.addItem({ description: "Treeview Options ...", subitems: layoutItems, icon: "eye" });
}
@@ -633,11 +633,10 @@ export class CollectionTreeView extends CollectionSubView(Document) {
description: "Buxton Layout", icon: "eye", event: () => {
DocListCast(this.dataDoc[this.props.fieldKey]).map(d => {
DocListCast(d.data).map((img, i) => {
- const caption = (d.captions as any)[i]?.data;
- if (caption instanceof ObjectField) {
- Doc.GetProto(img).caption = ObjectField.MakeCopy(caption);
+ const caption = (d.captions as any)[i];
+ if (caption) {
+ Doc.GetProto(img).caption = caption;
}
- d.captions = undefined;
});
});
const { TextDocument, ImageDocument, CarouselDocument, TreeDocument } = Docs.Create;
@@ -649,13 +648,12 @@ export class CollectionTreeView extends CollectionSubView(Document) {
const detailView = Docs.Create.StackingDocument([
CarouselDocument([], { title: "data", _height: 350, _itemIndex: 0, backgroundColor: "#9b9b9b3F" }),
textDoc,
- TextDocument("", { title: "short_description", _autoHeight: true }),
+ TextDocument("", { title: "shortDescription", _autoHeight: true }),
TreeDocument([], { title: "narratives", _height: 75, treeViewHideTitle: true })
], { _chromeStatus: "disabled", _width: 300, _height: 300, _autoHeight: true, title: "detailView" });
textDoc.data = new RichTextField(detailedTemplate, "year company");
detailView.isTemplateDoc = makeTemplate(detailView);
-
const heroView = ImageDocument(fallbackImg, { title: "heroView", isTemplateDoc: true, isTemplateForField: "hero", }); // this acts like a template doc and a template field ... a little weird, but seems to work?
heroView.proto!.layout = ImageBox.LayoutString("hero");
heroView.showTitle = "title";
@@ -673,7 +671,6 @@ export class CollectionTreeView extends CollectionSubView(Document) {
dragFactory: detailView, removeDropProperties: new List<string>(["dropAction"]), title: "detail view", icon: "file-alt"
}));
-
Document.childLayout = heroView;
Document.childDetailed = detailView;
Document._viewType = CollectionViewType.Time;
@@ -732,7 +729,7 @@ export class CollectionTreeView extends CollectionSubView(Document) {
{
TreeView.GetChildElements(this.childDocs, this.props.Document, this.props.Document, this.props.DataDoc, this.props.fieldKey, this.props.ContainingCollectionDoc, undefined, addDoc, this.remove,
moveDoc, dropAction, this.props.addDocTab, this.props.pinToPres, this.props.ScreenToLocalTransform,
- this.outerXf, this.props.active, this.props.PanelWidth, this.props.ChromeHeight, this.props.renderDepth, () => BoolCast(this.props.Document.hideHeaderFields),
+ this.outerXf, this.props.active, this.props.PanelWidth, this.props.ChromeHeight, this.props.renderDepth, () => BoolCast(this.props.Document.treeViewHideHeaderFields),
BoolCast(this.props.Document.preventTreeViewOpen), [], this.props.LibraryPath, ScriptCast(this.props.Document.onCheckedClick))
}
</ul>
@@ -764,7 +761,7 @@ Scripting.addGlobal(function readFacetData(layoutDoc: Doc, dataDoc: Doc, dataKey
});
Scripting.addGlobal(function determineCheckedState(layoutDoc: Doc, facetHeader: string, facetValue: string) {
- const docFilters = Cast(layoutDoc._docFilter, listSpec("string"), []);
+ const docFilters = Cast(layoutDoc._docFilters, listSpec("string"), []);
for (let i = 0; i < docFilters.length; i += 3) {
const [header, value, state] = docFilters.slice(i, i + 3);
if (header === facetHeader && value === facetValue) {
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index bdd908807..8dd844711 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -7,7 +7,7 @@ import * as React from 'react';
import Lightbox from 'react-image-lightbox-with-rotate';
import 'react-image-lightbox-with-rotate/style.css'; // This only needs to be imported once in your app
import { DateField } from '../../../new_fields/DateField';
-import { Doc, DocListCast } from '../../../new_fields/Doc';
+import { Doc, DocListCast, DataSym } from '../../../new_fields/Doc';
import { Id } from '../../../new_fields/FieldSymbols';
import { listSpec } from '../../../new_fields/Schema';
import { BoolCast, Cast, StrCast, NumCast } from '../../../new_fields/Types';
@@ -54,8 +54,7 @@ export enum CollectionViewType {
Time,
Carousel,
Linear,
- Staff,
- Timeline
+ Staff
}
export namespace CollectionViewType {
@@ -116,7 +115,7 @@ export class CollectionView extends Touchable<FieldViewProps> {
// chrome status is one of disabled, collapsed, or visible. this determines initial state from document
// chrome status may also be view-mode, in reference to stacking view's toggle mode. it is essentially disabled mode, but prevents the toggle button from showing up on the left sidebar.
const chromeStatus = this.props.Document._chromeStatus;
- if (chromeStatus && (chromeStatus === "disabled" || chromeStatus === "collapsed")) {
+ if (chromeStatus && (chromeStatus === "disabled" || chromeStatus === "collapsed" || chromeStatus === "replaced")) {
runInAction(() => this._collapsed = true);
}
});
@@ -133,7 +132,7 @@ export class CollectionView extends Touchable<FieldViewProps> {
@action.bound
addDocument(doc: Doc): boolean {
- const targetDataDoc = Doc.GetProto(this.props.DataDoc || this.props.Document);
+ const targetDataDoc = this.props.Document[DataSym];
Doc.AddDocToList(targetDataDoc, this.props.fieldKey, doc);
targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now()));
Doc.GetProto(doc).lastOpened = new DateField;
@@ -144,7 +143,7 @@ export class CollectionView extends Touchable<FieldViewProps> {
removeDocument(doc: Doc): boolean {
const docView = DocumentManager.Instance.getDocumentView(doc, this.props.ContainingCollectionView);
docView && SelectionManager.DeselectDoc(docView);
- const value = Cast((this.props.DataDoc || this.props.Document)[this.props.fieldKey], listSpec(Doc), []);
+ const value = Cast(this.props.Document[DataSym][this.props.fieldKey], listSpec(Doc), []);
let index = value.reduce((p, v, i) => (v instanceof Doc && v === doc) ? i : p, -1);
index = index !== -1 ? index : value.reduce((p, v, i) => (v instanceof Doc && Doc.AreProtosEqual(v, doc)) ? i : p, -1);
@@ -176,14 +175,14 @@ export class CollectionView extends Touchable<FieldViewProps> {
}
private SubViewHelper = (type: CollectionViewType, renderProps: CollectionRenderProps) => {
- const props = { ...this.props, ...renderProps, chromeCollapsed: this._collapsed, ChromeHeight: this.chromeHeight, CollectionView: this, annotationsKey: "" };
+ const props = { ...this.props, ...renderProps, ChromeHeight: this.chromeHeight, CollectionView: this, annotationsKey: "" };
switch (type) {
case CollectionViewType.Schema: return (<CollectionSchemaView key="collview" {...props} />);
case CollectionViewType.Docking: return (<CollectionDockingView key="collview" {...props} />);
case CollectionViewType.Tree: return (<CollectionTreeView key="collview" {...props} />);
- case CollectionViewType.Staff: return (<CollectionStaffView chromeCollapsed={true} key="collview" {...props} ChromeHeight={this.chromeHeight} CollectionView={this} />);
- case CollectionViewType.Multicolumn: return (<CollectionMulticolumnView chromeCollapsed={true} key="collview" {...props} ChromeHeight={this.chromeHeight} CollectionView={this} />);
- case CollectionViewType.Multirow: return (<CollectionMultirowView chromeCollapsed={true} key="rpwview" {...props} ChromeHeight={this.chromeHeight} CollectionView={this} />);
+ case CollectionViewType.Staff: return (<CollectionStaffView key="collview" {...props} />);
+ case CollectionViewType.Multicolumn: return (<CollectionMulticolumnView key="collview" {...props} />);
+ case CollectionViewType.Multirow: return (<CollectionMultirowView key="rpwview" {...props} />);
case CollectionViewType.Linear: { return (<CollectionLinearView key="collview" {...props} />); }
case CollectionViewType.Carousel: { return (<CollectionCarouselView key="collview" {...props} />); }
case CollectionViewType.Stacking: { this.props.Document.singleColumn = true; return (<CollectionStackingView key="collview" {...props} />); }
@@ -202,7 +201,7 @@ export class CollectionView extends Touchable<FieldViewProps> {
private SubView = (type: CollectionViewType, renderProps: CollectionRenderProps) => {
// currently cant think of a reason for collection docking view to have a chrome. mind may change if we ever have nested docking views -syip
- const chrome = this.props.Document._chromeStatus === "disabled" || type === CollectionViewType.Docking ? (null) :
+ const chrome = this.props.Document._chromeStatus === "disabled" || this.props.Document._chromeStatus === "replaced" || type === CollectionViewType.Docking ? (null) :
<CollectionViewBaseChrome CollectionView={this} key="chrome" type={type} collapse={this.collapse} />;
return [chrome, this.SubViewHelper(type, renderProps)];
}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
index baf09fe5b..050ca8347 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
@@ -43,6 +43,9 @@ export interface ViewDefResult {
bounds?: ViewDefBounds;
}
function toLabel(target: FieldResult<Field>) {
+ if (typeof target === "number" || Number(target)) {
+ return Number(target).toFixed(2).toString();
+ }
if (target instanceof ObjectField || target instanceof RefField) {
return target[ToString]();
}
@@ -186,7 +189,7 @@ export function computePivotLayout(
const maxColHeight = pivotAxisWidth * expander * Math.ceil(maxInColumn / numCols);
const dividers = sortedPivotKeys.map((key, i) =>
- ({ type: "div", color: "lightGray", x: i * pivotAxisWidth * (numCols * expander + gap), y: -maxColHeight + pivotAxisWidth, width: pivotAxisWidth * numCols * expander, height: maxColHeight, payload: pivotColumnGroups.get(key)!.filters }));
+ ({ type: "div", color: "lightGray", x: i * pivotAxisWidth * (numCols * expander + gap) - pivotAxisWidth * (expander - 1) / 2, y: -maxColHeight + pivotAxisWidth, width: pivotAxisWidth * numCols * expander, height: maxColHeight, payload: pivotColumnGroups.get(key)!.filters }));
groupNames.push(...dividers);
return normalizeResults(panelDim, max_text, childPairs, docMap, poolData, viewDefsToJSX, groupNames, 0, [], childDocs.filter(c => !filterDocs.includes(c)));
}
@@ -211,8 +214,8 @@ export function computeTimelineLayout(
const timelineFieldKey = Field.toString(pivotDoc._pivotField as Field);
const curTime = toNumber(pivotDoc[fieldKey + "-timelineCur"]);
const curTimeSpan = Cast(pivotDoc[fieldKey + "-timelineSpan"], "number", null);
- const minTimeReq = curTime === undefined ? Cast(pivotDoc[fieldKey + "-timelineMinReq"], "number", null) : curTimeSpan && (curTime - curTimeSpan);
- const maxTimeReq = curTime === undefined ? Cast(pivotDoc[fieldKey + "-timelineMaxReq"], "number", null) : curTimeSpan && (curTime + curTimeSpan);
+ const minTimeReq = curTimeSpan === undefined ? Cast(pivotDoc[fieldKey + "-timelineMinReq"], "number", null) : curTime && (curTime - curTimeSpan);
+ const maxTimeReq = curTimeSpan === undefined ? Cast(pivotDoc[fieldKey + "-timelineMaxReq"], "number", null) : curTime && (curTime + curTimeSpan);
const fontSize = NumCast(pivotDoc[fieldKey + "-timelineFontSize"], panelDim[1] > 58 ? 20 : Math.max(7, panelDim[1] / 3));
const fontHeight = panelDim[1] > 58 ? 30 : panelDim[1] / 2;
const findStack = (time: number, stack: number[]) => {
@@ -220,11 +223,11 @@ export function computeTimelineLayout(
return index === -1 ? stack.length : index;
}
- let minTime = Number.MAX_VALUE;
- let maxTime = -Number.MAX_VALUE;
+ let minTime = minTimeReq === undefined ? Number.MAX_VALUE : minTimeReq;
+ let maxTime = maxTimeReq === undefined ? -Number.MAX_VALUE : maxTimeReq;
filterDocs.map(doc => {
const num = NumCast(doc[timelineFieldKey], Number(StrCast(doc[timelineFieldKey])));
- if (!(Number.isNaN(num) || (minTimeReq && num < minTimeReq) || (maxTimeReq && num > maxTimeReq))) {
+ if (!Number.isNaN(num) && (!minTimeReq || num >= minTimeReq) && (!maxTimeReq || num <= maxTimeReq)) {
!pivotDateGroups.get(num) && pivotDateGroups.set(num, []);
pivotDateGroups.get(num)!.push(doc);
minTime = Math.min(num, minTime);
@@ -254,10 +257,10 @@ export function computeTimelineLayout(
let prevKey = Math.floor(minTime);
if (sortedKeys.length && scaling * (sortedKeys[0] - prevKey) > 25) {
- groupNames.push({ type: "text", text: prevKey.toString(), x: x, y: 0, height: fontHeight, fontSize, payload: undefined });
+ groupNames.push({ type: "text", text: toLabel(prevKey), x: x, y: 0, height: fontHeight, fontSize, payload: undefined });
}
if (!sortedKeys.length && curTime !== undefined) {
- groupNames.push({ type: "text", text: curTime.toString(), x: (curTime - minTime) * scaling, zIndex: 1000, color: "orange", y: 0, height: fontHeight, fontSize, payload: undefined });
+ groupNames.push({ type: "text", text: toLabel(curTime), x: (curTime - minTime) * scaling, zIndex: 1000, color: "orange", y: 0, height: fontHeight, fontSize, payload: undefined });
}
const pivotAxisWidth = NumCast(pivotDoc.pivotTimeWidth, panelDim[1] / 2.5);
@@ -265,7 +268,7 @@ export function computeTimelineLayout(
let zind = 0;
sortedKeys.forEach(key => {
if (curTime !== undefined && curTime > prevKey && curTime <= key) {
- groupNames.push({ type: "text", text: curTime.toString(), x: (curTime - minTime) * scaling, y: 0, zIndex: 1000, color: "orange", height: fontHeight, fontSize, payload: key });
+ groupNames.push({ type: "text", text: toLabel(curTime), x: (curTime - minTime) * scaling, y: 0, zIndex: 1000, color: "orange", height: fontHeight, fontSize, payload: key });
}
const keyDocs = pivotDateGroups.get(key)!;
x += scaling * (key - prevKey);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx
index bb9ae4326..92fa2781c 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx
@@ -8,74 +8,65 @@ import { CollectionViewProps } from "../CollectionSubView";
import "./CollectionFreeFormView.scss";
import React = require("react");
import v5 = require("uuid/v5");
+import { computed } from "mobx";
+import { FieldResult } from "../../../../new_fields/Doc";
+import { List } from "../../../../new_fields/List";
@observer
export class CollectionFreeFormRemoteCursors extends React.Component<CollectionViewProps> {
- protected getCursors(): CursorField[] {
+ @computed protected get cursors(): CursorField[] {
const doc = this.props.Document;
- const id = CurrentUserUtils.id;
- if (!id) {
+ let cursors: FieldResult<List<CursorField>>;
+ const { id } = CurrentUserUtils;
+ if (!id || !(cursors = Cast(doc.cursors, listSpec(CursorField)))) {
return [];
}
-
- const cursors = Cast(doc.cursors, listSpec(CursorField));
-
const now = mobxUtils.now();
- // const now = Date.now();
- return (cursors || []).filter(cursor => cursor.data.metadata.id !== id && (now - cursor.data.metadata.timestamp) < 1000);
+ return (cursors || []).filter(({ data: { metadata } }) => metadata.id !== id && (now - metadata.timestamp) < 1000);
}
- private crosshairs?: HTMLCanvasElement;
- drawCrosshairs = (backgroundColor: string) => {
- if (this.crosshairs) {
- const ctx = this.crosshairs.getContext('2d');
- if (ctx) {
- ctx.fillStyle = backgroundColor;
- ctx.fillRect(0, 0, 20, 20);
-
- ctx.fillStyle = "black";
- ctx.lineWidth = 0.5;
-
- ctx.beginPath();
+ @computed get renderedCursors() {
+ return this.cursors.map(({ data: { metadata, position: { x, y } } }) => {
+ return (
+ <div key={metadata.id} className="collectionFreeFormRemoteCursors-cont"
+ style={{ transform: `translate(${x - 10}px, ${y - 10}px)` }}
+ >
+ <canvas className="collectionFreeFormRemoteCursors-canvas"
+ ref={(el) => {
+ if (el) {
+ const ctx = el.getContext('2d');
+ if (ctx) {
+ ctx.fillStyle = "#" + v5(metadata.id, v5.URL).substring(0, 6).toUpperCase() + "22";
+ ctx.fillRect(0, 0, 20, 20);
- ctx.moveTo(10, 0);
- ctx.lineTo(10, 8);
+ ctx.fillStyle = "black";
+ ctx.lineWidth = 0.5;
- ctx.moveTo(10, 20);
- ctx.lineTo(10, 12);
+ ctx.beginPath();
- ctx.moveTo(0, 10);
- ctx.lineTo(8, 10);
+ ctx.moveTo(10, 0);
+ ctx.lineTo(10, 8);
- ctx.moveTo(20, 10);
- ctx.lineTo(12, 10);
+ ctx.moveTo(10, 20);
+ ctx.lineTo(10, 12);
- ctx.stroke();
+ ctx.moveTo(0, 10);
+ ctx.lineTo(8, 10);
- // ctx.font = "10px Arial";
- // ctx.fillText(Doc.CurrentUserEmail[0].toUpperCase(), 10, 10);
- }
- }
- }
+ ctx.moveTo(20, 10);
+ ctx.lineTo(12, 10);
- get sharedCursors() {
- return this.getCursors().map(c => {
- const m = c.data.metadata;
- const l = c.data.position;
- this.drawCrosshairs("#" + v5(m.id, v5.URL).substring(0, 6).toUpperCase() + "22");
- return (
- <div key={m.id} className="collectionFreeFormRemoteCursors-cont"
- style={{ transform: `translate(${l.x - 10}px, ${l.y - 10}px)` }}
- >
- <canvas className="collectionFreeFormRemoteCursors-canvas"
- ref={(el) => { if (el) this.crosshairs = el; }}
+ ctx.stroke();
+ }
+ }
+ }}
width={20}
height={20}
/>
<p className="collectionFreeFormRemoteCursors-symbol">
- {m.identifier[0].toUpperCase()}
+ {metadata.identifier[0].toUpperCase()}
</p>
</div>
);
@@ -83,6 +74,6 @@ export class CollectionFreeFormRemoteCursors extends React.Component<CollectionV
}
render() {
- return this.sharedCursors;
+ return this.renderedCursors;
}
} \ No newline at end of file
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 2518a4a55..07a5a2c7b 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1,20 +1,22 @@
import { library } from "@fortawesome/fontawesome-svg-core";
import { faEye } from "@fortawesome/free-regular-svg-icons";
import { faBraille, faChalkboard, faCompass, faCompressArrowsAlt, faExpandArrowsAlt, faFileUpload, faPaintBrush, faTable, faUpload } from "@fortawesome/free-solid-svg-icons";
-import { action, computed, observable, ObservableMap, reaction, runInAction, IReactionDisposer, trace } from "mobx";
+import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
-import { Doc, DocListCast, HeightSym, Opt, WidthSym, DocListCastAsync, Field } from "../../../../new_fields/Doc";
+import { computedFn } from "mobx-utils";
+import { Doc, DocListCast, HeightSym, Opt, WidthSym } from "../../../../new_fields/Doc";
import { documentSchema, positionSchema } from "../../../../new_fields/documentSchemas";
import { Id } from "../../../../new_fields/FieldSymbols";
-import { InkTool, InkField, InkData } from "../../../../new_fields/InkField";
-import { createSchema, makeInterface, listSpec } from "../../../../new_fields/Schema";
+import { InkTool } from "../../../../new_fields/InkField";
+import { createSchema, listSpec, makeInterface } from "../../../../new_fields/Schema";
import { ScriptField } from "../../../../new_fields/ScriptField";
-import { BoolCast, Cast, DateCast, NumCast, StrCast, ScriptCast } from "../../../../new_fields/Types";
+import { Cast, NumCast, ScriptCast, StrCast } from "../../../../new_fields/Types";
+import { TraceMobx } from "../../../../new_fields/util";
+import { GestureUtils } from "../../../../pen-gestures/GestureUtils";
import { CurrentUserUtils } from "../../../../server/authentication/models/current_user_utils";
-import { aggregateBounds, emptyFunction, intersectRect, returnOne, Utils } from "../../../../Utils";
+import { aggregateBounds, intersectRect, returnOne, Utils } from "../../../../Utils";
import { DocServer } from "../../../DocServer";
-import { Docs, DocUtils } from "../../../documents/Documents";
-import { DocumentType } from "../../../documents/DocumentTypes";
+import { Docs } from "../../../documents/Documents";
import { DocumentManager } from "../../../util/DocumentManager";
import { DragManager } from "../../../util/DragManager";
import { HistoryUtil } from "../../../util/History";
@@ -32,15 +34,12 @@ import { FormattedTextBox } from "../../nodes/FormattedTextBox";
import { pageSchema } from "../../nodes/ImageBox";
import PDFMenu from "../../pdf/PDFMenu";
import { CollectionSubView } from "../CollectionSubView";
-import { computePivotLayout, ViewDefResult, computeTimelineLayout, PoolData, ViewDefBounds } from "./CollectionFreeFormLayoutEngines";
+import { computePivotLayout, computeTimelineLayout, PoolData, ViewDefBounds, ViewDefResult } from "./CollectionFreeFormLayoutEngines";
import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCursors";
import "./CollectionFreeFormView.scss";
import MarqueeOptionsMenu from "./MarqueeOptionsMenu";
import { MarqueeView } from "./MarqueeView";
import React = require("react");
-import { computedFn } from "mobx-utils";
-import { TraceMobx } from "../../../../new_fields/util";
-import { GestureUtils } from "../../../../pen-gestures/GestureUtils";
library.add(faEye as any, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt, faCompass, faUpload, faBraille, faChalkboard, faFileUpload);
@@ -807,7 +806,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
doFreeformLayout(poolData: Map<string, any>) {
const layoutDocs = this.childLayoutPairs.map(pair => pair.layout);
const initResult = this.Document.arrangeInit && this.Document.arrangeInit.script.run({ docs: layoutDocs, collection: this.Document }, console.log);
- let state = initResult && initResult.success ? initResult.result.scriptState : undefined;
+ const state = initResult && initResult.success ? initResult.result.scriptState : undefined;
const elements = initResult && initResult.success ? this.viewDefsToJSX(initResult.result.views) : [];
this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map((pair, i) => {
@@ -827,7 +826,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
}
@computed get filterDocs() {
- const docFilters = Cast(this.props.Document._docFilter, listSpec("string"), []);
+ const docFilters = Cast(this.props.Document._docFilters, listSpec("string"), []);
+ const docRangeFilters = Cast(this.props.Document._docRangeFilters, listSpec("string"), []);
const clusters: { [key: string]: { [value: string]: string } } = {};
for (let i = 0; i < docFilters.length; i += 3) {
const [key, value, modifiers] = docFilters.slice(i, i + 3);
@@ -853,7 +853,19 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
}
return true;
}) : this.childDocs;
- return filteredDocs;
+ const rangeFilteredDocs = filteredDocs.filter(d => {
+ for (let i = 0; i < docRangeFilters.length; i += 3) {
+ const key = docRangeFilters[i];
+ const min = Number(docRangeFilters[i + 1]);
+ const max = Number(docRangeFilters[i + 2]);
+ const val = Cast(d[key], "number", null);
+ if (val !== undefined && (val < min || val > max)) {
+ return false;
+ }
+ }
+ return true;
+ });
+ return rangeFilteredDocs;
}
get doLayoutComputation() {
const { newPool, computedElementData } = this.doInternalLayoutComputation;
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index e16f4011e..4b0855635 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -346,8 +346,6 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
summary = (e: KeyboardEvent | React.PointerEvent | undefined) => {
const bounds = this.Bounds;
const selected = this.marqueeSelect(false);
- const newCollection = this.getCollection(selected, false);
-
selected.map(d => {
this.props.removeDocument(d);
d.x = NumCast(d.x) - bounds.left - bounds.width / 2;
@@ -355,23 +353,9 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
d.page = -1;
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-" });
- 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,
- _viewType: CollectionViewType.Stacking, _chromeStatus: "disabled", title: "-summary-"
- });
- Doc.GetProto(summary).maximizeLocation = "inPlace"; // or "onRight"
- this.props.addLiveTextDocument(container);
- } else if (e instanceof KeyboardEvent ? e.key === "S" : false) { // the summary stands alone, but is linked to a collection of the summarized documents - set the OnCLick behavior to link follow to access them
- Doc.GetProto(summary).maximizeLocation = "inTab"; // or "inPlace", or "onRight"
- this.props.addLiveTextDocument(summary);
- }
+ const summary = Docs.Create.TextDocument("", { x: bounds.left, y: bounds.top, _width: 200, _height: 200, _fitToBox: true, _showSidebar: true, backgroundColor: "#e2ad32" /* yellow */, title: "-summary-" });
+ Doc.GetProto(summary)["data-annotations"] = new List<Doc>(selected);
+ this.props.addLiveTextDocument(summary);
MarqueeOptionsMenu.Instance.fadeOut(true);
}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss
index 0c74b8ddb..821c8d804 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss
@@ -1,8 +1,8 @@
.collectionMulticolumnView_contents {
display: flex;
+ overflow: hidden;
width: 100%;
height: 100%;
- overflow: hidden;
.document-wrapper {
display: flex;
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.scss b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.scss
index 64f607680..a7e2c5707 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.scss
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.scss
@@ -1,8 +1,8 @@
.collectionMultirowView_contents {
display: flex;
+ overflow: hidden;
width: 100%;
height: 100%;
- overflow: hidden;
flex-direction: column;
.document-wrapper {
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index ff7c4998f..ec05443e5 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -258,6 +258,8 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
return (
<div className={"collectionMultirowView_contents"}
style={{
+ width: `calc(100% - ${2 * NumCast(this.props.Document._xMargin)}px)`,
+ height: `calc(100% - ${2 * NumCast(this.props.Document._yMargin)}px)`,
marginLeft: NumCast(this.props.Document._xMargin), marginRight: NumCast(this.props.Document._xMargin),
marginTop: NumCast(this.props.Document._yMargin), marginBottom: NumCast(this.props.Document._yMargin)
}} ref={this.createDashEventsTarget}>
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index bd1b6166f..671f5b96e 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -2,7 +2,7 @@ import React = require("react");
import { action, computed } from "mobx";
import { observer } from "mobx-react";
import "react-table/react-table.css";
-import { Doc } from "../../../new_fields/Doc";
+import { Doc, Opt } from "../../../new_fields/Doc";
import { ComputedField, ScriptField } from "../../../new_fields/ScriptField";
import { NumCast, StrCast } from "../../../new_fields/Types";
import { emptyFunction, returnEmptyString, returnOne } from "../../../Utils";
@@ -18,6 +18,7 @@ import { TraceMobx } from "../../../new_fields/util";
interface ContentFittingDocumentViewProps {
Document?: Doc;
DataDocument?: Doc;
+ LayoutDoc?: () => Opt<Doc>;
LibraryPath: Doc[];
childDocs?: Doc[];
renderDepth: number;
@@ -42,7 +43,7 @@ interface ContentFittingDocumentViewProps {
@observer
export class ContentFittingDocumentView extends React.Component<ContentFittingDocumentViewProps>{
public get displayName() { return "DocumentView(" + this.props.Document?.title + ")"; } // this makes mobx trace() statements more descriptive
- private get layoutDoc() { return this.props.Document && Doc.Layout(this.props.Document); }
+ private get layoutDoc() { return this.props.Document && (this.props.LayoutDoc?.() || Doc.Layout(this.props.Document)); }
private get nativeWidth() { return NumCast(this.layoutDoc?._nativeWidth, this.props.PanelWidth()); }
private get nativeHeight() { return NumCast(this.layoutDoc?._nativeHeight, this.props.PanelHeight()); }
@computed get scaling() {
@@ -97,6 +98,7 @@ export class ContentFittingDocumentView extends React.Component<ContentFittingDo
<DocumentView {...this.props}
Document={this.props.Document}
DataDoc={this.props.DataDocument}
+ LayoutDoc={this.props.LayoutDoc}
LibraryPath={this.props.LibraryPath}
fitToBox={this.props.fitToBox}
onClick={this.props.onClick}
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index ac80e2ec1..11a33b70a 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -1,7 +1,6 @@
import { computed } from "mobx";
import { observer } from "mobx-react";
import { Doc } from "../../../new_fields/Doc";
-import { ScriptField } from "../../../new_fields/ScriptField";
import { Cast, StrCast } from "../../../new_fields/Types";
import { OmitKeys, Without } from "../../../Utils";
import { HistogramBox } from "../../northstar/dash-nodes/HistogramBox";
@@ -14,13 +13,13 @@ import { LinkFollowBox } from "../linking/LinkFollowBox";
import { YoutubeBox } from "./../../apis/youtube/YoutubeBox";
import { AudioBox } from "./AudioBox";
import { ButtonBox } from "./ButtonBox";
+import { SliderBox } from "./SliderBox";
import { DocumentBox } from "./DocumentBox";
import { DocumentViewProps } from "./DocumentView";
import "./DocumentView.scss";
import { FontIconBox } from "./FontIconBox";
import { FieldView, FieldViewProps } from "./FieldView";
import { FormattedTextBox } from "./FormattedTextBox";
-import { IconBox } from "./IconBox";
import { ImageBox } from "./ImageBox";
import { KeyValueBox } from "./KeyValueBox";
import { PDFBox } from "./PDFBox";
@@ -83,10 +82,10 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
return this.props.DataDoc instanceof Promise ? undefined : this.props.DataDoc;
}
get layoutDoc() {
- if (this.props.DataDoc === undefined && typeof Doc.LayoutField(this.props.Document) !== "string") {
+ if (this.props.DataDoc === undefined && (this.props.LayoutDoc || 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 Doc.expandTemplateLayout(Doc.Layout(this.props.Document), this.props.Document);
+ return Doc.expandTemplateLayout(this.props.LayoutDoc?.() || Doc.Layout(this.props.Document), this.props.Document);
}
return Doc.Layout(this.props.Document);
}
@@ -106,7 +105,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
<ObserverJsxParser
blacklistedAttrs={[]}
components={{
- FormattedTextBox, ImageBox, IconBox, DirectoryImportBox, FontIconBox: FontIconBox, ButtonBox, FieldView,
+ FormattedTextBox, ImageBox, DirectoryImportBox, FontIconBox, ButtonBox, SliderBox, FieldView,
CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, WebBox, KeyValueBox,
PDFBox, VideoBox, AudioBox, HistogramBox, PresBox, YoutubeBox, LinkFollowBox, PresElementBox, QueryBox,
ColorBox, DashWebRTCVideo, DocuLinkBox, InkingStroke, DocumentBox
diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss
index b9045b11e..b121c6c18 100644
--- a/src/client/views/nodes/DocumentView.scss
+++ b/src/client/views/nodes/DocumentView.scss
@@ -71,7 +71,6 @@
width: 100%;
height: 25;
background: rgba(0, 0, 0, .4);
- padding: 4px;
text-align: center;
text-overflow: ellipsis;
white-space: pre;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 787f6b79b..95858af4c 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1,36 +1,42 @@
import { library } from '@fortawesome/fontawesome-svg-core';
import * as fa from '@fortawesome/free-solid-svg-icons';
-import { action, computed, runInAction, trace } from "mobx";
+import { action, computed, runInAction } from "mobx";
import { observer } from "mobx-react";
import * as rp from "request-promise";
import { Doc, DocListCast, DocListCastAsync, Opt } from "../../../new_fields/Doc";
import { Document, PositionDocument } from '../../../new_fields/documentSchemas';
import { Id } from '../../../new_fields/FieldSymbols';
+import { InkTool } from '../../../new_fields/InkField';
+import { List } from '../../../new_fields/List';
+import { RichTextField } from '../../../new_fields/RichTextField';
import { listSpec } from "../../../new_fields/Schema";
import { ScriptField } from '../../../new_fields/ScriptField';
import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types";
-import { ImageField, PdfField, VideoField, AudioField } from '../../../new_fields/URLField';
+import { AudioField, ImageField, PdfField, VideoField } from '../../../new_fields/URLField';
+import { TraceMobx } from '../../../new_fields/util';
+import { GestureUtils } from '../../../pen-gestures/GestureUtils';
import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
-import { emptyFunction, returnTransparent, returnTrue, Utils, returnOne } from "../../../Utils";
+import { emptyFunction, returnOne, returnTransparent, returnTrue, Utils } from "../../../Utils";
import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils';
import { DocServer } from "../../DocServer";
-import { Docs, DocUtils, DocumentOptions } from "../../documents/Documents";
+import { Docs, DocumentOptions, DocUtils } from "../../documents/Documents";
import { DocumentType } from '../../documents/DocumentTypes';
import { ClientUtils } from '../../util/ClientUtils';
import { DocumentManager } from "../../util/DocumentManager";
import { DragManager, dropActionType } from "../../util/DragManager";
+import { InteractionUtils } from '../../util/InteractionUtils';
import { Scripting } from '../../util/Scripting';
import { SelectionManager } from "../../util/SelectionManager";
import SharingManager from '../../util/SharingManager';
import { Transform } from "../../util/Transform";
import { undoBatch, UndoManager } from "../../util/UndoManager";
-import { CollectionViewType } from '../collections/CollectionView';
import { CollectionDockingView } from "../collections/CollectionDockingView";
-import { CollectionView } from "../collections/CollectionView";
+import { CollectionView, CollectionViewType } from '../collections/CollectionView';
import { ContextMenu } from "../ContextMenu";
import { ContextMenuProps } from '../ContextMenuItem';
import { DocComponent } from "../DocComponent";
import { EditableView } from '../EditableView';
+import { InkingControl } from '../InkingControl';
import { OverlayView } from '../OverlayView';
import { ScriptBox } from '../ScriptBox';
import { ScriptingRepl } from '../ScriptingRepl';
@@ -38,19 +44,7 @@ import { DocumentContentsView } from "./DocumentContentsView";
import "./DocumentView.scss";
import { FormattedTextBox } from './FormattedTextBox';
import React = require("react");
-import { InteractionUtils } from '../../util/InteractionUtils';
-import { InkingControl } from '../InkingControl';
-import { InkTool } from '../../../new_fields/InkField';
-import { TraceMobx } from '../../../new_fields/util';
-import { List } from '../../../new_fields/List';
-import { FormattedTextBoxComment } from './FormattedTextBoxComment';
-import { GestureUtils } from '../../../pen-gestures/GestureUtils';
-import { RadialMenu } from './RadialMenu';
-import { RadialMenuProps } from './RadialMenuItem';
-import { CollectionStackingView } from '../collections/CollectionStackingView';
-import { RichTextField } from '../../../new_fields/RichTextField';
-import { HistoryUtil } from '../../util/History';
library.add(fa.faEdit, fa.faTrash, fa.faShare, fa.faDownload, fa.faExpandArrowsAlt, fa.faCompressArrowsAlt, fa.faLayerGroup, fa.faExternalLinkAlt, fa.faAlignCenter, fa.faCaretSquareRight,
fa.faSquare, fa.faConciergeBell, fa.faWindowRestore, fa.faFolder, fa.faMapPin, fa.faLink, fa.faFingerprint, fa.faCrosshairs, fa.faDesktop, fa.faUnlock, fa.faLock, fa.faLaptopCode, fa.faMale,
@@ -61,6 +55,7 @@ export interface DocumentViewProps {
ContainingCollectionDoc: Opt<Doc>;
Document: Doc;
DataDoc?: Doc;
+ LayoutDoc?: () => Opt<Doc>;
LibraryPath: Doc[];
fitToBox?: boolean;
onClick?: ScriptField;
@@ -269,12 +264,10 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
SelectionManager.DeselectAll();
Doc.UnBrushDoc(this.props.Document);
} else if (this.onClickHandler && this.onClickHandler.script) {
+ SelectionManager.DeselectAll();
this.onClickHandler.script.run({ this: this.Document.isTemplateForField && this.props.DataDoc ? this.props.DataDoc : this.props.Document, containingCollection: this.props.ContainingCollectionDoc, shiftKey: e.shiftKey }, console.log);
} else if (this.Document.type === DocumentType.BUTTON) {
ScriptBox.EditButtonScript("On Button Clicked ...", this.props.Document, "onClick", e.clientX, e.clientY);
- } else if (this.props.Document.isButton === "Selector") { // this should be moved to an OnClick script
- FormattedTextBoxComment.Hide();
- this.Document.links?.[0] instanceof Doc && (Doc.UserDoc().SelectedDocs = new List([Doc.LinkOtherAnchor(this.Document.links[0], this.props.Document)]));
} else if (this.Document.isButton) {
SelectionManager.SelectDoc(this, e.ctrlKey); // don't think this should happen if a button action is actually triggered.
this.buttonClick(e.altKey, e.ctrlKey);
@@ -284,29 +277,11 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
}
preventDefault && e.preventDefault();
}
- })
+ });
buttonClick = async (altKey: boolean, ctrlKey: boolean) => {
- const maximizedDocs = await DocListCastAsync(this.Document.maximizedDocs);
- const summarizedDocs = await DocListCastAsync(this.Document.summarizedDocs);
const linkDocs = DocListCast(this.props.Document.links);
- let expandedDocs: Doc[] = [];
- expandedDocs = maximizedDocs ? [...maximizedDocs, ...expandedDocs] : expandedDocs;
- expandedDocs = summarizedDocs ? [...summarizedDocs, ...expandedDocs] : expandedDocs;
- // let expandedDocs = [ ...(maximizedDocs ? maximizedDocs : []), ...(summarizedDocs ? summarizedDocs : []),];
- if (expandedDocs.length) {
- SelectionManager.DeselectAll();
- let maxLocation = StrCast(this.Document.maximizeLocation, "inPlace");
- maxLocation = this.Document.maximizeLocation = (!ctrlKey ? !altKey ? maxLocation : (maxLocation !== "inPlace" ? "inPlace" : "onRight") : (maxLocation !== "inPlace" ? "inPlace" : "inTab"));
- if (maxLocation === "inPlace") {
- expandedDocs.forEach(maxDoc => this.props.addDocument && this.props.addDocument(maxDoc));
- const scrpt = this.props.ScreenToLocalTransform().scale(this.props.ContentScaling()).inverse().transformPoint(NumCast(this.layoutDoc.width) / 2, NumCast(this.layoutDoc.height) / 2);
- DocumentManager.Instance.animateBetweenPoint(scrpt, expandedDocs);
- } else {
- expandedDocs.forEach(maxDoc => (!this.props.addDocTab(maxDoc, undefined, "close") && this.props.addDocTab(maxDoc, undefined, maxLocation)));
- }
- }
- else if (linkDocs.length) {
+ if (linkDocs.length) {
DocumentManager.Instance.FollowLink(undefined, this.props.Document,
// open up target if it's not already in view ... by zooming into the button document first and setting flag to reset zoom afterwards
(doc: Doc, maxLocation: string) => this.props.focus(this.props.Document, true, 1, () => this.props.addDocTab(doc, undefined, maxLocation)),
@@ -563,7 +538,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
const docTemplate = docLayoutTemplate || creator(fieldTemplate ? [fieldTemplate] : [], { title: customName + "(" + doc.title + ")", isTemplateDoc: true, _width: _width + 20, _height: Math.max(100, _height + 45) });
fieldTemplate && Doc.MakeMetadataFieldTemplate(fieldTemplate, Doc.GetProto(docTemplate));
- Doc.ApplyTemplateTo(docTemplate, dataDoc || doc, customName, undefined);
+ Doc.ApplyTemplateTo(docTemplate, doc, customName, undefined);
} else {
doc.layoutKey = customName;
}
@@ -617,13 +592,17 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
}
@undoBatch
- @action
- freezeNativeDimensions = (): void => {
- this.layoutDoc._autoHeight = false;
- this.layoutDoc.ignoreAspect = !this.layoutDoc.ignoreAspect;
- if (!this.layoutDoc.ignoreAspect && !this.layoutDoc._nativeWidth) {
- this.layoutDoc._nativeWidth = this.props.PanelWidth();
- this.layoutDoc._nativeHeight = this.props.PanelHeight();
+ public static unfreezeNativeDimensions = action((layoutDoc: Doc): void => {
+ layoutDoc._nativeWidth = undefined;
+ layoutDoc._nativeHeight = undefined;
+ });
+
+ toggleNativeDimensions = () => {
+ if (this.Document._nativeWidth || this.Document._nativeHeight) {
+ DocumentView.unfreezeNativeDimensions(this.layoutDoc);
+ }
+ else {
+ Doc.freezeNativeDimensions(this.layoutDoc, this.props.PanelWidth(), this.props.PanelHeight());
}
}
@@ -657,7 +636,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
if (StrCast(tempDoc.title) === layout) {
foundLayout = tempDoc;
}
- })
+ });
DocumentView.
makeCustomViewClicked(this.props.Document, this.props.DataDoc, Docs.Create.StackingDocument, layout, foundLayout);
} else {
@@ -737,7 +716,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
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.ignoreAspect || !this.Document._nativeWidth || !this.Document._nativeHeight ? "Freeze" : "Unfreeze", event: this.freezeNativeDimensions, icon: "snowflake" });
+ layoutItems.push({ description: !this.Document._nativeWidth || !this.Document._nativeHeight ? "Freeze" : "Unfreeze", event: this.toggleNativeDimensions, 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" });
layoutItems.push({ description: "Center View", event: () => this.props.focus(this.props.Document, false), icon: "crosshairs" });
@@ -817,7 +796,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
}
});
const path = this.props.LibraryPath.reduce((p: string, d: Doc) => p + "/" + (Doc.AreProtosEqual(d, (Doc.UserDoc().LibraryBtn as Doc).sourcePanel as Doc) ? "" : d.title), "");
- cm.addItem({ description: "Pin to Presentation", event: () => this.props.pinToPres(this.props.Document), icon: "map-pin" });
cm.addItem({
description: `path: ${path}`, event: () => {
this.props.LibraryPath.map(lp => Doc.GetProto(lp).treeViewOpen = lp.treeViewOpen = true);
@@ -856,6 +834,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
ContainingCollectionDoc={this.props.ContainingCollectionDoc}
Document={this.props.Document}
DataDoc={this.props.DataDoc}
+ LayoutDoc={this.props.LayoutDoc}
fitToBox={this.props.fitToBox}
LibraryPath={this.props.LibraryPath}
addDocument={this.props.addDocument}
@@ -938,7 +917,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
this.contents
:
<div className="documentView-styleWrapper" >
- <div className="documentView-styleContentWrapper" style={{ height: showTextTitle ? "calc(100% - 29px)" : "100%", top: showTextTitle ? "29px" : undefined }}>
+ <div className="documentView-styleContentWrapper" style={{ height: showTextTitle ? "calc(100% - 25px)" : "100%", top: showTextTitle ? "25px" : undefined }}>
{this.contents}
</div>
{titleView}
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index dbbb76f83..8250f41f3 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -5,15 +5,10 @@ import { DateField } from "../../../new_fields/DateField";
import { Doc, FieldResult, Opt } from "../../../new_fields/Doc";
import { IconField } from "../../../new_fields/IconField";
import { List } from "../../../new_fields/List";
-import { RichTextField } from "../../../new_fields/RichTextField";
import { AudioField, ImageField, VideoField } from "../../../new_fields/URLField";
import { Transform } from "../../util/Transform";
import { CollectionView } from "../collections/CollectionView";
import { AudioBox } from "./AudioBox";
-import { FormattedTextBox } from "./FormattedTextBox";
-import { IconBox } from "./IconBox";
-import { ImageBox } from "./ImageBox";
-import { PDFBox } from "./PDFBox";
import { VideoBox } from "./VideoBox";
import { ScriptField } from "../../../new_fields/ScriptField";
@@ -48,6 +43,7 @@ export interface FieldViewProps {
setVideoBox?: (player: VideoBox) => void;
ContentScaling: () => number;
ChromeHeight?: () => number;
+ childLayoutTemplate?: () => Opt<Doc>;
}
@observer
@@ -78,9 +74,6 @@ export class FieldView extends React.Component<FieldViewProps> {
// else if (field instaceof PresBox) {
// return <PresBox {...this.props} />;
// }
- else if (field instanceof IconField) {
- return <IconBox {...this.props} />;
- }
else if (field instanceof VideoField) {
return <VideoBox {...this.props} />;
}
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 9370d3745..0cc276458 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -26,7 +26,7 @@ import { DocumentType } from '../../documents/DocumentTypes';
import { DictationManager } from '../../util/DictationManager';
import { DragManager } from "../../util/DragManager";
import buildKeymap from "../../util/ProsemirrorExampleTransfer";
-import { inpRules } from "../../util/RichTextRules";
+import { RichTextRules } from "../../util/RichTextRules";
import { DashDocCommentView, FootnoteView, ImageResizeView, DashDocView, OrderedListView, schema, SummaryView, DashFieldView } from "../../util/RichTextSchema";
import { SelectionManager } from "../../util/SelectionManager";
import { undoBatch, UndoManager } from "../../util/UndoManager";
@@ -197,7 +197,8 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
}
updateTitle = () => {
- if (StrCast(this.dataDoc.title).startsWith("-") && this._editorView && !this.Document.customTitle) {
+ if ((this.props.Document.isTemplateForField === "data" || !this.props.Document.isTemplateForField) && // only update the title if the data document's data field is changing
+ StrCast(this.dataDoc.title).startsWith("-") && this._editorView && !this.Document.customTitle) {
const str = this._editorView.state.doc.textContent;
const titlestr = str.substr(0, Math.min(40, str.length));
this.dataDoc.title = "-" + titlestr + (str.length > 40 ? "..." : "");
@@ -464,13 +465,14 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
}
_keymap: any = undefined;
+ _rules: RichTextRules | undefined;
@computed get config() {
this._keymap = buildKeymap(schema);
- (schema as any).Document = this.props.Document;
+ this._rules = new RichTextRules(this.props.Document, this);
return {
schema,
plugins: [
- inputRules(inpRules),
+ inputRules(this._rules.inpRules),
this.richTextMenuPlugin(),
history(),
keymap(this._keymap),
@@ -574,7 +576,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
if (ret.frag.size > 2 && ret.start >= 0) {
let selection = TextSelection.near(editor.state.doc.resolve(ret.start)); // default to near the start
if (ret.frag.firstChild) {
- selection = TextSelection.between(editor.state.doc.resolve(ret.start + 2), editor.state.doc.resolve(ret.start + ret.frag.firstChild.nodeSize)); // bcz: looks better to not have the target selected
+ selection = TextSelection.between(editor.state.doc.resolve(ret.start), editor.state.doc.resolve(ret.start + ret.frag.firstChild.nodeSize)); // bcz: looks better to not have the target selected
}
editor.dispatch(editor.state.tr.setSelection(new TextSelection(selection.$from, selection.$from)).scrollIntoView());
const mark = editor.state.schema.mark(this._editorView.state.schema.marks.search_highlight);
@@ -769,7 +771,6 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
clipboardTextSerializer: this.clipboardTextSerializer,
handlePaste: this.handlePaste,
});
- this._editorView.state.schema.Document = this.props.Document;
const startupText = !rtfField && this._editorView && Field.toString(this.dataDoc[fieldKey] as Field);
if (startupText) {
this._editorView.dispatch(this._editorView.state.tr.insertText(startupText));
@@ -1010,14 +1011,14 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
}
const state = this._editorView!.state;
if (!state.selection.empty && e.key === "%") {
- state.schema.EnteringStyle = true;
+ this._rules!.EnteringStyle = true;
e.preventDefault();
e.stopPropagation();
return;
}
- if (state.selection.empty || !state.schema.EnteringStyle) {
- state.schema.EnteringStyle = false;
+ if (state.selection.empty || !this._rules!.EnteringStyle) {
+ this._rules!.EnteringStyle = false;
}
if (e.key === "Escape") {
this._editorView!.dispatch(state.tr.setSelection(TextSelection.create(state.doc, state.selection.from, state.selection.from)));
@@ -1122,8 +1123,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
CollectionView={undefined}
ScreenToLocalTransform={this.sidebarScreenToLocal}
renderDepth={this.props.renderDepth + 1}
- ContainingCollectionDoc={this.props.ContainingCollectionDoc}
- chromeCollapsed={true}>
+ ContainingCollectionDoc={this.props.ContainingCollectionDoc}>
</CollectionFreeFormView>
<div className="formattedTextBox-sidebar-handle" onPointerDown={this.sidebarDown} onClick={e => this.toggleSidebar()} />
</div>}
diff --git a/src/client/views/nodes/IconBox.scss b/src/client/views/nodes/IconBox.scss
deleted file mode 100644
index 488681027..000000000
--- a/src/client/views/nodes/IconBox.scss
+++ /dev/null
@@ -1,23 +0,0 @@
-
-@import "../globalCssVariables";
-.iconBox-container {
- position: inherit;
- left:0;
- top:0;
- height: auto;
- width: max-content;
- // overflow: hidden;
- pointer-events: all;
- svg {
- width: $MINIMIZED_ICON_SIZE !important;
- height: $MINIMIZED_ICON_SIZE !important;
- height: auto;
- background: white;
- }
- .iconBox-label {
- position: absolute;
- width:max-content;
- font-size: 14px;
- margin-top: 3px;
- }
-} \ No newline at end of file
diff --git a/src/client/views/nodes/IconBox.tsx b/src/client/views/nodes/IconBox.tsx
deleted file mode 100644
index 172338eb6..000000000
--- a/src/client/views/nodes/IconBox.tsx
+++ /dev/null
@@ -1,93 +0,0 @@
-import React = require("react");
-import { library } from '@fortawesome/fontawesome-svg-core';
-import { faCaretUp, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote, faTag, faTextHeight } from '@fortawesome/free-solid-svg-icons';
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { computed, observable, runInAction } from "mobx";
-import { observer } from "mobx-react";
-import { FieldView, FieldViewProps } from './FieldView';
-import "./IconBox.scss";
-import { Cast, StrCast, BoolCast } from "../../../new_fields/Types";
-import { Doc, DocListCast } from "../../../new_fields/Doc";
-import { IconField } from "../../../new_fields/IconField";
-import { ContextMenu } from "../ContextMenu";
-import Measure from "react-measure";
-import { MINIMIZED_ICON_SIZE } from "../../views/globalCssVariables.scss";
-import { Scripting } from "../../util/Scripting";
-import { ComputedField } from "../../../new_fields/ScriptField";
-
-
-library.add(faCaretUp);
-library.add(faObjectGroup);
-library.add(faStickyNote);
-library.add(faFilePdf);
-library.add(faFilm, faTag, faTextHeight);
-
-@observer
-export class IconBox extends React.Component<FieldViewProps> {
- public static LayoutString(fieldKey: string) { return FieldView.LayoutString(IconBox, fieldKey); }
-
- @observable _panelWidth: number = 0;
- @observable _panelHeight: number = 0;
- @computed get layout(): string { const field = Cast(this.props.Document[this.props.fieldKey], IconField); return field ? field.icon : "<p>Error loading icon data</p>"; }
- @computed get minimizedIcon() { return IconBox.DocumentIcon(this.layout); }
-
- public static summaryTitleScript(inputDoc: Doc) {
- const sumDoc = Cast(inputDoc.summaryDoc, Doc) as Doc;
- if (sumDoc && StrCast(sumDoc.title).startsWith("-")) {
- return sumDoc.title + ".expanded";
- }
- return "???";
- }
- public static titleScript(inputDoc: Doc) {
- const maxDoc = DocListCast(inputDoc.maximizedDocs);
- if (maxDoc.length === 1) {
- return maxDoc[0].title + ".icon";
- }
- return maxDoc.length > 1 ? "-multiple-.icon" : "???";
- }
-
- public static AutomaticTitle(doc: Doc) {
- Doc.GetProto(doc).title = ComputedField.MakeFunction('iconTitle(this);');
- }
-
- public static DocumentIcon(layout: string) {
- const button = layout.indexOf("PDFBox") !== -1 ? faFilePdf :
- layout.indexOf("ImageBox") !== -1 ? faImage :
- layout.indexOf("Formatted") !== -1 ? faStickyNote :
- layout.indexOf("Video") !== -1 ? faFilm :
- layout.indexOf("Collection") !== -1 ? faObjectGroup :
- faCaretUp;
- return <FontAwesomeIcon icon={button} className="documentView-minimizedIcon" />;
- }
-
- setLabelField = (): void => {
- this.props.Document.hideLabel = !this.props.Document.hideLabel;
- }
-
- specificContextMenu = (): void => {
- const cm = ContextMenu.Instance;
- cm.addItem({ description: this.props.Document.hideLabel ? "Show label with icon" : "Remove label from icon", event: this.setLabelField, icon: "tag" });
- if (!this.props.Document.hideLabel) {
- cm.addItem({ description: "Use Target Title", event: () => IconBox.AutomaticTitle(this.props.Document), icon: "text-height" });
- }
- }
- render() {
- const label = this.props.Document.hideLabel ? "" : this.props.Document.title;
- return (
- <div className="iconBox-container" onContextMenu={this.specificContextMenu}>
- {this.minimizedIcon}
- <Measure offset onResize={(r) => runInAction(() => {
- if (r.offset!.width || this.props.Document.hideLabel) {
- this.props.Document.iconWidth = (r.offset!.width + Number(MINIMIZED_ICON_SIZE));
- if (this.props.Document._height === Number(MINIMIZED_ICON_SIZE)) this.props.Document._width = this.props.Document.iconWidth;
- }
- })}>
- {({ measureRef }) =>
- <span ref={measureRef} className="iconBox-label">{label}</span>
- }
- </Measure>
- </div>);
- }
-}
-Scripting.addGlobal(function iconTitle(doc: any) { return IconBox.titleScript(doc); });
-Scripting.addGlobal(function summaryTitle(doc: any) { return IconBox.summaryTitleScript(doc); }); \ No newline at end of file
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 896ac1685..c0e102195 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -207,7 +207,7 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
return url.href;
} else if (url.href.indexOf(window.location.origin) === -1) {
return Utils.CorsProxy(url.href);
- } else if (!(lower.endsWith(".png") || lower.endsWith(".jpg") || lower.endsWith(".jpeg"))) {
+ } else if (!/\.(png|jpg|jpeg|gif)$/.test(lower)) {
return url.href;//Why is this here
}
const ext = path.extname(url.href);
@@ -321,12 +321,12 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
const { dataDoc } = this;
const { success, failure, idle, loading } = uploadIcons;
runInAction(() => this.uploadIcon = loading);
- const [{ clientAccessPath }] = await Networking.PostToServer("/uploadRemoteImage", { sources: [primary] });
+ const [{ accessPaths }] = await Networking.PostToServer("/uploadRemoteImage", { sources: [primary] });
dataDoc.originalUrl = primary;
let succeeded = true;
let data: ImageField | undefined;
try {
- data = new ImageField(Utils.prepend(clientAccessPath));
+ data = new ImageField(Utils.prepend(accessPaths.agnostic.client));
} catch {
succeeded = false;
}
@@ -436,8 +436,7 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
CollectionView={undefined}
ScreenToLocalTransform={this.props.ScreenToLocalTransform}
renderDepth={this.props.renderDepth + 1}
- ContainingCollectionDoc={this.props.ContainingCollectionDoc}
- chromeCollapsed={true}>
+ ContainingCollectionDoc={this.props.ContainingCollectionDoc}>
{this.contentFunc}
</CollectionFreeFormView>
</div >);
diff --git a/src/client/views/nodes/KeyValueBox.scss b/src/client/views/nodes/KeyValueBox.scss
index 6e8a36c6a..a26880c9e 100644
--- a/src/client/views/nodes/KeyValueBox.scss
+++ b/src/client/views/nodes/KeyValueBox.scss
@@ -74,7 +74,7 @@ $header-height: 30px;
.keyValueBox-evenRow {
position: relative;
- display: inline-block;
+ display: flex;
width:100%;
height:$header-height;
background: $light-color;
@@ -114,7 +114,7 @@ $header-height: 30px;
.keyValueBox-oddRow {
position: relative;
- display: inline-block;
+ display: flex;
width:100%;
height:30px;
background: $light-color-secondary;
diff --git a/src/client/views/nodes/PresBox.scss b/src/client/views/nodes/PresBox.scss
index 7618aa7e3..6a20751cc 100644
--- a/src/client/views/nodes/PresBox.scss
+++ b/src/client/views/nodes/PresBox.scss
@@ -2,13 +2,11 @@
position: absolute;
z-index: 2;
box-shadow: #AAAAAA .2vw .2vw .4vw;
- right: 0;
- top: 0;
bottom: 0;
width: 100%;
min-width: 120px;
height: 100%;
- min-height: 50px;
+ min-height: 41px;
letter-spacing: 2px;
overflow: hidden;
transition: 0.7s opacity ease;
@@ -17,6 +15,10 @@
.presBox-buttons {
padding: 10px;
width: 100%;
+ background: gray;
+ padding-right: 10px;
+ padding-top: 5px;
+ padding-bottom: 5px;
.presBox-button {
margin-right: 2.5%;
margin-left: 2.5%;
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index 6c4cbba12..d4a47c159 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -2,27 +2,25 @@ import React = require("react");
import { library } from '@fortawesome/fontawesome-svg-core';
import { faArrowLeft, faArrowRight, faEdit, faMinus, faPlay, faPlus, faStop, faTimes } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { action, computed, IReactionDisposer, reaction, observable, runInAction } from "mobx";
+import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
import { Doc, DocListCast, DocListCastAsync } from "../../../new_fields/Doc";
-import { listSpec, makeInterface } from "../../../new_fields/Schema";
-import { Cast, FieldValue, NumCast } from "../../../new_fields/Types";
+import { InkTool } from "../../../new_fields/InkField";
+import { listSpec } from "../../../new_fields/Schema";
+import { BoolCast, Cast, FieldValue, NumCast } from "../../../new_fields/Types";
import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
+import { returnFalse } from "../../../Utils";
import { Docs } from "../../documents/Documents";
import { DocumentManager } from "../../util/DocumentManager";
import { undoBatch } from "../../util/UndoManager";
import { CollectionDockingView } from "../collections/CollectionDockingView";
import { CollectionView, CollectionViewType } from "../collections/CollectionView";
import { ContextMenu } from "../ContextMenu";
-import { FieldView, FieldViewProps } from './FieldView';
-import "./PresBox.scss";
-import { CollectionCarouselView } from "../collections/CollectionCarouselView";
-import { returnFalse } from "../../../Utils";
import { ContextMenuProps } from "../ContextMenuItem";
-import { CollectionTimeView } from "../collections/CollectionTimeView";
-import { documentSchema } from "../../../new_fields/documentSchemas";
import { InkingControl } from "../InkingControl";
-import { InkTool } from "../../../new_fields/InkField";
+import { FieldView, FieldViewProps } from './FieldView';
+import "./PresBox.scss";
+import { PrefetchProxy } from "../../../new_fields/Proxy";
library.add(faArrowLeft);
library.add(faArrowRight);
@@ -37,33 +35,14 @@ library.add(faEdit);
export class PresBox extends React.Component<FieldViewProps> {
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PresBox, fieldKey); }
_childReaction: IReactionDisposer | undefined;
- _slideshowReaction: IReactionDisposer | undefined;
@observable _isChildActive = false;
-
componentDidMount() {
- const userDoc = CurrentUserUtils.UserDocument;
- this._slideshowReaction = reaction(() => this.props.Document._slideshow,
- (slideshow) => {
- if (!slideshow) {
- let presTemp = Cast(userDoc.presentationTemplate, Doc);
- if (presTemp instanceof Promise) {
- presTemp.then(presTemp => this.props.Document.childLayout = presTemp);
- }
- else if (presTemp === undefined) {
- presTemp = userDoc.presentationTemplate = Docs.Create.PresElementBoxDocument({ backgroundColor: "transparent", _xMargin: 5, isTemplateDoc: true, isTemplateForField: "data" });
- }
- else {
- this.props.Document.childLayout = presTemp;
- }
- } else {
- this.props.Document.childLayout = undefined;
- }
- }, { fireImmediately: true });
+ this.props.Document._forceRenderEngine = "timeline";
+ this.props.Document._replacedChrome = "replaced";
this._childReaction = reaction(() => this.childDocs.slice(), (children) => children.forEach((child, i) => child.presentationIndex = i), { fireImmediately: true });
}
componentWillUnmount() {
this._childReaction?.();
- this._slideshowReaction?.();
}
@computed get childDocs() { return DocListCast(this.props.Document[this.props.fieldKey]); }
@@ -343,24 +322,27 @@ export class PresBox extends React.Component<FieldViewProps> {
});
}
- toggleMinimize = undoBatch(action((e: React.PointerEvent) => {
- if (this.props.Document.inOverlay) {
- Doc.RemoveDocFromList((CurrentUserUtils.UserDocument.overlays as Doc), this.props.fieldKey, this.props.Document);
- CollectionDockingView.AddRightSplit(this.props.Document, this.props.DataDoc);
- this.props.Document.inOverlay = false;
- } else {
- this.props.Document.x = e.clientX + 25;
- this.props.Document.y = e.clientY - 25;
- this.props.addDocTab && this.props.addDocTab(this.props.Document, this.props.DataDoc, "close");
- Doc.AddDocToList((CurrentUserUtils.UserDocument.overlays as Doc), this.props.fieldKey, this.props.Document);
+ updateMinimize = undoBatch(action((e: React.ChangeEvent, mode: number) => {
+ const toggle = BoolCast(this.props.Document.inOverlay) !== (mode === CollectionViewType.Invalid);
+ if (toggle) {
+ if (this.props.Document.inOverlay) {
+ Doc.RemoveDocFromList((CurrentUserUtils.UserDocument.overlays as Doc), this.props.fieldKey, this.props.Document);
+ CollectionDockingView.AddRightSplit(this.props.Document, this.props.DataDoc);
+ this.props.Document.inOverlay = false;
+ } else {
+ this.props.Document.x = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0)[0];// 500;//e.clientX + 25;
+ this.props.Document.y = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0)[1];////e.clientY - 25;
+ this.props.addDocTab && this.props.addDocTab(this.props.Document, this.props.DataDoc, "close");
+ Doc.AddDocToList((CurrentUserUtils.UserDocument.overlays as Doc), this.props.fieldKey, this.props.Document);
+ }
}
}));
specificContextMenu = (e: React.MouseEvent): void => {
const funcs: ContextMenuProps[] = [];
- funcs.push({ description: "Show as Slideshow", event: action(() => this.props.Document._slideshow = "slideshow"), icon: "asterisk" });
- funcs.push({ description: "Show as Timeline", event: action(() => this.props.Document._slideshow = "timeline"), icon: "asterisk" });
- funcs.push({ description: "Show as List", event: action(() => this.props.Document._slideshow = undefined), icon: "asterisk" });
+ funcs.push({ description: "Show as Slideshow", event: action(() => this.props.Document._viewType = CollectionViewType.Carousel), icon: "asterisk" });
+ funcs.push({ description: "Show as Timeline", event: action(() => this.props.Document._viewType = CollectionViewType.Time), icon: "asterisk" });
+ funcs.push({ description: "Show as List", event: action(() => this.props.Document._viewType = CollectionViewType.Invalid), icon: "asterisk" });
ContextMenu.Instance.addItem({ description: "Presentation Funcs...", subitems: funcs, icon: "asterisk" });
}
@@ -369,13 +351,11 @@ export class PresBox extends React.Component<FieldViewProps> {
* that they will be displayed in a canvas with scale 1.
*/
initializeScaleViews = (docList: Doc[], viewtype: number) => {
- this.props.Document._chromeStatus = "disabled";
const hgt = (viewtype === CollectionViewType.Tree) ? 50 : 46;
docList.forEach((doc: Doc) => {
doc.presBox = this.props.Document;
doc.presBoxKey = this.props.fieldKey;
doc.collapsedHeight = hgt;
- doc._nativeWidth = doc._nativeHeight = undefined;
const curScale = NumCast(doc.viewScale, null);
if (curScale === undefined) {
doc.viewScale = 1;
@@ -389,42 +369,48 @@ export class PresBox extends React.Component<FieldViewProps> {
}
getTransform = () => {
- return this.props.ScreenToLocalTransform().translate(0, -50);// listBox padding-left and pres-box-cont minHeight
+ return this.props.ScreenToLocalTransform().translate(-5, -65);// listBox padding-left and pres-box-cont minHeight
}
panelHeight = () => {
return this.props.PanelHeight() - 20;
}
+
+ @undoBatch
+ viewChanged = action((e: React.ChangeEvent) => {
+ //@ts-ignore
+ this.props.Document._viewType = Number(e.target.selectedOptions[0].value);
+ this.updateMinimize(e, Number(this.props.Document._viewType));
+ });
+
+ childLayoutTemplate = () => this.props.Document._viewType === CollectionViewType.Stacking ? Cast(Doc.UserDoc().presentationTemplate, Doc, null) : undefined;
render() {
- this.initializeScaleViews(this.childDocs, NumCast(this.props.Document._viewType));
- return (this.props.Document._slideshow ?
- <div className="presBox-cont" onContextMenu={this.specificContextMenu} style={{ pointerEvents: this.active() ? "all" : "none" }} >
- {this.props.Document.inOverlay ? (null) :
- <div className="presBox-listCont" >
- {this.props.Document._slideshow === "slideshow" ?
- <CollectionCarouselView {...this.props} PanelHeight={this.panelHeight} chromeCollapsed={true} annotationsKey={""} CollectionView={undefined}
- moveDocument={returnFalse}
- addDocument={this.addDocument} removeDocument={returnFalse} focus={this.selectElement} ScreenToLocalTransform={this.getTransform} />
- :
- <CollectionTimeView {...this.props} PanelHeight={this.panelHeight} chromeCollapsed={true} annotationsKey={""} CollectionView={undefined}
- moveDocument={returnFalse}
- addDocument={this.addDocument} removeDocument={returnFalse} focus={this.selectElement} ScreenToLocalTransform={this.getTransform} />
- }
- </div>}
- <button className="presBox-backward" title="Back" onClick={this.back}><FontAwesomeIcon icon={"arrow-left"} /></button>
- <button className="presBox-forward" title="Next" onClick={this.next}><FontAwesomeIcon icon={"arrow-right"} /></button>
+ const mode = NumCast(this.props.Document._viewType, CollectionViewType.Invalid);
+ this.initializeScaleViews(this.childDocs, mode);
+ return <div className="presBox-cont" onContextMenu={this.specificContextMenu} style={{ minWidth: this.props.Document.inOverlay ? 240 : undefined, pointerEvents: this.active() || this.props.Document.inOverlay ? "all" : "none" }} >
+ <div className="presBox-buttons" style={{ display: this.props.Document._chromeStatus === "disabled" ? "none" : undefined }}>
+ <select style={{ minWidth: 50, width: "5%", height: "25", position: "relative", display: "inline-block" }}
+ className="collectionViewBaseChrome-viewPicker"
+ onPointerDown={e => e.stopPropagation()}
+ onChange={this.viewChanged}
+ value={mode}>
+ <option className="collectionViewBaseChrome-viewOption" onPointerDown={e => e.stopPropagation()} value={CollectionViewType.Invalid}>Min</option>
+ <option className="collectionViewBaseChrome-viewOption" onPointerDown={e => e.stopPropagation()} value={CollectionViewType.Stacking}>List</option>
+ <option className="collectionViewBaseChrome-viewOption" onPointerDown={e => e.stopPropagation()} value={CollectionViewType.Time}>Time</option>
+ <option className="collectionViewBaseChrome-viewOption" onPointerDown={e => e.stopPropagation()} value={CollectionViewType.Carousel}>Slides</option>
+ </select>
+ <button className="presBox-button" title="Back" onClick={this.back}><FontAwesomeIcon icon={"arrow-left"} /></button>
+ <button className="presBox-button" title={"Reset Presentation" + this.props.Document.presStatus ? "" : " From Start"} onClick={this.startOrResetPres}>
+ <FontAwesomeIcon icon={this.props.Document.presStatus ? "stop" : "play"} />
+ </button>
+ <button className="presBox-button" title="Next" onClick={this.next}><FontAwesomeIcon icon={"arrow-right"} /></button>
+ </div>
+ <div className="presBox-listCont" >
+ {mode !== CollectionViewType.Invalid ?
+ <CollectionView {...this.props} PanelHeight={this.panelHeight} moveDocument={returnFalse} childLayoutTemplate={this.childLayoutTemplate}
+ addDocument={this.addDocument} removeDocument={returnFalse} focus={this.selectElement} ScreenToLocalTransform={this.getTransform} />
+ : (null)
+ }
</div>
- : <div className="presBox-cont" onContextMenu={this.specificContextMenu}>
- <div className="presBox-buttons">
- <button className="presBox-button" title="Back" onClick={this.back}><FontAwesomeIcon icon={"arrow-left"} /></button>
- <button className="presBox-button" title={"Reset Presentation" + this.props.Document.presStatus ? "" : " From Start"} onClick={this.startOrResetPres}>
- <FontAwesomeIcon icon={this.props.Document.presStatus ? "stop" : "play"} />
- </button>
- <button className="presBox-button" title="Next" onClick={this.next}><FontAwesomeIcon icon={"arrow-right"} /></button>
- <button className="presBox-button" title={this.props.Document.inOverlay ? "Expand" : "Minimize"} onClick={this.toggleMinimize}><FontAwesomeIcon icon={"eye"} /></button>
- {this.props.Document.inOverlay ? (null) :
- <div className="presBox-listCont">
- <CollectionView {...this.props} whenActiveChanged={this.whenActiveChanged} PanelHeight={this.panelHeight} addDocument={this.addDocument} focus={this.selectElement} ScreenToLocalTransform={this.getTransform} />
- </div>}
- </div></div>);
+ </div>;
}
} \ No newline at end of file
diff --git a/src/client/views/nodes/SliderBox-components.tsx b/src/client/views/nodes/SliderBox-components.tsx
new file mode 100644
index 000000000..874a1108f
--- /dev/null
+++ b/src/client/views/nodes/SliderBox-components.tsx
@@ -0,0 +1,256 @@
+import * as React from "react";
+import { SliderItem } from "react-compound-slider";
+import "./SliderBox-tooltip.css";
+
+const { Component, Fragment } = React;
+
+// *******************************************************
+// TOOLTIP RAIL
+// *******************************************************
+const railStyle: React.CSSProperties = {
+ position: "absolute",
+ width: "100%",
+ height: 40,
+ top: -13,
+ borderRadius: 7,
+ cursor: "pointer",
+ opacity: 0.3,
+ zIndex: 300,
+ border: "1px solid grey"
+};
+
+const railCenterStyle: React.CSSProperties = {
+ position: "absolute",
+ width: "100%",
+ height: 14,
+ borderRadius: 7,
+ cursor: "pointer",
+ pointerEvents: "none",
+ backgroundColor: "rgb(155,155,155)"
+};
+
+interface TooltipRailProps {
+ activeHandleID: string;
+ getRailProps: (props: object) => object;
+ getEventData: (e: Event) => object;
+}
+
+export class TooltipRail extends Component<TooltipRailProps> {
+ state = {
+ value: null,
+ percent: null
+ };
+
+ static defaultProps = {
+ disabled: false
+ };
+
+ onMouseEnter = () => {
+ document.addEventListener("mousemove", this.onMouseMove);
+ }
+
+ onMouseLeave = () => {
+ this.setState({ value: null, percent: null });
+ document.removeEventListener("mousemove", this.onMouseMove);
+ }
+
+ onMouseMove = (e: Event) => {
+ const { activeHandleID, getEventData } = this.props;
+
+ if (activeHandleID) {
+ this.setState({ value: null, percent: null });
+ } else {
+ this.setState(getEventData(e));
+ }
+ }
+
+ render() {
+ const { value, percent } = this.state;
+ const { activeHandleID, getRailProps } = this.props;
+
+ return (
+ <Fragment>
+ {!activeHandleID && value ? (
+ <div
+ style={{
+ left: `${percent}%`,
+ position: "absolute",
+ marginLeft: "-11px",
+ marginTop: "-35px"
+ }}
+ >
+ <div className="tooltip">
+ <span className="tooltiptext">Value: {value}</span>
+ </div>
+ </div>
+ ) : null}
+ <div
+ style={railStyle}
+ {...getRailProps({
+ onMouseEnter: this.onMouseEnter,
+ onMouseLeave: this.onMouseLeave
+ })}
+ />
+ <div style={railCenterStyle} />
+ </Fragment>
+ );
+ }
+}
+
+// *******************************************************
+// HANDLE COMPONENT
+// *******************************************************
+interface HandleProps {
+ key: string;
+ handle: SliderItem;
+ isActive: Boolean;
+ disabled?: Boolean;
+ domain: number[];
+ getHandleProps: (id: string, config: object) => object;
+}
+
+export class Handle extends Component<HandleProps> {
+ static defaultProps = {
+ disabled: false
+ };
+
+ state = {
+ mouseOver: false
+ };
+
+ onMouseEnter = () => {
+ this.setState({ mouseOver: true });
+ }
+
+ onMouseLeave = () => {
+ this.setState({ mouseOver: false });
+ }
+
+ render() {
+ const {
+ domain: [min, max],
+ handle: { id, value, percent },
+ isActive,
+ disabled,
+ getHandleProps
+ } = this.props;
+ const { mouseOver } = this.state;
+
+ return (
+ <Fragment>
+ {(mouseOver || isActive) && !disabled ? (
+ <div
+ style={{
+ left: `${percent}%`,
+ position: "absolute",
+ marginLeft: "-11px",
+ marginTop: "-35px"
+ }}
+ >
+ <div className="tooltip">
+ <span className="tooltiptext">Value: {value}</span>
+ </div>
+ </div>
+ ) : null}
+ <div
+ role="slider"
+ aria-valuemin={min}
+ aria-valuemax={max}
+ aria-valuenow={value}
+ style={{
+ left: `${percent}%`,
+ position: "absolute",
+ marginLeft: "-11px",
+ marginTop: "-6px",
+ zIndex: 400,
+ width: 24,
+ height: 24,
+ cursor: "pointer",
+ border: 0,
+ borderRadius: "50%",
+ boxShadow: "1px 1px 1px 1px rgba(0, 0, 0, 0.4)",
+ backgroundColor: disabled ? "#666" : "#3e1db3"
+ }}
+ {...getHandleProps(id, {
+ onMouseEnter: this.onMouseEnter,
+ onMouseLeave: this.onMouseLeave
+ })}
+ />
+ </Fragment>
+ );
+ }
+}
+
+// *******************************************************
+// TRACK COMPONENT
+// *******************************************************
+interface TrackProps {
+ source: SliderItem;
+ target: SliderItem;
+ disabled: Boolean;
+ getTrackProps: () => object;
+}
+
+export function Track({
+ source,
+ target,
+ getTrackProps,
+ disabled = false
+}: TrackProps) {
+ return (
+ <div
+ style={{
+ position: "absolute",
+ height: 14,
+ zIndex: 1,
+ backgroundColor: disabled ? "#999" : "#3e1db3",
+ borderRadius: 7,
+ cursor: "pointer",
+ left: `${source.percent}%`,
+ width: `${target.percent - source.percent}%`
+ }}
+ {...getTrackProps()}
+ />
+ );
+}
+
+// *******************************************************
+// TICK COMPONENT
+// *******************************************************
+interface TickProps {
+ tick: SliderItem;
+ count: number;
+ format: (val: number) => string;
+}
+
+const defaultFormat = (d: number) => `d`;
+
+export function Tick({ tick, count, format = defaultFormat }: TickProps) {
+ return (
+ <div>
+ <div
+ style={{
+ position: "absolute",
+ marginTop: 17,
+ width: 1,
+ height: 5,
+ backgroundColor: "rgb(200,200,200)",
+ left: `${tick.percent}%`
+ }}
+ />
+ <div
+ style={{
+ position: "absolute",
+ marginTop: 25,
+ fontSize: 10,
+ textAlign: "center",
+ marginLeft: `${-(100 / count) / 2}%`,
+ width: `${100 / count}%`,
+ left: `${tick.percent}%`
+ }}
+ >
+ {format(tick.value)}
+ </div>
+ </div>
+ );
+}
diff --git a/src/client/views/nodes/SliderBox-tooltip.css b/src/client/views/nodes/SliderBox-tooltip.css
new file mode 100644
index 000000000..8afde8eb5
--- /dev/null
+++ b/src/client/views/nodes/SliderBox-tooltip.css
@@ -0,0 +1,33 @@
+.tooltip {
+ position: relative;
+ display: inline-block;
+ border-bottom: 1px dotted #222;
+ margin-left: 22px;
+ }
+
+ .tooltip .tooltiptext {
+ width: 100px;
+ background-color: #222;
+ color: #fff;
+ opacity: 0.8;
+ text-align: center;
+ border-radius: 6px;
+ padding: 5px 0;
+ position: absolute;
+ z-index: 1;
+ bottom: 150%;
+ left: 50%;
+ margin-left: -60px;
+ }
+
+ .tooltip .tooltiptext::after {
+ content: "";
+ position: absolute;
+ top: 100%;
+ left: 50%;
+ margin-left: -5px;
+ border-width: 5px;
+ border-style: solid;
+ border-color: #222 transparent transparent transparent;
+ }
+ \ No newline at end of file
diff --git a/src/client/views/nodes/SliderBox.scss b/src/client/views/nodes/SliderBox.scss
new file mode 100644
index 000000000..4ef277d8c
--- /dev/null
+++ b/src/client/views/nodes/SliderBox.scss
@@ -0,0 +1,8 @@
+.sliderBox-outerDiv {
+ width: 100%;
+ height: 100%;
+ pointer-events: all;
+ border-radius: inherit;
+ display: flex;
+ flex-direction: column;
+} \ No newline at end of file
diff --git a/src/client/views/nodes/SliderBox.tsx b/src/client/views/nodes/SliderBox.tsx
new file mode 100644
index 000000000..844d95d11
--- /dev/null
+++ b/src/client/views/nodes/SliderBox.tsx
@@ -0,0 +1,130 @@
+import { library } from '@fortawesome/fontawesome-svg-core';
+import { faEdit } from '@fortawesome/free-regular-svg-icons';
+import { computed, runInAction } from 'mobx';
+import { observer } from 'mobx-react';
+import * as React from 'react';
+import { Handles, Rail, Slider, Tracks, Ticks } from 'react-compound-slider';
+import { Doc } from '../../../new_fields/Doc';
+import { documentSchema } from '../../../new_fields/documentSchemas';
+import { createSchema, listSpec, makeInterface } from '../../../new_fields/Schema';
+import { ScriptField } from '../../../new_fields/ScriptField';
+import { BoolCast, FieldValue, StrCast, NumCast, Cast } from '../../../new_fields/Types';
+import { DragManager } from '../../util/DragManager';
+import { ContextMenu } from '../ContextMenu';
+import { ContextMenuProps } from '../ContextMenuItem';
+import { DocComponent } from '../DocComponent';
+import './SliderBox.scss';
+import { Handle, TooltipRail, Track, Tick } from './SliderBox-components';
+import { FieldView, FieldViewProps } from './FieldView';
+import { ScriptBox } from '../ScriptBox';
+
+
+library.add(faEdit as any);
+
+const SliderSchema = createSchema({
+ _sliderMin: "number",
+ _sliderMax: "number",
+ _sliderMinThumb: "number",
+ _sliderMaxThumb: "number",
+});
+
+type SliderDocument = makeInterface<[typeof SliderSchema, typeof documentSchema]>;
+const SliderDocument = makeInterface(SliderSchema, documentSchema);
+
+@observer
+export class SliderBox extends DocComponent<FieldViewProps, SliderDocument>(SliderDocument) {
+ public static LayoutString(fieldKey: string) { return FieldView.LayoutString(SliderBox, fieldKey); }
+ private dropDisposer?: DragManager.DragDropDisposer;
+
+ @computed get dataDoc() {
+ return this.props.DataDoc &&
+ (this.Document.isTemplateForField || BoolCast(this.props.DataDoc.isTemplateForField) ||
+ this.props.DataDoc.layout === this.Document) ? this.props.DataDoc : Doc.GetProto(this.Document);
+ }
+
+ specificContextMenu = (e: React.MouseEvent): void => {
+ const funcs: ContextMenuProps[] = [];
+ funcs.push({ description: "Edit Thumb Change Script", icon: "edit", event: (obj: any) => ScriptBox.EditButtonScript("On Thumb Change ...", this.props.Document, "onThumbChange", obj.x, obj.y) });
+ ContextMenu.Instance.addItem({ description: "Slider Funcs...", subitems: funcs, icon: "asterisk" });
+ }
+ onChange = (values: readonly number[]) => runInAction(() => {
+ this.Document._sliderMinThumb = values[0];
+ this.Document._sliderMaxThumb = values[1];
+ Cast(this.Document.onThumbChanged, ScriptField, null)?.script.run({ range: values, this: this.props.Document });
+ })
+
+ render() {
+ const domain = [NumCast(this.props.Document._sliderMin), NumCast(this.props.Document._sliderMax)];
+ const defaultValues = [NumCast(this.props.Document._sliderMinThumb), NumCast(this.props.Document._sliderMaxThumb)];
+ return (
+ <div className="sliderBox-outerDiv" onContextMenu={this.specificContextMenu} onPointerDown={e => e.stopPropagation()}
+ style={{ boxShadow: this.Document.opacity === 0 ? undefined : StrCast(this.Document.boxShadow, "") }}>
+ <div className="sliderBox-mainButton" onContextMenu={this.specificContextMenu} style={{
+ background: this.Document.backgroundColor, color: this.Document.color || "black",
+ fontSize: this.Document.fontSize, letterSpacing: this.Document.letterSpacing || ""
+ }} >
+ <Slider
+ mode={2}
+ step={1}
+ domain={domain}
+ rootStyle={{ position: "relative", width: "100%" }}
+ onChange={this.onChange}
+ values={defaultValues}
+ >
+
+ <Rail>{railProps => <TooltipRail {...railProps} />}</Rail>
+ <Handles>
+ {({ handles, activeHandleID, getHandleProps }) => (
+ <div className="slider-handles">
+ {handles.map((handle, i) => {
+ const value = i === 0 ? this.Document._sliderMinThumb : this.Document._sliderMaxThumb;
+ return (
+ <div title={String(value)}>
+ <Handle
+ key={handle.id}
+ handle={handle}
+ domain={domain}
+ isActive={handle.id === activeHandleID}
+ getHandleProps={getHandleProps}
+ />
+ </div>
+ );
+ })}
+ </div>
+ )}
+ </Handles>
+ <Tracks left={false} right={false}>
+ {({ tracks, getTrackProps }) => (
+ <div className="slider-tracks">
+ {tracks.map(({ id, source, target }) => (
+ <Track
+ key={id}
+ source={source}
+ target={target}
+ disabled={false}
+ getTrackProps={getTrackProps}
+ />
+ ))}
+ </div>
+ )}
+ </Tracks>
+ <Ticks count={5}>
+ {({ ticks }) => (
+ <div className="slider-tracks">
+ {ticks.map((tick) => (
+ <Tick
+ key={tick.id}
+ tick={tick}
+ count={ticks.length}
+ format={(val: number) => val.toString()}
+ />
+ ))}
+ </div>
+ )}
+ </Ticks>
+ </Slider>
+ </div>
+ </div>
+ );
+ }
+} \ No newline at end of file
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index d12a8d151..6695e04c3 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -354,8 +354,7 @@ export class VideoBox extends DocAnnotatableComponent<FieldViewProps, VideoDocum
CollectionView={undefined}
ScreenToLocalTransform={this.props.ScreenToLocalTransform}
renderDepth={this.props.renderDepth + 1}
- ContainingCollectionDoc={this.props.ContainingCollectionDoc}
- chromeCollapsed={true}>
+ ContainingCollectionDoc={this.props.ContainingCollectionDoc}>
{this.contentFunc}
</CollectionFreeFormView>
</div>
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index a48dc286e..7e49d957d 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -211,8 +211,7 @@ export class WebBox extends DocAnnotatableComponent<FieldViewProps, WebDocument>
CollectionView={undefined}
ScreenToLocalTransform={this.props.ScreenToLocalTransform}
renderDepth={this.props.renderDepth + 1}
- ContainingCollectionDoc={this.props.ContainingCollectionDoc}
- chromeCollapsed={true}>
+ ContainingCollectionDoc={this.props.ContainingCollectionDoc}>
{() => [this.content]}
</CollectionFreeFormView>
</div >);
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index a7c1990e9..4f50be5b0 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -651,8 +651,7 @@ export class PDFViewer extends DocAnnotatableComponent<IViewerProps, PdfDocument
CollectionView={undefined}
ScreenToLocalTransform={this.overlayTransform}
renderDepth={this.props.renderDepth + 1}
- ContainingCollectionDoc={this.props.ContainingCollectionView?.props.Document}
- chromeCollapsed={true}>
+ ContainingCollectionDoc={this.props.ContainingCollectionView?.props.Document}>
</CollectionFreeFormView>
</div>;
}
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index 52773d466..888707ee3 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -2,19 +2,18 @@ import { library } from '@fortawesome/fontawesome-svg-core';
import { faFile as fileRegular } from '@fortawesome/free-regular-svg-icons';
import { faArrowDown, faArrowUp, faFile as fileSolid, faFileDownload, faLocationArrow, faSearch } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { action, computed, reaction, IReactionDisposer } from "mobx";
+import { action, computed, IReactionDisposer, reaction } from "mobx";
import { observer } from "mobx-react";
-import { Doc, DocListCast } from "../../../new_fields/Doc";
+import { Doc } from "../../../new_fields/Doc";
import { documentSchema } from '../../../new_fields/documentSchemas';
import { Id } from "../../../new_fields/FieldSymbols";
import { createSchema, makeInterface } from '../../../new_fields/Schema';
-import { Cast, NumCast, StrCast } from "../../../new_fields/Types";
-import { emptyFunction, returnFalse, emptyPath } from "../../../Utils";
-import { DocumentType } from "../../documents/DocumentTypes";
+import { Cast, NumCast } from "../../../new_fields/Types";
+import { emptyFunction, emptyPath, returnFalse } from "../../../Utils";
import { Transform } from "../../util/Transform";
import { CollectionViewType } from '../collections/CollectionView';
+import { DocExtendableComponent } from '../DocComponent';
import { ContentFittingDocumentView } from '../nodes/ContentFittingDocumentView';
-import { DocComponent, DocExtendableComponent } from '../DocComponent';
import { FieldView, FieldViewProps } from '../nodes/FieldView';
import "./PresElementBox.scss";
import React = require("react");
@@ -50,15 +49,16 @@ export class PresElementBox extends DocExtendableComponent<FieldViewProps, PresD
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PresElementBox, fieldKey); }
_heightDisposer: IReactionDisposer | undefined;
- @computed get indexInPres() { return NumCast(this.originalLayout?.presentationIndex); }
- @computed get presentationDoc() { return Cast(this.originalLayout?.presBox, Doc) as Doc; }
- @computed get originalLayout() { return this.props.Document.expandedTemplate as Doc; }
- @computed get targetDoc() { return this.originalLayout?.presentationTargetDoc as Doc; }
- @computed get currentIndex() { return NumCast(this.presentationDoc?._itemIndex); }
+ @computed get indexInPres() { return NumCast(this.presElementDoc?.presentationIndex); }
+ @computed get presBoxDoc() { return Cast(this.presElementDoc?.presBox, Doc) as Doc; }
+ @computed get presElementDoc() { return this.props.Document.expandedTemplate as Doc; }
+ @computed get presLayoutDoc() { return this.props.Document; }
+ @computed get targetDoc() { return this.presElementDoc?.presentationTargetDoc as Doc; }
+ @computed get currentIndex() { return NumCast(this.presBoxDoc?._itemIndex); }
componentDidMount() {
- this._heightDisposer = reaction(() => [this.originalLayout.embedOpen, this.originalLayout.collapsedHeight],
- params => this.originalLayout._height = NumCast(params[1]) + (Number(params[0]) ? 100 : 0), { fireImmediately: true });
+ this._heightDisposer = reaction(() => [this.presElementDoc.embedOpen, this.presElementDoc.collapsedHeight],
+ params => this.presLayoutDoc._height = NumCast(params[1]) + (Number(params[0]) ? 100 : 0), { fireImmediately: true });
}
componentWillUnmount() {
this._heightDisposer?.();
@@ -71,13 +71,13 @@ export class PresElementBox extends DocExtendableComponent<FieldViewProps, PresD
@action
onHideDocumentUntilPressClick = (e: React.MouseEvent) => {
e.stopPropagation();
- this.originalLayout.hideTillShownButton = !this.originalLayout.hideTillShownButton;
- if (!this.originalLayout.hideTillShownButton) {
+ this.presElementDoc.hideTillShownButton = !this.presElementDoc.hideTillShownButton;
+ if (!this.presElementDoc.hideTillShownButton) {
if (this.indexInPres >= this.currentIndex && this.targetDoc) {
this.targetDoc.opacity = 1;
}
} else {
- if (this.presentationDoc.presStatus && this.indexInPres > this.currentIndex && this.targetDoc) {
+ if (this.presBoxDoc.presStatus && this.indexInPres > this.currentIndex && this.targetDoc) {
this.targetDoc.opacity = 0;
}
}
@@ -91,14 +91,14 @@ export class PresElementBox extends DocExtendableComponent<FieldViewProps, PresD
@action
onHideDocumentAfterPresentedClick = (e: React.MouseEvent) => {
e.stopPropagation();
- this.originalLayout.hideAfterButton = !this.originalLayout.hideAfterButton;
- if (!this.originalLayout.hideAfterButton) {
+ this.presElementDoc.hideAfterButton = !this.presElementDoc.hideAfterButton;
+ if (!this.presElementDoc.hideAfterButton) {
if (this.indexInPres <= this.currentIndex && this.targetDoc) {
this.targetDoc.opacity = 1;
}
} else {
- if (this.originalLayout.fadeButton) this.originalLayout.fadeButton = false;
- if (this.presentationDoc.presStatus && this.indexInPres < this.currentIndex && this.targetDoc) {
+ if (this.presElementDoc.fadeButton) this.presElementDoc.fadeButton = false;
+ if (this.presBoxDoc.presStatus && this.indexInPres < this.currentIndex && this.targetDoc) {
this.targetDoc.opacity = 0;
}
}
@@ -112,14 +112,14 @@ export class PresElementBox extends DocExtendableComponent<FieldViewProps, PresD
@action
onFadeDocumentAfterPresentedClick = (e: React.MouseEvent) => {
e.stopPropagation();
- this.originalLayout.fadeButton = !this.originalLayout.fadeButton;
- if (!this.originalLayout.fadeButton) {
+ this.presElementDoc.fadeButton = !this.presElementDoc.fadeButton;
+ if (!this.presElementDoc.fadeButton) {
if (this.indexInPres <= this.currentIndex && this.targetDoc) {
this.targetDoc.opacity = 1;
}
} else {
- this.originalLayout.hideAfterButton = false;
- if (this.presentationDoc.presStatus && (this.indexInPres < this.currentIndex) && this.targetDoc) {
+ this.presElementDoc.hideAfterButton = false;
+ if (this.presBoxDoc.presStatus && (this.indexInPres < this.currentIndex) && this.targetDoc) {
this.targetDoc.opacity = 0.5;
}
}
@@ -131,11 +131,11 @@ export class PresElementBox extends DocExtendableComponent<FieldViewProps, PresD
@action
onNavigateDocumentClick = (e: React.MouseEvent) => {
e.stopPropagation();
- this.originalLayout.navButton = !this.originalLayout.navButton;
- if (this.originalLayout.navButton) {
- this.originalLayout.showButton = false;
+ this.presElementDoc.navButton = !this.presElementDoc.navButton;
+ if (this.presElementDoc.navButton) {
+ this.presElementDoc.showButton = false;
if (this.currentIndex === this.indexInPres) {
- this.props.focus(this.originalLayout);
+ this.props.focus(this.presElementDoc);
}
}
}
@@ -147,13 +147,13 @@ export class PresElementBox extends DocExtendableComponent<FieldViewProps, PresD
onZoomDocumentClick = (e: React.MouseEvent) => {
e.stopPropagation();
- this.originalLayout.showButton = !this.originalLayout.showButton;
- if (!this.originalLayout.showButton) {
- this.originalLayout.viewScale = 1;
+ this.presElementDoc.showButton = !this.presElementDoc.showButton;
+ if (!this.presElementDoc.showButton) {
+ this.presElementDoc.viewScale = 1;
} else {
- this.originalLayout.navButton = false;
+ this.presElementDoc.navButton = false;
if (this.currentIndex === this.indexInPres) {
- this.props.focus(this.originalLayout);
+ this.props.focus(this.presElementDoc);
}
}
}
@@ -162,14 +162,14 @@ export class PresElementBox extends DocExtendableComponent<FieldViewProps, PresD
*/
ScreenToLocalListTransform = (xCord: number, yCord: number) => [xCord, yCord];
- embedHeight = () => this.props.PanelHeight() - NumCast(this.originalLayout.collapsedHeight);
+ embedHeight = () => this.props.PanelHeight() - NumCast(this.presElementDoc.collapsedHeight);
embedWidth = () => this.props.PanelWidth() - 20;
/**
* The function that is responsible for rendering the a preview or not for this
* presentation element.
*/
renderEmbeddedInline = () => {
- return !this.originalLayout.embedOpen || !this.targetDoc ? (null) :
+ return !this.presElementDoc.embedOpen || !this.targetDoc ? (null) :
<div className="presElementBox-embedded" style={{ height: this.embedHeight() }}>
<ContentFittingDocumentView
Document={this.targetDoc}
@@ -196,24 +196,24 @@ export class PresElementBox extends DocExtendableComponent<FieldViewProps, PresD
const treecontainer = this.props.ContainingCollectionDoc?._viewType === CollectionViewType.Tree;
const className = "presElementBox-item" + (this.currentIndex === this.indexInPres ? " presElementBox-selected" : "");
const pbi = "presElementBox-interaction";
- return !this.originalLayout ? (null) : (
+ return !this.presElementDoc ? (null) : (
<div className={className} key={this.props.Document[Id] + this.indexInPres}
style={{ outlineWidth: Doc.IsBrushed(this.targetDoc) ? `1px` : "0px", }}
- onClick={e => { this.props.focus(this.originalLayout); e.stopPropagation(); }}>
+ onClick={e => { this.props.focus(this.presElementDoc); e.stopPropagation(); }}>
{treecontainer ? (null) : <>
<strong className="presElementBox-name">
{`${this.indexInPres + 1}. ${this.targetDoc?.title}`}
</strong>
- <button className="presElementBox-closeIcon" onPointerDown={e => e.stopPropagation()} onClick={e => this.props.removeDocument && this.props.removeDocument(this.originalLayout)}>X</button>
+ <button className="presElementBox-closeIcon" onPointerDown={e => e.stopPropagation()} onClick={e => this.props.removeDocument && this.props.removeDocument(this.presElementDoc)}>X</button>
<br />
</>}
- <button title="Zoom" className={pbi + (this.originalLayout.showButton ? "-selected" : "")} onPointerDown={e => e.stopPropagation()} onClick={this.onZoomDocumentClick}><FontAwesomeIcon icon={"search"} /></button>
- <button title="Navigate" className={pbi + (this.originalLayout.navButton ? "-selected" : "")} onPointerDown={e => e.stopPropagation()} onClick={this.onNavigateDocumentClick}><FontAwesomeIcon icon={"location-arrow"} /></button>
- <button title="Hide Before" className={pbi + (this.originalLayout.hideTillShownButton ? "-selected" : "")} onPointerDown={e => e.stopPropagation()} onClick={this.onHideDocumentUntilPressClick}><FontAwesomeIcon icon={fileSolid} /></button>
- <button title="Fade After" className={pbi + (this.originalLayout.fadeButton ? "-selected" : "")} onPointerDown={e => e.stopPropagation()} onClick={this.onFadeDocumentAfterPresentedClick}><FontAwesomeIcon icon={faFileDownload} /></button>
- <button title="Hide After" className={pbi + (this.originalLayout.hideAfterButton ? "-selected" : "")} onPointerDown={e => e.stopPropagation()} onClick={this.onHideDocumentAfterPresentedClick}><FontAwesomeIcon icon={faFileDownload} /></button>
- <button title="Group With Up" className={pbi + (this.originalLayout.groupButton ? "-selected" : "")} onPointerDown={e => e.stopPropagation()} onClick={e => { e.stopPropagation(); this.originalLayout.groupButton = !this.originalLayout.groupButton; }}><FontAwesomeIcon icon={"arrow-up"} /></button>
- <button title="Expand Inline" className={pbi + (this.originalLayout.embedOpen ? "-selected" : "")} onPointerDown={e => e.stopPropagation()} onClick={e => { e.stopPropagation(); this.originalLayout.embedOpen = !this.originalLayout.embedOpen; }}><FontAwesomeIcon icon={"arrow-down"} /></button>
+ <button title="Zoom" className={pbi + (this.presElementDoc.showButton ? "-selected" : "")} onPointerDown={e => e.stopPropagation()} onClick={this.onZoomDocumentClick}><FontAwesomeIcon icon={"search"} /></button>
+ <button title="Navigate" className={pbi + (this.presElementDoc.navButton ? "-selected" : "")} onPointerDown={e => e.stopPropagation()} onClick={this.onNavigateDocumentClick}><FontAwesomeIcon icon={"location-arrow"} /></button>
+ <button title="Hide Before" className={pbi + (this.presElementDoc.hideTillShownButton ? "-selected" : "")} onPointerDown={e => e.stopPropagation()} onClick={this.onHideDocumentUntilPressClick}><FontAwesomeIcon icon={fileSolid} /></button>
+ <button title="Fade After" className={pbi + (this.presElementDoc.fadeButton ? "-selected" : "")} onPointerDown={e => e.stopPropagation()} onClick={this.onFadeDocumentAfterPresentedClick}><FontAwesomeIcon icon={faFileDownload} /></button>
+ <button title="Hide After" className={pbi + (this.presElementDoc.hideAfterButton ? "-selected" : "")} onPointerDown={e => e.stopPropagation()} onClick={this.onHideDocumentAfterPresentedClick}><FontAwesomeIcon icon={faFileDownload} /></button>
+ <button title="Group With Up" className={pbi + (this.presElementDoc.groupButton ? "-selected" : "")} onPointerDown={e => e.stopPropagation()} onClick={e => { e.stopPropagation(); this.presElementDoc.groupButton = !this.presElementDoc.groupButton; }}><FontAwesomeIcon icon={"arrow-up"} /></button>
+ <button title="Expand Inline" className={pbi + (this.presElementDoc.embedOpen ? "-selected" : "")} onPointerDown={e => e.stopPropagation()} onClick={e => { e.stopPropagation(); this.presElementDoc.embedOpen = !this.presElementDoc.embedOpen; }}><FontAwesomeIcon icon={"arrow-down"} /></button>
<br style={{ lineHeight: 0.1 }} />
{this.renderEmbeddedInline()}