diff options
Diffstat (limited to 'src/client/views')
34 files changed, 709 insertions, 682 deletions
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index c7e4a269a..deed0fa7c 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -55,15 +55,15 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> enterPressed = (e: any) => { var key = e.keyCode || e.which; // enter pressed - if (key == 13) { + if (key === 13) { var text = e.target.value; - if (text[0] == '#') { + if (text[0] === '#') { let command = text.slice(1, text.length); this._fieldKey = new Key(command) - // if (command == "Title" || command == "title") { + // if (command === "Title" || command === "title") { // this._fieldKey = KeyStore.Title; // } - // else if (command == "Width" || command == "width") { + // else if (command === "Width" || command === "width") { // this._fieldKey = KeyStore.Width; // } this._title = "changed" @@ -117,23 +117,17 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> dragData.aliasOnDrop = false; dragData.xOffset = e.x - left; dragData.yOffset = e.y - top; - dragData.removeDocument = (dropCollectionView: CollectionView) => - dragData.draggedDocuments.map(d => { - if (dragDocView.props.RemoveDocument && dragDocView.props.ContainingCollectionView !== dropCollectionView) { - dragDocView.props.RemoveDocument(d); - } - }); + let move = SelectionManager.SelectedDocuments()[0].props.moveDocument; + dragData.moveDocument = move; this._dragging = true; document.removeEventListener("pointermove", this.onBackgroundMove); document.removeEventListener("pointerup", this.onBackgroundUp); - DragManager.StartDocumentDrag(SelectionManager.SelectedDocuments().map(docView => (docView as any)._mainCont!.current!), dragData, - e.x, e.y, - { - handlers: { - dragComplete: action(() => this._dragging = false), - }, - hideSource: true - }) + DragManager.StartDocumentDrag(SelectionManager.SelectedDocuments().map(docView => docView.ContentRef.current!), dragData, e.x, e.y, { + handlers: { + dragComplete: action(() => this._dragging = false), + }, + hideSource: true + }) e.stopPropagation(); } @@ -162,7 +156,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> onCloseUp = (e: PointerEvent): void => { e.stopPropagation(); if (e.button === 0) { - SelectionManager.SelectedDocuments().map(dv => dv.props.RemoveDocument && dv.props.RemoveDocument(dv.props.Document)); + SelectionManager.SelectedDocuments().map(dv => dv.props.removeDocument && dv.props.removeDocument(dv.props.Document)); SelectionManager.DeselectAll(); document.removeEventListener("pointermove", this.onCloseMove); document.removeEventListener("pointerup", this.onCloseUp); @@ -217,7 +211,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> } onLinkerButtonMoved = (e: PointerEvent): void => { - if (this._linkerButton.current != null) { + if (this._linkerButton.current !== null) { document.removeEventListener("pointermove", this.onLinkerButtonMoved) document.removeEventListener("pointerup", this.onLinkerButtonUp) let dragData = new DragManager.LinkDragData(SelectionManager.SelectedDocuments()[0]); @@ -246,25 +240,24 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> } onLinkButtonMoved = async (e: PointerEvent) => { - if (this._linkButton.current != null) { + if (this._linkButton.current !== null) { document.removeEventListener("pointermove", this.onLinkButtonMoved) document.removeEventListener("pointerup", this.onLinkButtonUp); let sourceDoc = SelectionManager.SelectedDocuments()[0].props.Document; let srcTarg = sourceDoc.GetT(KeyStore.Prototype, Document) - let draggedDocs = (srcTarg && srcTarg != FieldWaiting) ? + let draggedDocs = (srcTarg && srcTarg !== FieldWaiting) ? srcTarg.GetList(KeyStore.LinkedToDocs, [] as Document[]).map(linkDoc => (linkDoc.GetT(KeyStore.LinkedToDocs, Document)) as Document) : []; - let draggedFromDocs = (srcTarg && srcTarg != FieldWaiting) ? + let draggedFromDocs = (srcTarg && srcTarg !== FieldWaiting) ? srcTarg.GetList(KeyStore.LinkedFromDocs, [] as Document[]).map(linkDoc => (linkDoc.GetT(KeyStore.LinkedFromDocs, Document)) as Document) : []; draggedDocs.push(...draggedFromDocs); if (draggedDocs.length) { let moddrag = [] as Document[]; - for (let i = 0; i < draggedDocs.length; i++) { - let doc = await draggedDocs[i].GetTAsync(KeyStore.AnnotationOn, Document); - if (doc) - moddrag.push(doc); + for (const draggedDoc of draggedDocs) { + let doc = await draggedDoc.GetTAsync(KeyStore.AnnotationOn, Document); + if (doc) moddrag.push(doc); } let dragData = new DragManager.DocumentDragData(moddrag); DragManager.StartDocumentDrag([this._linkButton.current], dragData, e.x, e.y, { diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx index 29bf6add7..982aacdea 100644 --- a/src/client/views/EditableView.tsx +++ b/src/client/views/EditableView.tsx @@ -38,7 +38,7 @@ export class EditableView extends React.Component<EditableProps> { @action onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => { - if (e.key == "Enter") { + if (e.key === "Enter") { if (!e.ctrlKey) { if (this.props.SetValue(e.currentTarget.value)) { this.editing = false; @@ -47,7 +47,7 @@ export class EditableView extends React.Component<EditableProps> { this.props.OnFillDown(e.currentTarget.value); this.editing = false; } - } else if (e.key == "Escape") { + } else if (e.key === "Escape") { this.editing = false; } } diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx index 45ca52d00..4b3ea48c5 100644 --- a/src/client/views/InkingCanvas.tsx +++ b/src/client/views/InkingCanvas.tsx @@ -56,7 +56,7 @@ export class InkingCanvas extends React.Component<InkCanvasProps> { @action onPointerDown = (e: React.PointerEvent): void => { - if (e.button != 0 || e.altKey || e.ctrlKey || InkingControl.Instance.selectedTool === InkTool.None) { + if (e.button !== 0 || e.altKey || e.ctrlKey || InkingControl.Instance.selectedTool === InkTool.None) { return; } document.addEventListener("pointermove", this.onPointerMove, true); @@ -64,7 +64,7 @@ export class InkingCanvas extends React.Component<InkCanvasProps> { e.stopPropagation(); e.preventDefault(); - if (InkingControl.Instance.selectedTool != InkTool.Eraser) { + if (InkingControl.Instance.selectedTool !== InkTool.Eraser) { // start the new line, saves a uuid to represent the field of the stroke this._currentStrokeId = Utils.GenerateGuid(); this.inkData.set(this._currentStrokeId, { @@ -94,7 +94,7 @@ export class InkingCanvas extends React.Component<InkCanvasProps> { onPointerMove = (e: PointerEvent): void => { e.stopPropagation() e.preventDefault(); - if (InkingControl.Instance.selectedTool != InkTool.Eraser) { + if (InkingControl.Instance.selectedTool !== InkTool.Eraser) { let data = this.inkData; // add points to new line as it is being drawn let strokeData = data.get(this._currentStrokeId); if (strokeData) { @@ -121,7 +121,7 @@ export class InkingCanvas extends React.Component<InkCanvasProps> { get drawnPaths() { let curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1) let paths = Array.from(this.inkData).reduce((paths, [id, strokeData]) => { - if (strokeData.page == -1 || strokeData.page == curPage) + if (strokeData.page === -1 || strokeData.page === curPage) paths.push(<InkingStroke key={id} id={id} line={strokeData.pathData} offsetX={this.maxCanvasDim - this.inkMidX} offsetY={this.maxCanvasDim - this.inkMidY} @@ -131,16 +131,16 @@ export class InkingCanvas extends React.Component<InkCanvasProps> { }, [] as JSX.Element[]); return [<svg className={`inkingCanvas-paths-markers`} key="Markers" style={{ left: `${this.inkMidX - this.maxCanvasDim}px`, top: `${this.inkMidY - this.maxCanvasDim}px` }} > - {paths.filter(path => path.props.tool == InkTool.Highlighter)} + {paths.filter(path => path.props.tool === InkTool.Highlighter)} </svg>, <svg className={`inkingCanvas-paths-ink`} key="Pens" style={{ left: `${this.inkMidX - this.maxCanvasDim}px`, top: `${this.inkMidY - this.maxCanvasDim}px` }}> - {paths.filter(path => path.props.tool != InkTool.Highlighter)} + {paths.filter(path => path.props.tool !== InkTool.Highlighter)} </svg>]; } render() { - let svgCanvasStyle = InkingControl.Instance.selectedTool != InkTool.None ? "canSelect" : "noSelect"; + let svgCanvasStyle = InkingControl.Instance.selectedTool !== InkTool.None ? "canSelect" : "noSelect"; return ( <div className="inkingCanvas" > <div className={`inkingCanvas-${svgCanvasStyle}`} onPointerDown={this.onPointerDown} /> diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx index c1519dff8..13f0a0acc 100644 --- a/src/client/views/InkingControl.tsx +++ b/src/client/views/InkingControl.tsx @@ -36,9 +36,9 @@ export class InkingControl extends React.Component { @action switchColor = (color: ColorResult): void => { this._selectedColor = color.hex; - if (SelectionManager.SelectedDocuments().length == 1) { + if (SelectionManager.SelectedDocuments().length === 1) { var sdoc = SelectionManager.SelectedDocuments()[0]; - if (sdoc.props.ContainingCollectionView && sdoc.props.ContainingCollectionView) { + if (sdoc.props.ContainingCollectionView) { sdoc.props.Document.SetDataOnPrototype(KeyStore.BackgroundColor, color.hex, TextField); } } diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 615f8af7e..12b15a3f0 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -30,7 +30,7 @@ export class InkingStroke extends React.Component<StrokeProps> { } parseData = (line: Array<{ x: number, y: number }>): string => { - return !line.length ? "" : "M " + line.map(p => (p.x + this.props.offsetX) + " " + (p.y + this.props.offsetY)).join(" L "); + return !line.length ? "" : "M " + line.map(p => (p.x + this.props.offsetX) + " " + (p.y + this.props.offsetY)).join(" L ") } createStyle() { @@ -49,7 +49,7 @@ export class InkingStroke extends React.Component<StrokeProps> { let pathStyle = this.createStyle(); let pathData = this.parseData(this.props.line); - let pointerEvents: any = InkingControl.Instance.selectedTool == InkTool.Eraser ? "all" : "none"; + let pointerEvents: any = InkingControl.Instance.selectedTool === InkTool.Eraser ? "all" : "none"; return ( <path d={pathData} style={{ ...pathStyle, pointerEvents: pointerEvents }} strokeLinejoin="round" strokeLinecap="round" onPointerOver={this.deleteStroke} onPointerDown={this.deleteStroke} /> diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index c9467e130..9868f6c74 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -15,9 +15,10 @@ import { ListField } from '../../fields/ListField'; import { WorkspacesMenu } from '../../server/authentication/controllers/WorkspacesMenu'; import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils'; import { MessageStore } from '../../server/Message'; +import { Utils, returnTrue, emptyFunction } from '../../Utils'; +import * as rp from 'request-promise' import { RouteStore } from '../../server/RouteStore'; import { ServerUtils } from '../../server/ServerUtil'; -import { Utils } from '../../Utils'; import { Documents } from '../documents/Documents'; import { ColumnAttributeModel } from '../northstar/core/attribute/AttributeModel'; import { AttributeTransformationModel } from '../northstar/core/attribute/AttributeTransformationModel'; @@ -48,7 +49,7 @@ export class Main extends React.Component { @computed private get mainContainer(): Document | undefined { let doc = this.userDocument.GetT(KeyStore.ActiveWorkspace, Document); - return doc == FieldWaiting ? undefined : doc; + return doc === FieldWaiting ? undefined : doc; } private set mainContainer(doc: Document | undefined) { @@ -70,7 +71,7 @@ export class Main extends React.Component { configure({ enforceActions: "observed" }); if (window.location.pathname !== RouteStore.home) { let pathname = window.location.pathname.split("/"); - if (pathname.length > 1 && pathname[pathname.length - 2] == 'doc') { + if (pathname.length > 1 && pathname[pathname.length - 2] === 'doc') { CurrentUserUtils.MainDocId = pathname[pathname.length - 1]; } }; @@ -190,15 +191,12 @@ export class Main extends React.Component { @observable workspacesShown: boolean = false; - areWorkspacesShown = () => { - return this.workspacesShown; - } + areWorkspacesShown = () => this.workspacesShown @action toggleWorkspaces = () => { this.workspacesShown = !this.workspacesShown; } - screenToLocalTransform = () => Transform.Identity pwidthFunc = () => this.pwidth; pheightFunc = () => this.pheight; focusDocument = (doc: Document) => { } @@ -222,7 +220,7 @@ export class Main extends React.Component { let w: number = this._textRect.width; let h: number = this._textRect.height; return <div className="mainDiv-textInput" style={{ transform: `translate(${x}px, ${y}px)`, width: `${w}px`, height: `${h}px` }} > - <FormattedTextBox fieldKey={KeyStore.Archives} doc={this._textDoc} isSelected={() => true} select={() => { }} isTopMost={true} selectOnLoad={true} bindings={undefined} /> + <FormattedTextBox fieldKey={KeyStore.Archives} Document={this._textDoc} isSelected={returnTrue} select={emptyFunction} isTopMost={true} selectOnLoad={true} onActiveChanged={emptyFunction} active={returnTrue} ScreenToLocalTransform={Transform.Identity} focus={(doc) => { }} /> </ div> } else return (null); @@ -232,15 +230,17 @@ export class Main extends React.Component { get mainContent() { return !this.mainContainer ? (null) : <DocumentView Document={this.mainContainer} - AddDocument={undefined} - RemoveDocument={undefined} - ScreenToLocalTransform={this.screenToLocalTransform} + addDocument={undefined} + removeDocument={undefined} + ScreenToLocalTransform={Transform.Identity} ContentScaling={this.noScaling} PanelWidth={this.pwidthFunc} PanelHeight={this.pheightFunc} isTopMost={true} - SelectOnLoad={false} + selectOnLoad={false} focus={this.focusDocument} + parentActive={returnTrue} + onActiveChanged={emptyFunction} ContainingCollectionView={undefined} /> } @@ -385,8 +385,8 @@ export class Main extends React.Component { } } -Documents.initProtos().then(() => { - return CurrentUserUtils.loadCurrentUser() -}).then(() => { +(async () => { + await Documents.initProtos() + await CurrentUserUtils.loadCurrentUser() ReactDOM.render(<Main />, document.getElementById('root')); -}); +})() diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx new file mode 100644 index 000000000..7a5ab6e3c --- /dev/null +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -0,0 +1,166 @@ +import * as React from 'react'; +import { FieldViewProps } from '../nodes/FieldView'; +import { KeyStore } from '../../../fields/KeyStore'; +import { NumberField } from '../../../fields/NumberField'; +import { FieldWaiting, Field, FieldValue } from '../../../fields/Field'; +import { ContextMenu } from '../ContextMenu'; +import { SelectionManager } from '../../util/SelectionManager'; +import { Document } from '../../../fields/Document'; +import { ListField } from '../../../fields/ListField'; +import { action } from 'mobx'; +import { Transform } from '../../util/Transform'; +import { observer } from 'mobx-react'; + +export enum CollectionViewType { + Invalid, + Freeform, + Schema, + Docking, + Tree, +} + +export interface CollectionRenderProps { + addDocument: (document: Document, allowDuplicates?: boolean) => boolean; + removeDocument: (document: Document) => boolean; + moveDocument: (document: Document, targetCollection: Document, addDocument: (document: Document) => boolean) => boolean; + active: () => boolean; + onActiveChanged: (isActive: boolean) => void; +} + +export interface CollectionViewProps extends FieldViewProps { + onContextMenu?: (e: React.MouseEvent) => void; + children: (type: CollectionViewType, props: CollectionRenderProps) => JSX.Element | JSX.Element[] | null; + className?: string; + contentRef?: React.Ref<HTMLDivElement>; +} + +export const COLLECTION_BORDER_WIDTH = 1; + +@observer +export class CollectionBaseView extends React.Component<CollectionViewProps> { + get collectionViewType(): CollectionViewType { + let Document = this.props.Document; + let viewField = Document.GetT(KeyStore.ViewType, NumberField); + if (viewField === FieldWaiting) { + return CollectionViewType.Invalid; + } else if (viewField) { + return viewField.Data; + } else { + return CollectionViewType.Freeform; + } + } + + active = (): boolean => { + var isSelected = this.props.isSelected(); + var topMost = this.props.isTopMost; + return isSelected || this._isChildActive || topMost; + } + + //TODO should this be observable? + private _isChildActive = false; + onActiveChanged = (isActive: boolean) => { + this._isChildActive = isActive; + this.props.onActiveChanged(isActive); + } + + createsCycle(documentToAdd: Document, containerDocument: Document): boolean { + let data = documentToAdd.GetList<Document>(KeyStore.Data, []); + for (const doc of data) { + if (this.createsCycle(doc, containerDocument)) + return true; + } + let annots = documentToAdd.GetList<Document>(KeyStore.Annotations, []); + for (const annot of annots) { + if (this.createsCycle(annot, containerDocument)) + return true; + } + for (let containerProto: FieldValue<Document> = containerDocument; containerProto && containerProto !== FieldWaiting; containerProto = containerProto.GetPrototype()) { + if (containerProto.Id === documentToAdd.Id) + return true; + } + return false; + } + + @action.bound + addDocument(doc: Document, allowDuplicates: boolean = false): boolean { + let props = this.props; + var curPage = props.Document.GetNumber(KeyStore.CurPage, -1); + doc.SetOnPrototype(KeyStore.Page, new NumberField(curPage)); + if (curPage >= 0) { + doc.SetOnPrototype(KeyStore.AnnotationOn, props.Document); + } + if (props.Document.Get(props.fieldKey) instanceof Field) { + //TODO This won't create the field if it doesn't already exist + const value = props.Document.GetData(props.fieldKey, ListField, new Array<Document>()) + if (!this.createsCycle(doc, props.Document)) { + if (!value.some(v => v.Id === doc.Id) || allowDuplicates) + value.push(doc); + } + else + return false; + } else { + let proto = props.Document.GetPrototype(); + if (!proto || proto === FieldWaiting || !this.createsCycle(proto, doc)) { + props.Document.SetOnPrototype(props.fieldKey, new ListField([doc])); + } + else + return false; + } + return true; + } + + @action.bound + removeDocument(doc: Document): boolean { + const props = this.props; + //TODO This won't create the field if it doesn't already exist + const value = props.Document.GetData(props.fieldKey, ListField, new Array<Document>()) + let index = -1; + for (let i = 0; i < value.length; i++) { + if (value[i].Id === doc.Id) { + index = i; + break; + } + } + doc.GetTAsync(KeyStore.AnnotationOn, Document).then((annotationOn) => { + if (annotationOn === props.Document) { + doc.Set(KeyStore.AnnotationOn, undefined, true); + } + }) + + if (index !== -1) { + value.splice(index, 1) + + // SelectionManager.DeselectAll() + ContextMenu.Instance.clearItems() + return true; + } + return false + } + + @action.bound + moveDocument(doc: Document, targetCollection: Document, addDocument: (doc: Document) => boolean): boolean { + if (this.props.Document === targetCollection) { + return true; + } + if (this.removeDocument(doc)) { + return addDocument(doc); + } + return false; + } + + render() { + const props: CollectionRenderProps = { + addDocument: this.addDocument, + removeDocument: this.removeDocument, + moveDocument: this.moveDocument, + active: this.active, + onActiveChanged: this.onActiveChanged, + } + return ( + <div className={this.props.className || "collectionView-cont"} onContextMenu={this.props.onContextMenu} ref={this.props.contentRef}> + {this.props.children(this.collectionViewType, props)} + </div> + ) + } + +}
\ No newline at end of file diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 921ee4591..6640c843e 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -8,12 +8,12 @@ import { Document } from "../../../fields/Document"; import { KeyStore } from "../../../fields/KeyStore"; import Measure from "react-measure"; import { FieldId, Opt, Field } from "../../../fields/Field"; -import { Utils } from "../../../Utils"; +import { Utils, returnTrue, emptyFunction } from "../../../Utils"; import { Server } from "../../Server"; import { undoBatch } from "../../util/UndoManager"; import { DocumentView } from "../nodes/DocumentView"; import "./CollectionDockingView.scss"; -import { COLLECTION_BORDER_WIDTH } from "./CollectionView"; +import { COLLECTION_BORDER_WIDTH } from "./CollectionBaseView"; import React = require("react"); import { SubCollectionViewProps } from "./CollectionViewBase"; import { ServerUtils } from "../../../server/ServerUtil"; @@ -101,12 +101,12 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp newRow.addChild(newContentItem, undefined, true); newRow.addChild(collayout, 0, true); - collayout.config["width"] = 50; - newContentItem.config["width"] = 50; + collayout.config.width = 50; + newContentItem.config.width = 50; } if (minimize) { - newContentItem.config["width"] = 10; - newContentItem.config["height"] = 10; + newContentItem.config.width = 10; + newContentItem.config.height = 10; } newContentItem.callDownwards('_$init'); this._goldenLayout.root.callDownwards('setSize', [this._goldenLayout.width, this._goldenLayout.height]); @@ -124,7 +124,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp this._goldenLayout = new GoldenLayout(JSON.parse(config)); } else { - if (config == JSON.stringify(this._goldenLayout.toConfig())) + if (config === JSON.stringify(this._goldenLayout.toConfig())) return; try { this._goldenLayout.unbind('itemDropped', this.itemDropped); @@ -154,7 +154,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp reaction( () => this.props.Document.GetText(KeyStore.Data, ""), () => { - if (!this._goldenLayout || this._ignoreStateChange != JSON.stringify(this._goldenLayout.toConfig())) { + if (!this._goldenLayout || this._ignoreStateChange !== JSON.stringify(this._goldenLayout.toConfig())) { setTimeout(() => this.setupGoldenLayout(), 1); } this._ignoreStateChange = ""; @@ -193,7 +193,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp @action onPointerDown = (e: React.PointerEvent): void => { var className = (e.target as any).className; - if ((className == "lm_title" || className == "lm_tab lm_active") && (e.ctrlKey || e.altKey)) { + if ((className === "lm_title" || className === "lm_tab lm_active") && (e.ctrlKey || e.altKey)) { e.stopPropagation(); e.preventDefault(); let docid = (e.target as any).DashDocId; @@ -209,7 +209,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp }) })); } - if (className == "lm_drag_handle" || className == "lm_close" || className == "lm_maximise" || className == "lm_minimise" || className == "lm_close_tab") { + if (className === "lm_drag_handle" || className === "lm_close" || className === "lm_maximise" || className === "lm_minimise" || className === "lm_close_tab") { this._flush = true; } if (this.props.active()) { @@ -227,12 +227,12 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp this.stateChanged(); } tabCreated = (tab: any) => { - if (tab.hasOwnProperty("contentItem") && tab.contentItem.config.type != "stack") { - if (tab.titleElement[0].textContent.indexOf("-waiting") != -1) { + if (tab.hasOwnProperty("contentItem") && tab.contentItem.config.type !== "stack") { + if (tab.titleElement[0].textContent.indexOf("-waiting") !== -1) { Server.GetField(tab.contentItem.config.props.documentId, action((f: Opt<Field>) => { - if (f != undefined && f instanceof Document) { + if (f !== undefined && f instanceof Document) { f.GetTAsync(KeyStore.Title, TextField, (tfield) => { - if (tfield != undefined) { + if (tfield !== undefined) { tab.titleElement[0].textContent = f.Title; } }) @@ -296,9 +296,9 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> { Server.GetField(this.props.documentId, action((f: Opt<Field>) => this._document = f as Document)); } - private _nativeWidth = () => { return this._document!.GetNumber(KeyStore.NativeWidth, this._panelWidth); } - private _nativeHeight = () => { return this._document!.GetNumber(KeyStore.NativeHeight, this._panelHeight); } - private _contentScaling = () => { return this._panelWidth / (this._nativeWidth() ? this._nativeWidth() : this._panelWidth); } + private _nativeWidth = () => this._document!.GetNumber(KeyStore.NativeWidth, this._panelWidth) + private _nativeHeight = () => this._document!.GetNumber(KeyStore.NativeHeight, this._panelHeight) + private _contentScaling = () => this._panelWidth / (this._nativeWidth() ? this._nativeWidth() : this._panelWidth) ScreenToLocalTransform = () => { let { scale, translateX, translateY } = Utils.GetScreenTransform(this._mainCont.current!); @@ -311,14 +311,16 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> { var content = <div className="collectionDockingView-content" ref={this._mainCont}> <DocumentView key={this._document.Id} Document={this._document} - AddDocument={undefined} - RemoveDocument={undefined} + addDocument={undefined} + removeDocument={undefined} ContentScaling={this._contentScaling} PanelWidth={this._nativeWidth} PanelHeight={this._nativeHeight} ScreenToLocalTransform={this.ScreenToLocalTransform} isTopMost={true} - SelectOnLoad={false} + selectOnLoad={false} + parentActive={returnTrue} + onActiveChanged={emptyFunction} focus={(doc: Document) => { }} ContainingCollectionView={undefined} /> </div> diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx index 4d2daf149..1f2e71f6e 100644 --- a/src/client/views/collections/CollectionPDFView.tsx +++ b/src/client/views/collections/CollectionPDFView.tsx @@ -1,22 +1,20 @@ import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; -import { Document } from "../../../fields/Document"; import { KeyStore } from "../../../fields/KeyStore"; import { ContextMenu } from "../ContextMenu"; -import { CollectionView, CollectionViewType } from "./CollectionView"; import { CollectionViewProps } from "./CollectionViewBase"; import "./CollectionPDFView.scss" import React = require("react"); -import { FieldId } from "../../../fields/Field"; +import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; +import { FieldView } from "../nodes/FieldView"; +import { CollectionRenderProps, CollectionBaseView, CollectionViewType } from "./CollectionBaseView"; @observer export class CollectionPDFView extends React.Component<CollectionViewProps> { public static LayoutString(fieldKey: string = "DataKey") { - return `<${CollectionPDFView.name} Document={Document} - ScreenToLocalTransform={ScreenToLocalTransform} fieldKey={${fieldKey}} panelWidth={PanelWidth} panelHeight={PanelHeight} isSelected={isSelected} select={select} bindings={bindings} - isTopMost={isTopMost} SelectOnLoad={selectOnLoad} BackgroundView={BackgroundView} focus={focus}/>`; + return FieldView.LayoutString(CollectionPDFView, fieldKey); } private get curPage() { return this.props.Document.GetNumber(KeyStore.CurPage, -1); } @@ -30,30 +28,31 @@ export class CollectionPDFView extends React.Component<CollectionViewProps> { <div className="collectionPdfView-buttonTray" key="tray" style={{ transform: `scale(${scaling}, ${scaling})` }}> <button className="collectionPdfView-backward" onClick={this.onPageBack}>{"<"}</button> <button className="collectionPdfView-forward" onClick={this.onPageForward}>{">"}</button> - </div>); + </div> + ); } - // "inherited" CollectionView API starts here... - @observable - public SelectedDocs: FieldId[] = [] - public active: () => boolean = () => CollectionView.Active(this); - - addDocument = (doc: Document, allowDuplicates: boolean): boolean => { return CollectionView.AddDocument(this.props, doc, allowDuplicates); } - removeDocument = (doc: Document): boolean => { return CollectionView.RemoveDocument(this.props, doc); } - - specificContextMenu = (e: React.MouseEvent): void => { - if (!e.isPropagationStopped() && this.props.Document.Id != "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 + onContextMenu = (e: React.MouseEvent): void => { + if (!e.isPropagationStopped() && this.props.Document.Id !== "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 ContextMenu.Instance.addItem({ description: "PDFOptions", event: () => { } }); } } - get collectionViewType(): CollectionViewType { return CollectionViewType.Freeform; } - get subView(): any { return CollectionView.SubView(this); } + private subView = (_type: CollectionViewType, renderProps: CollectionRenderProps) => { + let props = { ...renderProps, ...this.props }; + return ( + <> + <CollectionFreeFormView {...props} /> + {this.props.isSelected() ? this.uIButtons : (null)} + </> + ) + } render() { - return (<div className="collectionPdfView-cont" onContextMenu={this.specificContextMenu}> - {this.subView} - {this.props.isSelected() ? this.uIButtons : (null)} - </div>) + return ( + <CollectionBaseView {...this.props} className="collectionPdfView-cont" onContextMenu={this.onContextMenu}> + {this.subView} + </CollectionBaseView> + ) } }
\ No newline at end of file diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index b10aaba98..4604945d1 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -22,9 +22,11 @@ import { EditableView } from "../EditableView"; import { DocumentView } from "../nodes/DocumentView"; import { FieldView, FieldViewProps } from "../nodes/FieldView"; import "./CollectionSchemaView.scss"; -import { CollectionView, COLLECTION_BORDER_WIDTH } from "./CollectionView"; +import { CollectionView } from "./CollectionView"; import { CollectionViewBase } from "./CollectionViewBase"; import { TextField } from "../../../fields/TextField"; +import { COLLECTION_BORDER_WIDTH } from "./CollectionBaseView"; +import { emptyFunction, returnFalse } from "../../../Utils"; // bcz: need to add drag and drop of rows and columns. This seems like it might work for rows: https://codesandbox.io/s/l94mn1q657 @@ -73,19 +75,22 @@ export class CollectionSchemaView extends CollectionViewBase { renderCell = (rowProps: CellInfo) => { let props: FieldViewProps = { - doc: rowProps.value[0], + Document: rowProps.value[0], fieldKey: rowProps.value[1], isSelected: () => false, select: () => { }, isTopMost: false, - bindings: {}, selectOnLoad: false, + ScreenToLocalTransform: Transform.Identity, + focus: emptyFunction, + active: returnFalse, + onActiveChanged: emptyFunction, } let contents = ( <FieldView {...props} /> ) let reference = React.createRef<HTMLDivElement>(); - let onItemDown = setupDrag(reference, () => props.doc, (containingCollection: CollectionView) => this.props.removeDocument(props.doc)); + let onItemDown = setupDrag(reference, () => props.Document, this.props.moveDocument); let applyToDoc = (doc: Document, run: (args?: { [name: string]: any }) => any) => { const res = run({ this: doc }); if (!res.success) return false; @@ -103,13 +108,13 @@ export class CollectionSchemaView extends CollectionViewBase { return false; } return ( - <div className="collectionSchemaView-cellContents" onPointerDown={onItemDown} style={{ height: "56px" }} key={props.doc.Id} ref={reference}> + <div className="collectionSchemaView-cellContents" onPointerDown={onItemDown} style={{ height: "56px" }} key={props.Document.Id} ref={reference}> <EditableView display={"inline"} contents={contents} height={56} GetValue={() => { - let field = props.doc.Get(props.fieldKey); + let field = props.Document.Get(props.fieldKey); if (field && field instanceof Field) { return field.ToScriptString(); } @@ -120,7 +125,7 @@ export class CollectionSchemaView extends CollectionViewBase { if (!script.compiled) { return false; } - return applyToDoc(props.doc, script.run); + return applyToDoc(props.Document, script.run); }} OnFillDown={(value: string) => { let script = CompileScript(value, { addReturn: true, params: { this: "Document" } }); @@ -155,8 +160,8 @@ export class CollectionSchemaView extends CollectionViewBase { } }), style: { - background: rowInfo.index == this._selectedIndex ? "lightGray" : "white", - //color: rowInfo.index == this._selectedIndex ? "white" : "black" + background: rowInfo.index === this._selectedIndex ? "lightGray" : "white", + //color: rowInfo.index === this._selectedIndex ? "white" : "black" } }; } @@ -184,8 +189,8 @@ export class CollectionSchemaView extends CollectionViewBase { @action toggleExpander = (event: React.ChangeEvent<HTMLInputElement>) => { this._startSplitPercent = this.splitPercentage; - if (this._startSplitPercent == this.splitPercentage) { - this.props.Document.SetNumber(KeyStore.SchemaSplitPercentage, this.splitPercentage == 0 ? 33 : 0); + if (this._startSplitPercent === this.splitPercentage) { + this.props.Document.SetNumber(KeyStore.SchemaSplitPercentage, this.splitPercentage === 0 ? 33 : 0); } } @@ -214,8 +219,8 @@ export class CollectionSchemaView extends CollectionViewBase { onDividerUp = (e: PointerEvent): void => { document.removeEventListener("pointermove", this.onDividerMove); document.removeEventListener('pointerup', this.onDividerUp); - if (this._startSplitPercent == this.splitPercentage) { - this.props.Document.SetNumber(KeyStore.SchemaSplitPercentage, this.splitPercentage == 0 ? 33 : 0); + if (this._startSplitPercent === this.splitPercentage) { + this.props.Document.SetNumber(KeyStore.SchemaSplitPercentage, this.splitPercentage === 0 ? 33 : 0); } } onDividerDown = (e: React.PointerEvent) => { @@ -243,12 +248,8 @@ export class CollectionSchemaView extends CollectionViewBase { getContentScaling = (): number => this._contentScaling; getPanelWidth = (): number => this._panelWidth; getPanelHeight = (): number => this._panelHeight; - getTransform = (): Transform => { - return this.props.ScreenToLocalTransform().translate(- COLLECTION_BORDER_WIDTH - this.DIVIDER_WIDTH - this._dividerX, - COLLECTION_BORDER_WIDTH).scale(1 / this._contentScaling); - } - getPreviewTransform = (): Transform => { - return this.props.ScreenToLocalTransform().translate(- COLLECTION_BORDER_WIDTH - this.DIVIDER_WIDTH - this._dividerX - this._tableWidth, - COLLECTION_BORDER_WIDTH).scale(1 / this._contentScaling); - } + getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(- COLLECTION_BORDER_WIDTH - this.DIVIDER_WIDTH - this._dividerX, - COLLECTION_BORDER_WIDTH).scale(1 / this._contentScaling) + getPreviewTransform = (): Transform => this.props.ScreenToLocalTransform().translate(- COLLECTION_BORDER_WIDTH - this.DIVIDER_WIDTH - this._dividerX - this._tableWidth, - COLLECTION_BORDER_WIDTH).scale(1 / this._contentScaling) focusDocument = (doc: Document) => { } @@ -299,28 +300,30 @@ export class CollectionSchemaView extends CollectionViewBase { let doc: any = selected ? selected.Get(new Key(this.previewScript)) : undefined; // let doc = CompileScript(this.previewScript, { this: selected }, true)(); - let content = this._selectedIndex == -1 || !selected ? (null) : ( + let content = this._selectedIndex === -1 || !selected ? (null) : ( <Measure onResize={this.setScaling}> {({ measureRef }) => <div className="collectionSchemaView-content" ref={measureRef}> - {doc instanceof Document ? <DocumentView Document={doc} - AddDocument={this.props.addDocument} RemoveDocument={this.props.removeDocument} - isTopMost={false} - SelectOnLoad={false} - ScreenToLocalTransform={this.getPreviewTransform} - ContentScaling={this.getContentScaling} - PanelWidth={this.getPanelWidth} - PanelHeight={this.getPanelHeight} - ContainingCollectionView={this.props.CollectionView} - focus={this.focusDocument} - /> : null} + {doc instanceof Document ? + <DocumentView Document={doc} + addDocument={this.props.addDocument} removeDocument={this.props.removeDocument} + isTopMost={false} + selectOnLoad={false} + ScreenToLocalTransform={this.getPreviewTransform} + ContentScaling={this.getContentScaling} + PanelWidth={this.getPanelWidth} + PanelHeight={this.getPanelHeight} + ContainingCollectionView={undefined} + focus={this.focusDocument} + parentActive={this.props.active} + onActiveChanged={this.props.onActiveChanged} /> : null} <input value={this.previewScript} onChange={this.onPreviewScriptChange} style={{ position: 'absolute', bottom: '0px' }} /> </div> } </Measure> ) - let dividerDragger = this.splitPercentage == 0 ? (null) : + let dividerDragger = this.splitPercentage === 0 ? (null) : <div className="collectionSchemaView-dividerDragger" onPointerDown={this.onDividerDown} style={{ width: `${this.DIVIDER_WIDTH}px` }} /> //options button and menu @@ -330,12 +333,11 @@ export class CollectionSchemaView extends CollectionViewBase { <div id="schema-options-header"><h5><b>Options</b></h5></div> <div id="options-flyout-div"> <h6 className="schema-options-subHeader">Preview Window</h6> - <div id="preview-schema-checkbox-div"><input type="checkbox" key={"Show Preview"} checked={this.splitPercentage != 0} onChange={this.toggleExpander} /> Show Preview </div> + <div id="preview-schema-checkbox-div"><input type="checkbox" key={"Show Preview"} checked={this.splitPercentage !== 0} onChange={this.toggleExpander} /> Show Preview </div> <h6 className="schema-options-subHeader" >Displayed Columns</h6> <ul id="schema-col-checklist" > - {Array.from(Object.keys(allKeys)).map(item => { - return (<KeyToggle checked={allKeys[item]} key={item} keyId={item} toggle={this.toggleKey} />) - })} + {Array.from(Object.keys(allKeys)).map(item => + (<KeyToggle checked={allKeys[item]} key={item} keyId={item} toggle={this.toggleKey} />))} </ul> <input value={this.newKeyName} onChange={this.newKeyChange} /> <button onClick={this.addColumn}><FontAwesomeIcon style={{ color: "white" }} icon="plus" size="lg" /></button> diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 0b12f11fd..dce35868e 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -7,17 +7,20 @@ import { Document } from "../../../fields/Document"; import { FieldWaiting } from "../../../fields/Field"; import { KeyStore } from "../../../fields/KeyStore"; import { ListField } from "../../../fields/ListField"; -import { setupDrag } from "../../util/DragManager"; +import { setupDrag, DragManager } from "../../util/DragManager"; import { EditableView } from "../EditableView"; import "./CollectionTreeView.scss"; -import { CollectionView, COLLECTION_BORDER_WIDTH } from "./CollectionView"; +import { CollectionView } from "./CollectionView"; import { CollectionViewBase } from "./CollectionViewBase"; import React = require("react") +import { COLLECTION_BORDER_WIDTH } from './CollectionBaseView'; +import { props } from 'bluebird'; export interface TreeViewProps { document: Document; deleteDoc: (doc: Document) => void; + moveDocument: DragManager.MoveFunction; copyOnDrag: boolean; } @@ -49,6 +52,16 @@ class TreeView extends React.Component<TreeViewProps> { } } + @action + move: DragManager.MoveFunction = (document, target, addDoc) => { + if (this.props.document === target) { + return true; + } + //TODO This should check if it was removed + this.remove(document) + return addDoc(document); + } + renderBullet(type: BulletType) { let onClicked = action(() => this._collapsed = !this._collapsed); let bullet: IconProp | undefined = undefined; @@ -64,7 +77,7 @@ class TreeView extends React.Component<TreeViewProps> { */ renderTitle() { let reference = React.createRef<HTMLDivElement>(); - let onItemDown = setupDrag(reference, () => this.props.document, (containingCollection: CollectionView) => this.props.deleteDoc(this.props.document), this.props.copyOnDrag); + let onItemDown = setupDrag(reference, () => this.props.document, this.props.moveDocument, this.props.copyOnDrag); let editableView = (titleString: string) => (<EditableView display={"inline"} @@ -91,8 +104,8 @@ class TreeView extends React.Component<TreeViewProps> { if (!this._collapsed) { bulletType = BulletType.Collapsible; childElements = <ul> - {children.Data.map(value => <TreeView key={value.Id} document={value} deleteDoc={this.remove} copyOnDrag={this.props.copyOnDrag} />)} - </ul> + {children.Data.map(value => <TreeView key={value.Id} document={value} deleteDoc={this.remove} moveDocument={this.move} copyOnDrag={this.props.copyOnDrag} />)} + </ul > } else bulletType = BulletType.Collapsed; } @@ -122,7 +135,7 @@ export class CollectionTreeView extends CollectionViewBase { let copyOnDrag = this.props.Document.GetBoolean(KeyStore.CopyDraggedItems, false); let childrenElement = !children || children === FieldWaiting ? (null) : (children.Data.map(value => - <TreeView document={value} key={value.Id} deleteDoc={this.remove} copyOnDrag={copyOnDrag} />) + <TreeView document={value} key={value.Id} deleteDoc={this.remove} moveDocument={this.props.moveDocument} copyOnDrag={copyOnDrag} />) ) return ( diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx index 470a853e3..afadfeefb 100644 --- a/src/client/views/collections/CollectionVideoView.tsx +++ b/src/client/views/collections/CollectionVideoView.tsx @@ -3,11 +3,14 @@ import { observer } from "mobx-react"; import { Document } from "../../../fields/Document"; import { KeyStore } from "../../../fields/KeyStore"; import { ContextMenu } from "../ContextMenu"; -import { CollectionView, CollectionViewType } from "./CollectionView"; +import { CollectionView } from "./CollectionView"; +import { CollectionViewType, CollectionBaseView, CollectionRenderProps } from "./CollectionBaseView"; import { CollectionViewProps } from "./CollectionViewBase"; import React = require("react"); import { FieldId } from "../../../fields/Field"; import "./CollectionVideoView.scss" +import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; +import { FieldView } from "../nodes/FieldView"; @observer @@ -19,9 +22,7 @@ export class CollectionVideoView extends React.Component<CollectionViewProps> { @observable _isPlaying: boolean = false; public static LayoutString(fieldKey: string = "DataKey") { - return `<${CollectionVideoView.name} Document={Document} - ScreenToLocalTransform={ScreenToLocalTransform} fieldKey={${fieldKey}} panelWidth={PanelWidth} panelHeight={PanelHeight} isSelected={isSelected} select={select} bindings={bindings} - isTopMost={isTopMost} SelectOnLoad={selectOnLoad} BackgroundView={BackgroundView} focus={focus}/>`; + return FieldView.LayoutString(CollectionVideoView, fieldKey); } private get uIButtons() { let scaling = Math.min(1.8, this.props.ScreenToLocalTransform().transformDirection(1, 1)[0]); @@ -42,7 +43,7 @@ export class CollectionVideoView extends React.Component<CollectionViewProps> { @action mainCont = (ele: HTMLDivElement | null) => { if (ele) { - this._player = ele!.getElementsByTagName("video")[0]; + this._player = ele.getElementsByTagName("video")[0]; if (this.props.Document.GetNumber(KeyStore.CurPage, -1) >= 0) { this._currentTimecode = this.props.Document.GetNumber(KeyStore.CurPage, -1); } @@ -60,7 +61,7 @@ export class CollectionVideoView extends React.Component<CollectionViewProps> { @action updateTimecode = () => { if (this._player) { - if ((this._player as any).AHackBecauseSomethingResetsTheVideoToZero != -1) { + if ((this._player as any).AHackBecauseSomethingResetsTheVideoToZero !== -1) { this._player.currentTime = (this._player as any).AHackBecauseSomethingResetsTheVideoToZero; (this._player as any).AHackBecauseSomethingResetsTheVideoToZero = -1; } else { @@ -101,30 +102,27 @@ export class CollectionVideoView extends React.Component<CollectionViewProps> { } - // "inherited" CollectionView API starts here... - - @observable - public SelectedDocs: FieldId[] = [] - public active: () => boolean = () => CollectionView.Active(this); - - addDocument = (doc: Document, allowDuplicates: boolean): boolean => { return CollectionView.AddDocument(this.props, doc, allowDuplicates); } - removeDocument = (doc: Document): boolean => { return CollectionView.RemoveDocument(this.props, doc); } - - specificContextMenu = (e: React.MouseEvent): void => { - if (!e.isPropagationStopped() && this.props.Document.Id != "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 + onContextMenu = (e: React.MouseEvent): void => { + if (!e.isPropagationStopped() && this.props.Document.Id !== "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 ContextMenu.Instance.addItem({ description: "VideoOptions", event: () => { } }); } } - get collectionViewType(): CollectionViewType { return CollectionViewType.Freeform; } - get subView(): any { return CollectionView.SubView(this); } - + private subView = (_type: CollectionViewType, renderProps: CollectionRenderProps) => { + let props = { ...renderProps, ...this.props }; + return ( + <> + <CollectionFreeFormView {...props} /> + {this.props.isSelected() ? this.uIButtons : (null)} + </> + ) + } render() { trace(); - return (<div className="collectionVideoView-cont" ref={this.mainCont} onContextMenu={this.specificContextMenu}> - {this.subView} - {this.props.isSelected() ? this.uIButtons : (null)} - </div>) + return ( + <CollectionBaseView {...this.props} className="collectionVideoView-cont" contentRef={this.mainCont} onContextMenu={this.onContextMenu}> + {this.subView} + </CollectionBaseView>) } }
\ No newline at end of file diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 014aa1d8f..1b0cfd57b 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -1,159 +1,45 @@ -import { action, computed, observable } from "mobx"; -import { observer } from "mobx-react"; -import { Document } from "../../../fields/Document"; -import { ListField } from "../../../fields/ListField"; -import { SelectionManager } from "../../util/SelectionManager"; -import { ContextMenu } from "../ContextMenu"; -import React = require("react"); -import { KeyStore } from "../../../fields/KeyStore"; -import { NumberField } from "../../../fields/NumberField"; -import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; -import { CollectionDockingView } from "./CollectionDockingView"; -import { CollectionSchemaView } from "./CollectionSchemaView"; -import { CollectionViewProps } from "./CollectionViewBase"; -import { CollectionTreeView } from "./CollectionTreeView"; -import { Field, FieldId, FieldWaiting } from "../../../fields/Field"; -import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; - -export enum CollectionViewType { - Invalid, - Freeform, - Schema, - Docking, - Tree -} - -export const COLLECTION_BORDER_WIDTH = 1; +import * as React from 'react' +import { FieldViewProps, FieldView } from '../nodes/FieldView'; +import { CollectionBaseView, CollectionViewType, CollectionRenderProps } from './CollectionBaseView'; +import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; +import { CollectionSchemaView } from './CollectionSchemaView'; +import { CollectionDockingView } from './CollectionDockingView'; +import { CollectionTreeView } from './CollectionTreeView'; +import { ContextMenu } from '../ContextMenu'; +import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils'; +import { KeyStore } from '../../../fields/KeyStore'; +import { observer } from 'mobx-react'; @observer -export class CollectionView extends React.Component<CollectionViewProps> { - - public static LayoutString(fieldKey: string = "DataKey") { - return `<${CollectionView.name} Document={Document} - ScreenToLocalTransform={ScreenToLocalTransform} fieldKey={${fieldKey}} panelWidth={PanelWidth} panelHeight={PanelHeight} isSelected={isSelected} select={select} bindings={bindings} - isTopMost={isTopMost} SelectOnLoad={selectOnLoad} BackgroundView={BackgroundView} focus={focus}/>`; - } - - @observable - public SelectedDocs: FieldId[] = []; - public active: () => boolean = () => CollectionView.Active(this); - addDocument = (doc: Document, allowDuplicates: boolean): boolean => { return CollectionView.AddDocument(this.props, doc, allowDuplicates); } - removeDocument = (doc: Document): boolean => { return CollectionView.RemoveDocument(this.props, doc); } - get subView() { return CollectionView.SubView(this); } - - public static Active(self: CollectionView): boolean { - var isSelected = self.props.isSelected(); - var childSelected = SelectionManager.SelectedDocuments().some(view => view.props.ContainingCollectionView == self); - var topMost = self.props.isTopMost; - return isSelected || childSelected || topMost; - } - - static createsCycle(documentToAdd: Document, containerDocument: Document): boolean { - let data = documentToAdd.GetList<Document>(KeyStore.Data, []); - for (let i = 0; i < data.length; i++) { - if (CollectionView.createsCycle(data[i], containerDocument)) - return true; - } - let annots = documentToAdd.GetList<Document>(KeyStore.Annotations, []); - for (let i = 0; i < annots.length; i++) { - if (CollectionView.createsCycle(annots[i], containerDocument)) - return true; - } - for (let containerProto: any = containerDocument; containerProto && containerProto != FieldWaiting; containerProto = containerProto.GetPrototype()) { - if (containerProto.Id == documentToAdd.Id) - return true; - } - return false; - } - - @action - public static AddDocument(props: CollectionViewProps, doc: Document, allowDuplicates: boolean): boolean { - var curPage = props.Document.GetNumber(KeyStore.CurPage, -1); - doc.SetOnPrototype(KeyStore.Page, new NumberField(curPage)); - if (curPage >= 0) { - doc.SetOnPrototype(KeyStore.AnnotationOn, props.Document); - } - if (props.Document.Get(props.fieldKey) instanceof Field) { - //TODO This won't create the field if it doesn't already exist - const value = props.Document.GetData(props.fieldKey, ListField, new Array<Document>()) - if (!CollectionView.createsCycle(doc, props.Document)) { - if (!value.some(v => v.Id == doc.Id) || allowDuplicates) - value.push(doc); - } - else - return false; - } else { - let proto = props.Document.GetPrototype(); - if (!proto || proto == FieldWaiting || !CollectionView.createsCycle(proto, doc)) { - props.Document.SetOnPrototype(props.fieldKey, new ListField([doc])); - } - else - return false; - } - return true; - } - - @action - public static RemoveDocument(props: CollectionViewProps, doc: Document): boolean { - //TODO This won't create the field if it doesn't already exist - const value = props.Document.GetData(props.fieldKey, ListField, new Array<Document>()) - let index = -1; - for (let i = 0; i < value.length; i++) { - if (value[i].Id == doc.Id) { - index = i; - break; - } - } - doc.GetTAsync(KeyStore.AnnotationOn, Document).then((annotationOn) => { - if (annotationOn == props.Document) { - doc.Set(KeyStore.AnnotationOn, undefined, true); - } - }) - - if (index !== -1) { - value.splice(index, 1) - - //SelectionManager.DeselectAll() - ContextMenu.Instance.clearItems() - return true; - } - return false - } - - get collectionViewType(): CollectionViewType { - let Document = this.props.Document; - let viewField = Document.GetT(KeyStore.ViewType, NumberField); - if (viewField === FieldWaiting) { - return CollectionViewType.Invalid; - } else if (viewField) { - return viewField.Data; - } else { - return CollectionViewType.Freeform; +export class CollectionView extends React.Component<FieldViewProps> { + public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(CollectionView, fieldStr) } + + private SubView = (type: CollectionViewType, renderProps: CollectionRenderProps) => { + let props = { ...this.props, ...renderProps }; + switch (type) { + case CollectionViewType.Schema: return (<CollectionSchemaView {...props} />) + case CollectionViewType.Docking: return (<CollectionDockingView {...props} />) + case CollectionViewType.Tree: return (<CollectionTreeView {...props} />) + case CollectionViewType.Freeform: + default: + return (<CollectionFreeFormView {...props} />) } + return (null); } - specificContextMenu = (e: React.MouseEvent): void => { - if (!e.isPropagationStopped() && this.props.Document.Id != CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 + onContextMenu = (e: React.MouseEvent): void => { + if (!e.isPropagationStopped() && this.props.Document.Id !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 ContextMenu.Instance.addItem({ description: "Freeform", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Freeform) }) ContextMenu.Instance.addItem({ description: "Schema", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Schema) }) ContextMenu.Instance.addItem({ description: "Treeview", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Tree) }) } } - public static SubView(self: CollectionView) { - let subProps = { ...self.props, addDocument: self.addDocument, removeDocument: self.removeDocument, active: self.active, CollectionView: self } - switch (self.collectionViewType) { - case CollectionViewType.Freeform: return (<CollectionFreeFormView {...subProps} />) - case CollectionViewType.Schema: return (<CollectionSchemaView {...subProps} />) - case CollectionViewType.Docking: return (<CollectionDockingView {...subProps} />) - case CollectionViewType.Tree: return (<CollectionTreeView {...subProps} />) - } - return (null); - } - render() { - return (<div className="collectionView-cont" onContextMenu={this.specificContextMenu}> - {this.subView} - </div>) + return ( + <CollectionBaseView {...this.props} onContextMenu={this.onContextMenu}> + {this.SubView} + </CollectionBaseView> + ) } -} +}
\ No newline at end of file diff --git a/src/client/views/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx index 7cf49e215..84d378e1c 100644 --- a/src/client/views/collections/CollectionViewBase.tsx +++ b/src/client/views/collections/CollectionViewBase.tsx @@ -17,27 +17,15 @@ import { NumberField } from "../../../fields/NumberField"; import request = require("request"); import { ServerUtils } from "../../../server/ServerUtil"; import { Server } from "../../Server"; -import { CollectionDockingView } from "./CollectionDockingView"; -import { runReactions } from "mobx/lib/internal"; +import { FieldViewProps } from "../nodes/FieldView"; -export interface CollectionViewProps { - fieldKey: Key; - Document: Document; - ScreenToLocalTransform: () => Transform; - isSelected: () => boolean; - isTopMost: boolean; - select: (ctrlPressed: boolean) => void; - bindings: any; - panelWidth: () => number; - panelHeight: () => number; - focus: (doc: Document) => void; +export interface CollectionViewProps extends FieldViewProps { + addDocument: (document: Document, allowDuplicates?: boolean) => boolean; + removeDocument: (document: Document) => boolean; + moveDocument: (document: Document, targetCollection: Document, addDocument: (document: Document) => boolean) => boolean; } export interface SubCollectionViewProps extends CollectionViewProps { - active: () => boolean; - addDocument: (doc: Document, allowDuplicates: boolean) => boolean; - removeDocument: (doc: Document) => boolean; - CollectionView: CollectionView; } export type CursorEntry = TupleField<[string, string], [number, number]>; @@ -87,9 +75,14 @@ export class CollectionViewBase extends React.Component<SubCollectionViewProps> de.data.draggedDocuments.map((draggedDocument: Document, i: number) => draggedDocument.GetTAsync(key, NumberField, (f: Opt<NumberField>) => f ? de.data.droppedDocuments[i].SetNumber(key, f.Data) : null))); } - let added = de.data.droppedDocuments.reduce((added, d) => this.props.addDocument(d, false), true); - if (added && de.data.removeDocument && !de.data.aliasOnDrop && !de.data.copyOnDrop) { - de.data.removeDocument(this.props.CollectionView); + let added = false; + if (de.data.aliasOnDrop) { + added = de.data.droppedDocuments.reduce((added: boolean, d) => added || this.props.addDocument(d), false); + } else if (de.data.moveDocument) { + const move = de.data.moveDocument; + added = de.data.droppedDocuments.reduce((added: boolean, d) => added || move(d, this.props.Document, this.props.addDocument), false) + } else { + added = de.data.droppedDocuments.reduce((added: boolean, d) => added || this.props.addDocument(d), false) } e.stopPropagation(); return added; @@ -98,11 +91,11 @@ export class CollectionViewBase extends React.Component<SubCollectionViewProps> let sourceDoc: Document = de.data.linkSourceDocumentView.props.Document; if (sourceDoc) runInAction(() => { let srcTarg = sourceDoc.GetT(KeyStore.Prototype, Document) - if (srcTarg && srcTarg != FieldWaiting) { + if (srcTarg && srcTarg !== FieldWaiting) { let linkDocs = srcTarg.GetList(KeyStore.LinkedToDocs, [] as Document[]); linkDocs.map(linkDoc => { let targDoc = linkDoc.GetT(KeyStore.LinkedToDocs, Document); - if (targDoc && targDoc != FieldWaiting) { + if (targDoc && targDoc !== FieldWaiting) { let dropdoc = targDoc.MakeDelegate(); de.data.droppedDocuments.push(dropdoc); this.props.addDocument(dropdoc, false); @@ -154,8 +147,6 @@ export class CollectionViewBase extends React.Component<SubCollectionViewProps> @action protected onDrop(e: React.DragEvent, options: DocumentOptions): void { - let that = this; - let html = e.dataTransfer.getData("text/html"); let text = e.dataTransfer.getData("text/plain"); @@ -165,7 +156,7 @@ export class CollectionViewBase extends React.Component<SubCollectionViewProps> e.stopPropagation() e.preventDefault() - if (html && html.indexOf("<img") != 0 && !html.startsWith("<a")) { + if (html && html.indexOf("<img") !== 0 && !html.startsWith("<a")) { console.log("not good"); let htmlDoc = Documents.HtmlDocument(html, { ...options, width: 300, height: 300 }); htmlDoc.SetText(KeyStore.DocumentText, text); @@ -173,10 +164,11 @@ export class CollectionViewBase extends React.Component<SubCollectionViewProps> return; } + // tslint:disable-next-line:prefer-for-of for (let i = 0; i < e.dataTransfer.items.length; i++) { const upload = window.location.origin + RouteStore.upload; let item = e.dataTransfer.items[i]; - if (item.kind === "string" && item.type.indexOf("uri") != -1) { + if (item.kind === "string" && item.type.indexOf("uri") !== -1) { e.dataTransfer.items[i].getAsString(action((s: string) => { request.head(ServerUtils.prepend(RouteStore.corsProxy + "/" + s), (err, res, body) => { let type = res.headers["content-type"]; @@ -191,7 +183,7 @@ export class CollectionViewBase extends React.Component<SubCollectionViewProps> })) } let type = item.type - if (item.kind == "file") { + if (item.kind === "file") { let file = item.getAsFile(); let formData = new FormData() @@ -202,19 +194,18 @@ export class CollectionViewBase extends React.Component<SubCollectionViewProps> fetch(upload, { method: 'POST', body: formData - }).then((res: Response) => { - return res.json() - }).then(json => { + }).then(async (res: Response) => { + const json = await res.json(); json.map((file: any) => { let path = window.location.origin + file runInAction(() => { let doc = this.getDocumentFromType(type, path, { ...options, nativeWidth: 300, width: 300 }) - let docs = that.props.Document.GetT(KeyStore.Data, ListField); - if (docs != FieldWaiting) { + let docs = this.props.Document.GetT(KeyStore.Data, ListField); + if (docs !== FieldWaiting) { if (!docs) { docs = new ListField<Document>(); - that.props.Document.Set(KeyStore.Data, docs) + this.props.Document.Set(KeyStore.Data, docs) } if (doc) { docs.Data.push(doc); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index 1189dd4e8..abc6cecff 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -31,17 +31,17 @@ export class CollectionFreeFormLinksView extends React.Component<CollectionViewP let x1w = srcDoc.GetNumber(KeyStore.Width, -1); let x2 = dstDoc.GetNumber(KeyStore.X, 0); let x2w = dstDoc.GetNumber(KeyStore.Width, -1); - if (x1w < 0 || x2w < 0 || i == j) + if (x1w < 0 || x2w < 0 || i === j) continue; let dstTarg = dstDoc; let srcTarg = srcDoc; let findBrush = (field: ListField<Document>) => field.Data.findIndex(brush => { let bdocs = brush ? brush.GetList(KeyStore.BrushingDocs, [] as Document[]) : []; - return (bdocs.length && ((bdocs[0] == dstTarg && bdocs[1] == srcTarg)) ? true : false) + return (bdocs.length && ((bdocs[0] === dstTarg && bdocs[1] === srcTarg)) ? true : false) }); let brushAction = (field: ListField<Document>) => { let found = findBrush(field); - if (found != -1) { + if (found !== -1) { console.log("REMOVE BRUSH " + srcTarg.Title + " " + dstTarg.Title); field.Data.splice(found, 1); } @@ -53,9 +53,9 @@ export class CollectionFreeFormLinksView extends React.Component<CollectionViewP linkDoc.SetData(KeyStore.BrushingDocs, [dstTarg, srcTarg], ListField); brushAction = brushAction = (field: ListField<Document>) => { - if (findBrush(field) == -1) { + if (findBrush(field) === -1) { console.log("ADD BRUSH " + srcTarg.Title + " " + dstTarg.Title); - (findBrush(field) == -1) && field.Data.push(linkDoc); + (findBrush(field) === -1) && field.Data.push(linkDoc); } }; } @@ -69,10 +69,10 @@ export class CollectionFreeFormLinksView extends React.Component<CollectionViewP documentAnchors(view: DocumentView) { let equalViews = [view]; let containerDoc = view.props.Document.GetT(KeyStore.AnnotationOn, Document); - if (containerDoc && containerDoc != FieldWaiting && containerDoc instanceof Document) { - equalViews = DocumentManager.Instance.getDocumentViews(containerDoc.GetPrototype() as Document) + if (containerDoc && containerDoc instanceof Document) { + equalViews = DocumentManager.Instance.getDocumentViews(containerDoc.GetPrototype()!) } - return equalViews.filter(sv => sv.props.ContainingCollectionView && sv.props.ContainingCollectionView.props.Document == this.props.Document); + return equalViews.filter(sv => sv.props.ContainingCollectionView && sv.props.ContainingCollectionView.props.Document === this.props.Document); } @computed @@ -84,14 +84,14 @@ export class CollectionFreeFormLinksView extends React.Component<CollectionViewP srcViews.map(sv => targetViews.map(tv => possiblePairs.push({ a: sv.props.Document, b: tv.props.Document }))); possiblePairs.map(possiblePair => { if (!drawnPairs.reduce((found, drawnPair) => { - let match = (possiblePair.a == drawnPair.a && possiblePair.b == drawnPair.b); + let match = (possiblePair.a === drawnPair.a && possiblePair.b === drawnPair.b); if (match) { - if (!drawnPair.l.reduce((found, link) => found || link.Id == connection.l.Id, false)) + if (!drawnPair.l.reduce((found, link) => found || link.Id === connection.l.Id, false)) drawnPair.l.push(connection.l); } return match || found; }, false)) { - drawnPairs.push({ a: possiblePair.a, b: possiblePair.b, l: [connection.l] as Document[] }); + drawnPairs.push({ a: possiblePair.a, b: possiblePair.b, l: [connection.l] }); } }) return drawnPairs diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx index 19382e66f..f664f4e65 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx @@ -1,21 +1,8 @@ -import { action, computed, observable } from "mobx"; +import { computed } from "mobx"; import { observer } from "mobx-react"; -import { Document } from "../../../../fields/Document"; -import { FieldWaiting } from "../../../../fields/Field"; import { KeyStore } from "../../../../fields/KeyStore"; -import { TextField } from "../../../../fields/TextField"; -import { DragManager } from "../../../util/DragManager"; -import { Transform } from "../../../util/Transform"; -import { undoBatch } from "../../../util/UndoManager"; -import { InkingCanvas } from "../../InkingCanvas"; -import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView"; -import { DocumentContentsView } from "../../nodes/DocumentContentsView"; -import { DocumentViewProps } from "../../nodes/DocumentView"; -import { COLLECTION_BORDER_WIDTH } from "../CollectionView"; -import { CollectionViewBase, CollectionViewProps, CursorEntry } from "../CollectionViewBase"; -import { CollectionFreeFormLinksView } from "./CollectionFreeFormLinksView"; +import { CollectionViewProps, CursorEntry } from "../CollectionViewBase"; import "./CollectionFreeFormView.scss"; -import { MarqueeView } from "./MarqueeView"; import React = require("react"); import v5 = require("uuid/v5"); import { CurrentUserUtils } from "../../../../server/authentication/models/current_user_utils"; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 2a86d0ee1..d542b8bc2 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -11,7 +11,7 @@ import { InkingCanvas } from "../../InkingCanvas"; import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView"; import { DocumentContentsView } from "../../nodes/DocumentContentsView"; import { DocumentViewProps } from "../../nodes/DocumentView"; -import { COLLECTION_BORDER_WIDTH } from "../CollectionView"; +import { COLLECTION_BORDER_WIDTH } from "../CollectionBaseView"; import { CollectionViewBase } from "../CollectionViewBase"; import { CollectionFreeFormLinksView } from "./CollectionFreeFormLinksView"; import "./CollectionFreeFormView.scss"; @@ -20,6 +20,8 @@ import React = require("react"); import v5 = require("uuid/v5"); import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCursors"; import { PreviewCursor } from "./PreviewCursor"; +import { DocumentManager } from "../../../util/DocumentManager"; +import { SelectionManager } from "../../../util/SelectionManager"; import { NumberField } from "../../../../fields/NumberField"; import { Main } from "../../Main"; @@ -41,15 +43,20 @@ export class CollectionFreeFormView extends CollectionViewBase { } public selectDocuments = (docs: Document[]) => { - this.props.CollectionView.SelectedDocs.length = 0; - docs.map(d => this.props.CollectionView.SelectedDocs.push(d.Id)); + SelectionManager.DeselectAll; + docs.map(doc => { + const dv = DocumentManager.Instance.getDocumentView(doc); + if (dv) { + SelectionManager.SelectDoc(dv, true); + } + }) } public getActiveDocuments = () => { var curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1); return this.props.Document.GetList(this.props.fieldKey, [] as Document[]).reduce((active, doc) => { var page = doc.GetNumber(KeyStore.Page, -1); - if (page == curPage || page == -1) { + if (page === curPage || page === -1) { active.push(doc); } return active; @@ -61,6 +68,8 @@ export class CollectionFreeFormView extends CollectionViewBase { @observable private _lastX: number = 0; @observable private _lastY: number = 0; + private outerElement?: HTMLDivElement; + @computed get panX(): number { return this.props.Document.GetNumber(KeyStore.PanX, 0) } @computed get panY(): number { return this.props.Document.GetNumber(KeyStore.PanY, 0) } @computed get scale(): number { return this.props.Document.GetNumber(KeyStore.Scale, 1); } @@ -68,38 +77,40 @@ export class CollectionFreeFormView extends CollectionViewBase { @computed get nativeWidth() { return this.props.Document.GetNumber(KeyStore.NativeWidth, 0); } @computed get nativeHeight() { return this.props.Document.GetNumber(KeyStore.NativeHeight, 0); } @computed get zoomScaling() { return this.props.Document.GetNumber(KeyStore.Scale, 1); } - @computed get centeringShiftX() { return !this.props.Document.GetNumber(KeyStore.NativeWidth, 0) ? this.props.panelWidth() / 2 : 0; } // shift so pan position is at center of window for non-overlay collections - @computed get centeringShiftY() { return !this.props.Document.GetNumber(KeyStore.NativeHeight, 0) ? this.props.panelHeight() / 2 : 0; }// shift so pan position is at center of window for non-overlay collections + @computed get centeringShiftX() { return !this.props.Document.GetNumber(KeyStore.NativeWidth, 0) && this.outerElement ? this.outerElement.clientWidth / 2 : 0; } // shift so pan position is at center of window for non-overlay collections + @computed get centeringShiftY() { return !this.props.Document.GetNumber(KeyStore.NativeHeight, 0) && this.outerElement ? this.outerElement.clientHeight / 2 : 0; }// shift so pan position is at center of window for non-overlay collections @undoBatch @action drop = (e: Event, de: DragManager.DropEvent) => { if (super.drop(e, de)) { - let droppedDocs = de.data.droppedDocuments as Document[]; - let xoff = de.data.xOffset as number || 0; - let yoff = de.data.yOffset as number || 0; - if (droppedDocs && droppedDocs.length) { - let screenX = de.x - xoff; - let screenY = de.y - yoff; - const [x, y] = this.getTransform().transformPoint(screenX, screenY); - let dragDoc = de.data.droppedDocuments[0]; - let dragX = dragDoc.GetNumber(KeyStore.X, 0); - let dragY = dragDoc.GetNumber(KeyStore.Y, 0); - droppedDocs.map(async d => { - let docX = d.GetNumber(KeyStore.X, 0); - let docY = d.GetNumber(KeyStore.Y, 0); - d.SetNumber(KeyStore.X, x + (docX - dragX)); - d.SetNumber(KeyStore.Y, y + (docY - dragY)); - let docW = await d.GetTAsync(KeyStore.Width, NumberField); - let docH = await d.GetTAsync(KeyStore.Height, NumberField); - if (!docW) { - d.SetNumber(KeyStore.Width, 300); - } - if (!docH) { - d.SetNumber(KeyStore.Height, 300); - } - this.bringToFront(d); - }) + if (de.data instanceof DragManager.DocumentDragData) { + let droppedDocs = de.data.droppedDocuments; + let xoff = de.data.xOffset as number || 0; + let yoff = de.data.yOffset as number || 0; + if (droppedDocs.length) { + let screenX = de.x - xoff; + let screenY = de.y - yoff; + const [x, y] = this.getTransform().transformPoint(screenX, screenY); + let dragDoc = droppedDocs[0]; + let dragX = dragDoc.GetNumber(KeyStore.X, 0); + let dragY = dragDoc.GetNumber(KeyStore.Y, 0); + droppedDocs.map(async d => { + let docX = d.GetNumber(KeyStore.X, 0); + let docY = d.GetNumber(KeyStore.Y, 0); + d.SetNumber(KeyStore.X, x + (docX - dragX)); + d.SetNumber(KeyStore.Y, y + (docY - dragY)); + let docW = await d.GetTAsync(KeyStore.Width, NumberField); + let docH = await d.GetTAsync(KeyStore.Height, NumberField); + if (!docW) { + d.SetNumber(KeyStore.Width, 300); + } + if (!docH) { + d.SetNumber(KeyStore.Height, 300); + } + this.bringToFront(d); + }) + } } return true; } @@ -115,7 +126,7 @@ export class CollectionFreeFormView extends CollectionViewBase { @action onPointerDown = (e: React.PointerEvent): void => { - if (((e.button === 2 && (!this.isAnnotationOverlay || this.zoomScaling != 1)) || e.button == 0) && this.props.active()) { + if (((e.button === 2 && (!this.isAnnotationOverlay || this.zoomScaling !== 1)) || e.button === 0) && this.props.active()) { document.removeEventListener("pointermove", this.onPointerMove); document.addEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); @@ -137,7 +148,7 @@ export class CollectionFreeFormView extends CollectionViewBase { @action onPointerMove = (e: PointerEvent): void => { if (!e.cancelBubble && this.props.active()) { - if ((!this.isAnnotationOverlay || this.zoomScaling != 1) && !e.shiftKey) { + if ((!this.isAnnotationOverlay || this.zoomScaling !== 1) && !e.shiftKey) { let x = this.props.Document.GetNumber(KeyStore.PanX, 0); let y = this.props.Document.GetNumber(KeyStore.PanY, 0); let [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY); @@ -166,8 +177,8 @@ export class CollectionFreeFormView extends CollectionViewBase { e.stopPropagation(); e.preventDefault(); } else { - // if (modes[e.deltaMode] == 'pixels') coefficient = 50; - // else if (modes[e.deltaMode] == 'lines') coefficient = 1000; // This should correspond to line-height?? + // if (modes[e.deltaMode] === 'pixels') coefficient = 50; + // else if (modes[e.deltaMode] === 'lines') coefficient = 1000; // This should correspond to line-height?? let transform = this.getTransform(); let deltaScale = (1 - (e.deltaY / coefficient)); @@ -244,16 +255,19 @@ export class CollectionFreeFormView extends CollectionViewBase { getDocumentViewProps(document: Document): DocumentViewProps { return { Document: document, - AddDocument: this.props.addDocument, - RemoveDocument: this.props.removeDocument, + addDocument: this.props.addDocument, + removeDocument: this.props.removeDocument, + moveDocument: this.props.moveDocument, ScreenToLocalTransform: this.getTransform, isTopMost: false, - SelectOnLoad: document.Id == this._selectOnLoaded, + selectOnLoad: document.Id === this._selectOnLoaded, PanelWidth: document.Width, PanelHeight: document.Height, ContentScaling: this.noScaling, - ContainingCollectionView: this.props.CollectionView, - focus: this.focusDocument + ContainingCollectionView: undefined, + focus: this.focusDocument, + parentActive: this.props.active, + onActiveChanged: this.props.active, } } @@ -262,7 +276,7 @@ export class CollectionFreeFormView extends CollectionViewBase { var curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1); return this.props.Document.GetList(this.props.fieldKey, [] as Document[]).filter(doc => doc).reduce((prev, doc) => { var page = doc.GetNumber(KeyStore.Page, -1); - if (page == curPage || page == -1) + if (page === curPage || page === -1) prev.push(<CollectionFreeFormDocumentView key={doc.Id} {...this.getDocumentViewProps(doc)} />); return prev; }, [] as JSX.Element[]) @@ -283,7 +297,7 @@ export class CollectionFreeFormView extends CollectionViewBase { getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-COLLECTION_BORDER_WIDTH, -COLLECTION_BORDER_WIDTH).translate(-this.centeringShiftX, -this.centeringShiftY).transform(this.getLocalTransform()) getContainerTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-COLLECTION_BORDER_WIDTH, -COLLECTION_BORDER_WIDTH) - getLocalTransform = (): Transform => Transform.Identity.scale(1 / this.scale).translate(this.panX, this.panY); + getLocalTransform = (): Transform => Transform.Identity().scale(1 / this.scale).translate(this.panX, this.panY); noScaling = () => 1; childViews = () => this.views; diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index df150a045..704db1d4a 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -48,7 +48,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps> @action onPointerDown = (e: React.PointerEvent): void => { - if (e.buttons == 1 && !e.altKey && !e.metaKey && this.props.container.props.active()) { + if (e.buttons === 1 && !e.altKey && !e.metaKey && this.props.container.props.active()) { this._downX = this._lastX = e.pageX; this._downY = this._lastY = e.pageY; this._used = false; @@ -63,7 +63,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps> this._lastX = e.pageX; this._lastY = e.pageY; if (!e.cancelBubble) { - if (!this._used && e.buttons == 1 && !e.altKey && !e.metaKey && + if (!this._used && e.buttons === 1 && !e.altKey && !e.metaKey && (Math.abs(this._lastX - this._downX) > MarqueeView.DRAG_THRESHOLD || Math.abs(this._lastY - this._downY) > MarqueeView.DRAG_THRESHOLD)) { this._visible = true; } @@ -99,15 +99,15 @@ export class MarqueeView extends React.Component<MarqueeViewProps> @action marqueeCommand = (e: KeyboardEvent) => { - if (e.key == "Backspace" || e.key == "Delete") { + if (e.key === "Backspace" || e.key === "Delete") { this.marqueeSelect().map(d => this.props.removeDocument(d)); let ink = this.props.container.props.Document.GetT(KeyStore.Ink, InkField); - if (ink && ink != FieldWaiting) { + if (ink && ink !== FieldWaiting) { this.marqueeInkDelete(ink.Data); } this.cleanupInteractions(); } - if (e.key == "c") { + if (e.key === "c") { let bounds = this.Bounds; let selected = this.marqueeSelect().map(d => { this.props.removeDocument(d); @@ -118,7 +118,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps> return d; }); let ink = this.props.container.props.Document.GetT(KeyStore.Ink, InkField); - let inkData = ink && ink != FieldWaiting ? ink.Data : undefined; + let inkData = ink && ink !== FieldWaiting ? ink.Data : undefined; //setTimeout(() => { let newCollection = Documents.FreeformDocument(selected, { x: bounds.left, @@ -147,7 +147,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps> if (InkingCanvas.IntersectStrokeRect(value, this.Bounds)) { idata.set(key, { - pathData: value.pathData.map(val => { return { x: val.x + centerShiftX, y: val.y + centerShiftY } }), + pathData: value.pathData.map(val => ({ x: val.x + centerShiftX, y: val.y + centerShiftY })), color: value.color, width: value.width, tool: value.tool, diff --git a/src/client/views/collections/collectionFreeForm/PreviewCursor.tsx b/src/client/views/collections/collectionFreeForm/PreviewCursor.tsx index 93c98f7b0..599461f85 100644 --- a/src/client/views/collections/collectionFreeForm/PreviewCursor.tsx +++ b/src/client/views/collections/collectionFreeForm/PreviewCursor.tsx @@ -33,7 +33,7 @@ export class PreviewCursor extends React.Component<PreviewCursorProps> { @action onPointerDown = (e: React.PointerEvent) => { - if (e.button == 0 && this.props.container.props.active()) { + if (e.button === 0 && this.props.container.props.active()) { document.removeEventListener("keypress", this.onKeyPress, false); this._showOnUp = true; this.DownX = e.pageX; diff --git a/src/client/views/nodes/Annotation.tsx b/src/client/views/nodes/Annotation.tsx index a2c7be1a8..e4f17940c 100644 --- a/src/client/views/nodes/Annotation.tsx +++ b/src/client/views/nodes/Annotation.tsx @@ -4,13 +4,13 @@ import { observer } from "mobx-react" import { observable, action } from 'mobx'; import 'react-pdf/dist/Page/AnnotationLayer.css' -interface IProps{ +interface IProps { Span: HTMLSpanElement; - X: number; - Y: number; - Highlights: any[]; - Annotations: any[]; - CurrAnno: any[]; + X: number; + Y: number; + Highlights: any[]; + Annotations: any[]; + CurrAnno: any[]; } @@ -23,95 +23,95 @@ interface IProps{ */ @observer export class Annotation extends React.Component<IProps> { - + /** * changes color of the span (highlighted section) */ - onColorChange = (e:React.PointerEvent) => { - if (e.currentTarget.innerHTML == "r"){ + onColorChange = (e: React.PointerEvent) => { + if (e.currentTarget.innerHTML === "r") { this.props.Span.style.backgroundColor = "rgba(255,0,0, 0.3)" - } else if (e.currentTarget.innerHTML == "b"){ + } else if (e.currentTarget.innerHTML === "b") { this.props.Span.style.backgroundColor = "rgba(0,255, 255, 0.3)" - } else if (e.currentTarget.innerHTML == "y"){ + } else if (e.currentTarget.innerHTML === "y") { this.props.Span.style.backgroundColor = "rgba(255,255,0, 0.3)" - } else if (e.currentTarget.innerHTML == "g"){ + } else if (e.currentTarget.innerHTML === "g") { this.props.Span.style.backgroundColor = "rgba(76, 175, 80, 0.3)" } - + } /** * removes the highlighted span. Supposed to remove Annotation too, but I don't know how to unmount this */ @action - onRemove = (e:any) => { - let index:number = -1; + onRemove = (e: any) => { + let index: number = -1; //finding the highlight in the highlight array this.props.Highlights.forEach((e) => { - for (let i = 0; i < e.spans.length; i++){ - if (e.spans[i] == this.props.Span){ - index = this.props.Highlights.indexOf(e); - this.props.Highlights.splice(index, 1); + for (const span of e.spans) { + if (span === this.props.Span) { + index = this.props.Highlights.indexOf(e); + this.props.Highlights.splice(index, 1); } } }) //removing from CurrAnno and Annotation array - this.props.Annotations.splice(index, 1); + this.props.Annotations.splice(index, 1); this.props.CurrAnno.pop() - + //removing span from div - if(this.props.Span.parentElement){ - let nodesArray = this.props.Span.parentElement.childNodes; + if (this.props.Span.parentElement) { + let nodesArray = this.props.Span.parentElement.childNodes; nodesArray.forEach((e) => { - if (e == this.props.Span){ - if (this.props.Span.parentElement){ + if (e === this.props.Span) { + if (this.props.Span.parentElement) { this.props.Highlights.forEach((item) => { - if (item == e){ - item.remove(); + if (item === e) { + item.remove(); } }) - e.remove(); + e.remove(); } } - }) + }) } - - + + } render() { return ( - <div - style = {{ - position: "absolute", - top: "20px", - left: "0px", - zIndex: 1, - transform: `translate(${this.props.X}px, ${this.props.Y}px)`, - - }}> - <div style = {{width:"200px", height:"50px", backgroundColor: "orange"}}> + <div + style={{ + position: "absolute", + top: "20px", + left: "0px", + zIndex: 1, + transform: `translate(${this.props.X}px, ${this.props.Y}px)`, + + }}> + <div style={{ width: "200px", height: "50px", backgroundColor: "orange" }}> <button - style = {{borderRadius: "25px", width:"25%", height:"100%"}} - onClick = {this.onRemove} + style={{ borderRadius: "25px", width: "25%", height: "100%" }} + onClick={this.onRemove} >x</button> - <div style = {{width:"75%", height: "100%" , display:"inline-block"}}> - <button onPointerDown = {this.onColorChange} style = {{backgroundColor:"red", borderRadius:"50%", color: "transparent"}}>r</button> - <button onPointerDown = {this.onColorChange} style = {{backgroundColor:"blue", borderRadius:"50%", color: "transparent"}}>b</button> - <button onPointerDown = {this.onColorChange} style = {{backgroundColor:"yellow", borderRadius:"50%", color:"transparent"}}>y</button> - <button onPointerDown = {this.onColorChange} style = {{backgroundColor:"green", borderRadius:"50%", color:"transparent"}}>g</button> + <div style={{ width: "75%", height: "100%", display: "inline-block" }}> + <button onPointerDown={this.onColorChange} style={{ backgroundColor: "red", borderRadius: "50%", color: "transparent" }}>r</button> + <button onPointerDown={this.onColorChange} style={{ backgroundColor: "blue", borderRadius: "50%", color: "transparent" }}>b</button> + <button onPointerDown={this.onColorChange} style={{ backgroundColor: "yellow", borderRadius: "50%", color: "transparent" }}>y</button> + <button onPointerDown={this.onColorChange} style={{ backgroundColor: "green", borderRadius: "50%", color: "transparent" }}>g</button> </div> - + </div> - <div style = {{width:"200px", height:"200"}}> - <textarea style = {{width: "100%", height: "100%"}} - defaultValue = "Enter Text Here..." - + <div style={{ width: "200px", height: "200" }}> + <textarea style={{ width: "100%", height: "100%" }} + defaultValue="Enter Text Here..." + ></textarea> </div> </div> - + ); } }
\ No newline at end of file diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 6daf15f5f..1bd934c25 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -28,8 +28,8 @@ export class AudioBox extends React.Component<FieldViewProps> { render() { - let field = this.props.doc.Get(this.props.fieldKey) - let path = field == FieldWaiting ? "http://techslides.com/demos/samples/sample.mp3" : + let field = this.props.Document.Get(this.props.fieldKey) + let path = field === FieldWaiting ? "http://techslides.com/demos/samples/sample.mp3" : field instanceof AudioField ? field.Data.href : "http://techslides.com/demos/samples/sample.mp3"; return ( diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 1a0f0cbbd..dcf82ccd4 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -52,14 +52,12 @@ export class CollectionFreeFormDocumentView extends React.Component<DocumentView this.props.Document.SetData(KeyStore.ZIndex, h, NumberField) } - contentScaling = () => { - return this.nativeWidth > 0 ? this.width / this.nativeWidth : 1; - } + contentScaling = () => this.nativeWidth > 0 ? this.width / this.nativeWidth : 1 - getTransform = (): Transform => { - return this.props.ScreenToLocalTransform(). - translate(-this.props.Document.GetNumber(KeyStore.X, 0), -this.props.Document.GetNumber(KeyStore.Y, 0)).scale(1 / this.contentScaling()); - } + getTransform = (): Transform => + this.props.ScreenToLocalTransform() + .translate(-this.props.Document.GetNumber(KeyStore.X, 0), -this.props.Document.GetNumber(KeyStore.Y, 0)) + .scale(1 / this.contentScaling()) @computed get docView() { diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 77551649c..34cc326aa 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -1,6 +1,6 @@ import { computed } from "mobx"; import { observer } from "mobx-react"; -import { FieldWaiting } from "../../../fields/Field"; +import { FieldWaiting, Field } from "../../../fields/Field"; import { Key } from "../../../fields/Key"; import { KeyStore } from "../../../fields/KeyStore"; import { ListField } from "../../../fields/ListField"; @@ -11,7 +11,7 @@ import { CollectionSchemaView } from "../collections/CollectionSchemaView"; import { CollectionVideoView } from "../collections/CollectionVideoView"; import { CollectionView } from "../collections/CollectionView"; import { AudioBox } from "./AudioBox"; -import { DocumentViewProps, JsxBindings } from "./DocumentView"; +import { DocumentViewProps } from "./DocumentView"; import "./DocumentView.scss"; import { FormattedTextBox } from "./FormattedTextBox"; import { ImageBox } from "./ImageBox"; @@ -21,8 +21,16 @@ import { VideoBox } from "./VideoBox"; import { WebBox } from "./WebBox"; import { HistogramBox } from "../../northstar/dash-nodes/HistogramBox"; import React = require("react"); +import { Document } from "../../../fields/Document"; +import { FieldViewProps } from "./FieldView"; +import { Without } from "../../../Utils"; const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? +type BindingProps = Without<FieldViewProps, 'fieldKey'> +export interface JsxBindings { + props: BindingProps; + [keyName: string]: BindingProps | Field; +} @observer export class DocumentContentsView extends React.Component<DocumentViewProps & { @@ -36,13 +44,40 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & { CreateBindings(): JsxBindings { - let bindings: JsxBindings = { ...this.props, }; + let + { + Document, + isSelected, + select, + isTopMost, + selectOnLoad, + ScreenToLocalTransform, + addDocument, + removeDocument, + onActiveChanged, + parentActive: active, + } = this.props; + let bindings: JsxBindings = { + props: { + Document, + isSelected, + select, + isTopMost, + selectOnLoad, + ScreenToLocalTransform, + active, + onActiveChanged, + addDocument, + removeDocument, + focus, + } + }; for (const key of this.layoutKeys) { bindings[key.Name + "Key"] = key; // this maps string values of the form <keyname>Key to an actual key Kestore.keyname e.g, "DataKey" => KeyStore.Data } for (const key of this.layoutFields) { let field = this.props.Document.Get(key); - bindings[key.Name] = field && field != FieldWaiting ? field.GetValue() : field; + bindings[key.Name] = field && field !== FieldWaiting ? field.GetValue() : field; } return bindings; } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 7514e782d..ab9cd2d53 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -15,24 +15,28 @@ import { DragManager } from "../../util/DragManager"; import { SelectionManager } from "../../util/SelectionManager"; import { Transform } from "../../util/Transform"; import { CollectionDockingView } from "../collections/CollectionDockingView"; -import { CollectionView, CollectionViewType } from "../collections/CollectionView"; +import { CollectionView } from "../collections/CollectionView"; import { ContextMenu } from "../ContextMenu"; import { DocumentContentsView } from "./DocumentContentsView"; import "./DocumentView.scss"; import React = require("react"); + export interface DocumentViewProps { ContainingCollectionView: Opt<CollectionView>; Document: Document; - AddDocument?: (doc: Document, allowDuplicates: boolean) => boolean; - RemoveDocument?: (doc: Document) => boolean; + addDocument?: (doc: Document, allowDuplicates?: boolean) => boolean; + removeDocument?: (doc: Document) => boolean; + moveDocument?: (doc: Document, targetCollection: Document, addDocument: (document: Document) => boolean) => boolean; ScreenToLocalTransform: () => Transform; isTopMost: boolean; ContentScaling: () => number; PanelWidth: () => number; PanelHeight: () => number; focus: (doc: Document) => void; - SelectOnLoad: boolean; + selectOnLoad: boolean; + parentActive: () => boolean; + onActiveChanged: (isActive: boolean) => void; } export interface JsxArgs extends DocumentViewProps { Keys: { [name: string]: Key }; @@ -76,60 +80,20 @@ export function FakeJsxArgs(keys: string[], fields: string[] = []): JsxArgs { return args; } -export interface JsxBindings { - Document: Document; - isSelected: () => boolean; - select: (isCtrlPressed: boolean) => void; - isTopMost: boolean; - SelectOnLoad: boolean; - [prop: string]: any; -} - @observer export class DocumentView extends React.Component<DocumentViewProps> { private _mainCont = React.createRef<HTMLDivElement>(); + public get ContentRef() { + return this._mainCont; + } private _downX: number = 0; private _downY: number = 0; - - private _reactionDisposer: Opt<IReactionDisposer>; - @computed get active(): boolean { - return ( - SelectionManager.IsSelected(this) || - !this.props.ContainingCollectionView || - this.props.ContainingCollectionView.active() - ); - } - @computed get topMost(): boolean { - return ( - !this.props.ContainingCollectionView || - this.props.ContainingCollectionView.collectionViewType == - CollectionViewType.Docking - ); - } - @computed get layout(): string { - return this.props.Document.GetText( - KeyStore.Layout, - "<p>Error loading layout data</p>" - ); - } - @computed get layoutKeys(): Key[] { - return this.props.Document.GetData( - KeyStore.LayoutKeys, - ListField, - new Array<Key>() - ); - } - @computed get layoutFields(): Key[] { - return this.props.Document.GetData( - KeyStore.LayoutFields, - ListField, - new Array<Key>() - ); - } - screenRect = (): ClientRect | DOMRect => - this._mainCont.current - ? this._mainCont.current.getBoundingClientRect() - : new DOMRect(); + @computed get active(): boolean { return SelectionManager.IsSelected(this) || this.props.parentActive(); } + @computed get topMost(): boolean { return this.props.isTopMost; } + @computed get layout(): string { return this.props.Document.GetText(KeyStore.Layout, "<p>Error loading layout data</p>"); } + @computed get layoutKeys(): Key[] { return this.props.Document.GetData(KeyStore.LayoutKeys, ListField, new Array<Key>()); } + @computed get layoutFields(): Key[] { return this.props.Document.GetData(KeyStore.LayoutFields, ListField, new Array<Key>()); } + screenRect = (): ClientRect | DOMRect => this._mainCont.current ? this._mainCont.current.getBoundingClientRect() : new DOMRect(); onPointerDown = (e: React.PointerEvent): void => { this._downX = e.clientX; this._downY = e.clientY; @@ -159,20 +123,6 @@ export class DocumentView extends React.Component<DocumentViewProps> { }); } runInAction(() => DocumentManager.Instance.DocumentViews.push(this)); - this._reactionDisposer = reaction( - () => - this.props.ContainingCollectionView && - this.props.ContainingCollectionView.SelectedDocs.slice(), - () => { - if ( - this.props.ContainingCollectionView && - this.props.ContainingCollectionView.SelectedDocs.indexOf( - this.props.Document.Id - ) != -1 - ) - SelectionManager.SelectDoc(this, true); - } - ); } componentDidUpdate() { @@ -190,15 +140,7 @@ export class DocumentView extends React.Component<DocumentViewProps> { if (this.dropDisposer) { this.dropDisposer(); } - runInAction(() => - DocumentManager.Instance.DocumentViews.splice( - DocumentManager.Instance.DocumentViews.indexOf(this), - 1 - ) - ); - if (this._reactionDisposer) { - this._reactionDisposer(); - } + runInAction(() => DocumentManager.Instance.DocumentViews.splice(DocumentManager.Instance.DocumentViews.indexOf(this), 1)); } startDragging(x: number, y: number, dropAliasOfDraggedDoc: boolean) { @@ -211,14 +153,7 @@ export class DocumentView extends React.Component<DocumentViewProps> { dragData.aliasOnDrop = dropAliasOfDraggedDoc; dragData.xOffset = x - left; dragData.yOffset = y - top; - dragData.removeDocument = (dropCollectionView: CollectionView) => { - if ( - this.props.RemoveDocument && - this.props.ContainingCollectionView !== dropCollectionView - ) { - this.props.RemoveDocument(this.props.Document); - } - }; + dragData.moveDocument = this.props.moveDocument; DragManager.StartDocumentDrag([this._mainCont.current], dragData, x, y, { handlers: { dragComplete: action(() => { }) @@ -238,7 +173,7 @@ export class DocumentView extends React.Component<DocumentViewProps> { ) { document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); - if (!this.topMost || e.buttons == 2 || e.altKey) { + if (!this.topMost || e.buttons === 2 || e.altKey) { this.startDragging(this._downX, this._downY, e.ctrlKey || e.altKey); } } @@ -261,17 +196,14 @@ export class DocumentView extends React.Component<DocumentViewProps> { }; deleteClicked = (): void => { - if (this.props.RemoveDocument) { - this.props.RemoveDocument(this.props.Document); + if (this.props.removeDocument) { + this.props.removeDocument(this.props.Document); } }; fieldsClicked = (e: React.MouseEvent): void => { - if (this.props.AddDocument) { - this.props.AddDocument( - Documents.KVPDocument(this.props.Document, { width: 300, height: 300 }), - false - ); + if (this.props.addDocument) { + this.props.addDocument(Documents.KVPDocument(this.props.Document, { width: 300, height: 300 }), false); } }; fullScreenClicked = (e: React.MouseEvent): void => { @@ -438,9 +370,7 @@ export class DocumentView extends React.Component<DocumentViewProps> { ); }; - isSelected = () => { - return SelectionManager.IsSelected(this); - }; + isSelected = () => SelectionManager.IsSelected(this) select = (ctrlPressed: boolean) => { SelectionManager.SelectDoc(this, ctrlPressed); diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 4e83ec7b9..d9422ae9b 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -19,6 +19,7 @@ import { ListField } from "../../../fields/ListField"; import { DocumentContentsView } from "./DocumentContentsView"; import { Transform } from "../../util/Transform"; import { KeyStore } from "../../../fields/KeyStore"; +import { returnFalse } from "../../../Utils"; // @@ -28,23 +29,29 @@ import { KeyStore } from "../../../fields/KeyStore"; // export interface FieldViewProps { fieldKey: Key; - doc: Document; + Document: Document; isSelected: () => boolean; - select: () => void; + select: (isCtrlPressed: boolean) => void; isTopMost: boolean; selectOnLoad: boolean; - bindings: any; + addDocument?: (document: Document, allowDuplicates?: boolean) => boolean; + removeDocument?: (document: Document) => boolean; + moveDocument?: (document: Document, targetCollection: Document, addDocument: (document: Document) => boolean) => boolean; + ScreenToLocalTransform: () => Transform; + active: () => boolean; + onActiveChanged: (isActive: boolean) => void; + focus: (doc: Document) => void; } @observer export class FieldView extends React.Component<FieldViewProps> { public static LayoutString(fieldType: { name: string }, fieldStr: string = "DataKey") { - return `<${fieldType.name} doc={Document} DocumentViewForField={DocumentView} bindings={bindings} fieldKey={${fieldStr}} isSelected={isSelected} select={select} selectOnLoad={SelectOnLoad} isTopMost={isTopMost} />`; + return `<${fieldType.name} {...props} fieldKey={${fieldStr}} />`; } @computed get field(): FieldValue<Field> { - const { doc, fieldKey } = this.props; + const { Document: doc, fieldKey } = this.props; return doc.Get(fieldKey); } render() { @@ -68,26 +75,28 @@ export class FieldView extends React.Component<FieldViewProps> { return <AudioBox {...this.props} /> } else if (field instanceof Document) { - return (<DocumentContentsView Document={field} - AddDocument={undefined} - RemoveDocument={undefined} - ScreenToLocalTransform={() => Transform.Identity} - ContentScaling={() => 1} - PanelWidth={() => 100} - PanelHeight={() => 100} - isTopMost={true} - SelectOnLoad={false} - focus={() => { }} - isSelected={() => false} - select={() => false} - layoutKey={KeyStore.Layout} - ContainingCollectionView={undefined} />) + return ( + <DocumentContentsView Document={field} + addDocument={undefined} + removeDocument={undefined} + ScreenToLocalTransform={Transform.Identity} + ContentScaling={() => 1} + PanelWidth={() => 100} + PanelHeight={() => 100} + isTopMost={true} //TODO Why is this top most? + selectOnLoad={false} + focus={() => { }} + isSelected={() => false} + select={() => false} + layoutKey={KeyStore.Layout} + ContainingCollectionView={undefined} + parentActive={this.props.active} + onActiveChanged={this.props.onActiveChanged} /> + ) } else if (field instanceof ListField) { return (<div> - {(field as ListField<Field>).Data.map(f => { - return f instanceof Document ? f.Title : f.GetValue().toString(); - }).join(", ")} + {(field as ListField<Field>).Data.map(f => f instanceof Document ? f.Title : f.GetValue().toString()).join(", ")} </div>) } // bcz: this belongs here, but it doesn't render well so taking it out for now @@ -97,7 +106,7 @@ export class FieldView extends React.Component<FieldViewProps> { else if (field instanceof NumberField) { return <p>{field.Data}</p> } - else if (field != FieldWaiting) { + else if (field !== FieldWaiting) { return <p>{JSON.stringify(field.GetValue())}</p> } else diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index e59179874..ebac61c78 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -63,7 +63,7 @@ export class FormattedTextBox extends React.Component<FieldViewProps> { } }; - get FieldDoc() { return this.props.fieldKey === KeyStore.Archives ? Main.Instance._textDoc! : this.props.doc; } + get FieldDoc() { return this.props.fieldKey === KeyStore.Archives ? Main.Instance._textDoc! : this.props.Document; } get FieldKey() { return this.props.fieldKey === KeyStore.Archives ? KeyStore.Data : this.props.fieldKey; } componentDidMount() { @@ -92,7 +92,7 @@ export class FormattedTextBox extends React.Component<FieldViewProps> { this._reactionDisposer = reaction( () => { const field = this.FieldDoc.GetT(this.FieldKey, RichTextField); - return field && field != FieldWaiting ? field.Data : undefined; + return field && field !== FieldWaiting ? field.Data : undefined; }, field => { if (field && this._editorView) { @@ -109,7 +109,7 @@ export class FormattedTextBox extends React.Component<FieldViewProps> { let state: EditorState; let field = this.FieldDoc.GetT(this.FieldKey, RichTextField); - if (field && field != FieldWaiting && field.Data) { + if (field && field !== FieldWaiting && field.Data) { state = EditorState.fromJSON(config, JSON.parse(field.Data)); } else { state = EditorState.create(config); @@ -122,7 +122,7 @@ export class FormattedTextBox extends React.Component<FieldViewProps> { } if (this.props.selectOnLoad) { - this.props.select(); + this.props.select(false); this._editorView!.focus(); } } @@ -145,8 +145,8 @@ export class FormattedTextBox extends React.Component<FieldViewProps> { @action onChange(e: React.ChangeEvent<HTMLInputElement>) { - const { fieldKey, doc } = this.props; - doc.SetOnPrototype(fieldKey, new RichTextField(e.target.value)); + const { fieldKey, Document } = this.props; + Document.SetOnPrototype(fieldKey, new RichTextField(e.target.value)); // doc.SetData(fieldKey, e.target.value, RichTextField); } onPointerDown = (e: React.PointerEvent): void => { @@ -162,13 +162,13 @@ export class FormattedTextBox extends React.Component<FieldViewProps> { } if (this.props.fieldKey !== KeyStore.Archives) { e.preventDefault(); - Main.Instance.SetTextDoc(this.props.doc, this._ref.current!); + Main.Instance.SetTextDoc(this.props.Document, this._ref.current!); } }; onFocused = (e: React.FocusEvent): void => { if (this.props.fieldKey !== KeyStore.Archives) { - Main.Instance.SetTextDoc(this.props.doc, this._ref.current!); + Main.Instance.SetTextDoc(this.props.Document, this._ref.current!); } } diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 60d1f7214..c5f29f7b0 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -39,7 +39,7 @@ export class ImageBox extends React.Component<FieldViewProps> { onLoad = (target: any) => { var h = this._imgRef.current!.naturalHeight; var w = this._imgRef.current!.naturalWidth; - this.props.doc.SetNumber(KeyStore.NativeHeight, this.props.doc.GetNumber(KeyStore.NativeWidth, 0) * h / w) + this.props.Document.SetNumber(KeyStore.NativeHeight, this.props.Document.GetNumber(KeyStore.NativeWidth, 0) * h / w) } componentDidMount() { @@ -91,7 +91,7 @@ export class ImageBox extends React.Component<FieldViewProps> { } specificContextMenu = (e: React.MouseEvent): void => { - let field = this.props.doc.GetT(this.props.fieldKey, ImageField); + let field = this.props.Document.GetT(this.props.fieldKey, ImageField); if (field && field !== FieldWaiting) { let url = field.Data.href; ContextMenu.Instance.addItem({ @@ -103,10 +103,10 @@ export class ImageBox extends React.Component<FieldViewProps> { } render() { - let field = this.props.doc.Get(this.props.fieldKey); - let path = field == FieldWaiting ? "https://image.flaticon.com/icons/svg/66/66163.svg" : + let field = this.props.Document.Get(this.props.fieldKey); + let path = field === FieldWaiting ? "https://image.flaticon.com/icons/svg/66/66163.svg" : field instanceof ImageField ? field.Data.href : "http://www.cs.brown.edu/~bcz/face.gif"; - let nativeWidth = this.props.doc.GetNumber(KeyStore.NativeWidth, 1); + let nativeWidth = this.props.Document.GetNumber(KeyStore.NativeWidth, 1); return ( <div className="imageBox-cont" onPointerDown={this.onPointerDown} ref={this._ref} onContextMenu={this.specificContextMenu}> <img src={path} width={nativeWidth} alt="Image not found" ref={this._imgRef} onLoad={this.onLoad} /> diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx index 9bd6c1052..8a7f32e6d 100644 --- a/src/client/views/nodes/KeyValueBox.tsx +++ b/src/client/views/nodes/KeyValueBox.tsx @@ -32,10 +32,10 @@ export class KeyValueBox extends React.Component<FieldViewProps> { @action onEnterKey = (e: React.KeyboardEvent): void => { - if (e.key == 'Enter') { + if (e.key === 'Enter') { if (this._keyInput && this._valueInput) { - let doc = this.props.doc.GetT(KeyStore.Data, Document); - if (!doc || doc == FieldWaiting) { + let doc = this.props.Document.GetT(KeyStore.Data, Document); + if (!doc || doc === FieldWaiting) { return } let realDoc = doc; @@ -71,8 +71,8 @@ export class KeyValueBox extends React.Component<FieldViewProps> { } createTable = () => { - let doc = this.props.doc.GetT(KeyStore.Data, Document); - if (!doc || doc == FieldWaiting) { + let doc = this.props.Document.GetT(KeyStore.Data, Document); + if (!doc || doc === FieldWaiting) { return <tr><td>Loading...</td></tr> } let realDoc = doc; @@ -105,14 +105,13 @@ export class KeyValueBox extends React.Component<FieldViewProps> { this._valueInput = e.currentTarget.value; } - newKeyValue = () => { - return ( + newKeyValue = () => + ( <tr> <td><input type="text" value={this._keyInput} placeholder="Key" onChange={this.keyChanged} /></td> <td><input type="text" value={this._valueInput} placeholder="Value" onChange={this.valueChanged} onKeyPress={this.onEnterKey} /></td> </tr> ) - } render() { return (<div className="keyValueBox-cont" onWheel={this.onPointerWheel}> diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index 5647f45bf..c6a0a7296 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -11,6 +11,8 @@ import { Key } from '../../../fields/Key'; import { Server } from "../../Server" import { EditableView } from "../EditableView"; import { CompileScript, ToField } from "../../util/Scripting"; +import { Transform } from '../../util/Transform'; +import { returnFalse, emptyFunction } from '../../../Utils'; // Represents one row in a key value plane @@ -43,13 +45,16 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> { } let props: FieldViewProps = { - doc: this.props.doc, + Document: this.props.doc, fieldKey: this.key, - isSelected: () => false, - select: () => { }, + isSelected: returnFalse, + select: emptyFunction, isTopMost: false, - bindings: {}, selectOnLoad: false, + active: returnFalse, + onActiveChanged: emptyFunction, + ScreenToLocalTransform: Transform.Identity, + focus: emptyFunction, } let contents = ( <FieldView {...props} /> @@ -61,15 +66,15 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> { <div className="container"> <div>{this.key.Name}</div> <button className="delete" onClick={() => { - let field = props.doc.Get(props.fieldKey); + let field = props.Document.Get(props.fieldKey); if (field && field instanceof Field) { - props.doc.Set(props.fieldKey, undefined); + props.Document.Set(props.fieldKey, undefined); } }}>X</button> </div> </td> <td><EditableView contents={contents} height={36} GetValue={() => { - let field = props.doc.Get(props.fieldKey); + let field = props.Document.Get(props.fieldKey); if (field && field instanceof Field) { return field.ToScriptString(); } @@ -84,12 +89,12 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> { if (!res.success) return false; const field = res.result; if (field instanceof Field) { - props.doc.Set(props.fieldKey, field); + props.Document.Set(props.fieldKey, field); return true; } else { let dataField = ToField(field); if (dataField) { - props.doc.Set(props.fieldKey, dataField); + props.Document.Set(props.fieldKey, dataField); return true; } } diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx index e81f8fec7..4791d6029 100644 --- a/src/client/views/nodes/LinkBox.tsx +++ b/src/client/views/nodes/LinkBox.tsx @@ -49,7 +49,7 @@ export class LinkBox extends React.Component<Props> { } else if (contextDoc instanceof Document) { this.props.pairedDoc.GetTAsync(KeyStore.Page, NumberField).then((pfield: any) => { contextDoc.GetTAsync(KeyStore.CurPage, NumberField).then((cfield: any) => { - if (pfield != cfield) + if (pfield !== cfield) contextDoc.SetNumber(KeyStore.CurPage, pfield.Data); let contextView = DocumentManager.Instance.getDocumentView(contextDoc); if (contextView) { diff --git a/src/client/views/nodes/LinkMenu.tsx b/src/client/views/nodes/LinkMenu.tsx index 5eeb40772..6c2d24630 100644 --- a/src/client/views/nodes/LinkMenu.tsx +++ b/src/client/views/nodes/LinkMenu.tsx @@ -24,7 +24,7 @@ export class LinkMenu extends React.Component<Props> { renderLinkItems(links: Document[], key: Key, type: string) { return links.map(link => { let doc = link.GetT(key, Document); - if (doc && doc != FieldWaiting) { + if (doc && doc !== FieldWaiting) { return <LinkBox key={doc.Id} linkDoc={link} linkName={link.Title} pairedDoc={doc} showEditor={action(() => this._editingLink = link)} type={type} /> } }) diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 7039b0c41..774d9be3e 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -89,14 +89,14 @@ export class PDFBox extends React.Component<FieldViewProps> { @observable private _interactive: boolean = false; @observable private _loaded: boolean = false; - @computed private get curPage() { return this.props.doc.GetNumber(KeyStore.CurPage, 1); } - @computed private get thumbnailPage() { return this.props.doc.GetNumber(KeyStore.ThumbnailPage, -1); } + @computed private get curPage() { return this.props.Document.GetNumber(KeyStore.CurPage, 1); } + @computed private get thumbnailPage() { return this.props.Document.GetNumber(KeyStore.ThumbnailPage, -1); } componentDidMount() { this._reactionDisposer = reaction( () => [SelectionManager.SelectedDocuments().slice()], () => { - if (this.curPage > 0 && this.thumbnailPage > 0 && this.curPage != this.thumbnailPage && !this.props.isSelected()) { + if (this.curPage > 0 && this.thumbnailPage > 0 && this.curPage !== this.thumbnailPage && !this.props.isSelected()) { this.saveThumbnail(); this._interactive = true; } @@ -167,16 +167,16 @@ export class PDFBox extends React.Component<FieldViewProps> { let obj: Object = { parentDivs: [], spans: [] }; //@ts-ignore - if (range.commonAncestorContainer.className == 'react-pdf__Page__textContent') { //multiline highlighting case + if (range.commonAncestorContainer.className === 'react-pdf__Page__textContent') { //multiline highlighting case obj = this.highlightNodes(range.commonAncestorContainer.childNodes) } else { //single line highlighting case let parentDiv = range.commonAncestorContainer.parentElement if (parentDiv) { - if (parentDiv.className == 'react-pdf__Page__textContent') { //when highlight is overwritten + if (parentDiv.className === 'react-pdf__Page__textContent') { //when highlight is overwritten obj = this.highlightNodes(parentDiv.childNodes) } else { parentDiv.childNodes.forEach((child) => { - if (child.nodeName == 'SPAN') { + if (child.nodeName === 'SPAN') { //@ts-ignore obj.parentDivs.push(parentDiv) //@ts-ignore @@ -199,7 +199,7 @@ export class PDFBox extends React.Component<FieldViewProps> { let temp = { parentDivs: [], spans: [] } nodes.forEach((div) => { div.childNodes.forEach((child) => { - if (child.nodeName == 'SPAN') { + if (child.nodeName === 'SPAN') { //@ts-ignore temp.parentDivs.push(div) //@ts-ignore @@ -223,7 +223,7 @@ export class PDFBox extends React.Component<FieldViewProps> { let index: any; this._pageInfo.divs.forEach((obj: any) => { obj.spans.forEach((element: any) => { - if (element == span) { + if (element === span) { if (!index) { index = this._pageInfo.divs.indexOf(obj); } @@ -232,11 +232,11 @@ export class PDFBox extends React.Component<FieldViewProps> { }) if (this._pageInfo.anno.length >= index + 1) { - if (this._currAnno.length == 0) { + if (this._currAnno.length === 0) { this._currAnno.push(this._pageInfo.anno[index]); } } else { - if (this._currAnno.length == 0) { //if there are no current annotation + if (this._currAnno.length === 0) { //if there are no current annotation let div = span.offsetParent; //@ts-ignore let divX = div.style.left @@ -317,7 +317,7 @@ export class PDFBox extends React.Component<FieldViewProps> { * starts drawing the line when user presses down. */ onDraw = () => { - if (this._currTool != null) { + if (this._currTool !== null) { this._currTool.style.backgroundColor = "grey"; } @@ -342,13 +342,13 @@ export class PDFBox extends React.Component<FieldViewProps> { * for changing color (for ink/pen) */ onColorChange = (e: React.PointerEvent) => { - if (e.currentTarget.innerHTML == "Red") { + if (e.currentTarget.innerHTML === "Red") { this._currColor = "red"; - } else if (e.currentTarget.innerHTML == "Blue") { + } else if (e.currentTarget.innerHTML === "Blue") { this._currColor = "blue"; - } else if (e.currentTarget.innerHTML == "Green") { + } else if (e.currentTarget.innerHTML === "Green") { this._currColor = "green"; - } else if (e.currentTarget.innerHTML == "Black") { + } else if (e.currentTarget.innerHTML === "Black") { this._currColor = "black"; } @@ -360,7 +360,7 @@ export class PDFBox extends React.Component<FieldViewProps> { */ onHighlight = () => { this._drawToolOn = false; - if (this._currTool != null) { + if (this._currTool !== null) { this._currTool.style.backgroundColor = "grey"; } if (this._highlightTool.current) { @@ -381,12 +381,12 @@ export class PDFBox extends React.Component<FieldViewProps> { this._renderAsSvg = false; setTimeout(() => { var me = this; - let nwidth = me.props.doc.GetNumber(KeyStore.NativeWidth, 0); - let nheight = me.props.doc.GetNumber(KeyStore.NativeHeight, 0); + let nwidth = me.props.Document.GetNumber(KeyStore.NativeWidth, 0); + let nheight = me.props.Document.GetNumber(KeyStore.NativeHeight, 0); htmlToImage.toPng(this._mainDiv.current!, { width: nwidth, height: nheight, quality: 1 }) .then(action((dataUrl: string) => { - me.props.doc.SetData(KeyStore.Thumbnail, new URL(dataUrl), ImageField); - me.props.doc.SetNumber(KeyStore.ThumbnailPage, me.props.doc.GetNumber(KeyStore.CurPage, -1)); + me.props.Document.SetData(KeyStore.Thumbnail, new URL(dataUrl), ImageField); + me.props.Document.SetNumber(KeyStore.ThumbnailPage, me.props.Document.GetNumber(KeyStore.CurPage, -1)); me._renderAsSvg = true; })) .catch(function (error: any) { @@ -399,7 +399,7 @@ export class PDFBox extends React.Component<FieldViewProps> { onLoaded = (page: any) => { if (this._mainDiv.current) { this._mainDiv.current.childNodes.forEach((element) => { - if (element.nodeName == "DIV") { + if (element.nodeName === "DIV") { element.childNodes[0].childNodes.forEach((e) => { if (e instanceof HTMLCanvasElement) { @@ -414,8 +414,8 @@ export class PDFBox extends React.Component<FieldViewProps> { } // bcz: the number of pages should really be set when the document is imported. - this.props.doc.SetNumber(KeyStore.NumPages, page._transport.numPages); - if (this._perPageInfo.length == 0) { //Makes sure it only runs once + this.props.Document.SetNumber(KeyStore.NumPages, page._transport.numPages); + if (this._perPageInfo.length === 0) { //Makes sure it only runs once this._perPageInfo = [...Array(page._transport.numPages)] } this._loaded = true; @@ -426,11 +426,11 @@ export class PDFBox extends React.Component<FieldViewProps> { // bcz: the nativeHeight should really be set when the document is imported. // also, the native dimensions could be different for different pages of the PDF // so this design is flawed. - var nativeWidth = this.props.doc.GetNumber(KeyStore.NativeWidth, 0); - if (!this.props.doc.GetNumber(KeyStore.NativeHeight, 0)) { + var nativeWidth = this.props.Document.GetNumber(KeyStore.NativeWidth, 0); + if (!this.props.Document.GetNumber(KeyStore.NativeHeight, 0)) { var nativeHeight = nativeWidth * r.entry.height / r.entry.width; - this.props.doc.SetNumber(KeyStore.Height, nativeHeight / nativeWidth * this.props.doc.GetNumber(KeyStore.Width, 0)); - this.props.doc.SetNumber(KeyStore.NativeHeight, nativeHeight); + this.props.Document.SetNumber(KeyStore.Height, nativeHeight / nativeWidth * this.props.Document.GetNumber(KeyStore.Width, 0)); + this.props.Document.SetNumber(KeyStore.NativeHeight, nativeHeight); } } @@ -438,8 +438,8 @@ export class PDFBox extends React.Component<FieldViewProps> { get pdfContent() { let page = this.curPage; const renderHeight = 2400; - let pdfUrl = this.props.doc.GetT(this.props.fieldKey, PDFField); - let xf = this.props.doc.GetNumber(KeyStore.NativeHeight, 0) / renderHeight; + let pdfUrl = this.props.Document.GetT(this.props.fieldKey, PDFField); + let xf = this.props.Document.GetNumber(KeyStore.NativeHeight, 0) / renderHeight; return <div className="pdfBox-contentContainer" key="container" style={{ transform: `scale(${xf}, ${xf})` }}> <Document file={window.origin + RouteStore.corsProxy + `/${pdfUrl}`} renderMode={this._renderAsSvg ? "svg" : ""}> <Measure onResize={this.setScaling}> @@ -456,8 +456,8 @@ export class PDFBox extends React.Component<FieldViewProps> { @computed get pdfRenderer() { let proxy = this._loaded ? (null) : this.imageProxyRenderer; - let pdfUrl = this.props.doc.GetT(this.props.fieldKey, PDFField); - if ((!this._interactive && proxy) || !pdfUrl || pdfUrl == FieldWaiting) { + let pdfUrl = this.props.Document.GetT(this.props.fieldKey, PDFField); + if ((!this._interactive && proxy) || !pdfUrl || pdfUrl === FieldWaiting) { return proxy; } return [ @@ -470,9 +470,9 @@ export class PDFBox extends React.Component<FieldViewProps> { @computed get imageProxyRenderer() { - let thumbField = this.props.doc.Get(KeyStore.Thumbnail); + let thumbField = this.props.Document.Get(KeyStore.Thumbnail); if (thumbField) { - let path = thumbField == FieldWaiting || this.thumbnailPage != this.curPage ? "https://image.flaticon.com/icons/svg/66/66163.svg" : + let path = thumbField === FieldWaiting || this.thumbnailPage !== this.curPage ? "https://image.flaticon.com/icons/svg/66/66163.svg" : thumbField instanceof ImageField ? thumbField.Data.href : "http://cs.brown.edu/people/bcz/prairie.jpg"; return <img src={path} width="100%" />; } diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 7c0db83a8..a08b320e8 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -20,7 +20,7 @@ export class VideoBox extends React.Component<FieldViewProps> { super(props); } - @computed private get curPage() { return this.props.doc.GetNumber(KeyStore.CurPage, -1); } + @computed private get curPage() { return this.props.Document.GetNumber(KeyStore.CurPage, -1); } _loaded: boolean = false; @@ -31,12 +31,12 @@ export class VideoBox extends React.Component<FieldViewProps> { // bcz: the nativeHeight should really be set when the document is imported. // also, the native dimensions could be different for different pages of the PDF // so this design is flawed. - var nativeWidth = this.props.doc.GetNumber(KeyStore.NativeWidth, 0); - var nativeHeight = this.props.doc.GetNumber(KeyStore.NativeHeight, 0); + var nativeWidth = this.props.Document.GetNumber(KeyStore.NativeWidth, 0); + var nativeHeight = this.props.Document.GetNumber(KeyStore.NativeHeight, 0); var newNativeHeight = nativeWidth * r.entry.height / r.entry.width; - if (!nativeHeight && newNativeHeight != nativeHeight && !isNaN(newNativeHeight)) { - this.props.doc.SetNumber(KeyStore.Height, newNativeHeight / nativeWidth * this.props.doc.GetNumber(KeyStore.Width, 0)); - this.props.doc.SetNumber(KeyStore.NativeHeight, newNativeHeight); + if (!nativeHeight && newNativeHeight !== nativeHeight && !isNaN(newNativeHeight)) { + this.props.Document.SetNumber(KeyStore.Height, newNativeHeight / nativeWidth * this.props.Document.GetNumber(KeyStore.Width, 0)); + this.props.Document.SetNumber(KeyStore.NativeHeight, newNativeHeight); } } else { this._loaded = true; @@ -50,13 +50,13 @@ export class VideoBox extends React.Component<FieldViewProps> { @action setVideoRef = (vref: HTMLVideoElement | null) => { if (this.curPage >= 0 && vref) { - vref!.currentTime = this.curPage; - (vref! as any).AHackBecauseSomethingResetsTheVideoToZero = this.curPage; + vref.currentTime = this.curPage; + (vref as any).AHackBecauseSomethingResetsTheVideoToZero = this.curPage; } } render() { - let field = this.props.doc.GetT(this.props.fieldKey, VideoField); + let field = this.props.Document.GetT(this.props.fieldKey, VideoField); if (!field || field === FieldWaiting) { return <div>Loading</div> } diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 2ca8d49ce..c1d389001 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -16,11 +16,11 @@ export class WebBox extends React.Component<FieldViewProps> { super(props); } - @computed get html(): string { return this.props.doc.GetHtml(KeyStore.Data, ""); } + @computed get html(): string { return this.props.Document.GetHtml(KeyStore.Data, ""); } render() { - let field = this.props.doc.Get(this.props.fieldKey); - let path = field == FieldWaiting ? "https://image.flaticon.com/icons/svg/66/66163.svg" : + let field = this.props.Document.Get(this.props.fieldKey); + let path = field === FieldWaiting ? "https://image.flaticon.com/icons/svg/66/66163.svg" : field instanceof WebField ? field.Data.href : "https://crossorigin.me/" + "https://cs.brown.edu"; let content = this.html ? |
