From 0a5e02a87fdabff5ff8399829ff857cae90fc1e2 Mon Sep 17 00:00:00 2001 From: mehekj Date: Sun, 20 Mar 2022 10:29:42 -0400 Subject: Revert "Merge remote-tracking branch 'origin/speedups2' into temporalmedia-mehek" This reverts commit 1f7cf7babc76ecff5aef5fe663c48e067e85dd26, reversing changes made to 1e3ad4de06f83eab54628de660529fefb9a0dc63. --- src/client/views/DocComponent.tsx | 12 +- src/client/views/DocumentDecorations.tsx | 24 +- src/client/views/GestureOverlay.tsx | 12 +- src/client/views/InkControlPtHandles.tsx | 1 - src/client/views/InkingStroke.tsx | 7 +- src/client/views/Main.tsx | 16 +- src/client/views/MainView.tsx | 50 +-- src/client/views/OverlayView.tsx | 8 +- src/client/views/PropertiesButtons.tsx | 19 - src/client/views/PropertiesView.tsx | 5 +- src/client/views/ScriptBox.tsx | 20 +- src/client/views/ScriptingRepl.tsx | 7 +- src/client/views/StyleProvider.tsx | 2 +- src/client/views/TemplateMenu.tsx | 6 +- src/client/views/animationtimeline/Keyframe.tsx | 21 +- src/client/views/animationtimeline/Timeline.tsx | 9 +- .../views/animationtimeline/TimelineMenu.tsx | 5 +- .../views/collections/CollectionCarousel3DView.tsx | 12 +- .../views/collections/CollectionCarouselView.tsx | 11 +- .../views/collections/CollectionDockingView.tsx | 20 +- src/client/views/collections/CollectionMenu.tsx | 4 +- .../views/collections/CollectionPileView.tsx | 2 +- .../collections/CollectionStackedTimeline.tsx | 23 +- .../views/collections/CollectionStackingView.tsx | 17 +- .../views/collections/CollectionStaffView.tsx | 2 +- src/client/views/collections/CollectionSubView.tsx | 10 +- .../views/collections/CollectionTimeView.tsx | 15 +- .../views/collections/CollectionTreeView.tsx | 6 +- src/client/views/collections/CollectionView.tsx | 15 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 249 +++++-------- .../collections/collectionFreeForm/MarqueeView.tsx | 23 +- .../collectionGrid/CollectionGridView.tsx | 7 +- .../collectionLinear/CollectionLinearView.tsx | 9 +- .../CollectionMulticolumnView.tsx | 11 +- .../CollectionMultirowView.tsx | 12 +- .../collectionSchema/CollectionSchemaCells.tsx | 14 +- .../collectionSchema/CollectionSchemaView.tsx | 27 +- .../collections/collectionSchema/SchemaTable.tsx | 1 + src/client/views/nodes/AudioBox.tsx | 4 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 17 +- src/client/views/nodes/ColorBox.tsx | 7 +- src/client/views/nodes/ComparisonBox.tsx | 9 +- src/client/views/nodes/DocumentIcon.tsx | 2 +- src/client/views/nodes/DocumentLinksButton.scss | 4 +- src/client/views/nodes/DocumentLinksButton.tsx | 24 +- src/client/views/nodes/DocumentView.scss | 5 +- src/client/views/nodes/DocumentView.tsx | 72 ++-- src/client/views/nodes/EquationBox.tsx | 11 +- src/client/views/nodes/FilterBox.tsx | 17 +- src/client/views/nodes/FunctionPlotBox.tsx | 2 +- src/client/views/nodes/ImageBox.tsx | 19 +- src/client/views/nodes/KeyValueBox.tsx | 2 +- src/client/views/nodes/LabelBox.tsx | 9 +- src/client/views/nodes/LinkAnchorBox.tsx | 6 +- src/client/views/nodes/LinkBox.tsx | 7 +- src/client/views/nodes/MapBox/MapBox.tsx | 9 +- src/client/views/nodes/PDFBox.scss | 1 - src/client/views/nodes/PDFBox.tsx | 64 ++-- src/client/views/nodes/ScreenshotBox.tsx | 14 +- src/client/views/nodes/ScriptingBox.tsx | 34 +- src/client/views/nodes/SliderBox.tsx | 15 +- src/client/views/nodes/VideoBox.tsx | 30 +- src/client/views/nodes/WebBox.scss | 7 - src/client/views/nodes/WebBox.tsx | 176 ++++----- src/client/views/nodes/WebBoxRenderer.js | 395 --------------------- src/client/views/nodes/button/ButtonScripts.ts | 6 +- src/client/views/nodes/button/FontIconBox.tsx | 199 ++++++----- .../views/nodes/formattedText/FormattedTextBox.tsx | 25 +- .../formattedText/ProsemirrorExampleTransfer.ts | 24 +- .../views/nodes/formattedText/RichTextRules.ts | 26 +- src/client/views/nodes/trails/PresBox.tsx | 12 +- src/client/views/nodes/trails/PresElementBox.tsx | 29 +- src/client/views/pdf/PDFViewer.tsx | 9 +- src/client/views/search/SearchBox.tsx | 18 +- src/client/views/webcam/DashWebRTCVideo.tsx | 5 +- 75 files changed, 833 insertions(+), 1196 deletions(-) delete mode 100644 src/client/views/nodes/WebBoxRenderer.js (limited to 'src/client/views') diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index 2e6ea1faa..b9772fd57 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -20,10 +20,10 @@ export interface DocComponentProps { LayoutTemplate?: () => Opt; LayoutTemplateString?: string; } -export function DocComponent

() { +export function DocComponent

(schemaCtor: (doc: Doc) => T) { class Component extends Touchable

{ //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then - @computed get Document() { return this.props.Document; } + @computed get Document(): T { return schemaCtor(this.props.Document); } // This is the "The Document" -- it encapsulates, data, layout, and any templates @computed get rootDoc() { return Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document; } // This is the rendering data of a document -- it may be "The Document", or it may be some template document that holds the rendering info @@ -48,7 +48,7 @@ interface ViewBoxBaseProps { renderDepth: number; rootSelected: (outsideReaction?: boolean) => boolean; } -export function ViewBoxBaseComponent

() { +export function ViewBoxBaseComponent

(schemaCtor: (doc: Doc) => T) { class Component extends Touchable

{ //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then //@computed get Document(): T { return schemaCtor(this.props.Document); } @@ -92,17 +92,17 @@ export interface ViewBoxAnnotatableProps { renderDepth: number; isAnnotationOverlay?: boolean; } -export function ViewBoxAnnotatableComponent

() { +export function ViewBoxAnnotatableComponent

(schemaCtor: (doc: Doc) => T) { class Component extends Touchable

{ @observable _annotationKeySuffix = () => "annotations"; @observable _isAnyChildContentActive = false; //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then - @computed get Document() { return this.props.Document; } + @computed get Document(): T { return schemaCtor(this.props.Document); } // This is the "The Document" -- it encapsulates, data, layout, and any templates @computed get rootDoc() { return Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document; } // This is the rendering data of a document -- it may be "The Document", or it may be some template document that holds the rendering info - @computed get layoutDoc() { return Doc.Layout(this.props.Document); } + @computed get layoutDoc() { return schemaCtor(Doc.Layout(this.props.Document)); } // This is the data part of a document -- ie, the data that is constant across all views of the document @computed get dataDoc() { return this.props.DataDoc && (this.props.Document.isTemplateForField || this.props.Document.isTemplateDoc) ? this.props.DataDoc : this.props.Document[DataSym]; } diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 657d92b8a..cb95a1237 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -22,13 +22,13 @@ import { CollectionDockingView } from './collections/CollectionDockingView'; import { DocumentButtonBar } from './DocumentButtonBar'; import './DocumentDecorations.scss'; import { KeyManager } from './GlobalKeyHandler'; -import { InkingStroke } from './InkingStroke'; import { InkStrokeProperties } from './InkStrokeProperties'; import { LightboxView } from './LightboxView'; import { DocumentView } from "./nodes/DocumentView"; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; import React = require("react"); -import { CollectionFreeFormView } from './collections/collectionFreeForm'; +import { InkingStroke } from './InkingStroke'; +import e = require('express'); @observer export class DocumentDecorations extends React.Component<{ PanelWidth: number, PanelHeight: number, boundsLeft: number, boundsTop: number }, { value: string }> { @@ -148,7 +148,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P pageY: e.pageY, preventDefault: emptyFunction, button: 0 - }, [SelectionManager.Views().slice(-1)[0].rootDoc]); + }, [SelectionManager.Views().lastElement().rootDoc]); return true; }, emptyFunction, this.onMaximizeClick, false, false); } @@ -233,13 +233,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P this._resizeUndo = UndoManager.StartBatch("DocDecs resize"); this._snapX = e.pageX; this._snapY = e.pageY; - const ffviewSet = new Set(); - SelectionManager.Views().forEach(docView => { - const ffview = docView.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView; - ffview && ffviewSet.add(ffview); - this._dragHeights.set(docView.layoutDoc, { start: NumCast(docView.rootDoc._height), lowest: NumCast(docView.rootDoc._height) }); - }); - Array.from(ffviewSet).map(ffview => ffview.setupDragLines(false)); + SelectionManager.Views().forEach(docView => this._dragHeights.set(docView.layoutDoc, { start: NumCast(docView.rootDoc._height), lowest: NumCast(docView.rootDoc._height) })); } onPointerMove = (e: PointerEvent, down: number[], move: number[]): boolean => { @@ -401,10 +395,10 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P this._inkDragDocs.map(oldbds => ({ oldbds, inkPts: Cast(oldbds.doc.data, InkField)?.inkData || [] })) .forEach(({ oldbds: { doc, x, y, width, height }, inkPts }) => { Doc.GetProto(doc).data = new InkField(inkPts.map(ipt => // (new x — oldx) + newWidth * (oldxpoint /oldWidth) - ({ - X: (NumCast(doc.x) - x) + NumCast(doc.width) * ipt.X / width, - Y: (NumCast(doc.y) - y) + NumCast(doc.height) * ipt.Y / height - }))); + ({ + X: (NumCast(doc.x) - x) + NumCast(doc.width) * ipt.X / width, + Y: (NumCast(doc.y) - y) + NumCast(doc.height) * ipt.Y / height + }))); Doc.SetNativeWidth(doc, undefined); Doc.SetNativeHeight(doc, undefined); }); @@ -430,7 +424,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P render() { const bounds = this.Bounds; - const seldoc = SelectionManager.Views().slice(-1)[0]; + const seldoc = SelectionManager.Views().lastElement(); if (SnappingManager.GetIsDragging() || bounds.r - bounds.x < 1 || bounds.x === Number.MAX_VALUE || !seldoc || this._hidden || isNaN(bounds.r) || isNaN(bounds.b) || isNaN(bounds.x) || isNaN(bounds.y)) { return (null); } diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index 50dca0a99..04abdbf37 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -13,7 +13,7 @@ import { CognitiveServices } from "../cognitive_services/CognitiveServices"; import { DocUtils } from "../documents/Documents"; import { CurrentUserUtils } from "../util/CurrentUserUtils"; import { InteractionUtils } from "../util/InteractionUtils"; -import { ScriptingGlobals } from "../util/ScriptingGlobals"; +import { Scripting } from "../util/Scripting"; import { SelectionManager } from "../util/SelectionManager"; import { Transform } from "../util/Transform"; import { CollectionFreeFormViewChrome } from "./collections/CollectionMenu"; @@ -943,11 +943,11 @@ export enum ToolglassTools { None = "none", } -ScriptingGlobals.add("GestureOverlay", GestureOverlay); -ScriptingGlobals.add(function setToolglass(tool: any) { +Scripting.addGlobal("GestureOverlay", GestureOverlay); +Scripting.addGlobal(function setToolglass(tool: any) { runInAction(() => GestureOverlay.Instance.Tool = tool); }); -ScriptingGlobals.add(function setPen(width: any, color: any, fill: any, arrowStart: any, arrowEnd: any, dash: any) { +Scripting.addGlobal(function setPen(width: any, color: any, fill: any, arrowStart: any, arrowEnd: any, dash: any) { runInAction(() => { GestureOverlay.Instance.SavedColor = ActiveInkColor(); SetActiveInkColor(color); @@ -959,12 +959,12 @@ ScriptingGlobals.add(function setPen(width: any, color: any, fill: any, arrowSta SetActiveDash(dash); }); }); -ScriptingGlobals.add(function resetPen() { +Scripting.addGlobal(function resetPen() { runInAction(() => { SetActiveInkColor(GestureOverlay.Instance.SavedColor ?? "rgb(0, 0, 0)"); SetActiveInkWidth(GestureOverlay.Instance.SavedWidth?.toString() ?? "2"); }); }, "resets the pen tool"); -ScriptingGlobals.add(function createText(text: any, x: any, y: any) { +Scripting.addGlobal(function createText(text: any, x: any, y: any) { GestureOverlay.Instance.dispatchGesture("text", [{ X: x, Y: y }], text); }, "creates a text document with inputted text and coordinates", "(text: any, x: any, y: any)"); diff --git a/src/client/views/InkControlPtHandles.tsx b/src/client/views/InkControlPtHandles.tsx index a7f511ab4..24f796105 100644 --- a/src/client/views/InkControlPtHandles.tsx +++ b/src/client/views/InkControlPtHandles.tsx @@ -51,7 +51,6 @@ export class InkControlPtHandles extends React.Component { const handleIndexB = (order === 3 ? controlIndex + 2 : controlIndex + 1) % this.props.inkCtrlPoints.length; const brokenIndices = Cast(this.props.inkDoc.brokenInkIndices, listSpec("number")); const wasSelected = InkStrokeProperties.Instance._currentPoint === controlIndex; - if (!wasSelected) InkStrokeProperties.Instance._currentPoint = -1; const origInk = this.props.inkCtrlPoints.slice(); setupMoveUpEvents(this, e, action((e: PointerEvent, down: number[], delta: number[]) => { diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 40fe6aa68..9dbd97c16 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -24,7 +24,9 @@ import React = require("react"); import { action, IReactionDisposer, observable, reaction } from "mobx"; import { observer } from "mobx-react"; import { Doc, WidthSym } from "../../fields/Doc"; +import { documentSchema } from "../../fields/documentSchemas"; import { InkData, InkField, InkTool } from "../../fields/InkField"; +import { makeInterface } from "../../fields/Schema"; import { BoolCast, Cast, NumCast, StrCast } from "../../fields/Types"; import { TraceMobx } from "../../fields/util"; import { OmitKeys, returnFalse, setupMoveUpEvents } from "../../Utils"; @@ -44,8 +46,11 @@ import { FieldView, FieldViewProps } from "./nodes/FieldView"; import { FormattedTextBox } from "./nodes/formattedText/FormattedTextBox"; import Color = require("color"); +type InkDocument = makeInterface<[typeof documentSchema]>; +const InkDocument = makeInterface(documentSchema); + @observer -export class InkingStroke extends ViewBoxBaseComponent() { +export class InkingStroke extends ViewBoxBaseComponent(InkDocument) { static readonly MaskDim = 50000; // choose a really big number to make sure mask fits over container (which in theory can be arbitrarily big) public static LayoutString(fieldStr: string) { return FieldView.LayoutString(InkingStroke, fieldStr); } public static IsClosed(inkData: InkData) { diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 8560ccb29..7553c8118 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -1,15 +1,13 @@ -// if ((module as any).hot) { -// (module as any).hot.accept(); -// } - -import * as React from 'react'; -import * as ReactDOM from 'react-dom'; -import { AssignAllExtensions } from "../../extensions/General/Extensions"; +import { MainView } from "./MainView"; import { Docs } from "../documents/Documents"; import { CurrentUserUtils } from "../util/CurrentUserUtils"; -import { LinkManager } from "../util/LinkManager"; +import * as ReactDOM from 'react-dom'; +import * as React from 'react'; +import { DocServer } from "../DocServer"; +import { AssignAllExtensions } from "../../extensions/General/Extensions"; +import { Networking } from "../Network"; import { CollectionView } from "./collections/CollectionView"; -import { MainView } from "./MainView"; +import { LinkManager } from "../util/LinkManager"; AssignAllExtensions(); diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 8c0795881..fc1c694a2 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -5,6 +5,7 @@ import * as fa from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, configure, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; +import "normalize.css"; import * as React from 'react'; import * as ReactDOM from 'react-dom'; import { Doc, DocListCast, Opt } from '../../fields/Doc'; @@ -23,7 +24,7 @@ import { DocumentManager } from '../util/DocumentManager'; import { GroupManager } from '../util/GroupManager'; import { HistoryUtil } from '../util/History'; import { Hypothesis } from '../util/HypothesisUtils'; -import { ScriptingGlobals } from '../util/ScriptingGlobals'; +import { Scripting } from '../util/Scripting'; import { SelectionManager } from '../util/SelectionManager'; import { ColorScheme, SettingsManager } from '../util/SettingsManager'; import { SharingManager } from '../util/SharingManager'; @@ -44,6 +45,7 @@ import { GestureOverlay } from './GestureOverlay'; import { DASHBOARD_SELECTOR_HEIGHT, LEFT_MENU_WIDTH } from './global/globalCssVariables.scss'; import { Colors } from './global/globalEnums'; import { KeyManager } from './GlobalKeyHandler'; +import { InkStrokeProperties } from './InkStrokeProperties'; import { LightboxView } from './LightboxView'; import { LinkMenu } from './linking/LinkMenu'; import "./MainView.scss"; @@ -163,28 +165,28 @@ export class MainView extends React.Component { } } - library.add(...[fa.faEdit, fa.faTrash, fa.faTrashAlt, fa.faShare, fa.faDownload, fa.faExpandArrowsAlt, fa.faLayerGroup, fa.faExternalLinkAlt, fa.faCalendar, - fa.faSquare, far.faSquare as any, fa.faConciergeBell, fa.faWindowRestore, fa.faFolder, fa.faMapPin, fa.faMapMarker, fa.faFingerprint, fa.faCrosshairs, fa.faDesktop, fa.faUnlock, - fa.faLock, fa.faLaptopCode, fa.faMale, fa.faCopy, fa.faHandPointLeft, fa.faHandPointRight, fa.faCompass, fa.faSnowflake, fa.faMicrophone, fa.faKeyboard, - fa.faQuestion, fa.faTasks, fa.faPalette, fa.faAngleLeft, fa.faAngleRight, fa.faBell, fa.faCamera, fa.faExpand, fa.faCaretDown, fa.faCaretLeft, fa.faCaretRight, - fa.faCaretSquareDown, fa.faCaretSquareRight, fa.faArrowsAltH, fa.faPlus, fa.faMinus, fa.faTerminal, fa.faToggleOn, fa.faFile, fa.faLocationArrow, - fa.faSearch, fa.faFileDownload, fa.faFileUpload, fa.faStop, fa.faCalculator, fa.faWindowMaximize, fa.faAddressCard, fa.faQuestionCircle, fa.faArrowLeft, - fa.faArrowRight, fa.faArrowDown, fa.faArrowUp, fa.faBolt, fa.faBullseye, fa.faCaretUp, fa.faCat, fa.faCheck, fa.faChevronRight, fa.faChevronLeft, fa.faChevronDown, fa.faChevronUp, - fa.faClone, fa.faCloudUploadAlt, fa.faCommentAlt, fa.faCompressArrowsAlt, fa.faCut, fa.faEllipsisV, fa.faEraser, fa.faExclamation, fa.faFileAlt, - fa.faFileAudio, fa.faFileVideo, fa.faFilePdf, fa.faFilm, fa.faFilter, fa.faFont, fa.faGlobeAmericas, fa.faGlobeAsia, fa.faHighlighter, fa.faLongArrowAltRight, fa.faMousePointer, - fa.faMusic, fa.faObjectGroup, fa.faPause, fa.faPen, fa.faPenNib, fa.faPhone, fa.faPlay, fa.faPortrait, fa.faRedoAlt, fa.faStamp, fa.faStickyNote, fa.faArrowsAltV, - fa.faTimesCircle, fa.faThumbtack, fa.faTree, fa.faTv, fa.faUndoAlt, fa.faVideo, fa.faAsterisk, fa.faBrain, fa.faImage, fa.faPaintBrush, fa.faTimes, - fa.faEye, fa.faArrowsAlt, fa.faQuoteLeft, fa.faSortAmountDown, fa.faAlignLeft, fa.faAlignCenter, fa.faAlignRight, fa.faHeading, fa.faRulerCombined, - fa.faFillDrip, fa.faLink, fa.faUnlink, fa.faBold, fa.faItalic, fa.faClipboard, fa.faUnderline, fa.faStrikethrough, fa.faSuperscript, fa.faSubscript, - fa.faIndent, fa.faEyeDropper, fa.faPaintRoller, fa.faBars, fa.faBrush, fa.faShapes, fa.faEllipsisH, fa.faHandPaper, fa.faMap, fa.faUser, faHireAHelper as any, - fa.faTrashRestore, fa.faUsers, fa.faWrench, fa.faCog, fa.faMap, fa.faBellSlash, fa.faExpandAlt, fa.faArchive, fa.faBezierCurve, fa.faCircle, far.faCircle as any, - fa.faLongArrowAltRight, fa.faPenFancy, fa.faAngleDoubleRight, faBuffer as any, fa.faExpand, fa.faUndo, fa.faSlidersH, fa.faAngleDoubleLeft, fa.faAngleUp, - fa.faAngleDown, fa.faPlayCircle, fa.faClock, fa.faRocket, fa.faExchangeAlt, fa.faHashtag, fa.faAlignJustify, fa.faCheckSquare, fa.faListUl, - fa.faWindowMinimize, fa.faWindowRestore, fa.faTextWidth, fa.faTextHeight, fa.faClosedCaptioning, fa.faInfoCircle, fa.faTag, fa.faSyncAlt, fa.faPhotoVideo, - fa.faArrowAltCircleDown, fa.faArrowAltCircleUp, fa.faArrowAltCircleLeft, fa.faArrowAltCircleRight, fa.faStopCircle, fa.faCheckCircle, fa.faGripVertical, - fa.faSortUp, fa.faSortDown, fa.faTable, fa.faTh, fa.faThList, fa.faProjectDiagram, fa.faSignature, fa.faColumns, fa.faChevronCircleUp, fa.faUpload, fa.faBorderAll, - fa.faBraille, fa.faChalkboard, fa.faPencilAlt, fa.faEyeSlash, fa.faSmile, fa.faIndent, fa.faOutdent, fa.faChartBar, fa.faBan, fa.faPhoneSlash, fa.faGripLines, - fa.faSave, fa.faBookmark, fa.faList, fa.faListOl, fa.faFolderPlus, fa.faLightbulb, fa.faBookOpen, fa.faMapMarkerAlt]); + library.add(fa.faEdit, fa.faTrash, fa.faTrashAlt, fa.faShare, fa.faDownload, fa.faExpandArrowsAlt, fa.faLayerGroup, fa.faExternalLinkAlt, fa.faCalendar, + fa.faSquare, far.faSquare as any, fa.faConciergeBell, fa.faWindowRestore, fa.faFolder, fa.faMapPin, fa.faMapMarker, fa.faFingerprint, fa.faCrosshairs, fa.faDesktop, fa.faUnlock, + fa.faLock, fa.faLaptopCode, fa.faMale, fa.faCopy, fa.faHandPointLeft, fa.faHandPointRight, fa.faCompass, fa.faSnowflake, fa.faMicrophone, fa.faKeyboard, + fa.faQuestion, fa.faTasks, fa.faPalette, fa.faAngleLeft, fa.faAngleRight, fa.faBell, fa.faCamera, fa.faExpand, fa.faCaretDown, fa.faCaretLeft, fa.faCaretRight, + fa.faCaretSquareDown, fa.faCaretSquareRight, fa.faArrowsAltH, fa.faPlus, fa.faMinus, fa.faTerminal, fa.faToggleOn, fa.faFile, fa.faLocationArrow, + fa.faSearch, fa.faFileDownload, fa.faFileUpload, fa.faStop, fa.faCalculator, fa.faWindowMaximize, fa.faAddressCard, fa.faQuestionCircle, fa.faArrowLeft, + fa.faArrowRight, fa.faArrowDown, fa.faArrowUp, fa.faBolt, fa.faBullseye, fa.faCaretUp, fa.faCat, fa.faCheck, fa.faChevronRight, fa.faChevronLeft, fa.faChevronDown, fa.faChevronUp, + fa.faClone, fa.faCloudUploadAlt, fa.faCommentAlt, fa.faCompressArrowsAlt, fa.faCut, fa.faEllipsisV, fa.faEraser, fa.faExclamation, fa.faFileAlt, + fa.faFileAudio, fa.faFileVideo, fa.faFilePdf, fa.faFilm, fa.faFilter, fa.faFont, fa.faGlobeAmericas, fa.faGlobeAsia, fa.faHighlighter, fa.faLongArrowAltRight, fa.faMousePointer, + fa.faMusic, fa.faObjectGroup, fa.faPause, fa.faPen, fa.faPenNib, fa.faPhone, fa.faPlay, fa.faPortrait, fa.faRedoAlt, fa.faStamp, fa.faStickyNote, fa.faArrowsAltV, + fa.faTimesCircle, fa.faThumbtack, fa.faTree, fa.faTv, fa.faUndoAlt, fa.faVideo, fa.faAsterisk, fa.faBrain, fa.faImage, fa.faPaintBrush, fa.faTimes, + fa.faEye, fa.faArrowsAlt, fa.faQuoteLeft, fa.faSortAmountDown, fa.faAlignLeft, fa.faAlignCenter, fa.faAlignRight, fa.faHeading, fa.faRulerCombined, + fa.faFillDrip, fa.faLink, fa.faUnlink, fa.faBold, fa.faItalic, fa.faClipboard, fa.faUnderline, fa.faStrikethrough, fa.faSuperscript, fa.faSubscript, + fa.faIndent, fa.faEyeDropper, fa.faPaintRoller, fa.faBars, fa.faBrush, fa.faShapes, fa.faEllipsisH, fa.faHandPaper, fa.faMap, fa.faUser, faHireAHelper as any, + fa.faTrashRestore, fa.faUsers, fa.faWrench, fa.faCog, fa.faMap, fa.faBellSlash, fa.faExpandAlt, fa.faArchive, fa.faBezierCurve, fa.faCircle, far.faCircle as any, + fa.faLongArrowAltRight, fa.faPenFancy, fa.faAngleDoubleRight, faBuffer as any, fa.faExpand, fa.faUndo, fa.faSlidersH, fa.faAngleDoubleLeft, fa.faAngleUp, + fa.faAngleDown, fa.faPlayCircle, fa.faClock, fa.faRocket, fa.faExchangeAlt, fa.faHashtag, fa.faAlignJustify, fa.faCheckSquare, fa.faListUl, + fa.faWindowMinimize, fa.faWindowRestore, fa.faTextWidth, fa.faTextHeight, fa.faClosedCaptioning, fa.faInfoCircle, fa.faTag, fa.faSyncAlt, fa.faPhotoVideo, + fa.faArrowAltCircleDown, fa.faArrowAltCircleUp, fa.faArrowAltCircleLeft, fa.faArrowAltCircleRight, fa.faStopCircle, fa.faCheckCircle, fa.faGripVertical, + fa.faSortUp, fa.faSortDown, fa.faTable, fa.faTh, fa.faThList, fa.faProjectDiagram, fa.faSignature, fa.faColumns, fa.faChevronCircleUp, fa.faUpload, fa.faBorderAll, + fa.faBraille, fa.faChalkboard, fa.faPencilAlt, fa.faEyeSlash, fa.faSmile, fa.faIndent, fa.faOutdent, fa.faChartBar, fa.faBan, fa.faPhoneSlash, fa.faGripLines, + fa.faSave, fa.faBookmark, fa.faList, fa.faListOl, fa.faFolderPlus, fa.faLightbulb, fa.faBookOpen, fa.faSearchPlus, fa.faVolumeUp, fa.faVolumeMute, fa.faMapMarkerAlt); this.initAuthenticationRouters(); } @@ -694,4 +696,4 @@ export class MainView extends React.Component { } } -ScriptingGlobals.add(function selectMainMenu(doc: Doc, title: string) { MainView.Instance.selectMenu(doc); }); \ No newline at end of file +Scripting.addGlobal(function selectMainMenu(doc: Doc, title: string) { MainView.Instance.selectMenu(doc); }); \ No newline at end of file diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx index 0f51cf9b2..7cf388872 100644 --- a/src/client/views/OverlayView.tsx +++ b/src/client/views/OverlayView.tsx @@ -5,17 +5,17 @@ import ReactLoading from 'react-loading'; import { Doc } from "../../fields/Doc"; import { Id } from "../../fields/FieldSymbols"; import { Cast, NumCast } from "../../fields/Types"; -import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, returnTrue, setupMoveUpEvents, Utils } from "../../Utils"; -import { DocUtils } from "../documents/Documents"; +import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, returnTrue, setupMoveUpEvents, Utils, emptyPath } from "../../Utils"; import { CurrentUserUtils } from "../util/CurrentUserUtils"; import { DragManager } from "../util/DragManager"; -import { ScriptingGlobals } from "../util/ScriptingGlobals"; +import { Scripting } from "../util/Scripting"; import { Transform } from "../util/Transform"; import { CollectionFreeFormLinksView } from "./collections/collectionFreeForm/CollectionFreeFormLinksView"; import { DocumentView } from "./nodes/DocumentView"; import './OverlayView.scss'; import { ScriptingRepl } from './ScriptingRepl'; import { DefaultStyleProvider } from "./StyleProvider"; +import { DocUtils } from "../documents/Documents"; export type OverlayDisposer = () => void; @@ -226,6 +226,6 @@ export class OverlayView extends React.Component { } } // bcz: ugh ... want to be able to pass ScriptingRepl as tag argument, but that doesn't seem to work.. runtime error -ScriptingGlobals.add(function addOverlayWindow(type: string, options: OverlayElementOptions) { +Scripting.addGlobal(function addOverlayWindow(type: string, options: OverlayElementOptions) { OverlayView.Instance.addWindow(, options); }); \ No newline at end of file diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx index dd6448654..f9dab9f82 100644 --- a/src/client/views/PropertiesButtons.tsx +++ b/src/client/views/PropertiesButtons.tsx @@ -18,10 +18,6 @@ import React = require("react"); import { Colors } from "./global/globalEnums"; import { CollectionFreeFormView } from "./collections/collectionFreeForm"; import { DocumentManager } from "../util/DocumentManager"; -import { pasteImageBitmap } from "./nodes/WebBoxRenderer"; -import { VideoBox } from "./nodes/VideoBox"; -import { Id } from "../../fields/FieldSymbols"; -import { ImageField } from "../../fields/URLField"; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -96,20 +92,6 @@ export class PropertiesButtons extends React.Component<{}, {}> { @computed get groupButton() { return this.propertyToggleBtn("Group", "isGroup", on => `Display collection as a Group`, on => "object-group", (dv, doc) => { doc.isGroup = !doc.isGroup; doc.forceActive = doc.isGroup; }); } - @computed get freezeThumb() { - return this.propertyToggleBtn("Freeze\Thumb", "_thumb-frozen", on => `${on ? "Freeze" : "Unfreeze"} thumbnail`, on => "arrows-alt-h", (dv, doc) => { - if (doc["thumb-frozen"]) doc["thumb-frozen"] = undefined; - else { - document.body.focus(); // so that we can access the clipboard without an error - setTimeout(() => - pasteImageBitmap((data: any, error: any) => { - error && console.log(error); - data && VideoBox.convertDataUri(data, doc[Id] + "-thumb-frozen", true).then( - returnedfilename => doc["thumb-frozen"] = new ImageField(returnedfilename)); - })); - } - }); - } @computed get snapButton() { return this.propertyToggleBtn("Snap\xA0Lines", "showSnapLines", on => `Display snapping lines when objects are dragged`, on => "border-all", undefined, true); } @@ -240,7 +222,6 @@ export class PropertiesButtons extends React.Component<{}, {}> { {toggle(this.dictationButton, { display: isNovice ? "none" : "" })} {toggle(this.onClickButton)} {toggle(this.fitWidthButton)} - {toggle(this.freezeThumb)} {toggle(this.fitContentButton, { display: !isFreeForm && !isMap ? "none" : "" })} {toggle(this.autoHeightButton, { display: !isText && !isStacking && !isTree ? "none" : "" })} {toggle(this.maskButton, { display: !isInk ? "none" : "" })} diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index 47a5cd07e..f53944805 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -33,7 +33,6 @@ import { PropertiesDocContextSelector } from "./PropertiesDocContextSelector"; import "./PropertiesView.scss"; import { DefaultStyleProvider } from "./StyleProvider"; import { PresBox } from "./nodes/trails"; -import { IconLookup } from "@fortawesome/fontawesome-svg-core"; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -1302,7 +1301,7 @@ export class PropertiesView extends React.Component { onPointerDown={this.toggleAnchor} onClick={e => e.stopPropagation()} className="propertiesButton" > - +

@@ -1312,7 +1311,7 @@ export class PropertiesView extends React.Component { onPointerDown={this.toggleArrow} onClick={e => e.stopPropagation()} className="propertiesButton" > - +
diff --git a/src/client/views/ScriptBox.tsx b/src/client/views/ScriptBox.tsx index b7ea124b9..e2b5d8dc3 100644 --- a/src/client/views/ScriptBox.tsx +++ b/src/client/views/ScriptBox.tsx @@ -1,17 +1,17 @@ -import { action, observable } from "mobx"; -import { observer } from "mobx-react"; import * as React from "react"; -import { Doc, Opt } from "../../fields/Doc"; -import { ScriptField } from "../../fields/ScriptField"; -import { ScriptCast } from "../../fields/Types"; +import { observer } from "mobx-react"; +import { observable, action } from "mobx"; + +import "./ScriptBox.scss"; +import { OverlayView } from "./OverlayView"; +import { DocumentIconContainer } from "./nodes/DocumentIcon"; +import { Opt, Doc } from "../../fields/Doc"; import { emptyFunction } from "../../Utils"; -import { DragManager } from "../util/DragManager"; +import { ScriptCast } from "../../fields/Types"; import { CompileScript } from "../util/Scripting"; +import { ScriptField } from "../../fields/ScriptField"; +import { DragManager } from "../util/DragManager"; import { EditableView } from "./EditableView"; -import { DocumentIconContainer } from "./nodes/DocumentIcon"; -import { OverlayView } from "./OverlayView"; -import "./ScriptBox.scss"; - export interface ScriptBoxProps { onSave: (text: string, onError: (error: string) => void) => void; diff --git a/src/client/views/ScriptingRepl.tsx b/src/client/views/ScriptingRepl.tsx index 4ed6da24a..c598b2861 100644 --- a/src/client/views/ScriptingRepl.tsx +++ b/src/client/views/ScriptingRepl.tsx @@ -3,8 +3,7 @@ import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { DocumentManager } from '../util/DocumentManager'; -import { CompileScript, Transformer, ts } from '../util/Scripting'; -import { ScriptingGlobals } from '../util/ScriptingGlobals'; +import { CompileScript, Scripting, Transformer, ts } from '../util/Scripting'; import { DocumentIconContainer } from './nodes/DocumentIcon'; import { OverlayView } from './OverlayView'; import './ScriptingRepl.scss'; @@ -82,7 +81,7 @@ export class ScriptingRepl extends React.Component { transformer: context => { const knownVars: { [name: string]: number } = {}; const usedDocuments: number[] = []; - ScriptingGlobals.getGlobals().forEach((global: any) => knownVars[global] = 1); + Scripting.getGlobals().forEach(global => knownVars[global] = 1); return root => { function visit(node: ts.Node) { let skip = false; @@ -125,7 +124,7 @@ export class ScriptingRepl extends React.Component { case "Enter": { const docGlobals: { [name: string]: any } = {}; DocumentManager.Instance.DocumentViews.forEach((dv, i) => docGlobals[`d${i}`] = dv.props.Document); - const globals = ScriptingGlobals.makeMutableGlobalsCopy(docGlobals); + const globals = Scripting.makeMutableGlobalsCopy(docGlobals); const script = CompileScript(this.commandString, { typecheck: false, addReturn: true, editable: true, params: { args: "any" }, transformer: this.getTransformer(), globals }); if (!script.compiled) { this.commands.push({ command: this.commandString, result: script.errors }); diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 2782574c5..ce363cc47 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -7,7 +7,7 @@ import { Doc, Opt, StrListCast } from "../../fields/Doc"; import { List } from '../../fields/List'; import { listSpec } from '../../fields/Schema'; import { BoolCast, Cast, NumCast, StrCast } from "../../fields/Types"; -import { DashColor, lightOrDark } from '../../Utils'; +import { lightOrDark, DashColor } from '../../Utils'; import { DocumentType } from '../documents/DocumentTypes'; import { CurrentUserUtils } from '../util/CurrentUserUtils'; import { ColorScheme } from '../util/SettingsManager'; diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index b3a24e031..ff3f92364 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -5,9 +5,9 @@ import { List } from "../../fields/List"; import { ScriptField } from "../../fields/ScriptField"; import { Cast, StrCast } from "../../fields/Types"; import { TraceMobx } from "../../fields/util"; -import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from "../../Utils"; +import { emptyFunction, emptyPath, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from "../../Utils"; import { Docs, DocUtils } from "../documents/Documents"; -import { ScriptingGlobals } from "../util/ScriptingGlobals"; +import { Scripting } from "../util/Scripting"; import { Transform } from "../util/Transform"; import { undoBatch } from "../util/UndoManager"; import { CollectionTreeView } from "./collections/CollectionTreeView"; @@ -164,7 +164,7 @@ export class TemplateMenu extends React.Component { } } -ScriptingGlobals.add(function switchView(doc: Doc, template: Doc | undefined) { +Scripting.addGlobal(function switchView(doc: Doc, template: Doc | undefined) { if (template?.dragFactory) { template = Cast(template.dragFactory, Doc, null); } diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index 92d3e2bed..82b0218bf 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -1,17 +1,18 @@ -import { action, computed, observable, runInAction } from "mobx"; -import { observer } from "mobx-react"; import * as React from "react"; -import { Doc, DocListCast, Opt } from "../../../fields/Doc"; -import { List } from "../../../fields/List"; -import { createSchema, defaultSpec, listSpec, makeInterface } from "../../../fields/Schema"; -import { Cast, NumCast } from "../../../fields/Types"; -import { Docs } from "../../documents/Documents"; -import { Transform } from "../../util/Transform"; -import { CollectionDockingView } from "../collections/CollectionDockingView"; -import "../global/globalCssVariables.scss"; import "./Keyframe.scss"; import "./Timeline.scss"; +import "../global/globalCssVariables.scss"; +import { observer } from "mobx-react"; +import { observable, reaction, action, IReactionDisposer, observe, computed, runInAction, trace } from "mobx"; +import { Doc, DocListCast, DocListCastAsync, Opt } from "../../../fields/Doc"; +import { Cast, NumCast } from "../../../fields/Types"; +import { List } from "../../../fields/List"; +import { createSchema, defaultSpec, makeInterface, listSpec } from "../../../fields/Schema"; +import { Transform } from "../../util/Transform"; import { TimelineMenu } from "./TimelineMenu"; +import { Docs } from "../../documents/Documents"; +import { CollectionDockingView } from "../collections/CollectionDockingView"; +import { emptyPath } from "../../../Utils"; /** diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index e80ba6f36..c7e62c15d 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -13,7 +13,6 @@ import { TimelineOverview } from "./TimelineOverview"; import { Track } from "./Track"; import clamp from "../../util/clamp"; import { DocumentType } from "../../documents/DocumentTypes"; -import { IconLookup } from "@fortawesome/fontawesome-svg-core"; /** * Timeline class controls most of timeline functions besides individual keyframe and track mechanism. Main functions are @@ -347,9 +346,9 @@ export class Timeline extends React.Component { return (
-
-
-
+
+
+
@@ -507,7 +506,7 @@ export class Timeline extends React.Component { {this.children.map(doc =>
{ Doc.BrushDoc(doc); }} onPointerOut={() => { Doc.UnBrushDoc(doc); }}>

{doc.title}

)}
- +
diff --git a/src/client/views/animationtimeline/TimelineMenu.tsx b/src/client/views/animationtimeline/TimelineMenu.tsx index aa422c092..53ca9acad 100644 --- a/src/client/views/animationtimeline/TimelineMenu.tsx +++ b/src/client/views/animationtimeline/TimelineMenu.tsx @@ -5,7 +5,6 @@ import "./TimelineMenu.scss"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faChartLine, faRoad, faClipboard, faPen, faTrash, faTable } from "@fortawesome/free-solid-svg-icons"; import { Utils } from "../../../Utils"; -import { IconLookup } from "@fortawesome/fontawesome-svg-core"; @observer @@ -42,7 +41,7 @@ export class TimelineMenu extends React.Component { if (type === "input") { const inputRef = React.createRef(); let text = ""; - this._currentMenu.push(
{ + this._currentMenu.push(
{ e.stopPropagation(); text = e.target.value; }} onKeyDown={(e) => { @@ -53,7 +52,7 @@ export class TimelineMenu extends React.Component { } }} />
); } else if (type === "button") { - this._currentMenu.push(

{ + this._currentMenu.push(

{ e.preventDefault(); e.stopPropagation(); event(e); diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx index 01f41869e..3c66faf0c 100644 --- a/src/client/views/collections/CollectionCarousel3DView.tsx +++ b/src/client/views/collections/CollectionCarousel3DView.tsx @@ -3,17 +3,23 @@ import { computed } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc } from '../../../fields/Doc'; +import { collectionSchema, documentSchema } from '../../../fields/documentSchemas'; import { Id } from '../../../fields/FieldSymbols'; +import { makeInterface } from '../../../fields/Schema'; +import { ScriptField } from '../../../fields/ScriptField'; import { NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { OmitKeys, returnFalse, Utils } from '../../../Utils'; import { DragManager } from '../../util/DragManager'; import { DocumentView } from '../nodes/DocumentView'; -import { StyleProp } from '../StyleProvider'; import "./CollectionCarousel3DView.scss"; import { CollectionSubView } from './CollectionSubView'; +import { StyleProp } from '../StyleProvider'; + +type Carousel3DDocument = makeInterface<[typeof documentSchema, typeof collectionSchema]>; +const Carousel3DDocument = makeInterface(documentSchema, collectionSchema); @observer -export class CollectionCarousel3DView extends CollectionSubView() { +export class CollectionCarousel3DView extends CollectionSubView(Carousel3DDocument) { @computed get scrollSpeed() { return this.layoutDoc._autoScrollSpeed ? NumCast(this.layoutDoc._autoScrollSpeed) : 1000; //default scroll speed } @@ -22,7 +28,7 @@ export class CollectionCarousel3DView extends CollectionSubView() { componentWillUnmount() { this._dropDisposer?.(); } - protected createDashEventsTarget = (ele: HTMLDivElement | null) => { //used for stacking and masonry view + protected createDashEventsTarget = (ele: HTMLDivElement) => { //used for stacking and masonry view this._dropDisposer?.(); if (ele) { this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc); diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx index 467c2893f..6c2c27e8e 100644 --- a/src/client/views/collections/CollectionCarouselView.tsx +++ b/src/client/views/collections/CollectionCarouselView.tsx @@ -3,6 +3,8 @@ import { computed } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, Opt } from '../../../fields/Doc'; +import { collectionSchema, documentSchema } from '../../../fields/documentSchemas'; +import { makeInterface } from '../../../fields/Schema'; import { NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { OmitKeys, returnFalse } from '../../../Utils'; import { DragManager } from '../../util/DragManager'; @@ -10,15 +12,18 @@ import { DocumentView, DocumentViewProps } from '../nodes/DocumentView'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { StyleProp } from '../StyleProvider'; import "./CollectionCarouselView.scss"; -import { CollectionSubView } from './CollectionSubView'; +import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView'; + +type CarouselDocument = makeInterface<[typeof documentSchema, typeof collectionSchema]>; +const CarouselDocument = makeInterface(documentSchema, collectionSchema); @observer -export class CollectionCarouselView extends CollectionSubView() { +export class CollectionCarouselView extends CollectionSubView(CarouselDocument) { private _dropDisposer?: DragManager.DragDropDisposer; componentWillUnmount() { this._dropDisposer?.(); } - protected createDashEventsTarget = (ele: HTMLDivElement | null) => { //used for stacking and masonry view + protected createDashEventsTarget = (ele: HTMLDivElement) => { //used for stacking and masonry view this._dropDisposer?.(); if (ele) { this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc); diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 9e8374605..f543d924d 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -4,31 +4,31 @@ import { action, IReactionDisposer, observable, reaction, runInAction } from "mo import { observer } from "mobx-react"; import * as ReactDOM from 'react-dom'; import * as GoldenLayout from "../../../client/goldenLayout"; -import { DataSym, Doc, DocListCast, DocListCastAsync, Opt } from "../../../fields/Doc"; +import { Doc, DocListCast, Opt, DocListCastAsync, DataSym } from "../../../fields/Doc"; import { Id } from '../../../fields/FieldSymbols'; import { InkTool } from '../../../fields/InkField'; import { List } from '../../../fields/List'; -import { listSpec } from '../../../fields/Schema'; import { Cast, NumCast, StrCast } from "../../../fields/Types"; -import { inheritParentAcls } from '../../../fields/util'; import { DocServer } from "../../DocServer"; import { Docs } from '../../documents/Documents'; -import { DocumentType } from '../../documents/DocumentTypes'; import { CurrentUserUtils } from '../../util/CurrentUserUtils'; import { DragManager } from "../../util/DragManager"; import { InteractionUtils } from '../../util/InteractionUtils'; -import { ScriptingGlobals } from '../../util/ScriptingGlobals'; +import { Scripting } from '../../util/Scripting'; import { undoBatch, UndoManager } from "../../util/UndoManager"; -import { LightboxView } from '../LightboxView'; import "./CollectionDockingView.scss"; import { CollectionSubView, SubCollectionViewProps } from "./CollectionSubView"; import { CollectionViewType } from './CollectionView'; import { TabDocView } from './TabDocView'; import React = require("react"); +import { DocumentType } from '../../documents/DocumentTypes'; +import { listSpec } from '../../../fields/Schema'; +import { LightboxView } from '../LightboxView'; +import { inheritParentAcls } from '../../../fields/util'; const _global = (window /* browser */ || global /* node */) as any; @observer -export class CollectionDockingView extends CollectionSubView() { +export class CollectionDockingView extends CollectionSubView(doc => doc) { @observable public static Instance: CollectionDockingView; public static makeDocumentConfig(document: Doc, panelName?: string, width?: number) { return { @@ -468,8 +468,8 @@ export class CollectionDockingView extends CollectionSubView() { } } -ScriptingGlobals.add(function openInLightbox(doc: any) { LightboxView.AddDocTab(doc, "lightbox"); }, +Scripting.addGlobal(function openInLightbox(doc: any) { LightboxView.AddDocTab(doc, "lightbox"); }, "opens up document in a lightbox", "(doc: any)"); -ScriptingGlobals.add(function openOnRight(doc: any) { return CollectionDockingView.AddSplit(doc, "right"); }, +Scripting.addGlobal(function openOnRight(doc: any) { return CollectionDockingView.AddSplit(doc, "right"); }, "opens up document in tab on right side of the screen", "(doc: any)"); -ScriptingGlobals.add(function useRightSplit(doc: any, shiftKey?: boolean) { CollectionDockingView.ReplaceTab(doc, "right", undefined, shiftKey); }); \ No newline at end of file +Scripting.addGlobal(function useRightSplit(doc: any, shiftKey?: boolean) { CollectionDockingView.ReplaceTab(doc, "right", undefined, shiftKey); }); \ No newline at end of file diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index 364a2440e..131f5ba46 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -20,7 +20,7 @@ import { Docs } from "../../documents/Documents"; import { DocumentType } from "../../documents/DocumentTypes"; import { CurrentUserUtils } from "../../util/CurrentUserUtils"; import { DragManager } from "../../util/DragManager"; -import { ScriptingGlobals } from "../../util/ScriptingGlobals"; +import { Scripting } from "../../util/Scripting"; import { SelectionManager } from "../../util/SelectionManager"; import { Transform } from "../../util/Transform"; import { undoBatch } from "../../util/UndoManager"; @@ -1285,7 +1285,7 @@ export class CollectionGridViewChrome extends React.Component doc) { _originalChrome: any = ""; _disposers: { [name: string]: IReactionDisposer } = {}; diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx index 61ddbe70d..7d9dc39ae 100644 --- a/src/client/views/collections/CollectionStackedTimeline.tsx +++ b/src/client/views/collections/CollectionStackedTimeline.tsx @@ -11,7 +11,7 @@ import { computedFn } from "mobx-utils"; import { Doc, DocListCast } from "../../../fields/Doc"; import { Id } from "../../../fields/FieldSymbols"; import { List } from "../../../fields/List"; -import { listSpec } from "../../../fields/Schema"; +import { listSpec, makeInterface } from "../../../fields/Schema"; import { ComputedField, ScriptField } from "../../../fields/ScriptField"; import { Cast, NumCast } from "../../../fields/Types"; import { @@ -25,7 +25,7 @@ import { Docs } from "../../documents/Documents"; import { DocumentManager } from "../../util/DocumentManager"; import { DragManager } from "../../util/DragManager"; import { LinkManager } from "../../util/LinkManager"; -import { ScriptingGlobals } from "../../util/ScriptingGlobals"; +import { Scripting } from "../../util/Scripting"; import { SelectionManager } from "../../util/SelectionManager"; import { SnappingManager } from "../../util/SnappingManager"; import { Transform } from "../../util/Transform"; @@ -43,6 +43,8 @@ import { import { LabelBox } from "../nodes/LabelBox"; import "./CollectionStackedTimeline.scss"; +type PanZoomDocument = makeInterface<[]>; +const PanZoomDocument = makeInterface(); export type CollectionStackedTimelineProps = { Play: () => void; Pause: () => void; @@ -65,8 +67,11 @@ export enum TrimScope { } @observer -export class CollectionStackedTimeline extends CollectionSubView() { - @observable static SelectingRegion: CollectionStackedTimeline | undefined = undefined; +export class CollectionStackedTimeline extends CollectionSubView< + PanZoomDocument, + CollectionStackedTimelineProps +>(PanZoomDocument) { + @observable static SelectingRegion: CollectionStackedTimeline | undefined; @observable public static CurrentlyPlaying: Doc[]; static RangeScript: ScriptField; @@ -928,9 +933,7 @@ class StackedTimelineAnchor extends React.Component

- this.onAnchorDown(e, this.props.mark, false) - } + onPointerDown={(e) => this.onAnchorDown(e, this.props.mark, false)} /> )} @@ -938,12 +941,12 @@ class StackedTimelineAnchor extends React.Component ); } } -ScriptingGlobals.add(function formatToTime(time: number): any { +Scripting.addGlobal(function formatToTime(time: number): any { return formatTime(time); }); -ScriptingGlobals.add(function min(num1: number, num2: number): number { +Scripting.addGlobal(function min(num1: number, num2: number): number { return Math.min(num1, num2); }); -ScriptingGlobals.add(function max(num1: number, num2: number): number { +Scripting.addGlobal(function max(num1: number, num2: number): number { return Math.max(num1, num2); }); \ No newline at end of file diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 8634ea139..cdc680a08 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -3,15 +3,16 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { CursorProperty } from "csstype"; import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; -import { DataSym, Doc, HeightSym, Opt, WidthSym } from "../../../fields/Doc"; +import { DataSym, Doc, HeightSym, Opt, WidthSym, DocListCast } from "../../../fields/Doc"; +import { collectionSchema, documentSchema } from "../../../fields/documentSchemas"; import { Id } from "../../../fields/FieldSymbols"; import { List } from "../../../fields/List"; -import { listSpec } from "../../../fields/Schema"; +import { listSpec, makeInterface } from "../../../fields/Schema"; import { SchemaHeaderField } from "../../../fields/SchemaHeaderField"; import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../fields/Types"; import { TraceMobx } from "../../../fields/util"; -import { emptyFunction, returnEmptyDoclist, returnFalse, returnTrue, returnZero, setupMoveUpEvents, smoothScroll, Utils } from "../../../Utils"; -import { Docs, DocUtils } from "../../documents/Documents"; +import { emptyFunction, returnFalse, returnZero, setupMoveUpEvents, smoothScroll, Utils, returnTrue, returnEmptyDoclist, returnEmptyFilter } from "../../../Utils"; +import { DocUtils, Docs } from "../../documents/Documents"; import { DragManager, dropActionType } from "../../util/DragManager"; import { SnappingManager } from "../../util/SnappingManager"; import { Transform } from "../../util/Transform"; @@ -22,14 +23,18 @@ import { EditableView } from "../EditableView"; import { LightboxView } from "../LightboxView"; import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView"; import { DocFocusOptions, DocumentView, DocumentViewProps, ViewAdjustment } from "../nodes/DocumentView"; -import { StyleProp } from "../StyleProvider"; +import { StyleProp, DefaultStyleProvider } from "../StyleProvider"; import { CollectionMasonryViewFieldRow } from "./CollectionMasonryViewFieldRow"; import "./CollectionStackingView.scss"; import { CollectionStackingViewFieldColumn } from "./CollectionStackingViewFieldColumn"; import { CollectionSubView } from "./CollectionSubView"; import { CollectionViewType } from "./CollectionView"; +import { FontIconBox } from "../nodes/button/FontIconBox"; +import { CurrentUserUtils } from "../../util/CurrentUserUtils"; const _global = (window /* browser */ || global /* node */) as any; +type StackingDocument = makeInterface<[typeof collectionSchema, typeof documentSchema]>; +const StackingDocument = makeInterface(collectionSchema, documentSchema); export type collectionStackingViewProps = { chromeHidden?: boolean; @@ -39,7 +44,7 @@ export type collectionStackingViewProps = { }; @observer -export class CollectionStackingView extends CollectionSubView>() { +export class CollectionStackingView extends CollectionSubView>(StackingDocument) { _masonryGridRef: HTMLDivElement | null = null; _draggerRef = React.createRef(); _pivotFieldDisposer?: IReactionDisposer; diff --git a/src/client/views/collections/CollectionStaffView.tsx b/src/client/views/collections/CollectionStaffView.tsx index c025e94a8..c5c3f96e8 100644 --- a/src/client/views/collections/CollectionStaffView.tsx +++ b/src/client/views/collections/CollectionStaffView.tsx @@ -6,7 +6,7 @@ import "./CollectionStaffView.scss"; import { observer } from "mobx-react"; @observer -export class CollectionStaffView extends CollectionSubView() { +export class CollectionStaffView extends CollectionSubView(doc => doc) { private _reactionDisposer: IReactionDisposer | undefined; @observable private _staves = NumCast(this.props.Document.staves); diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 42e157396..34209ebc9 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -10,14 +10,14 @@ import { Cast, ScriptCast, NumCast, StrCast } from "../../../fields/Types"; import { GestureUtils } from "../../../pen-gestures/GestureUtils"; import { Utils, returnFalse, returnEmptyFilter } from "../../../Utils"; import { DocServer } from "../../DocServer"; +import { Networking } from "../../Network"; import { ImageUtils } from "../../util/Import & Export/ImageUtils"; import { InteractionUtils } from "../../util/InteractionUtils"; import { undoBatch, UndoManager } from "../../util/UndoManager"; import { DocComponent } from "../DocComponent"; import React = require("react"); -import ReactLoading from 'react-loading'; import * as rp from 'request-promise'; -import { Networking } from "../../Network"; +import ReactLoading from 'react-loading'; export interface SubCollectionViewProps extends CollectionViewProps { @@ -25,15 +25,15 @@ export interface SubCollectionViewProps extends CollectionViewProps { isAnyChildContentActive: () => boolean; } -export function CollectionSubView(moreProps?: X) { - class CollectionSubView extends DocComponent() { +export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: X) { + class CollectionSubView extends DocComponent(schemaCtor) { private dropDisposer?: DragManager.DragDropDisposer; private gestureDisposer?: GestureUtils.GestureEventDisposer; protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer; protected _mainCont?: HTMLDivElement; @observable _focusFilters: Opt; // docFilters that are overridden when previewing a link to an anchor which has docFilters set on it @observable _focusRangeFilters: Opt; // docRangeFilters that are overridden when previewing a link to an anchor which has docRangeFilters set on it - protected createDashEventsTarget = (ele: HTMLDivElement | null) => { //used for stacking and masonry view + protected createDashEventsTarget = (ele: HTMLDivElement) => { //used for stacking and masonry view this.dropDisposer?.(); this.gestureDisposer?.(); this._multiTouchDisposer?.(); diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index d6398fda5..292dfd77c 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -1,17 +1,17 @@ import { toUpper } from "lodash"; import { action, computed, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; -import { Doc, Opt, StrListCast } from "../../../fields/Doc"; +import { Doc, DocCastAsync, Opt, StrListCast } from "../../../fields/Doc"; import { List } from "../../../fields/List"; import { ObjectField } from "../../../fields/ObjectField"; import { RichTextField } from "../../../fields/RichTextField"; import { listSpec } from "../../../fields/Schema"; import { ComputedField, ScriptField } from "../../../fields/ScriptField"; import { Cast, NumCast, StrCast } from "../../../fields/Types"; -import { emptyFunction, returnEmptyString, returnFalse, returnTrue, setupMoveUpEvents } from "../../../Utils"; -import { Docs } from "../../documents/Documents"; +import { emptyFunction, returnFalse, returnTrue, setupMoveUpEvents, returnEmptyString } from "../../../Utils"; +import { Docs, DocUtils } from "../../documents/Documents"; import { DocumentManager } from "../../util/DocumentManager"; -import { ScriptingGlobals } from "../../util/ScriptingGlobals"; +import { Scripting } from "../../util/Scripting"; import { ContextMenu } from "../ContextMenu"; import { ContextMenuProps } from "../ContextMenuItem"; import { EditableView } from "../EditableView"; @@ -20,10 +20,13 @@ import { ViewDefBounds } from "./collectionFreeForm/CollectionFreeFormLayoutEngi import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; import { CollectionSubView } from "./CollectionSubView"; import "./CollectionTimeView.scss"; +const higflyout = require("@hig/flyout"); +export const { anchorPoints } = higflyout; +export const Flyout = higflyout.default; import React = require("react"); @observer -export class CollectionTimeView extends CollectionSubView() { +export class CollectionTimeView extends CollectionSubView(doc => doc) { _changing = false; @observable _layoutEngine = "pivot"; @observable _collapsed: boolean = false; @@ -233,7 +236,7 @@ export class CollectionTimeView extends CollectionSubView() { } } -ScriptingGlobals.add(function pivotColumnClick(pivotDoc: Doc, bounds: ViewDefBounds) { +Scripting.addGlobal(function pivotColumnClick(pivotDoc: Doc, bounds: ViewDefBounds) { let prevFilterIndex = NumCast(pivotDoc._prevFilterIndex); pivotDoc["_prevDocFilter" + prevFilterIndex] = ObjectField.MakeCopy(pivotDoc._docFilters as ObjectField); pivotDoc["_prevDocRangeFilters" + prevFilterIndex] = ObjectField.MakeCopy(pivotDoc._docRangeFilters as ObjectField); diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index e84517f40..ea077ea40 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -3,11 +3,11 @@ import { observer } from "mobx-react"; import { DataSym, Doc, DocListCast, HeightSym, Opt, StrListCast, WidthSym } from '../../../fields/Doc'; import { Id } from '../../../fields/FieldSymbols'; import { InkTool } from '../../../fields/InkField'; -import { listSpec } from '../../../fields/Schema'; +import { Document, listSpec } from '../../../fields/Schema'; import { ScriptField } from '../../../fields/ScriptField'; import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; -import { emptyFunction, OmitKeys, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, returnTrue } from '../../../Utils'; +import { emptyFunction, OmitKeys, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, returnOne } from '../../../Utils'; import { DocUtils } from '../../documents/Documents'; import { CurrentUserUtils } from '../../util/CurrentUserUtils'; import { DocumentManager } from '../../util/DocumentManager'; @@ -40,7 +40,7 @@ export type collectionTreeViewProps = { }; @observer -export class CollectionTreeView extends CollectionSubView>() { +export class CollectionTreeView extends CollectionSubView>(Document) { private _treedropDisposer?: DragManager.DragDropDisposer; private _mainEle?: HTMLDivElement; private _titleRef?: HTMLDivElement | HTMLInputElement | null; diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index ee2c28b5f..681a15e3d 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -1,14 +1,15 @@ -import { computed, observable, runInAction } from 'mobx'; +import { computed, observable, runInAction, action } from 'mobx'; import { observer } from "mobx-react"; import * as React from 'react'; import 'react-image-lightbox-with-rotate/style.css'; // This only needs to be imported once in your app -import { Doc, DocListCast } from '../../../fields/Doc'; +import { Doc, DocListCast, StrListCast } from '../../../fields/Doc'; +import { documentSchema } from '../../../fields/documentSchemas'; import { Id } from '../../../fields/FieldSymbols'; import { ObjectField } from '../../../fields/ObjectField'; +import { makeInterface } from '../../../fields/Schema'; import { ScriptField } from '../../../fields/ScriptField'; import { Cast, ScriptCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; -import { returnEmptyString } from '../../../Utils'; import { DocUtils } from '../../documents/Documents'; import { BranchCreate, BranchTask } from '../../documents/Gitlike'; import { CurrentUserUtils } from '../../util/CurrentUserUtils'; @@ -32,7 +33,10 @@ import { CollectionStackingView } from './CollectionStackingView'; import { SubCollectionViewProps } from './CollectionSubView'; import { CollectionTimeView } from './CollectionTimeView'; import { CollectionTreeView } from "./CollectionTreeView"; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import './CollectionView.scss'; +import { returnEmptyString } from '../../../Utils'; +import { InkTool } from '../../../fields/InkField'; export const COLLECTION_BORDER_WIDTH = 2; const path = require('path'); @@ -80,8 +84,11 @@ export interface CollectionViewProps extends FieldViewProps { childClickScript?: ScriptField; childDoubleClickScript?: ScriptField; } + +type CollectionDocument = makeInterface<[typeof documentSchema]>; +const CollectionDocument = makeInterface(documentSchema); @observer -export class CollectionView extends ViewBoxAnnotatableComponent() { +export class CollectionView extends ViewBoxAnnotatableComponent(CollectionDocument) { public static LayoutString(fieldStr: string) { return FieldView.LayoutString(CollectionView, fieldStr); } @observable private static _safeMode = false; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index e2ea81392..aeda71d01 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -4,12 +4,13 @@ import { observer } from "mobx-react"; import { computedFn } from "mobx-utils"; import { DateField } from "../../../../fields/DateField"; import { Doc, HeightSym, Opt, StrListCast, WidthSym } from "../../../../fields/Doc"; +import { collectionSchema, documentSchema } from "../../../../fields/documentSchemas"; import { Id } from "../../../../fields/FieldSymbols"; import { InkData, InkField, InkTool, PointData, Segment } from "../../../../fields/InkField"; import { List } from "../../../../fields/List"; import { ObjectField } from "../../../../fields/ObjectField"; import { RichTextField } from "../../../../fields/RichTextField"; -import { createSchema, listSpec } from "../../../../fields/Schema"; +import { createSchema, listSpec, makeInterface } from "../../../../fields/Schema"; import { ScriptField } from "../../../../fields/ScriptField"; import { BoolCast, Cast, FieldValue, NumCast, ScriptCast, StrCast } from "../../../../fields/Types"; import { TraceMobx } from "../../../../fields/util"; @@ -40,6 +41,7 @@ import { LightboxView } from "../../LightboxView"; import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView"; import { DocFocusOptions, DocumentView, DocumentViewProps, ViewAdjustment, ViewSpecPrefix } from "../../nodes/DocumentView"; import { FormattedTextBox } from "../../nodes/formattedText/FormattedTextBox"; +import { pageSchema } from "../../nodes/ImageBox"; import { PresBox } from "../../nodes/trails/PresBox"; import { StyleLayers, StyleProp } from "../../StyleProvider"; import { CollectionDockingView } from "../CollectionDockingView"; @@ -65,6 +67,8 @@ export const panZoomSchema = createSchema({ scrollHeight: "number" // this will be set when the collection is an annotation overlay for a PDF/Webpage }); +type PanZoomDocument = makeInterface<[typeof panZoomSchema, typeof collectionSchema, typeof documentSchema, typeof pageSchema]>; +const PanZoomDocument = makeInterface(panZoomSchema, collectionSchema, documentSchema, pageSchema); export type collectionFreeformViewProps = { annotationLayerHostsContent?: boolean; // whether to force scaling of content (needed by ImageBox) viewDefDivClick?: ScriptField; @@ -77,7 +81,7 @@ export type collectionFreeformViewProps = { }; @observer -export class CollectionFreeFormView extends CollectionSubView>() { +export class CollectionFreeFormView extends CollectionSubView>(PanZoomDocument) { public get displayName() { return "CollectionFreeFormView(" + this.props.Document.title?.toString() + ")"; } // this makes mobx trace() statements more descriptive private _lastNudge: any; @@ -91,7 +95,6 @@ export class CollectionFreeFormView extends CollectionSubView(); private _layoutPoolData = observable.map(); private _layoutSizeData = observable.map(); private _cachedPool: Map = new Map(); @@ -106,7 +109,6 @@ export class CollectionFreeFormView extends CollectionSubView !this._firstRender && (this.fitToContent || force) ? this.fitToContentVals : undefined; + freeformData = (force?: boolean) => this.fitToContent || force ? this.fitToContentVals : undefined; reverseNativeScaling = () => this.fitToContent ? true : false; panX = () => this.freeformData()?.bounds.cx ?? NumCast(this.Document._panX); panY = () => this.freeformData()?.bounds.cy ?? NumCast(this.Document._panY); @@ -203,7 +205,7 @@ export class CollectionFreeFormView extends CollectionSubView { const [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY); - this.setPan(NumCast(this.Document._panX) - dx, NumCast(this.Document._panY) - dy, 0, true); + this.setPan((this.Document._panX || 0) - dx, (this.Document._panY || 0) - dy, 0, true); this._lastX = e.clientX; this._lastY = e.clientY; } @@ -965,10 +967,10 @@ export class CollectionFreeFormView extends CollectionSubView pos && size).map(({ pos, size }) => ({ pos: pos!, size: size! })); if (measuredDocs.length) { const ranges = measuredDocs.reduce(({ xrange, yrange }, { pos, size }) => // computes range of content - ({ - xrange: { min: Math.min(xrange.min, pos.x), max: Math.max(xrange.max, pos.x + (size.width || 0)) }, - yrange: { min: Math.min(yrange.min, pos.y), max: Math.max(yrange.max, pos.y + (size.height || 0)) } - }) + ({ + xrange: { min: Math.min(xrange.min, pos.x), max: Math.max(xrange.max, pos.x + (size.width || 0)) }, + yrange: { min: Math.min(yrange.min, pos.y), max: Math.max(yrange.max, pos.y + (size.height || 0)) } + }) , { xrange: { min: Number.MAX_VALUE, max: -Number.MAX_VALUE }, yrange: { min: Number.MAX_VALUE, max: -Number.MAX_VALUE } @@ -1043,11 +1045,11 @@ export class CollectionFreeFormView extends CollectionSubView this.props.isSelected() || this.props.isContentActive(); - getChildDocView(entry: PoolData, renderIndex: number) { + getChildDocView(entry: PoolData) { const childLayout = entry.pair.layout; const childData = entry.pair.data; const engine = this.props.layoutEngine?.() || StrCast(this.props.Document._layoutEngine); @@ -1151,8 +1153,6 @@ export class CollectionFreeFormView extends CollectionSubView { return this._layoutPoolData.get(doc[Id] + (replica || "")); } @@ -1306,7 +1300,6 @@ export class CollectionFreeFormView extends CollectionSubView this._cachedPool.set(k[0], k[1])); const elements = computedElementData.slice(); - Array.from(newPool.entries()).filter(entry => this.isCurrent(entry[1].pair.layout)).forEach((entry, i) => + Array.from(newPool.entries()).filter(entry => this.isCurrent(entry[1].pair.layout)).forEach(entry => elements.push({ - ele: this.getChildDocView(entry[1], i), + ele: this.getChildDocView(entry[1]), bounds: this.childDataProvider(entry[1].pair.layout, entry[1].replica) })); @@ -1376,38 +1369,35 @@ export class CollectionFreeFormView extends CollectionSubView { - this._firstRender = false; - this._disposers.layoutComputation = reaction(() => this.doLayoutComputation, - (elements) => this._layoutElements = elements || [], - { fireImmediately: true, name: "doLayout" }); - - this._marqueeRef.current?.addEventListener("dashDragAutoScroll", this.onDragAutoScroll as any); - - this._disposers.groupBounds = reaction(() => { - if (this.props.Document._isGroup && this.childDocs.length === this.childDocList?.length) { - const clist = this.childDocs.map(cd => ({ x: NumCast(cd.x), y: NumCast(cd.y), width: cd[WidthSym](), height: cd[HeightSym]() })); - return aggregateBounds(clist, NumCast(this.layoutDoc._xPadding), NumCast(this.layoutDoc._yPadding)); + this._disposers.layoutComputation = reaction(() => this.doLayoutComputation, + (elements) => this._layoutElements = elements || [], + { fireImmediately: true, name: "doLayout" }); + + this._marqueeRef.current?.addEventListener("dashDragAutoScroll", this.onDragAutoScroll as any); + + this._disposers.groupBounds = reaction(() => { + if (this.props.Document._isGroup && this.childDocs.length === this.childDocList?.length) { + const clist = this.childDocs.map(cd => ({ x: NumCast(cd.x), y: NumCast(cd.y), width: cd[WidthSym](), height: cd[HeightSym]() })); + return aggregateBounds(clist, NumCast(this.layoutDoc._xPadding), NumCast(this.layoutDoc._yPadding)); + } + return undefined; + }, + (cbounds) => { + if (cbounds) { + const c = [NumCast(this.layoutDoc.x) + this.layoutDoc[WidthSym]() / 2, NumCast(this.layoutDoc.y) + this.layoutDoc[HeightSym]() / 2]; + const p = [NumCast(this.layoutDoc._panX), NumCast(this.layoutDoc._panY)]; + const pbounds = { + x: (cbounds.x - p[0]) * this.zoomScaling() + c[0], y: (cbounds.y - p[1]) * this.zoomScaling() + c[1], + r: (cbounds.r - p[0]) * this.zoomScaling() + c[0], b: (cbounds.b - p[1]) * this.zoomScaling() + c[1] + }; + this.layoutDoc._width = (pbounds.r - pbounds.x); + this.layoutDoc._height = (pbounds.b - pbounds.y); + this.layoutDoc._panX = (cbounds.r + cbounds.x) / 2; + this.layoutDoc._panY = (cbounds.b + cbounds.y) / 2; + this.layoutDoc.x = pbounds.x; + this.layoutDoc.y = pbounds.y; } - return undefined; - }, - (cbounds) => { - if (cbounds) { - const c = [NumCast(this.layoutDoc.x) + this.layoutDoc[WidthSym]() / 2, NumCast(this.layoutDoc.y) + this.layoutDoc[HeightSym]() / 2]; - const p = [NumCast(this.layoutDoc._panX), NumCast(this.layoutDoc._panY)]; - const pbounds = { - x: (cbounds.x - p[0]) * this.zoomScaling() + c[0], y: (cbounds.y - p[1]) * this.zoomScaling() + c[1], - r: (cbounds.r - p[0]) * this.zoomScaling() + c[0], b: (cbounds.b - p[1]) * this.zoomScaling() + c[1] - }; - this.layoutDoc._width = (pbounds.r - pbounds.x); - this.layoutDoc._height = (pbounds.b - pbounds.y); - this.layoutDoc._panX = (cbounds.r + cbounds.x) / 2; - this.layoutDoc._panY = (cbounds.b + cbounds.y) / 2; - this.layoutDoc.x = pbounds.x; - this.layoutDoc.y = pbounds.y; - } - }, { fireImmediately: true }); - })); + }, { fireImmediately: true }); } componentWillUnmount() { @@ -1459,8 +1449,8 @@ export class CollectionFreeFormView extends CollectionSubView NumCast(doc._height))) + 20; const dim = Math.ceil(Math.sqrt(docs.length)); docs.forEach((doc, i) => { - doc.x = NumCast(this.Document._panX) + (i % dim) * width - width * dim / 2; - doc.y = NumCast(this.Document._panY) + Math.floor(i / dim) * height - height * dim / 2; + doc.x = (this.Document._panX || 0) + (i % dim) * width - width * dim / 2; + doc.y = (this.Document._panY || 0) + Math.floor(i / dim) * height - height * dim / 2; }); } @@ -1567,35 +1557,58 @@ export class CollectionFreeFormView extends CollectionSubView { - if (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this.props.docViewPath())) { - const unrendered = this.childDocs.filter(doc => !this._renderCutoffData.get(doc[Id])); - const loadIncrement = 5; - for (var i = 0; i < Math.min(unrendered.length, loadIncrement); i++) { - this._renderCutoffData.set(unrendered[i][Id] + "", true); - } - } - this.childDocs.some(doc => !this._renderCutoffData.get(doc[Id])) && setTimeout(this.incrementalRender, 1); - }); - children = () => { - this.incrementalRender(); const children = typeof this.props.children === "function" ? (this.props.children as any)() as JSX.Element[] : []; - return [ - ...children, - ...this.views, - - ]; + return [...children, ...this.views, ]; + } + + chooseGridSpace = (gridSpace: number): number => { + if (!this.zoomScaling()) return 50; + const divisions = this.props.PanelWidth() / this.zoomScaling() / gridSpace + 3; + return divisions < 60 ? gridSpace : this.chooseGridSpace(gridSpace * 10); + } + + @computed get backgroundGrid() { + const gridSpace = this.chooseGridSpace(NumCast(this.layoutDoc["_backgroundGrid-spacing"], 50)); + const shiftX = (this.props.isAnnotationOverlay ? 0 : -this.panX() % gridSpace - gridSpace) * this.zoomScaling(); + const shiftY = (this.props.isAnnotationOverlay ? 0 : -this.panY() % gridSpace - gridSpace) * this.zoomScaling(); + const renderGridSpace = gridSpace * this.zoomScaling(); + const w = this.props.PanelWidth() + 2 * renderGridSpace; + const h = this.props.PanelHeight() + 2 * renderGridSpace; + const strokeStyle = CurrentUserUtils.ActiveDashboard?.colorScheme === ColorScheme.Dark ? "rgba(255,255,255,0.5)" : "rgba(0, 0,0,0.5)"; + return { + const ctx = el?.getContext('2d'); + if (ctx) { + const Cx = this.cachedCenteringShiftX % renderGridSpace; + const Cy = this.cachedCenteringShiftY % renderGridSpace; + ctx.lineWidth = Math.min(1, Math.max(0.5, this.zoomScaling())); + ctx.setLineDash(gridSpace > 50 ? [3, 3] : [1, 5]); + ctx.clearRect(0, 0, w, h); + if (ctx) { + ctx.strokeStyle = strokeStyle; + ctx.beginPath(); + for (let x = Cx - renderGridSpace; x <= w - Cx; x += renderGridSpace) { + ctx.moveTo(x, Cy - h); + ctx.lineTo(x, Cy + h); + } + for (let y = Cy - renderGridSpace; y <= h - Cy; y += renderGridSpace) { + ctx.moveTo(Cx - w, y); + ctx.lineTo(Cx + w, y); + } + ctx.stroke(); + } + } + }} />; } @computed get placeholder() { - return
+ return
{this.props.Document.title?.toString()}
; } @computed get marqueeView() { - TraceMobx(); return
- {this.layoutDoc._backgroundGridShow ? - : (null)} + {this.layoutDoc._backgroundGridShow ? this.backgroundGrid : (null)} - {this._firstRender || (this.Document._freeformLOD && !this.props.isContentActive() && !this.props.isAnnotationOverlay && this.props.renderDepth > 0) ? + {this.Document._freeformLOD && !this.props.isContentActive() && !this.props.isAnnotationOverlay && this.props.renderDepth > 0 ? this.placeholder : this.marqueeView} {this.props.noOverlay ? (null) : } @@ -1852,59 +1854,4 @@ class CollectionFreeFormViewPannableContents extends React.Component; } -} - -interface CollectionFreeFormViewBackgroundGridProps { - panX: () => number; - panY: () => number; - PanelWidth: () => number; - PanelHeight: () => number; - isAnnotationOverlay?: boolean; - zoomScaling: () => number; - layoutDoc: Doc; - cachedCenteringShiftX: number; - cachedCenteringShiftY: number; -} -@observer -class CollectionFreeFormBackgroundGrid extends React.Component { - - - chooseGridSpace = (gridSpace: number): number => { - if (!this.props.zoomScaling()) return 50; - const divisions = this.props.PanelWidth() / this.props.zoomScaling() / gridSpace + 3; - return divisions < 60 ? gridSpace : this.chooseGridSpace(gridSpace * 10); - } - render() { - const gridSpace = this.chooseGridSpace(NumCast(this.props.layoutDoc["_backgroundGrid-spacing"], 50)); - const shiftX = (this.props.isAnnotationOverlay ? 0 : -this.props.panX() % gridSpace - gridSpace) * this.props.zoomScaling(); - const shiftY = (this.props.isAnnotationOverlay ? 0 : -this.props.panY() % gridSpace - gridSpace) * this.props.zoomScaling(); - const renderGridSpace = gridSpace * this.props.zoomScaling(); - const w = this.props.PanelWidth() + 2 * renderGridSpace; - const h = this.props.PanelHeight() + 2 * renderGridSpace; - const strokeStyle = CurrentUserUtils.ActiveDashboard?.colorScheme === ColorScheme.Dark ? "rgba(255,255,255,0.5)" : "rgba(0, 0,0,0.5)"; - return { - const ctx = el?.getContext('2d'); - if (ctx) { - const Cx = this.props.cachedCenteringShiftX % renderGridSpace; - const Cy = this.props.cachedCenteringShiftY % renderGridSpace; - ctx.lineWidth = Math.min(1, Math.max(0.5, this.props.zoomScaling())); - ctx.setLineDash(gridSpace > 50 ? [3, 3] : [1, 5]); - ctx.clearRect(0, 0, w, h); - if (ctx) { - ctx.strokeStyle = strokeStyle; - ctx.beginPath(); - for (let x = Cx - renderGridSpace; x <= w - Cx; x += renderGridSpace) { - ctx.moveTo(x, Cy - h); - ctx.lineTo(x, Cy + h); - } - for (let y = Cy - renderGridSpace; y <= h - Cy; y += renderGridSpace) { - ctx.moveTo(Cx - w, y); - ctx.lineTo(Cx + w, y); - } - ctx.stroke(); - } - } - }} />; - } } \ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index b10b0912f..08da682bb 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -30,9 +30,6 @@ import "./MarqueeView.scss"; import React = require("react"); import { StyleLayers } from "../../StyleProvider"; import { TreeView } from "../TreeView"; -import { VideoBox } from "../../nodes/VideoBox"; -import { ImageField, WebField } from "../../../../fields/URLField"; -import { pasteImageBitmap } from "../../nodes/WebBoxRenderer"; interface MarqueeViewProps { getContainerTransform: () => Transform; @@ -137,15 +134,17 @@ export class MarqueeView extends React.Component - pasteImageBitmap((data: any, error: any) => { - error && console.log(error); - data && VideoBox.convertDataUri(data, this.props.Document[Id] + "-thumb-frozen").then(returnedfilename => { - this.props.Document["thumb-frozen"] = new ImageField(returnedfilename); - }); - })); - } else if (e.key === "s" && e.ctrlKey) { + // e.preventDefault(); + // navigator.clipboard.readText().then(text => { + // const ns = text.split("\n").filter(t => t.trim() !== "\r" && t.trim() !== ""); + // if (ns.length === 1 && text.startsWith("http")) { + // this.props.addDocument(Docs.Create.ImageDocument(text, { _nativeWidth: 300, _width: 300, x: x, y: y }));// paste an image from its URL in the paste buffer + // } else { + // this.pasteTable(ns, x, y); + // } + // }); + // e.stopPropagation(); + e.preventDefault(); const slide = Doc.copyDragFactory(Doc.UserDoc().emptySlide as Doc)!; slide.x = x; diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx index 58ea7410d..b0030471d 100644 --- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx +++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx @@ -2,7 +2,9 @@ import { action, computed, Lambda, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from "react"; import { Doc, Opt } from '../../../../fields/Doc'; +import { documentSchema } from '../../../../fields/documentSchemas'; import { Id } from '../../../../fields/FieldSymbols'; +import { makeInterface } from '../../../../fields/Schema'; import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; import { emptyFunction, OmitKeys, returnFalse, setupMoveUpEvents } from '../../../../Utils'; import { Docs } from '../../../documents/Documents'; @@ -18,8 +20,11 @@ import { CollectionSubView } from '../CollectionSubView'; import "./CollectionGridView.scss"; import Grid, { Layout } from "./Grid"; +type GridSchema = makeInterface<[typeof documentSchema]>; +const GridSchema = makeInterface(documentSchema); + @observer -export class CollectionGridView extends CollectionSubView() { +export class CollectionGridView extends CollectionSubView(GridSchema) { private _containerRef: React.RefObject = React.createRef(); private _changeListenerDisposer: Opt; // listens for changes in this.childLayoutPairs private _resetListenerDisposer: Opt; // listens for when the reset button is clicked diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx index 160134b60..70c8c9436 100644 --- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx +++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx @@ -4,7 +4,9 @@ import { action, IReactionDisposer, observable, reaction, runInAction } from 'mo import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, HeightSym, Opt, WidthSym } from '../../../../fields/Doc'; +import { documentSchema } from '../../../../fields/documentSchemas'; import { Id } from '../../../../fields/FieldSymbols'; +import { makeInterface } from '../../../../fields/Schema'; import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; import { emptyFunction, returnEmptyDoclist, returnTrue, Utils } from '../../../../Utils'; import { DocUtils } from '../../../documents/Documents'; @@ -23,6 +25,9 @@ import { CollectionViewType } from '../CollectionView'; import "./CollectionLinearView.scss"; +type LinearDocument = makeInterface<[typeof documentSchema,]>; +const LinearDocument = makeInterface(documentSchema); + /** * CollectionLinearView is the class for rendering the horizontal collection * of documents, it useful for horizontal menus. It can either be expandable @@ -32,7 +37,7 @@ import "./CollectionLinearView.scss"; * - It is used for the context sensitive toolbar at the top (see contMenuButtons() in CollectionMenu.tsx) */ @observer -export class CollectionLinearView extends CollectionSubView() { +export class CollectionLinearView extends CollectionSubView(LinearDocument) { @observable public addMenuToggle = React.createRef(); @observable private _selectedIndex = -1; private _dropDisposer?: DragManager.DragDropDisposer; @@ -73,7 +78,7 @@ export class CollectionLinearView extends CollectionSubView() { { fireImmediately: true } ); } - protected createDashEventsTarget = (ele: HTMLDivElement | null) => { //used for stacking and masonry view + protected createDashEventsTarget = (ele: HTMLDivElement) => { //used for stacking and masonry view this._dropDisposer && this._dropDisposer(); if (ele) { this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc); diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index 2bdf92417..ec1cbadd5 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -2,9 +2,11 @@ import { action, computed } from 'mobx'; import { observer } from 'mobx-react'; import * as React from "react"; import { Doc } from '../../../../fields/Doc'; +import { documentSchema } from '../../../../fields/documentSchemas'; import { List } from '../../../../fields/List'; +import { makeInterface } from '../../../../fields/Schema'; import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; -import { emptyFunction, returnFalse } from '../../../../Utils'; +import { returnFalse, emptyPath, returnEmptyDoclist, emptyFunction } from '../../../../Utils'; import { DragManager, dropActionType } from '../../../util/DragManager'; import { Transform } from '../../../util/Transform'; import { undoBatch } from '../../../util/UndoManager'; @@ -14,6 +16,8 @@ import "./CollectionMulticolumnView.scss"; import ResizeBar from './MulticolumnResizer'; import WidthLabel from './MulticolumnWidthLabel'; +type MulticolumnDocument = makeInterface<[typeof documentSchema]>; +const MulticolumnDocument = makeInterface(documentSchema); interface WidthSpecifier { magnitude: number; @@ -34,7 +38,7 @@ const resolvedUnits = Object.values(DimUnit); const resizerWidth = 8; @observer -export class CollectionMulticolumnView extends CollectionSubView() { +export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocument) { /** * @returns the list of layout documents whose width unit is @@ -47,8 +51,7 @@ export class CollectionMulticolumnView extends CollectionSubView() { @computed private get minimumDim() { - const ratioDocs = this.ratioDefinedDocs.filter(layout => layout._dimMagnitude); - return ratioDocs.length ? Math.min(...ratioDocs.map(layout => NumCast(layout._dimMagnitude))) : 1; + return Math.min(...this.ratioDefinedDocs.filter(layout => layout._dimMagnitude).map(layout => NumCast(layout._dimMagnitude))); } /** diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx index 7e2b83230..a2d51e2e7 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx @@ -2,9 +2,11 @@ import { action, computed } from 'mobx'; import { observer } from 'mobx-react'; import * as React from "react"; import { Doc } from '../../../../fields/Doc'; +import { documentSchema } from '../../../../fields/documentSchemas'; import { List } from '../../../../fields/List'; +import { makeInterface } from '../../../../fields/Schema'; import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; -import { emptyFunction, returnFalse } from '../../../../Utils'; +import { returnFalse, emptyPath, returnEmptyDoclist, emptyFunction } from '../../../../Utils'; import { DragManager, dropActionType } from '../../../util/DragManager'; import { Transform } from '../../../util/Transform'; import { undoBatch } from '../../../util/UndoManager'; @@ -14,6 +16,9 @@ import "./CollectionMultirowView.scss"; import HeightLabel from './MultirowHeightLabel'; import ResizeBar from './MultirowResizer'; +type MultirowDocument = makeInterface<[typeof documentSchema]>; +const MultirowDocument = makeInterface(documentSchema); + interface HeightSpecifier { magnitude: number; unit: string; @@ -33,7 +38,7 @@ const resolvedUnits = Object.values(DimUnit); const resizerHeight = 8; @observer -export class CollectionMultirowView extends CollectionSubView() { +export class CollectionMultirowView extends CollectionSubView(MultirowDocument) { /** * @returns the list of layout documents whose width unit is @@ -46,8 +51,7 @@ export class CollectionMultirowView extends CollectionSubView() { @computed private get minimumDim() { - const ratioDocs = this.ratioDefinedDocs.filter(layout => layout._dimMagnitude); - return ratioDocs.length ? Math.min(...ratioDocs.map(layout => NumCast(layout._dimMagnitude))) : 1; + return Math.min(...this.ratioDefinedDocs.filter(layout => layout._dimMagnitude).map(layout => NumCast(layout._dimMagnitude))); } /** diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx index c2bb3b3ac..a439a7998 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx @@ -2,18 +2,19 @@ import React = require("react"); import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; -import { extname } from "path"; import DatePicker from "react-datepicker"; +import "react-datepicker/dist/react-datepicker.css"; import { CellInfo } from "react-table"; +import "react-table/react-table.css"; import { DateField } from "../../../../fields/DateField"; import { Doc, DocListCast, Field, Opt } from "../../../../fields/Doc"; import { Id } from "../../../../fields/FieldSymbols"; import { List } from "../../../../fields/List"; import { SchemaHeaderField } from "../../../../fields/SchemaHeaderField"; import { ComputedField } from "../../../../fields/ScriptField"; -import { BoolCast, Cast, DateCast, FieldValue, StrCast } from "../../../../fields/Types"; +import { BoolCast, Cast, DateCast, FieldValue, NumCast, StrCast } from "../../../../fields/Types"; import { ImageField } from "../../../../fields/URLField"; -import { emptyFunction, Utils } from "../../../../Utils"; +import { Utils, emptyFunction } from "../../../../Utils"; import { Docs } from "../../../documents/Documents"; import { DocumentType } from "../../../documents/DocumentTypes"; import { DocumentManager } from "../../../util/DocumentManager"; @@ -28,8 +29,9 @@ import { EditableView } from "../../EditableView"; import { MAX_ROW_HEIGHT } from '../../global/globalCssVariables.scss'; import { DocumentIconContainer } from "../../nodes/DocumentIcon"; import { OverlayView } from "../../OverlayView"; -import { CollectionView } from "../CollectionView"; import "./CollectionSchemaView.scss"; +import { CollectionView } from "../CollectionView"; +const path = require('path'); // intialize cell properties export interface CellProps { @@ -493,8 +495,8 @@ export class CollectionSchemaImageCell extends CollectionSchemaCell { if (url.href.indexOf(window.location.origin) === -1) return Utils.CorsProxy(url.href); // otherwise, put it through the cors proxy erver if (!/\.(png|jpg|jpeg|gif|webp)$/.test(url.href.toLowerCase())) return url.href;//Why is this here — good question - const ext = extname(url.href); - return url.href.replace(ext, "_o" + ext); + const ext = path.extname(url.href); // the extension of the file + return url.href.replace(ext, "_o" + path.extname(url.href)); } render() { diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index 8b73351d5..b89246489 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -4,6 +4,7 @@ import { action, computed, observable, untracked, trace } from "mobx"; import { observer } from "mobx-react"; import Measure from "react-measure"; import { Resize } from "react-table"; +import "react-table/react-table.css"; import { Doc, Opt } from "../../../../fields/Doc"; import { List } from "../../../../fields/List"; import { listSpec } from "../../../../fields/Schema"; @@ -46,7 +47,7 @@ const columnTypes: Map = new Map([ ]); @observer -export class CollectionSchemaView extends CollectionSubView() { +export class CollectionSchemaView extends CollectionSubView(doc => doc) { private _previewCont?: HTMLDivElement; @observable _previewDoc: Doc | undefined = undefined; @@ -146,43 +147,43 @@ export class CollectionSchemaView extends CollectionSubView() { const anyType =
this.setColumnType(col, ColumnType.Any)}> - Any -
; + Any +
; const numType =
this.setColumnType(col, ColumnType.Number)}> - Number -
; + Number +
; const textType =
this.setColumnType(col, ColumnType.String)}> Text -
; +
; const boolType =
this.setColumnType(col, ColumnType.Boolean)}> Checkbox -
; +
; const listType =
this.setColumnType(col, ColumnType.List)}> List -
; +
; const docType =
this.setColumnType(col, ColumnType.Doc)}> Document -
; +
; const imageType =
this.setColumnType(col, ColumnType.Image)}> Image -
; + ; const dateType =
this.setColumnType(col, ColumnType.Date)}> - Date -
; + Date + ; const allColumnTypes =
@@ -556,7 +557,7 @@ export class CollectionSchemaView extends CollectionSubView() { style={{ overflow: this.props.scrollOverflow === true ? "scroll" : undefined, backgroundColor: "white", pointerEvents: this.props.Document._searchDoc !== undefined && !this.props.isContentActive() && !SnappingManager.GetIsDragging() ? "none" : undefined, - width: this.props.PanelWidth() || "100%", height: this.props.PanelHeight() || "100%", position: "relative", + width: name === "collectionSchemaView-searchContainer" ? "auto" : this.props.PanelWidth() || "100%", height: this.props.PanelHeight() || "100%", position: "relative", }} >
{ - console.log("Data available", e); const [{ result }] = await Networking.UploadFilesToServer(e.data); - console.log("Data result", result); if (!(result instanceof Error)) { this.props.Document[this.fieldKey] = new AudioField(result.accessPaths.agnostic.client); } @@ -604,4 +602,4 @@ export class AudioBox extends ViewBoxAnnotatableComponent; } -} +} \ No newline at end of file diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index c2a526804..fe34d6687 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -1,6 +1,7 @@ import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; import { Doc, Opt } from "../../../fields/Doc"; +import { Document } from "../../../fields/documentSchemas"; import { List } from "../../../fields/List"; import { listSpec } from "../../../fields/Schema"; import { ComputedField } from "../../../fields/ScriptField"; @@ -22,27 +23,25 @@ export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { dataProvider?: (doc: Doc, replica: string) => { x: number, y: number, zIndex?: number, opacity?: number, highlight?: boolean, z: number, transition?: string } | undefined; sizeProvider?: (doc: Doc, replica: string) => { width: number, height: number } | undefined; layerProvider: ((doc: Doc, assign?: boolean) => boolean) | undefined; - renderCutoffProvider: (doc: Doc) => boolean; zIndex?: number; highlight?: boolean; jitterRotation: number; dataTransition?: string; replica: string; - renderIndex: number; CollectionFreeFormView: CollectionFreeFormView; } @observer -export class CollectionFreeFormDocumentView extends DocComponent() { +export class CollectionFreeFormDocumentView extends DocComponent(Document) { public static animFields = ["_height", "_width", "x", "y", "_scrollTop", "opacity"]; // fields that are configured to be animatable using animation frames @observable _animPos: number[] | undefined = undefined; @observable _contentView: DocumentView | undefined | null; get displayName() { return "CollectionFreeFormDocumentView(" + this.rootDoc.title + ")"; } // this makes mobx trace() statements more descriptive get maskCentering() { return this.props.Document.isInkMask ? InkingStroke.MaskDim / 2 : 0; } get transform() { return `translate(${this.X - this.maskCentering}px, ${this.Y - this.maskCentering}px) rotate(${this.props.jitterRotation}deg)`; } - get X() { return this.dataProvider ? this.dataProvider.x : NumCast(this.Document.x); } - get Y() { return this.dataProvider ? this.dataProvider.y : NumCast(this.Document.y); } - get ZInd() { return this.dataProvider ? this.dataProvider.zIndex : NumCast(this.Document.zIndex); } + get X() { return this.dataProvider ? this.dataProvider.x : (this.Document.x || 0); } + get Y() { return this.dataProvider ? this.dataProvider.y : (this.Document.y || 0); } + get ZInd() { return this.dataProvider ? this.dataProvider.zIndex : (this.Document.zIndex || 0); } get Opacity() { return this.dataProvider ? this.dataProvider.opacity : undefined; } get Highlight() { return this.dataProvider?.highlight; } @computed get dataProvider() { return this.props.dataProvider?.(this.props.Document, this.props.replica); } @@ -177,11 +176,7 @@ export class CollectionFreeFormDocumentView extends DocComponent - {this.props.renderCutoffProvider(this.props.Document) ? -
- : - this._contentView = r)} /> - } + this._contentView = r)} />
; } } diff --git a/src/client/views/nodes/ColorBox.tsx b/src/client/views/nodes/ColorBox.tsx index d975baf9b..8da5cd1b1 100644 --- a/src/client/views/nodes/ColorBox.tsx +++ b/src/client/views/nodes/ColorBox.tsx @@ -3,7 +3,9 @@ import { action } from "mobx"; import { observer } from "mobx-react"; import { ColorState, SketchPicker } from 'react-color'; import { Doc, HeightSym, WidthSym } from '../../../fields/Doc'; +import { documentSchema } from "../../../fields/documentSchemas"; import { InkTool } from "../../../fields/InkField"; +import { makeInterface } from "../../../fields/Schema"; import { StrCast } from "../../../fields/Types"; import { DocumentType } from "../../documents/DocumentTypes"; import { CurrentUserUtils } from "../../util/CurrentUserUtils"; @@ -15,8 +17,11 @@ import "./ColorBox.scss"; import { FieldView, FieldViewProps } from './FieldView'; import { RichTextMenu } from "./formattedText/RichTextMenu"; +type ColorDocument = makeInterface<[typeof documentSchema]>; +const ColorDocument = makeInterface(documentSchema); + @observer -export class ColorBox extends ViewBoxBaseComponent() { +export class ColorBox extends ViewBoxBaseComponent(ColorDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ColorBox, fieldKey); } @undoBatch diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index cbc61ffdb..d47e8340c 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -2,6 +2,8 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, observable } from 'mobx'; import { observer } from "mobx-react"; import { Doc, Opt } from '../../../fields/Doc'; +import { documentSchema } from '../../../fields/documentSchemas'; +import { createSchema, makeInterface } from '../../../fields/Schema'; import { Cast, NumCast, StrCast } from '../../../fields/Types'; import { emptyFunction, OmitKeys, returnFalse, setupMoveUpEvents } from '../../../Utils'; import { DragManager } from '../../util/DragManager'; @@ -13,10 +15,15 @@ import "./ComparisonBox.scss"; import { DocumentView, DocumentViewProps } from './DocumentView'; import { FieldView, FieldViewProps } from './FieldView'; import React = require("react"); +import { DocumentType } from '../../documents/DocumentTypes'; +export const comparisonSchema = createSchema({}); + +type ComparisonDocument = makeInterface<[typeof comparisonSchema, typeof documentSchema]>; +const ComparisonDocument = makeInterface(comparisonSchema, documentSchema); @observer -export class ComparisonBox extends ViewBoxAnnotatableComponent() { +export class ComparisonBox extends ViewBoxAnnotatableComponent(ComparisonDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ComparisonBox, fieldKey); } protected _multiTouchDisposer?: import("../../util/InteractionUtils").InteractionUtils.MultiTouchEventDisposer | undefined; private _disposers: (DragManager.DragDropDisposer | undefined)[] = [undefined, undefined]; diff --git a/src/client/views/nodes/DocumentIcon.tsx b/src/client/views/nodes/DocumentIcon.tsx index 433a0bf48..123212608 100644 --- a/src/client/views/nodes/DocumentIcon.tsx +++ b/src/client/views/nodes/DocumentIcon.tsx @@ -2,7 +2,7 @@ import { observer } from "mobx-react"; import * as React from "react"; import { DocumentView } from "./DocumentView"; import { DocumentManager } from "../../util/DocumentManager"; -import { Transformer, ts } from "../../util/Scripting"; +import { Transformer, Scripting, ts } from "../../util/Scripting"; import { Field } from "../../../fields/Doc"; @observer diff --git a/src/client/views/nodes/DocumentLinksButton.scss b/src/client/views/nodes/DocumentLinksButton.scss index 9ab3171d3..228e1bdcb 100644 --- a/src/client/views/nodes/DocumentLinksButton.scss +++ b/src/client/views/nodes/DocumentLinksButton.scss @@ -1,8 +1,6 @@ @import "../global/globalCssVariables.scss"; -.documentLinksButton-wrapper { - transform-origin: top left; -} + .documentLinksButton-menu { width: 100%; height: 100%; diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx index 7e6ca4248..93cd02d93 100644 --- a/src/client/views/nodes/DocumentLinksButton.tsx +++ b/src/client/views/nodes/DocumentLinksButton.tsx @@ -20,7 +20,6 @@ import { DocumentView } from "./DocumentView"; import { LinkDescriptionPopup } from "./LinkDescriptionPopup"; import { TaskCompletionBox } from "./TaskCompletedBox"; import React = require("react"); -import { Transform } from "../../util/Transform"; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; @@ -32,7 +31,6 @@ interface DocumentLinksButtonProps { AlwaysOn?: boolean; InMenu?: boolean; StartLink?: boolean; //whether the link HAS been started (i.e. now needs to be completed) - ContentScaling?: () => number; } @observer export class DocumentLinksButton extends React.Component { @@ -304,16 +302,16 @@ export class DocumentLinksButton extends React.Component - { - (this.props.InMenu && (DocumentLinksButton.StartLink || this.props.StartLink)) || - (!DocumentLinksButton.LinkEditorDocView && !this.props.InMenu) ? - {title}
}> - {this.linkButtonInner} - - : this.linkButtonInner - } -
; + return !Array.from(this.filteredLinks).length && !this.props.AlwaysOn ? (null) : + this.props.InMenu && (DocumentLinksButton.StartLink || this.props.StartLink) ? + {title}}> + {this.linkButtonInner} + + : + !DocumentLinksButton.LinkEditorDocView && !this.props.InMenu ? + {title}}> + {this.linkButtonInner} + + : this.linkButtonInner; } } diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss index 4565f8504..9fcd45e72 100644 --- a/src/client/views/nodes/DocumentView.scss +++ b/src/client/views/nodes/DocumentView.scss @@ -58,10 +58,9 @@ .documentView-audioBackground { display: inline-block; width: 10%; - height: 25; position: absolute; - top: 10px; - left: 10px; + top: 0px; + left: 0px; border-radius: 25px; background: white; opacity: 0.3; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index e7de87ea5..707c15bff 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1,4 +1,3 @@ -import { IconProp } from "@fortawesome/fontawesome-svg-core"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; @@ -10,11 +9,11 @@ import { List } from "../../../fields/List"; import { ObjectField } from "../../../fields/ObjectField"; import { listSpec } from "../../../fields/Schema"; import { ScriptField } from '../../../fields/ScriptField'; -import { BoolCast, Cast, ImageCast, NumCast, ScriptCast, StrCast } from "../../../fields/Types"; +import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../fields/Types"; import { AudioField } from "../../../fields/URLField"; import { GetEffectiveAcl, SharingPermissions, TraceMobx } from '../../../fields/util'; import { MobileInterface } from '../../../mobile/MobileInterface'; -import { emptyFunction, hasDescendantTarget, lightOrDark, OmitKeys, returnEmptyString, returnTrue, returnVal, simulateMouseClick, Utils } from "../../../Utils"; +import { emptyFunction, hasDescendantTarget, OmitKeys, returnTrue, returnVal, Utils, lightOrDark, simulateMouseClick, returnEmptyString } from "../../../Utils"; import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils'; import { Docs, DocUtils } from "../../documents/Documents"; import { DocumentType } from '../../documents/DocumentTypes'; @@ -24,7 +23,7 @@ import { DocumentManager } from "../../util/DocumentManager"; import { DragManager, dropActionType } from "../../util/DragManager"; import { InteractionUtils } from '../../util/InteractionUtils'; import { LinkManager } from '../../util/LinkManager'; -import { ScriptingGlobals } from '../../util/ScriptingGlobals'; +import { Scripting } from '../../util/Scripting'; import { SelectionManager } from "../../util/SelectionManager"; import { SharingManager } from '../../util/SharingManager'; import { SnappingManager } from '../../util/SnappingManager'; @@ -49,6 +48,8 @@ import { RadialMenu } from './RadialMenu'; import { ScriptingBox } from "./ScriptingBox"; import { PresBox } from './trails/PresBox'; import React = require("react"); +import { IconProp } from "@fortawesome/fontawesome-svg-core"; +import { ColorScheme } from "../../util/SettingsManager"; const { Howl } = require('howler'); interface Window { @@ -109,7 +110,6 @@ export interface DocumentViewSharedProps { fitContentsToDoc?: () => boolean; // used by freeformview to fit its contents to its panel. corresponds to _fitToBox property on a Document ContainingCollectionView: Opt; ContainingCollectionDoc: Opt; - thumbShown?: () => boolean; setContentView?: (view: DocComponentView) => any; CollectionFreeFormDocumentView?: () => CollectionFreeFormDocumentView; PanelWidth: () => number; @@ -179,12 +179,11 @@ export interface DocumentViewInternalProps extends DocumentViewProps { } @observer -export class DocumentViewInternal extends DocComponent() { +export class DocumentViewInternal extends DocComponent(Document) { public static SelectAfterContextMenu = true; // whether a document should be selected after it's contextmenu is triggered. @observable _animateScalingTo = 0; @observable _mediaState = 0; @observable _pendingDoubleClick = false; - private _disposers: { [name: string]: IReactionDisposer } = {}; private _downX: number = 0; private _downY: number = 0; private _firstX: number = -1; @@ -205,7 +204,6 @@ export class DocumentViewInternal extends DocComponent); } @computed get ContentScale() { return this.props.ContentScaling?.() || 1; } - @computed get thumb() { return ImageCast(this.layoutDoc["thumb-frozen"], ImageCast(this.layoutDoc.thumb))?.url.href.replace(".png", "_m.png"); } @computed get hidden() { return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Hidden); } @computed get opacity() { return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Opacity); } @computed get boxShadow() { return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BoxShadow); } @@ -241,7 +239,6 @@ export class DocumentViewInternal extends DocComponent disposer?.()); } handle1PointerHoldStart = (e: Event, me: InteractionUtils.MultiTouchEvent): any => { @@ -488,7 +485,6 @@ export class DocumentViewInternal extends DocComponent this.onClickHandler.script.run({ this: this.layoutDoc, self: this.rootDoc, - _readOnly_: false, scriptContext: this.props.scriptContext, thisContainer: this.props.ContainingCollectionDoc, documentView: this.props.DocumentView(), @@ -840,13 +836,14 @@ export class DocumentViewInternal extends DocComponent !this.props.isSelected() && LightboxView.LightboxDoc !== this.rootDoc && this.thumb && - !this._componentView?.isAnyChildContentActive?.() ? true : false; @computed get contents() { TraceMobx(); const audioView = !this.layoutDoc._showAudio ? (null) : -
+
@@ -856,17 +853,8 @@ export class DocumentViewInternal extends DocComponent - {!this._retryThumb || !this.thumbShown() ? (null) : - showTitle.split(";").length === 1 ? showTitle + "=" + Field.toString(targetDoc[showTitle.split(";")[0]] as any as Field) : "#" + showTitle} - SetValue={undoBatch((input: string) => { + SetValue={undoBatch(input => { if (input?.startsWith("#")) { if (this.props.showTitle) { this.rootDoc._showTitle = input?.substring(1) ? input.substring(1) : undefined; } else { Doc.UserDoc().showTitle = input?.substring(1) ? input.substring(1) : "creationDate"; } + return true; } else { - var value = input.replace(new RegExp(showTitle + "="), "") as string | number; + var value = input.replace(new RegExp(showTitle + "="), ""); if (showTitle !== "title" && Number(value).toString() === value) value = Number(value); if (showTitle.includes("Date") || showTitle === "author") return true; - Doc.SetInPlace(targetDoc, showTitle, value, true); + return Doc.SetInPlace(targetDoc, showTitle, value, true) ? true : true; } return true; })} @@ -1059,17 +1048,15 @@ export class DocumentViewInternal extends DocComponent; } - @observable _: string = ""; @computed get renderDoc() { TraceMobx(); - const thumb = ImageCast(this.layoutDoc["thumb-frozen"], ImageCast(this.layoutDoc.thumb))?.url.href.replace(".png", "_m.png"); - const isButton = this.props.Document.type === DocumentType.FONTICON; + const isButton: boolean = this.props.Document.type === DocumentType.FONTICON; if (!(this.props.Document instanceof Doc) || GetEffectiveAcl(this.props.Document[DataSym]) === AclPrivate || this.hidden) return null; return this.docContents ??
- {this.innards} {this.onClickHandler && this.props.ContainingCollectionView?.props.Document._viewType === CollectionViewType.Time ?
: (null)} {this.widgetDecorations ?? null} @@ -1157,7 +1143,7 @@ export class DocumentView extends React.Component { get LayoutFieldKey() { return this.docView?.LayoutFieldKey || "layout"; } get fitWidth() { return this.props.fitWidth?.(this.rootDoc) || this.layoutDoc.fitWidth; } - @computed get docViewPath(): DocumentView[] { return this.props.docViewPath ? [...this.props.docViewPath(), this] : [this]; } + @computed get docViewPath() { return this.props.docViewPath ? [...this.props.docViewPath(), this] : [this]; } @computed get layoutDoc() { return Doc.Layout(this.Document, this.props.LayoutTemplate?.()); } @computed get nativeWidth() { return this.docView?._componentView?.reverseNativeScaling?.() ? 0 : @@ -1295,7 +1281,7 @@ export class DocumentView extends React.Component { } } -ScriptingGlobals.add(function toggleDetail(dv: DocumentView, detailLayoutKeySuffix: string) { +Scripting.addGlobal(function toggleDetail(dv: DocumentView, detailLayoutKeySuffix: string) { if (dv.Document.layoutKey === "layout_" + detailLayoutKeySuffix) dv.switchViews(false, "layout"); else dv.switchViews(true, detailLayoutKeySuffix); }); \ No newline at end of file diff --git a/src/client/views/nodes/EquationBox.tsx b/src/client/views/nodes/EquationBox.tsx index c170f9867..f1f802c13 100644 --- a/src/client/views/nodes/EquationBox.tsx +++ b/src/client/views/nodes/EquationBox.tsx @@ -3,18 +3,25 @@ import { action, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { WidthSym } from '../../../fields/Doc'; +import { documentSchema } from '../../../fields/documentSchemas'; import { Id } from '../../../fields/FieldSymbols'; +import { createSchema, makeInterface } from '../../../fields/Schema'; import { NumCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; import { Docs } from '../../documents/Documents'; import { ViewBoxBaseComponent } from '../DocComponent'; import { LightboxView } from '../LightboxView'; -import './EquationBox.scss'; import { FieldView, FieldViewProps } from './FieldView'; +import './EquationBox.scss'; + + +const EquationSchema = createSchema({}); +type EquationDocument = makeInterface<[typeof EquationSchema, typeof documentSchema]>; +const EquationDocument = makeInterface(EquationSchema, documentSchema); @observer -export class EquationBox extends ViewBoxBaseComponent() { +export class EquationBox extends ViewBoxBaseComponent(EquationDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(EquationBox, fieldKey); } public static SelectOnLoad: string = ""; _ref: React.RefObject = React.createRef(); diff --git a/src/client/views/nodes/FilterBox.tsx b/src/client/views/nodes/FilterBox.tsx index ba65acee0..fb8e89da9 100644 --- a/src/client/views/nodes/FilterBox.tsx +++ b/src/client/views/nodes/FilterBox.tsx @@ -4,17 +4,18 @@ import { action, computed, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; import Select from "react-select"; import { Doc, DocListCast, DocListCastAsync, Field, HeightSym, Opt } from "../../../fields/Doc"; +import { documentSchema } from "../../../fields/documentSchemas"; import { List } from "../../../fields/List"; import { RichTextField } from "../../../fields/RichTextField"; -import { listSpec } from "../../../fields/Schema"; +import { listSpec, makeInterface } from "../../../fields/Schema"; import { ComputedField, ScriptField } from "../../../fields/ScriptField"; -import { Cast, NumCast, StrCast } from "../../../fields/Types"; +import { Cast, StrCast, NumCast } from "../../../fields/Types"; import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from "../../../Utils"; import { Docs } from "../../documents/Documents"; import { DocumentType } from "../../documents/DocumentTypes"; import { CurrentUserUtils } from "../../util/CurrentUserUtils"; import { UserOptions } from "../../util/GroupManager"; -import { ScriptingGlobals } from "../../util/ScriptingGlobals"; +import { Scripting } from "../../util/Scripting"; import { SelectionManager } from "../../util/SelectionManager"; import { CollectionTreeView } from "../collections/CollectionTreeView"; import { CollectionView } from "../collections/CollectionView"; @@ -29,8 +30,11 @@ const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; +type FilterBoxDocument = makeInterface<[typeof documentSchema]>; +const FilterBoxDocument = makeInterface(documentSchema); + @observer -export class FilterBox extends ViewBoxBaseComponent() { +export class FilterBox extends ViewBoxBaseComponent(FilterBoxDocument) { constructor(props: Readonly) { super(props); @@ -421,6 +425,7 @@ export class FilterBox extends ViewBoxBaseComponent() { treeViewHideTitle={true} focus={returnFalse} treeViewHideHeaderFields={false} + onCheckedClick={this.scriptField} dontRegisterView={true} styleProvider={this.FilterStyleProvider} layerProvider={this.props.layerProvider} @@ -470,7 +475,7 @@ export class FilterBox extends ViewBoxBaseComponent() { } } -ScriptingGlobals.add(function determineCheckedState(layoutDoc: Doc, facetHeader: string, facetValue: string) { +Scripting.addGlobal(function determineCheckedState(layoutDoc: Doc, facetHeader: string, facetValue: string) { const docFilters = Cast(layoutDoc._docFilters, listSpec("string"), []); for (const filter of docFilters) { const fields = filter.split(":"); // split into key:value:modifiers @@ -480,7 +485,7 @@ ScriptingGlobals.add(function determineCheckedState(layoutDoc: Doc, facetHeader: } return undefined; }); -ScriptingGlobals.add(function readFacetData(layoutDoc: Doc, childKey: string, facetHeader: string) { +Scripting.addGlobal(function readFacetData(layoutDoc: Doc, childKey: string, facetHeader: string) { const allCollectionDocs = new Set(); const activeTabs = DocListCast(layoutDoc[childKey]); SearchBox.foreachRecursiveDoc(activeTabs, (depth: number, doc: Doc) => allCollectionDocs.add(doc)); diff --git a/src/client/views/nodes/FunctionPlotBox.tsx b/src/client/views/nodes/FunctionPlotBox.tsx index 3ab0a3ff2..5050fc2d2 100644 --- a/src/client/views/nodes/FunctionPlotBox.tsx +++ b/src/client/views/nodes/FunctionPlotBox.tsx @@ -19,7 +19,7 @@ type EquationDocument = makeInterface<[typeof EquationSchema, typeof documentSch const EquationDocument = makeInterface(EquationSchema, documentSchema); @observer -export class FunctionPlotBox extends ViewBoxBaseComponent() { +export class FunctionPlotBox extends ViewBoxBaseComponent(EquationDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(FunctionPlotBox, fieldKey); } public static GraphCount = 0; _plot: any; diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 0a4168698..89f70985c 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -1,12 +1,12 @@ -import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from 'mobx'; +import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction, trace } from 'mobx'; import { observer } from "mobx-react"; -import { extname } from 'path'; import { DataSym, Doc, DocListCast, WidthSym } from '../../../fields/Doc'; +import { documentSchema } from '../../../fields/documentSchemas'; import { Id } from '../../../fields/FieldSymbols'; import { InkTool } from '../../../fields/InkField'; import { List } from '../../../fields/List'; import { ObjectField } from '../../../fields/ObjectField'; -import { createSchema } from '../../../fields/Schema'; +import { createSchema, makeInterface } from '../../../fields/Schema'; import { ComputedField } from '../../../fields/ScriptField'; import { Cast, NumCast } from '../../../fields/Types'; import { ImageField } from '../../../fields/URLField'; @@ -29,11 +29,16 @@ import { FaceRectangles } from './FaceRectangles'; import { FieldView, FieldViewProps } from './FieldView'; import "./ImageBox.scss"; import React = require("react"); +import { SnappingManager } from '../../util/SnappingManager'; +const path = require('path'); export const pageSchema = createSchema({ googlePhotosUrl: "string", googlePhotosTags: "string" }); +type ImageDocument = makeInterface<[typeof pageSchema, typeof documentSchema]>; +const ImageDocument = makeInterface(pageSchema, documentSchema); + const uploadIcons = { idle: "downarrow.png", loading: "loading.gif", @@ -42,7 +47,7 @@ const uploadIcons = { }; @observer -export class ImageBox extends ViewBoxAnnotatableComponent() { +export class ImageBox extends ViewBoxAnnotatableComponent(ImageDocument) { protected _multiTouchDisposer?: import("../../util/InteractionUtils").InteractionUtils.MultiTouchEventDisposer | undefined; public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ImageBox, fieldKey); } private _imgRef: React.RefObject = React.createRef(); @@ -185,7 +190,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent -
+
{ value = eq ? value.substr(1) : value; const dubEq = value.startsWith(":=") ? "computed" : value.startsWith(";=") ? "script" : false; value = dubEq ? value.substr(2) : value; - const options: ScriptOptions = { addReturn: true, params: { this: Doc.name, self: Doc.name, _last_: "any", _readOnly_: "boolean" }, editable: false }; + const options: ScriptOptions = { addReturn: true, params: { this: "Doc", _last_: "any" }, editable: false }; if (dubEq) options.typecheck = false; const script = CompileScript(value, options); return !script.compiled ? undefined : { script, type: dubEq, onDelegate: eq }; diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx index 0015f0b71..dae72bb78 100644 --- a/src/client/views/nodes/LabelBox.tsx +++ b/src/client/views/nodes/LabelBox.tsx @@ -2,8 +2,9 @@ import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, DocListCast } from '../../../fields/Doc'; +import { documentSchema } from '../../../fields/documentSchemas'; import { List } from '../../../fields/List'; -import { listSpec } from '../../../fields/Schema'; +import { createSchema, listSpec, makeInterface } from '../../../fields/Schema'; import { Cast, StrCast } from '../../../fields/Types'; import { DragManager } from '../../util/DragManager'; import { undoBatch } from '../../util/UndoManager'; @@ -15,13 +16,17 @@ import { FieldView, FieldViewProps } from './FieldView'; import BigText from './LabelBigText'; import './LabelBox.scss'; +const LabelSchema = createSchema({}); + +type LabelDocument = makeInterface<[typeof LabelSchema, typeof documentSchema]>; +const LabelDocument = makeInterface(LabelSchema, documentSchema); export interface LabelBoxProps { label?: string; } @observer -export class LabelBox extends ViewBoxBaseComponent<(FieldViewProps & LabelBoxProps)>() { +export class LabelBox extends ViewBoxBaseComponent<(FieldViewProps & LabelBoxProps), LabelDocument>(LabelDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(LabelBox, fieldKey); } public static LayoutStringWithTitle(fieldType: { name: string }, fieldStr: string, label: string) { return `<${fieldType.name} fieldKey={'${fieldStr}'} label={'${label}'} {...props} />`; //e.g., "" diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx index 437d29f39..a7bfb93eb 100644 --- a/src/client/views/nodes/LinkAnchorBox.tsx +++ b/src/client/views/nodes/LinkAnchorBox.tsx @@ -2,6 +2,8 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, observable } from "mobx"; import { observer } from "mobx-react"; import { Doc } from "../../../fields/Doc"; +import { documentSchema } from "../../../fields/documentSchemas"; +import { makeInterface } from "../../../fields/Schema"; import { Cast, NumCast, StrCast } from "../../../fields/Types"; import { TraceMobx } from "../../../fields/util"; import { emptyFunction, setupMoveUpEvents, Utils } from '../../../Utils'; @@ -21,9 +23,11 @@ const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; +type LinkAnchorSchema = makeInterface<[typeof documentSchema]>; +const LinkAnchorDocument = makeInterface(documentSchema); @observer -export class LinkAnchorBox extends ViewBoxBaseComponent() { +export class LinkAnchorBox extends ViewBoxBaseComponent(LinkAnchorDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(LinkAnchorBox, fieldKey); } _doubleTap = false; _lastTap: number = 0; diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx index 43f4b43fb..879a63248 100644 --- a/src/client/views/nodes/LinkBox.tsx +++ b/src/client/views/nodes/LinkBox.tsx @@ -1,5 +1,7 @@ import React = require("react"); import { observer } from "mobx-react"; +import { documentSchema } from "../../../fields/documentSchemas"; +import { makeInterface } from "../../../fields/Schema"; import { emptyFunction, returnFalse } from "../../../Utils"; import { ViewBoxBaseComponent } from "../DocComponent"; import { StyleProp } from "../StyleProvider"; @@ -7,8 +9,11 @@ import { ComparisonBox } from "./ComparisonBox"; import { FieldView, FieldViewProps } from './FieldView'; import "./LinkBox.scss"; +type LinkDocument = makeInterface<[typeof documentSchema]>; +const LinkDocument = makeInterface(documentSchema); + @observer -export class LinkBox extends ViewBoxBaseComponent() { +export class LinkBox extends ViewBoxBaseComponent(LinkDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(LinkBox, fieldKey); } isContentActiveFunc = () => this.isContentActive(); render() { diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx index aa2130af5..50444c73a 100644 --- a/src/client/views/nodes/MapBox/MapBox.tsx +++ b/src/client/views/nodes/MapBox/MapBox.tsx @@ -1,11 +1,14 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Autocomplete, GoogleMap, GoogleMapProps, Marker } from '@react-google-maps/api'; +import * as dotenv from 'dotenv'; import { action, computed, IReactionDisposer, observable, ObservableMap } from 'mobx'; import { observer } from "mobx-react"; import * as React from "react"; import { Doc, DocListCast, Opt, WidthSym } from '../../../../fields/Doc'; +import { documentSchema } from '../../../../fields/documentSchemas'; import { Id } from '../../../../fields/FieldSymbols'; import { InkTool } from '../../../../fields/InkField'; +import { makeInterface } from '../../../../fields/Schema'; import { NumCast, StrCast } from '../../../../fields/Types'; import { TraceMobx } from '../../../../fields/util'; import { emptyFunction, OmitKeys, returnFalse, returnOne, setupMoveUpEvents, Utils } from '../../../../Utils'; @@ -40,6 +43,9 @@ import { MapBoxInfoWindow } from './MapBoxInfoWindow'; // const _global = (window /* browser */ || global /* node */) as any; +type MapDocument = makeInterface<[typeof documentSchema]>; +const MapDocument = makeInterface(documentSchema); + const mapContainerStyle = { height: '100%', }; @@ -53,6 +59,7 @@ const mapOptions = { fullscreenControl: false, }; +dotenv.config({ path: __dirname + '/.env' }); const apiKey = process.env.GOOGLE_MAPS; const script = document.createElement('script'); @@ -86,7 +93,7 @@ const options = { } as google.maps.places.AutocompleteOptions; @observer -export class MapBox extends ViewBoxAnnotatableComponent>() { +export class MapBox extends ViewBoxAnnotatableComponent, MapDocument>(MapDocument) { private _dropDisposer?: DragManager.DragDropDisposer; private _disposers: { [name: string]: IReactionDisposer } = {}; diff --git a/src/client/views/nodes/PDFBox.scss b/src/client/views/nodes/PDFBox.scss index 8a68f9647..f44355929 100644 --- a/src/client/views/nodes/PDFBox.scss +++ b/src/client/views/nodes/PDFBox.scss @@ -248,7 +248,6 @@ .pdfBox-background { width: 100%; height: 100%; - cursor: ew-resize; background: lightGray; } diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 9807cee7c..d54b65d92 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -3,14 +3,17 @@ import { action, computed, IReactionDisposer, observable, reaction, runInAction import { observer } from "mobx-react"; import * as Pdfjs from "pdfjs-dist"; import "pdfjs-dist/web/pdf_viewer.css"; -import { Doc, DocListCast, Opt, WidthSym } from "../../../fields/Doc"; -import { Cast, NumCast, StrCast, ImageCast } from '../../../fields/Types'; +import { Doc, DocListCast, Opt, WidthSym, StrListCast } from "../../../fields/Doc"; +import { documentSchema } from '../../../fields/documentSchemas'; +import { makeInterface, listSpec } from "../../../fields/Schema"; +import { Cast, NumCast, StrCast } from '../../../fields/Types'; import { PdfField } from "../../../fields/URLField"; import { TraceMobx } from '../../../fields/util'; import { emptyFunction, returnOne, setupMoveUpEvents, Utils } from '../../../Utils'; import { Docs } from '../../documents/Documents'; import { KeyCodes } from '../../util/KeyCodes'; import { undoBatch } from '../../util/UndoManager'; +import { panZoomSchema } from '../collections/collectionFreeForm/CollectionFreeFormView'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from "../DocComponent"; @@ -19,14 +22,18 @@ import { AnchorMenu } from '../pdf/AnchorMenu'; import { PDFViewer } from "../pdf/PDFViewer"; import { SidebarAnnos } from '../SidebarAnnos'; import { FieldView, FieldViewProps } from './FieldView'; +import { pageSchema } from "./ImageBox"; import "./PDFBox.scss"; import React = require("react"); +import { CurrentUserUtils } from '../../util/CurrentUserUtils'; + +type PdfDocument = makeInterface<[typeof documentSchema, typeof panZoomSchema, typeof pageSchema]>; +const PdfDocument = makeInterface(documentSchema, panZoomSchema, pageSchema); @observer -export class PDFBox extends ViewBoxAnnotatableComponent() { +export class PDFBox extends ViewBoxAnnotatableComponent(PdfDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PDFBox, fieldKey); } public static openSidebarWidth = 250; - public static sidebarResizerWidth = 5; private _searchString: string = ""; private _initialScrollTarget: Opt; private _pdfViewer: PDFViewer | undefined; @@ -39,7 +46,6 @@ export class PDFBox extends ViewBoxAnnotatableComponent this._pdf = PDFBox.pdfcache.get(this.pdfUrl!.url.href)); - else if (PDFBox.pdfpromise.get(this.pdfUrl.url.href)) PDFBox.pdfpromise.get(this.pdfUrl.url.href)?.then(action((pdf: any) => this._pdf = pdf)); + else if (PDFBox.pdfpromise.get(this.pdfUrl.url.href)) PDFBox.pdfpromise.get(this.pdfUrl.url.href)?.then(action(pdf => this._pdf = pdf)); } } @@ -74,7 +80,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent this._pdfViewer?.prevAnnotation(); public nextAnnotation = () => this._pdfViewer?.nextAnnotation(); - public backPage = () => { this.Document._curPage = (NumCast(this.Document._curPage) || 1) - 1; return true; }; - public forwardPage = () => { this.Document._curPage = (NumCast(this.Document._curPage) || 1) + 1; return true; }; + public backPage = () => { this.Document._curPage = (this.Document._curPage || 1) - 1; return true; }; + public forwardPage = () => { this.Document._curPage = (this.Document._curPage || 1) + 1; return true; }; public gotoPage = (p: number) => this.Document._curPage = p; @undoBatch @@ -136,15 +142,15 @@ export class PDFBox extends ViewBoxAnnotatableComponent { // onButton determines whether the width of the pdf box changes, or just the ratio of the sidebar to the pdf + sidebarBtnDown = (e: React.PointerEvent) => { setupMoveUpEvents(this, e, (e, down, delta) => { const localDelta = this.props.ScreenToLocalTransform().scale(this.props.scaling?.() || 1).transformDirection(delta[0], delta[1]); const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + "-nativeWidth"]); const curNativeWidth = NumCast(this.layoutDoc.nativeWidth, nativeWidth); - const ratio = (curNativeWidth + (onButton ? 1 : -1) * localDelta[0] / (this.props.scaling?.() || 1)) / nativeWidth; + const ratio = (curNativeWidth + localDelta[0] / (this.props.scaling?.() || 1)) / nativeWidth; if (ratio >= 1) { this.layoutDoc.nativeWidth = nativeWidth * ratio; - onButton && (this.layoutDoc._width = this.layoutDoc[WidthSym]() + localDelta[0]); + this.layoutDoc._width = this.layoutDoc[WidthSym]() + localDelta[0]; this.layoutDoc._showSidebar = nativeWidth !== this.layoutDoc._nativeWidth; } return false; @@ -154,17 +160,16 @@ export class PDFBox extends ViewBoxAnnotatableComponent = undefined; toggleSidebar = action((preview: boolean = false) => { const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + "-nativeWidth"]); - const sideratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? PDFBox.openSidebarWidth : 0) + nativeWidth) / nativeWidth; - const pdfratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? PDFBox.openSidebarWidth + PDFBox.sidebarResizerWidth : 0) + nativeWidth) / nativeWidth; + const ratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? PDFBox.openSidebarWidth : 0) + nativeWidth) / nativeWidth; const curNativeWidth = NumCast(this.layoutDoc.nativeWidth, nativeWidth); if (preview) { - this._previewNativeWidth = nativeWidth * sideratio; - this._previewWidth = this.layoutDoc[WidthSym]() * nativeWidth * sideratio / curNativeWidth; + this._previewNativeWidth = nativeWidth * ratio; + this._previewWidth = this.layoutDoc[WidthSym]() * nativeWidth * ratio / curNativeWidth; this._showSidebar = true; } else { - this.layoutDoc.nativeWidth = nativeWidth * pdfratio; - this.layoutDoc._width = this.layoutDoc[WidthSym]() * nativeWidth * pdfratio / curNativeWidth; + this.layoutDoc.nativeWidth = nativeWidth * ratio; + this.layoutDoc._width = this.layoutDoc[WidthSym]() * nativeWidth * ratio / curNativeWidth; this.layoutDoc._showSidebar = nativeWidth !== this.layoutDoc._nativeWidth; } }); @@ -180,7 +185,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent ; const searchTitle = `${!this._searching ? "Open" : "Close"} Search Bar`; - const curPage = NumCast(this.Document._curPage) || 1; + const curPage = this.Document._curPage || 1; return !this.props.isContentActive() ? (null) :
[KeyCodes.BACKSPACE, KeyCodes.DELETE].includes(e.keyCode) ? e.stopPropagation() : true} onPointerDown={e => e.stopPropagation()} style={{ display: this.props.isContentActive() ? "flex" : "none" }}> @@ -218,7 +223,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent this.sidebarBtnDown(e, true)} > + onPointerDown={this.sidebarBtnDown} >
; @@ -248,20 +253,18 @@ export class PDFBox extends ViewBoxAnnotatableComponent 1; - isPdfContentActive = () => this.isAnyChildContentActive() || this.props.isSelected(); @computed get renderPdfView() { TraceMobx(); const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1; const scale = previewScale * (this.props.scaling?.() || 1); return
600) ? NumCast(this.Document._height) * this.props.PanelWidth() / NumCast(this.Document._width) : undefined }}> -
this.sidebarBtnDown(e, false)} /> +
(); - static pdfpromise = new Map>(); + static pdfpromise = new Map>(); render() { TraceMobx(); - if (this._pdf) { - if (!this.props.thumbShown?.()) { - return this.renderPdfView; - } - return null; - } + if (this._pdf) return this.renderPdfView; const href = this.pdfUrl?.url.href; if (href) { if (PDFBox.pdfcache.get(href)) setTimeout(action(() => this._pdf = PDFBox.pdfcache.get(href))); else { if (!PDFBox.pdfpromise.get(href)) PDFBox.pdfpromise.set(href, Pdfjs.getDocument(href).promise); - PDFBox.pdfpromise.get(href)?.then(action((pdf: any) => PDFBox.pdfcache.set(href, this._pdf = pdf))); + PDFBox.pdfpromise.get(href)?.then(action(pdf => PDFBox.pdfcache.set(href, this._pdf = pdf))); } } return this.renderTitleBox; diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx index dbb567d3a..0c631e5f9 100644 --- a/src/client/views/nodes/ScreenshotBox.tsx +++ b/src/client/views/nodes/ScreenshotBox.tsx @@ -1,17 +1,20 @@ import React = require("react"); import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; // import { Canvas } from '@react-three/fiber'; -import { computed, observable, runInAction } from "mobx"; +import { action, computed, observable, reaction, trace, runInAction } from "mobx"; import { observer } from "mobx-react"; // import { BufferAttribute, Camera, Vector2, Vector3 } from 'three'; import { DateField } from "../../../fields/DateField"; -import { Doc, HeightSym, WidthSym } from "../../../fields/Doc"; +import { Doc, WidthSym, HeightSym } from "../../../fields/Doc"; +import { documentSchema } from "../../../fields/documentSchemas"; import { Id } from "../../../fields/FieldSymbols"; +import { InkTool } from "../../../fields/InkField"; +import { makeInterface } from "../../../fields/Schema"; import { ComputedField } from "../../../fields/ScriptField"; import { Cast, NumCast } from "../../../fields/Types"; import { AudioField, VideoField } from "../../../fields/URLField"; import { TraceMobx } from "../../../fields/util"; -import { emptyFunction, OmitKeys, returnFalse, returnOne } from "../../../Utils"; +import { emptyFunction, numberRange, OmitKeys, returnFalse, returnOne, Utils } from "../../../Utils"; import { DocUtils } from "../../documents/Documents"; import { DocumentType } from "../../documents/DocumentTypes"; import { Networking } from "../../Network"; @@ -29,6 +32,9 @@ declare class MediaRecorder { constructor(e: any, options?: any); // whatever MediaRecorder has } +type ScreenshotDocument = makeInterface<[typeof documentSchema]>; +const ScreenshotDocument = makeInterface(documentSchema); + // interface VideoTileProps { // raised: { coord: Vector2, off: Vector3 }[]; // setRaised: (r: { coord: Vector2, off: Vector3 }[]) => void; @@ -106,7 +112,7 @@ declare class MediaRecorder { // } @observer -export class ScreenshotBox extends ViewBoxAnnotatableComponent() { +export class ScreenshotBox extends ViewBoxAnnotatableComponent(ScreenshotDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ScreenshotBox, fieldKey); } private _audioRec: any; private _videoRec: any; diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx index 366c3fc2f..183140cd7 100644 --- a/src/client/views/nodes/ScriptingBox.tsx +++ b/src/client/views/nodes/ScriptingBox.tsx @@ -1,19 +1,18 @@ import ReactTextareaAutocomplete from "@webscopeio/react-textarea-autocomplete"; import "@webscopeio/react-textarea-autocomplete/style.css"; -import { action, computed, observable } from "mobx"; +import { action, computed, observable, runInAction, trace } from "mobx"; import { observer } from "mobx-react"; import * as React from "react"; import { Doc } from "../../../fields/Doc"; +import { documentSchema } from "../../../fields/documentSchemas"; import { List } from "../../../fields/List"; -import { listSpec } from "../../../fields/Schema"; +import { createSchema, listSpec, makeInterface } from "../../../fields/Schema"; import { ScriptField } from "../../../fields/ScriptField"; -import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../fields/Types"; -import { TraceMobx } from "../../../fields/util"; +import { Cast, NumCast, ScriptCast, StrCast, BoolCast } from "../../../fields/Types"; import { returnEmptyString } from "../../../Utils"; import { DragManager } from "../../util/DragManager"; import { InteractionUtils } from "../../util/InteractionUtils"; -import { CompileScript, ScriptParam } from "../../util/Scripting"; -import { ScriptingGlobals } from "../../util/ScriptingGlobals"; +import { CompileScript, Scripting, ScriptParam } from "../../util/Scripting"; import { ScriptManager } from "../../util/ScriptManager"; import { ContextMenu } from "../ContextMenu"; import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from "../DocComponent"; @@ -22,10 +21,15 @@ import { FieldView, FieldViewProps } from "../nodes/FieldView"; import { OverlayView } from "../OverlayView"; import { DocumentIconContainer } from "./DocumentIcon"; import "./ScriptingBox.scss"; +import { TraceMobx } from "../../../fields/util"; const _global = (window /* browser */ || global /* node */) as any; +const ScriptingSchema = createSchema({}); +type ScriptingDocument = makeInterface<[typeof ScriptingSchema, typeof documentSchema]>; +const ScriptingDocument = makeInterface(ScriptingSchema, documentSchema); + @observer -export class ScriptingBox extends ViewBoxAnnotatableComponent() { +export class ScriptingBox extends ViewBoxAnnotatableComponent(ScriptingDocument) { private dropDisposer?: DragManager.DragDropDisposer; protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer | undefined; @@ -38,9 +42,9 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent; } - renderFuncListElement(value: string | object) { - return (typeof value !== "string") ? (null) :
+ renderFuncListElement(value: string) { + return
{value}
diff --git a/src/client/views/nodes/SliderBox.tsx b/src/client/views/nodes/SliderBox.tsx index b96977f32..92d1f7446 100644 --- a/src/client/views/nodes/SliderBox.tsx +++ b/src/client/views/nodes/SliderBox.tsx @@ -2,19 +2,30 @@ import { runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Handles, Rail, Slider, Ticks, Tracks } from 'react-compound-slider'; +import { documentSchema } from '../../../fields/documentSchemas'; +import { createSchema, makeInterface } from '../../../fields/Schema'; import { NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; import { ViewBoxBaseComponent } from '../DocComponent'; import { ScriptBox } from '../ScriptBox'; -import { StyleProp } from '../StyleProvider'; import { FieldView, FieldViewProps } from './FieldView'; import { Handle, Tick, TooltipRail, Track } from './SliderBox-components'; import './SliderBox.scss'; +import { StyleProp } from '../StyleProvider'; + +const SliderSchema = createSchema({ + _sliderMin: "number", + _sliderMax: "number", + _sliderMinThumb: "number", + _sliderMaxThumb: "number", +}); +type SliderDocument = makeInterface<[typeof SliderSchema, typeof documentSchema]>; +const SliderDocument = makeInterface(SliderSchema, documentSchema); @observer -export class SliderBox extends ViewBoxBaseComponent() { +export class SliderBox extends ViewBoxBaseComponent(SliderDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(SliderBox, fieldKey); } get minThumbKey() { return this.fieldKey + "-minThumb"; } diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index fafa39deb..56cb562bc 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -3,10 +3,11 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { Tooltip } from "@material-ui/core"; import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction, untracked } from "mobx"; import { observer } from "mobx-react"; -import { basename } from "path"; import * as rp from 'request-promise'; import { Doc, DocListCast } from "../../../fields/Doc"; +import { documentSchema } from "../../../fields/documentSchemas"; import { InkTool } from "../../../fields/InkField"; +import { makeInterface } from "../../../fields/Schema"; import { Cast, NumCast, StrCast } from "../../../fields/Types"; import { AudioField, VideoField } from "../../../fields/URLField"; import { emptyFunction, formatTime, OmitKeys, returnFalse, returnOne, setupMoveUpEvents, Utils } from "../../../Utils"; @@ -35,7 +36,7 @@ type VideoDocument = makeInterface<[typeof documentSchema]>; const VideoDocument = makeInterface(documentSchema); @observer -export class VideoBox extends ViewBoxAnnotatableComponent() { +export class VideoBox extends ViewBoxAnnotatableComponent(VideoDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(VideoBox, fieldKey); } static async convertDataUri(imageUri: string, returnedFilename: string) { try { @@ -188,7 +189,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent returnedFilename && this.createRealSummaryLink(returnedFilename, downX, downY)); } @@ -232,12 +232,12 @@ export class VideoBox extends ViewBoxAnnotatableComponent { const url = !imagePath.startsWith("/") ? Utils.CorsProxy(imagePath) : imagePath; - const width = NumCast(this.layoutDoc._width) || 1; - const height = NumCast(this.layoutDoc._height); + const width = this.layoutDoc._width || 1; + const height = this.layoutDoc._height || 0; const imageSummary = Docs.Create.ImageDocument(url, { _nativeWidth: Doc.NativeWidth(this.layoutDoc), _nativeHeight: Doc.NativeHeight(this.layoutDoc), - x: NumCast(this.layoutDoc.x) + width, y: NumCast(this.layoutDoc.y), _isLinkButton: true, - _width: 150, _height: height / width * 150, title: "--snapshot" + NumCast(this.layoutDoc._currentTimecode) + " image-" + x: (this.layoutDoc.x || 0) + width, y: (this.layoutDoc.y || 0), _isLinkButton: true, + _width: 150, _height: height / width * 150, title: "--snapshot" + (this.layoutDoc._currentTimecode || 0) + " image-" }); Doc.SetNativeWidth(Doc.GetProto(imageSummary), Doc.NativeWidth(this.layoutDoc)); Doc.SetNativeHeight(Doc.GetProto(imageSummary), Doc.NativeHeight(this.layoutDoc)); @@ -282,7 +282,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent this._fullScreen = vref.webkitDisplayingFullscreen); this._disposers.reactionDisposer?.(); - this._disposers.reactionDisposer = reaction(() => NumCast(this.layoutDoc._currentTimecode), + this._disposers.reactionDisposer = reaction(() => (this.layoutDoc._currentTimecode || 0), time => !this._playing && (vref.currentTime = time), { fireImmediately: true }); } } @@ -373,7 +373,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent { this._disposers.reactionDisposer?.(); this._disposers.youtubeReactionDisposer?.(); - this._disposers.reactionDisposer = reaction(() => this.layoutDoc._currentTimecode, () => !this._playing && this.Seek(NumCast(this.layoutDoc._currentTimecode))); + this._disposers.reactionDisposer = reaction(() => this.layoutDoc._currentTimecode, () => !this._playing && this.Seek((this.layoutDoc._currentTimecode || 0))); this._disposers.youtubeReactionDisposer = reaction( () => CurrentUserUtils.SelectedTool === InkTool.None && this.props.isSelected(true) && !SnappingManager.GetIsDragging() && !DocumentDecorations.Instance.Interacting, (interactive) => iframe.style.pointerEvents = interactive ? "all" : "none", { fireImmediately: true }); @@ -460,7 +460,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent Math.round(NumCast(this.layoutDoc._currentTimecode))); + const start = untracked(() => Math.round((this.layoutDoc._currentTimecode || 0))); return