aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/nodes')
-rw-r--r--src/client/views/nodes/AudioBox.tsx4
-rw-r--r--src/client/views/nodes/CollectionFreeFormDocumentView.tsx17
-rw-r--r--src/client/views/nodes/ColorBox.tsx7
-rw-r--r--src/client/views/nodes/ComparisonBox.tsx9
-rw-r--r--src/client/views/nodes/DocumentIcon.tsx2
-rw-r--r--src/client/views/nodes/DocumentLinksButton.scss4
-rw-r--r--src/client/views/nodes/DocumentLinksButton.tsx24
-rw-r--r--src/client/views/nodes/DocumentView.scss5
-rw-r--r--src/client/views/nodes/DocumentView.tsx72
-rw-r--r--src/client/views/nodes/EquationBox.tsx11
-rw-r--r--src/client/views/nodes/FilterBox.tsx17
-rw-r--r--src/client/views/nodes/FunctionPlotBox.tsx2
-rw-r--r--src/client/views/nodes/ImageBox.tsx19
-rw-r--r--src/client/views/nodes/KeyValueBox.tsx2
-rw-r--r--src/client/views/nodes/LabelBox.tsx9
-rw-r--r--src/client/views/nodes/LinkAnchorBox.tsx6
-rw-r--r--src/client/views/nodes/LinkBox.tsx7
-rw-r--r--src/client/views/nodes/MapBox/MapBox.tsx9
-rw-r--r--src/client/views/nodes/PDFBox.scss1
-rw-r--r--src/client/views/nodes/PDFBox.tsx64
-rw-r--r--src/client/views/nodes/ScreenshotBox.tsx14
-rw-r--r--src/client/views/nodes/ScriptingBox.tsx34
-rw-r--r--src/client/views/nodes/SliderBox.tsx15
-rw-r--r--src/client/views/nodes/VideoBox.tsx30
-rw-r--r--src/client/views/nodes/WebBox.scss7
-rw-r--r--src/client/views/nodes/WebBox.tsx176
-rw-r--r--src/client/views/nodes/WebBoxRenderer.js395
-rw-r--r--src/client/views/nodes/button/ButtonScripts.ts6
-rw-r--r--src/client/views/nodes/button/FontIconBox.tsx199
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx25
-rw-r--r--src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts24
-rw-r--r--src/client/views/nodes/formattedText/RichTextRules.ts26
-rw-r--r--src/client/views/nodes/trails/PresBox.tsx12
-rw-r--r--src/client/views/nodes/trails/PresElementBox.tsx29
34 files changed, 814 insertions, 469 deletions
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index eb7b9a773..c2b4d0eee 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -215,7 +215,9 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
this.dataDoc[this.fieldKey + "-recordingStart"] = new DateField();
DocUtils.ActiveRecordings.push(this);
this._recorder.ondataavailable = async (e: any) => {
+ 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);
}
@@ -602,4 +604,4 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
{!this.path ? this.recordingControls : this.playbackControls}
</div>;
}
-} \ No newline at end of file
+}
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index fe34d6687..c2a526804 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -1,7 +1,6 @@
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";
@@ -23,25 +22,27 @@ 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<CollectionFreeFormDocumentViewProps, Document>(Document) {
+export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeFormDocumentViewProps>() {
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 : (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 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 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); }
@@ -176,7 +177,11 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
mixBlendMode,
display: this.ZInd === -99 ? "none" : undefined
}} >
- <DocumentView {...divProps} ref={action((r: DocumentView | null) => this._contentView = r)} />
+ {this.props.renderCutoffProvider(this.props.Document) ?
+ <div style={{ position: "absolute", width: this.panelWidth(), height: this.panelHeight(), background: "lightGreen" }} />
+ :
+ <DocumentView {...divProps} ref={action((r: DocumentView | null) => this._contentView = r)} />
+ }
</div>;
}
}
diff --git a/src/client/views/nodes/ColorBox.tsx b/src/client/views/nodes/ColorBox.tsx
index 8da5cd1b1..d975baf9b 100644
--- a/src/client/views/nodes/ColorBox.tsx
+++ b/src/client/views/nodes/ColorBox.tsx
@@ -3,9 +3,7 @@ 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";
@@ -17,11 +15,8 @@ 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<FieldViewProps, ColorDocument>(ColorDocument) {
+export class ColorBox extends ViewBoxBaseComponent<FieldViewProps>() {
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 d47e8340c..cbc61ffdb 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -2,8 +2,6 @@ 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';
@@ -15,15 +13,10 @@ 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<ViewBoxAnnotatableProps & FieldViewProps, ComparisonDocument>(ComparisonDocument) {
+export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps>() {
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 123212608..433a0bf48 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, Scripting, ts } from "../../util/Scripting";
+import { Transformer, 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 228e1bdcb..9ab3171d3 100644
--- a/src/client/views/nodes/DocumentLinksButton.scss
+++ b/src/client/views/nodes/DocumentLinksButton.scss
@@ -1,6 +1,8 @@
@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 93cd02d93..7e6ca4248 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -20,6 +20,7 @@ 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;
@@ -31,6 +32,7 @@ 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<DocumentLinksButtonProps, {}> {
@@ -302,16 +304,16 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
const title = this.props.InMenu ? menuTitle : buttonTitle;
//render circular tooltip if it isn't set to invisible and show the number of doc links the node has, and render inner-menu link button for starting/stopping links if currently in menu
- return !Array.from(this.filteredLinks).length && !this.props.AlwaysOn ? (null) :
- this.props.InMenu && (DocumentLinksButton.StartLink || this.props.StartLink) ?
- <Tooltip title={<div className="dash-tooltip">{title}</div>}>
- {this.linkButtonInner}
- </Tooltip>
- :
- !DocumentLinksButton.LinkEditorDocView && !this.props.InMenu ?
- <Tooltip title={<div className="dash-tooltip">{title}</div>}>
- {this.linkButtonInner}
- </Tooltip>
- : this.linkButtonInner;
+ return (!Array.from(this.filteredLinks).length && !this.props.AlwaysOn) ? (null) :
+ <div className="documentLinksButton-wrapper" >
+ {
+ (this.props.InMenu && (DocumentLinksButton.StartLink || this.props.StartLink)) ||
+ (!DocumentLinksButton.LinkEditorDocView && !this.props.InMenu) ?
+ <Tooltip title={<div className="dash-tooltip">{title}</div>}>
+ {this.linkButtonInner}
+ </Tooltip>
+ : this.linkButtonInner
+ }
+ </div>;
}
}
diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss
index 9fcd45e72..4565f8504 100644
--- a/src/client/views/nodes/DocumentView.scss
+++ b/src/client/views/nodes/DocumentView.scss
@@ -58,9 +58,10 @@
.documentView-audioBackground {
display: inline-block;
width: 10%;
+ height: 25;
position: absolute;
- top: 0px;
- left: 0px;
+ top: 10px;
+ left: 10px;
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 707c15bff..e7de87ea5 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1,3 +1,4 @@
+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";
@@ -9,11 +10,11 @@ import { List } from "../../../fields/List";
import { ObjectField } from "../../../fields/ObjectField";
import { listSpec } from "../../../fields/Schema";
import { ScriptField } from '../../../fields/ScriptField';
-import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../fields/Types";
+import { BoolCast, Cast, ImageCast, 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, OmitKeys, returnTrue, returnVal, Utils, lightOrDark, simulateMouseClick, returnEmptyString } from "../../../Utils";
+import { emptyFunction, hasDescendantTarget, lightOrDark, OmitKeys, returnEmptyString, returnTrue, returnVal, simulateMouseClick, Utils } from "../../../Utils";
import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils';
import { Docs, DocUtils } from "../../documents/Documents";
import { DocumentType } from '../../documents/DocumentTypes';
@@ -23,7 +24,7 @@ import { DocumentManager } from "../../util/DocumentManager";
import { DragManager, dropActionType } from "../../util/DragManager";
import { InteractionUtils } from '../../util/InteractionUtils';
import { LinkManager } from '../../util/LinkManager';
-import { Scripting } from '../../util/Scripting';
+import { ScriptingGlobals } from '../../util/ScriptingGlobals';
import { SelectionManager } from "../../util/SelectionManager";
import { SharingManager } from '../../util/SharingManager';
import { SnappingManager } from '../../util/SnappingManager';
@@ -48,8 +49,6 @@ 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 {
@@ -110,6 +109,7 @@ export interface DocumentViewSharedProps {
fitContentsToDoc?: () => boolean; // used by freeformview to fit its contents to its panel. corresponds to _fitToBox property on a Document
ContainingCollectionView: Opt<CollectionView>;
ContainingCollectionDoc: Opt<Doc>;
+ thumbShown?: () => boolean;
setContentView?: (view: DocComponentView) => any;
CollectionFreeFormDocumentView?: () => CollectionFreeFormDocumentView;
PanelWidth: () => number;
@@ -179,11 +179,12 @@ export interface DocumentViewInternalProps extends DocumentViewProps {
}
@observer
-export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps, Document>(Document) {
+export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps>() {
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;
@@ -204,6 +205,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
public get LayoutFieldKey() { return Doc.LayoutFieldKey(this.layoutDoc); }
@computed get ShowTitle() { return this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.ShowTitle) as (Opt<string>); }
@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); }
@@ -239,6 +241,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
this._multiTouchDisposer?.();
this._holdDisposer?.();
unbrush && Doc.UnBrushDoc(this.props.Document);
+ Object.values(this._disposers).forEach(disposer => disposer?.());
}
handle1PointerHoldStart = (e: Event, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>): any => {
@@ -485,6 +488,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
const func = () => this.onClickHandler.script.run({
this: this.layoutDoc,
self: this.rootDoc,
+ _readOnly_: false,
scriptContext: this.props.scriptContext,
thisContainer: this.props.ContainingCollectionDoc,
documentView: this.props.DocumentView(),
@@ -836,14 +840,13 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
this._componentView?.isAnyChildContentActive?.() ||
this.props.isContentActive()) ? true : undefined;
}
+ @observable _retryThumb = 1;
+ thumbShown = () => !this.props.isSelected() && LightboxView.LightboxDoc !== this.rootDoc && this.thumb &&
+ !this._componentView?.isAnyChildContentActive?.() ? true : false;
@computed get contents() {
TraceMobx();
const audioView = !this.layoutDoc._showAudio ? (null) :
- <div className="documentView-audioBackground"
- onPointerDown={this.recordAudioAnnotation}
- onPointerEnter={this.onPointerEnter}
- style={{ height: 25, position: "absolute", top: 10, left: 10 }}
- >
+ <div className="documentView-audioBackground" onPointerDown={this.recordAudioAnnotation} onPointerEnter={this.onPointerEnter} >
<FontAwesomeIcon className="documentView-audioFont"
style={{ color: [DocListCast(this.dataDoc[this.LayoutFieldKey + "-audioAnnotations"]).length ? "blue" : "gray", "green", "red"][this._mediaState] }}
icon={!DocListCast(this.dataDoc[this.LayoutFieldKey + "-audioAnnotations"]).length ? "microphone" : "file-audio"} size="sm" />
@@ -853,8 +856,17 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
pointerEvents: this.props.pointerEvents as any ? this.props.pointerEvents as any : (this.rootDoc.type !== DocumentType.INK && ((this.props.contentPointerEvents as any) || (this.isContentActive())) ? "all" : "none"),
height: this.headerMargin ? `calc(100% - ${this.headerMargin}px)` : undefined,
}}>
- <DocumentContentsView key={1} {...this.props}
+ {!this._retryThumb || !this.thumbShown() ? (null) :
+ <img style={{ background: "white", top: 0, position: "absolute" }} src={this.thumb} // + '?d=' + (new Date()).getTime()}
+ width={this.props.PanelWidth()} height={this.props.PanelHeight()}
+ onError={(e: any) => {
+ setTimeout(action(() => this._retryThumb = 0), 0);
+ setTimeout(action(() => this._retryThumb = 1), 150);
+ }} />}
+ <DocumentContentsView key={1}
+ {...this.props}
docViewPath={this.props.viewPath}
+ thumbShown={this.thumbShown}
setContentView={this.setContentView}
scaling={this.contentScaling}
PanelHeight={this.panelHeight}
@@ -866,11 +878,11 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
focus={this.focus}
layoutKey={this.finalLayoutKey} />
{this.layoutDoc.hideAllLinks ? (null) : this.allLinkEndpoints}
- {this.hideLinkButton || this.props.renderDepth === -1 ? (null) :
- <div style={{ transformOrigin: "top left", transform: `scale(${Math.min(1, this.props.ScreenToLocalTransform().scale(this.props.ContentScaling?.() || 1).Scale)})` }}>
- <DocumentLinksButton View={this.props.DocumentView()} Offset={[this.topMost ? 0 : -15, undefined, undefined, this.topMost ? 10 : -20]} />
- </div>}
-
+ {this.hideLinkButton || this.props.renderDepth === -1 || SnappingManager.GetIsDragging() ? (null) :
+ <DocumentLinksButton View={this.props.DocumentView()}
+ ContentScaling={this.props.ContentScaling}
+ Offset={[this.topMost ? 0 : -15, undefined, undefined, this.topMost ? 10 : -20]} />
+ }
{audioView}
</div>;
}
@@ -984,7 +996,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
captionStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewInternalProps>, property: string) => this.props?.styleProvider?.(doc, props, property + ":caption");
@computed get innards() {
TraceMobx();
- const ffscale = (this.props.DocumentView().props.CollectionFreeFormDocumentView?.().props.ScreenToLocalTransform().Scale || 1);
+ const ffscale = () => (this.props.DocumentView().props.CollectionFreeFormDocumentView?.().props.ScreenToLocalTransform().Scale || 1);
const showTitle = this.ShowTitle?.split(":")[0];
const showTitleHover = this.ShowTitle?.includes(":hover");
const showCaption = !this.props.hideCaptions && this.Document._viewType !== CollectionViewType.Carousel ? StrCast(this.layoutDoc._showCaption) : undefined;
@@ -992,14 +1004,14 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
<div className="documentView-captionWrapper"
style={{
pointerEvents: this.onClickHandler || this.Document.ignoreClick ? "none" : this.isContentActive() || this.props.isDocumentActive?.() ? "all" : undefined,
- minWidth: 50 * ffscale,
- maxHeight: `max(100%, ${20 * ffscale}px)`
+ minWidth: 50 * ffscale(),
+ maxHeight: `max(100%, ${20 * ffscale()}px)`
}}>
<FormattedTextBox {...OmitKeys(this.props, ['children']).omit}
yPadding={10}
xPadding={10}
fieldKey={showCaption}
- fontSize={12 * Math.max(1, 2 * ffscale / 3)}
+ fontSize={12 * Math.max(1, 2 * ffscale() / 3)}
styleProvider={this.captionStyleProvider}
dontRegisterView={true}
noSidebar={true}
@@ -1023,19 +1035,18 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
display={"block"}
fontSize={10}
GetValue={() => showTitle.split(";").length === 1 ? showTitle + "=" + Field.toString(targetDoc[showTitle.split(";")[0]] as any as Field) : "#" + showTitle}
- SetValue={undoBatch(input => {
+ SetValue={undoBatch((input: string) => {
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 + "="), "");
+ var value = input.replace(new RegExp(showTitle + "="), "") as string | number;
if (showTitle !== "title" && Number(value).toString() === value) value = Number(value);
if (showTitle.includes("Date") || showTitle === "author") return true;
- return Doc.SetInPlace(targetDoc, showTitle, value, true) ? true : true;
+ Doc.SetInPlace(targetDoc, showTitle, value, true);
}
return true;
})}
@@ -1048,15 +1059,17 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
{captionView}
</div>;
}
+ @observable _: string = "";
@computed get renderDoc() {
TraceMobx();
- const isButton: boolean = this.props.Document.type === DocumentType.FONTICON;
+ 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;
if (!(this.props.Document instanceof Doc) || GetEffectiveAcl(this.props.Document[DataSym]) === AclPrivate || this.hidden) return null;
return this.docContents ??
<div className={`documentView-node${this.topMost ? "-topmost" : ""}`}
id={this.props.Document[Id]}
style={{
- background: isButton ? undefined : this.backgroundColor,
+ background: isButton || thumb ? undefined : this.backgroundColor,
opacity: this.opacity,
color: StrCast(this.layoutDoc.color, "inherit"),
fontFamily: StrCast(this.Document._fontFamily, "inherit"),
@@ -1065,6 +1078,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
transform: this._animateScalingTo ? `scale(${this._animateScalingTo})` : undefined,
transition: !this._animateScalingTo ? StrCast(this.Document.dataTransition) : `transform 0.5s ease-${this._animateScalingTo < 1 ? "in" : "out"}`,
}}>
+
{this.innards}
{this.onClickHandler && this.props.ContainingCollectionView?.props.Document._viewType === CollectionViewType.Time ? <div className="documentView-contentBlocker" /> : (null)}
{this.widgetDecorations ?? null}
@@ -1143,7 +1157,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
get LayoutFieldKey() { return this.docView?.LayoutFieldKey || "layout"; }
get fitWidth() { return this.props.fitWidth?.(this.rootDoc) || this.layoutDoc.fitWidth; }
- @computed get docViewPath() { return this.props.docViewPath ? [...this.props.docViewPath(), this] : [this]; }
+ @computed get docViewPath(): DocumentView[] { 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 :
@@ -1281,7 +1295,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
}
}
-Scripting.addGlobal(function toggleDetail(dv: DocumentView, detailLayoutKeySuffix: string) {
+ScriptingGlobals.add(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 f1f802c13..c170f9867 100644
--- a/src/client/views/nodes/EquationBox.tsx
+++ b/src/client/views/nodes/EquationBox.tsx
@@ -3,25 +3,18 @@ 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 { FieldView, FieldViewProps } from './FieldView';
import './EquationBox.scss';
+import { FieldView, FieldViewProps } from './FieldView';
-const EquationSchema = createSchema({});
-
-type EquationDocument = makeInterface<[typeof EquationSchema, typeof documentSchema]>;
-const EquationDocument = makeInterface(EquationSchema, documentSchema);
-
@observer
-export class EquationBox extends ViewBoxBaseComponent<FieldViewProps, EquationDocument>(EquationDocument) {
+export class EquationBox extends ViewBoxBaseComponent<FieldViewProps>() {
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(EquationBox, fieldKey); }
public static SelectOnLoad: string = "";
_ref: React.RefObject<EquationEditor> = React.createRef();
diff --git a/src/client/views/nodes/FilterBox.tsx b/src/client/views/nodes/FilterBox.tsx
index fb8e89da9..ba65acee0 100644
--- a/src/client/views/nodes/FilterBox.tsx
+++ b/src/client/views/nodes/FilterBox.tsx
@@ -4,18 +4,17 @@ 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, makeInterface } from "../../../fields/Schema";
+import { listSpec } from "../../../fields/Schema";
import { ComputedField, ScriptField } from "../../../fields/ScriptField";
-import { Cast, StrCast, NumCast } from "../../../fields/Types";
+import { Cast, NumCast, StrCast } 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 { Scripting } from "../../util/Scripting";
+import { ScriptingGlobals } from "../../util/ScriptingGlobals";
import { SelectionManager } from "../../util/SelectionManager";
import { CollectionTreeView } from "../collections/CollectionTreeView";
import { CollectionView } from "../collections/CollectionView";
@@ -30,11 +29,8 @@ 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<FieldViewProps, FilterBoxDocument>(FilterBoxDocument) {
+export class FilterBox extends ViewBoxBaseComponent<FieldViewProps>() {
constructor(props: Readonly<FieldViewProps>) {
super(props);
@@ -425,7 +421,6 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc
treeViewHideTitle={true}
focus={returnFalse}
treeViewHideHeaderFields={false}
- onCheckedClick={this.scriptField}
dontRegisterView={true}
styleProvider={this.FilterStyleProvider}
layerProvider={this.props.layerProvider}
@@ -475,7 +470,7 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc
}
}
-Scripting.addGlobal(function determineCheckedState(layoutDoc: Doc, facetHeader: string, facetValue: string) {
+ScriptingGlobals.add(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
@@ -485,7 +480,7 @@ Scripting.addGlobal(function determineCheckedState(layoutDoc: Doc, facetHeader:
}
return undefined;
});
-Scripting.addGlobal(function readFacetData(layoutDoc: Doc, childKey: string, facetHeader: string) {
+ScriptingGlobals.add(function readFacetData(layoutDoc: Doc, childKey: string, facetHeader: string) {
const allCollectionDocs = new Set<Doc>();
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 5050fc2d2..3ab0a3ff2 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<FieldViewProps, EquationDocument>(EquationDocument) {
+export class FunctionPlotBox extends ViewBoxBaseComponent<FieldViewProps>() {
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 89f70985c..0a4168698 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, trace } from 'mobx';
+import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } 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, makeInterface } from '../../../fields/Schema';
+import { createSchema } from '../../../fields/Schema';
import { ComputedField } from '../../../fields/ScriptField';
import { Cast, NumCast } from '../../../fields/Types';
import { ImageField } from '../../../fields/URLField';
@@ -29,16 +29,11 @@ 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",
@@ -47,7 +42,7 @@ const uploadIcons = {
};
@observer
-export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps, ImageDocument>(ImageDocument) {
+export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps>() {
protected _multiTouchDisposer?: import("../../util/InteractionUtils").InteractionUtils.MultiTouchEventDisposer | undefined;
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ImageBox, fieldKey); }
private _imgRef: React.RefObject<HTMLImageElement> = React.createRef();
@@ -190,7 +185,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
if (url.href.indexOf(window.location.origin) === -1) return Utils.CorsProxy(url.href);
if (!/\.(png|jpg|jpeg|gif|webp)$/.test(lower)) return url.href; //Why is this here
- const ext = path.extname(url.href);
+ const ext = extname(url.href);
return url.href.replace(ext, this._curSuffix + ext);
}
@@ -286,7 +281,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
}
return <div className="imageBox-cont" key={this.layoutDoc[Id]} ref={this.createDropTarget} onPointerDown={this.marqueeDown}>
- <div className="imageBox-fader" style={{ overflow: this.props.docViewPath?.().lastElement().fitWidth ? "auto" : undefined }} >
+ <div className="imageBox-fader" style={{ overflow: Array.from(this.props.docViewPath?.()).slice(-1)[0].fitWidth ? "auto" : undefined }} >
<img key="paths" ref={this._imgRef}
src={srcpath}
style={{ transform, transformOrigin }}
@@ -376,7 +371,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
scrollTop={0}
down={this._marqueeing}
scaling={this.props.scaling}
- docView={this.props.docViewPath().lastElement()}
+ docView={this.props.docViewPath().slice(-1)[0]}
addDocument={this.addDocument}
finishMarquee={this.finishMarquee}
savedAnnotations={this._savedAnnotations}
diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index 111509fdb..c44c8c828 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -58,7 +58,7 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
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", _last_: "any" }, editable: false };
+ const options: ScriptOptions = { addReturn: true, params: { this: Doc.name, self: Doc.name, _last_: "any", _readOnly_: "boolean" }, 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 dae72bb78..0015f0b71 100644
--- a/src/client/views/nodes/LabelBox.tsx
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -2,9 +2,8 @@ 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 { createSchema, listSpec, makeInterface } from '../../../fields/Schema';
+import { listSpec } from '../../../fields/Schema';
import { Cast, StrCast } from '../../../fields/Types';
import { DragManager } from '../../util/DragManager';
import { undoBatch } from '../../util/UndoManager';
@@ -16,17 +15,13 @@ 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), LabelDocument>(LabelDocument) {
+export class LabelBox extends ViewBoxBaseComponent<(FieldViewProps & LabelBoxProps)>() {
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., "<ImageBox {...props} fieldKey={"data} />"
diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx
index a7bfb93eb..437d29f39 100644
--- a/src/client/views/nodes/LinkAnchorBox.tsx
+++ b/src/client/views/nodes/LinkAnchorBox.tsx
@@ -2,8 +2,6 @@ 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';
@@ -23,11 +21,9 @@ 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<FieldViewProps, LinkAnchorSchema>(LinkAnchorDocument) {
+export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps>() {
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 879a63248..43f4b43fb 100644
--- a/src/client/views/nodes/LinkBox.tsx
+++ b/src/client/views/nodes/LinkBox.tsx
@@ -1,7 +1,5 @@
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";
@@ -9,11 +7,8 @@ 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<FieldViewProps, LinkDocument>(LinkDocument) {
+export class LinkBox extends ViewBoxBaseComponent<FieldViewProps>() {
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 50444c73a..aa2130af5 100644
--- a/src/client/views/nodes/MapBox/MapBox.tsx
+++ b/src/client/views/nodes/MapBox/MapBox.tsx
@@ -1,14 +1,11 @@
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';
@@ -43,9 +40,6 @@ 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%',
};
@@ -59,7 +53,6 @@ const mapOptions = {
fullscreenControl: false,
};
-dotenv.config({ path: __dirname + '/.env' });
const apiKey = process.env.GOOGLE_MAPS;
const script = document.createElement('script');
@@ -93,7 +86,7 @@ const options = {
} as google.maps.places.AutocompleteOptions;
@observer
-export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps & Partial<GoogleMapProps>, MapDocument>(MapDocument) {
+export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps & Partial<GoogleMapProps>>() {
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 f44355929..8a68f9647 100644
--- a/src/client/views/nodes/PDFBox.scss
+++ b/src/client/views/nodes/PDFBox.scss
@@ -248,6 +248,7 @@
.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 d54b65d92..9807cee7c 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -3,17 +3,14 @@ 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, StrListCast } from "../../../fields/Doc";
-import { documentSchema } from '../../../fields/documentSchemas';
-import { makeInterface, listSpec } from "../../../fields/Schema";
-import { Cast, NumCast, StrCast } from '../../../fields/Types';
+import { Doc, DocListCast, Opt, WidthSym } from "../../../fields/Doc";
+import { Cast, NumCast, StrCast, ImageCast } 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";
@@ -22,18 +19,14 @@ 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<ViewBoxAnnotatableProps & FieldViewProps, PdfDocument>(PdfDocument) {
+export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps>() {
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PDFBox, fieldKey); }
public static openSidebarWidth = 250;
+ public static sidebarResizerWidth = 5;
private _searchString: string = "";
private _initialScrollTarget: Opt<Doc>;
private _pdfViewer: PDFViewer | undefined;
@@ -46,6 +39,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
@observable private _pageControls = false;
@computed get pdfUrl() { return Cast(this.dataDoc[this.props.fieldKey], PdfField); }
+ @computed get pdfThumb() { return ImageCast(this.layoutDoc["thumb-frozen"], ImageCast(this.layoutDoc.thumb))?.url; }
constructor(props: any) {
super(props);
@@ -54,7 +48,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
!this.Document._fitWidth && (this.Document._height = this.Document[WidthSym]() * (nh / nw));
if (this.pdfUrl) {
if (PDFBox.pdfcache.get(this.pdfUrl.url.href)) runInAction(() => 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 => this._pdf = pdf));
+ else if (PDFBox.pdfpromise.get(this.pdfUrl.url.href)) PDFBox.pdfpromise.get(this.pdfUrl.url.href)?.then(action((pdf: any) => this._pdf = pdf));
}
}
@@ -80,7 +74,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
const anchor =
AnchorMenu.Instance?.GetAnchor() ??
Docs.Create.TextanchorDocument({
- title: StrCast(this.rootDoc.title + "@" + this.layoutDoc._scrollTop?.toFixed(0)),
+ title: StrCast(this.rootDoc.title + "@" + NumCast(this.layoutDoc._scrollTop)?.toFixed(0)),
y: NumCast(this.layoutDoc._scrollTop),
unrendered: true
});
@@ -110,8 +104,8 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
});
public prevAnnotation = () => this._pdfViewer?.prevAnnotation();
public nextAnnotation = () => this._pdfViewer?.nextAnnotation();
- 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 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 gotoPage = (p: number) => this.Document._curPage = p;
@undoBatch
@@ -142,15 +136,15 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
if (!this.layoutDoc._showSidebar) this.toggleSidebar();
return this.addDocument(doc, sidebarKey);
}
- sidebarBtnDown = (e: React.PointerEvent) => {
+ sidebarBtnDown = (e: React.PointerEvent, onButton: boolean) => { // onButton determines whether the width of the pdf box changes, or just the ratio of the sidebar to the pdf
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 + localDelta[0] / (this.props.scaling?.() || 1)) / nativeWidth;
+ const ratio = (curNativeWidth + (onButton ? 1 : -1) * localDelta[0] / (this.props.scaling?.() || 1)) / nativeWidth;
if (ratio >= 1) {
this.layoutDoc.nativeWidth = nativeWidth * ratio;
- this.layoutDoc._width = this.layoutDoc[WidthSym]() + localDelta[0];
+ onButton && (this.layoutDoc._width = this.layoutDoc[WidthSym]() + localDelta[0]);
this.layoutDoc._showSidebar = nativeWidth !== this.layoutDoc._nativeWidth;
}
return false;
@@ -160,16 +154,17 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
@observable _previewWidth: Opt<number> = undefined;
toggleSidebar = action((preview: boolean = false) => {
const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + "-nativeWidth"]);
- const ratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? PDFBox.openSidebarWidth : 0) + nativeWidth) / 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 curNativeWidth = NumCast(this.layoutDoc.nativeWidth, nativeWidth);
if (preview) {
- this._previewNativeWidth = nativeWidth * ratio;
- this._previewWidth = this.layoutDoc[WidthSym]() * nativeWidth * ratio / curNativeWidth;
+ this._previewNativeWidth = nativeWidth * sideratio;
+ this._previewWidth = this.layoutDoc[WidthSym]() * nativeWidth * sideratio / curNativeWidth;
this._showSidebar = true;
}
else {
- this.layoutDoc.nativeWidth = nativeWidth * ratio;
- this.layoutDoc._width = this.layoutDoc[WidthSym]() * nativeWidth * ratio / curNativeWidth;
+ this.layoutDoc.nativeWidth = nativeWidth * pdfratio;
+ this.layoutDoc._width = this.layoutDoc[WidthSym]() * nativeWidth * pdfratio / curNativeWidth;
this.layoutDoc._showSidebar = nativeWidth !== this.layoutDoc._nativeWidth;
}
});
@@ -185,7 +180,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
</button>
</>;
const searchTitle = `${!this._searching ? "Open" : "Close"} Search Bar`;
- const curPage = this.Document._curPage || 1;
+ const curPage = NumCast(this.Document._curPage) || 1;
return !this.props.isContentActive() ? (null) :
<div className="pdfBox-ui" onKeyDown={e => [KeyCodes.BACKSPACE, KeyCodes.DELETE].includes(e.keyCode) ? e.stopPropagation() : true}
onPointerDown={e => e.stopPropagation()} style={{ display: this.props.isContentActive() ? "flex" : "none" }}>
@@ -223,7 +218,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
top: StrCast(this.rootDoc._showTitle) === "title" ? 20 : 5,
backgroundColor: this.SidebarShown ? Colors.MEDIUM_BLUE : Colors.BLACK
}}
- onPointerDown={this.sidebarBtnDown} >
+ onPointerDown={e => this.sidebarBtnDown(e, true)} >
<FontAwesomeIcon style={{ color: Colors.WHITE }} icon={"comment-alt"} size="sm" />
</div>
</div>;
@@ -253,18 +248,20 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
@computed get SidebarShown() { return this._showSidebar || this.layoutDoc._showSidebar ? true : false; }
contentScaling = () => 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 <div className={"pdfBox"} onContextMenu={this.specificContextMenu}
style={{
+ display: this.props.thumbShown?.() ? "none" : undefined,
height: this.props.Document._scrollTop && !this.Document._fitWidth && (window.screen.width > 600) ?
NumCast(this.Document._height) * this.props.PanelWidth() / NumCast(this.Document._width) : undefined
}}>
- <div className="pdfBox-background" />
+ <div className="pdfBox-background" onPointerDown={e => this.sidebarBtnDown(e, false)} />
<div style={{
- width: `calc(${100 / scale}% - ${this.sidebarWidth() / scale * (this._previewWidth ? scale : 1)}px)`,
+ width: `calc(${100 / scale}% - ${(this.sidebarWidth() + PDFBox.sidebarResizerWidth) / scale * (this._previewWidth ? scale : 1)}px)`,
height: `${100 / scale}%`,
transform: `scale(${scale})`,
position: "absolute",
@@ -277,7 +274,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
dataDoc={this.dataDoc}
pdf={this._pdf!}
url={this.pdfUrl!.url.pathname}
- isContentActive={this.props.isContentActive}
+ isContentActive={this.isPdfContentActive}
anchorMenuClick={this.anchorMenuClick}
loaded={!Doc.NativeAspect(this.dataDoc) ? this.loaded : undefined}
setPdfViewer={this.setPdfViewer}
@@ -307,17 +304,22 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
}
static pdfcache = new Map<string, Pdfjs.PDFDocumentProxy>();
- static pdfpromise = new Map<string, Pdfjs.PDFPromise<Pdfjs.PDFDocumentProxy>>();
+ static pdfpromise = new Map<string, Promise<Pdfjs.PDFDocumentProxy>>();
render() {
TraceMobx();
- if (this._pdf) return this.renderPdfView;
+ if (this._pdf) {
+ if (!this.props.thumbShown?.()) {
+ return this.renderPdfView;
+ }
+ return null;
+ }
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 => PDFBox.pdfcache.set(href, this._pdf = pdf)));
+ PDFBox.pdfpromise.get(href)?.then(action((pdf: any) => 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 0c631e5f9..dbb567d3a 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -1,20 +1,17 @@
import React = require("react");
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
// import { Canvas } from '@react-three/fiber';
-import { action, computed, observable, reaction, trace, runInAction } from "mobx";
+import { computed, observable, runInAction } from "mobx";
import { observer } from "mobx-react";
// import { BufferAttribute, Camera, Vector2, Vector3 } from 'three';
import { DateField } from "../../../fields/DateField";
-import { Doc, WidthSym, HeightSym } from "../../../fields/Doc";
-import { documentSchema } from "../../../fields/documentSchemas";
+import { Doc, HeightSym, WidthSym } from "../../../fields/Doc";
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, numberRange, OmitKeys, returnFalse, returnOne, Utils } from "../../../Utils";
+import { emptyFunction, OmitKeys, returnFalse, returnOne } from "../../../Utils";
import { DocUtils } from "../../documents/Documents";
import { DocumentType } from "../../documents/DocumentTypes";
import { Networking } from "../../Network";
@@ -32,9 +29,6 @@ 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;
@@ -112,7 +106,7 @@ const ScreenshotDocument = makeInterface(documentSchema);
// }
@observer
-export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps, ScreenshotDocument>(ScreenshotDocument) {
+export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps>() {
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 183140cd7..366c3fc2f 100644
--- a/src/client/views/nodes/ScriptingBox.tsx
+++ b/src/client/views/nodes/ScriptingBox.tsx
@@ -1,18 +1,19 @@
import ReactTextareaAutocomplete from "@webscopeio/react-textarea-autocomplete";
import "@webscopeio/react-textarea-autocomplete/style.css";
-import { action, computed, observable, runInAction, trace } from "mobx";
+import { action, computed, observable } 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 { createSchema, listSpec, makeInterface } from "../../../fields/Schema";
+import { listSpec } from "../../../fields/Schema";
import { ScriptField } from "../../../fields/ScriptField";
-import { Cast, NumCast, ScriptCast, StrCast, BoolCast } from "../../../fields/Types";
+import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../fields/Types";
+import { TraceMobx } from "../../../fields/util";
import { returnEmptyString } from "../../../Utils";
import { DragManager } from "../../util/DragManager";
import { InteractionUtils } from "../../util/InteractionUtils";
-import { CompileScript, Scripting, ScriptParam } from "../../util/Scripting";
+import { CompileScript, ScriptParam } from "../../util/Scripting";
+import { ScriptingGlobals } from "../../util/ScriptingGlobals";
import { ScriptManager } from "../../util/ScriptManager";
import { ContextMenu } from "../ContextMenu";
import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from "../DocComponent";
@@ -21,15 +22,10 @@ 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<ViewBoxAnnotatableProps & FieldViewProps, ScriptingDocument>(ScriptingDocument) {
+export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps>() {
private dropDisposer?: DragManager.DragDropDisposer;
protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer | undefined;
@@ -42,9 +38,9 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
@observable private _function: boolean = false;
@observable private _spaced: boolean = false;
- @observable private _scriptKeys: any = Scripting.getGlobals();
- @observable private _scriptingDescriptions: any = Scripting.getDescriptions();
- @observable private _scriptingParams: any = Scripting.getParameters();
+ @observable private _scriptKeys: any = ScriptingGlobals.getGlobals();
+ @observable private _scriptingDescriptions: any = ScriptingGlobals.getDescriptions();
+ @observable private _scriptingParams: any = ScriptingGlobals.getParameters();
@observable private _currWord: string = "";
@observable private _suggestions: string[] = [];
@@ -224,9 +220,9 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
ScriptManager.Instance.addScript(this.dataDoc);
- this._scriptKeys = Scripting.getGlobals();
- this._scriptingDescriptions = Scripting.getDescriptions();
- this._scriptingParams = Scripting.getParameters();
+ this._scriptKeys = ScriptingGlobals.getGlobals();
+ this._scriptingDescriptions = ScriptingGlobals.getDescriptions();
+ this._scriptingParams = ScriptingGlobals.getParameters();
}
// overlays document numbers (ex. d32) over all documents when clicked on
@@ -577,8 +573,8 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
</div>;
}
- renderFuncListElement(value: string) {
- return <div>
+ renderFuncListElement(value: string | object) {
+ return (typeof value !== "string") ? (null) : <div>
<div style={{ fontSize: "14px" }}>
{value}
</div>
diff --git a/src/client/views/nodes/SliderBox.tsx b/src/client/views/nodes/SliderBox.tsx
index 92d1f7446..b96977f32 100644
--- a/src/client/views/nodes/SliderBox.tsx
+++ b/src/client/views/nodes/SliderBox.tsx
@@ -2,30 +2,19 @@ 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<FieldViewProps, SliderDocument>(SliderDocument) {
+export class SliderBox extends ViewBoxBaseComponent<FieldViewProps>() {
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 56cb562bc..fafa39deb 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -3,11 +3,10 @@ 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";
@@ -36,7 +35,7 @@ type VideoDocument = makeInterface<[typeof documentSchema]>;
const VideoDocument = makeInterface(documentSchema);
@observer
-export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps, VideoDocument>(VideoDocument) {
+export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps>() {
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(VideoBox, fieldKey); }
static async convertDataUri(imageUri: string, returnedFilename: string) {
try {
@@ -189,7 +188,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
}
@action public Snapshot(downX?: number, downY?: number) {
- const width = (this.layoutDoc._width || 0);
+ const width = NumCast(this.layoutDoc._width);
const canvas = document.createElement('canvas');
canvas.width = 640;
canvas.height = 640 * Doc.NativeHeight(this.layoutDoc) / (Doc.NativeWidth(this.layoutDoc) || 1);
@@ -203,7 +202,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
if (!this._videoRef) {
const b = Docs.Create.LabelDocument({
- x: (this.layoutDoc.x || 0) + width, y: (this.layoutDoc.y || 1),
+ x: NumCast(this.layoutDoc.x) + width, y: NumCast(this.layoutDoc.y, 1),
_width: 150, _height: 50, title: (this.layoutDoc._currentTimecode || 0).toString(),
_isLinkButton: true
});
@@ -224,7 +223,8 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
const dataUrl = canvas.toDataURL('image/png'); // can also use 'image/png'
// if you want to preview the captured image,
const retitled = StrCast(this.rootDoc.title).replace(/[ -\.]/g, "");
- const filename = path.basename(encodeURIComponent("snapshot" + retitled + "_" + (this.layoutDoc._currentTimecode || 0).toString().replace(/\./, "_")));
+ const encodedFilename = encodeURIComponent("snapshot" + retitled + "_" + (this.layoutDoc._currentTimecode || 0).toString().replace(/\./, "_"));
+ const filename = basename(encodedFilename);
VideoBox.convertDataUri(dataUrl, filename).then((returnedFilename: string) =>
returnedFilename && this.createRealSummaryLink(returnedFilename, downX, downY));
}
@@ -232,12 +232,12 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
createRealSummaryLink = (imagePath: string, downX?: number, downY?: number) => {
const url = !imagePath.startsWith("/") ? Utils.CorsProxy(imagePath) : imagePath;
- const width = this.layoutDoc._width || 1;
- const height = this.layoutDoc._height || 0;
+ const width = NumCast(this.layoutDoc._width) || 1;
+ const height = NumCast(this.layoutDoc._height);
const imageSummary = Docs.Create.ImageDocument(url, {
_nativeWidth: Doc.NativeWidth(this.layoutDoc), _nativeHeight: Doc.NativeHeight(this.layoutDoc),
- 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-"
+ 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-"
});
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<ViewBoxAnnotatableProp
// @ts-ignore
// vref.onfullscreenchange = action((e) => this._fullScreen = vref.webkitDisplayingFullscreen);
this._disposers.reactionDisposer?.();
- this._disposers.reactionDisposer = reaction(() => (this.layoutDoc._currentTimecode || 0),
+ this._disposers.reactionDisposer = reaction(() => NumCast(this.layoutDoc._currentTimecode),
time => !this._playing && (vref.currentTime = time), { fireImmediately: true });
}
}
@@ -373,7 +373,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
const onYoutubePlayerReady = (event: any) => {
this._disposers.reactionDisposer?.();
this._disposers.youtubeReactionDisposer?.();
- this._disposers.reactionDisposer = reaction(() => this.layoutDoc._currentTimecode, () => !this._playing && this.Seek((this.layoutDoc._currentTimecode || 0)));
+ this._disposers.reactionDisposer = reaction(() => this.layoutDoc._currentTimecode, () => !this._playing && this.Seek(NumCast(this.layoutDoc._currentTimecode)));
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<ViewBoxAnnotatableProp
this._youtubeIframeId = VideoBox._youtubeIframeCounter++;
this._youtubeContentCreated = this._forceCreateYouTubeIFrame ? true : true;
const classname = "videoBox-content-YouTube" + (this._fullScreen ? "-fullScreen" : "");
- const start = untracked(() => Math.round((this.layoutDoc._currentTimecode || 0)));
+ const start = untracked(() => Math.round(NumCast(this.layoutDoc._currentTimecode)));
return <iframe key={this._youtubeIframeId} id={`${this.youtubeVideoId + this._youtubeIframeId}-player`}
onPointerLeave={this.updateTimecode}
onLoad={this.youtubeIframeLoaded} className={classname} width={Doc.NativeWidth(this.layoutDoc) || 640} height={Doc.NativeHeight(this.layoutDoc) || 390}
@@ -719,7 +719,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
style={{
pointerEvents: this.props.layerProvider?.(this.layoutDoc) === false ? "none" : undefined,
borderRadius,
- overflow: this.props.docViewPath?.().lastElement().fitWidth ? "auto" : undefined
+ overflow: this.props.docViewPath?.().slice(-1)[0].fitWidth ? "auto" : undefined
}} onWheel={e => { e.stopPropagation(); e.preventDefault(); }}>
<div className="videoBox-viewer" onPointerDown={this.marqueeDown} >
<div style={{
@@ -755,7 +755,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
scrollTop={0}
down={this._marqueeing}
scaling={this.marqueeFitScaling}
- docView={this.props.docViewPath().lastElement()}
+ docView={this.props.docViewPath().slice(-1)[0]}
containerOffset={this.marqueeOffset}
addDocument={this.addDocWithTimecode}
finishMarquee={this.finishMarquee}
diff --git a/src/client/views/nodes/WebBox.scss b/src/client/views/nodes/WebBox.scss
index 79289abaa..7dc970496 100644
--- a/src/client/views/nodes/WebBox.scss
+++ b/src/client/views/nodes/WebBox.scss
@@ -5,6 +5,12 @@
height: 100%;
position: relative;
display: flex;
+ .webBox-background {
+ width: 100%;
+ height: 100%;
+ cursor: ew-resize;
+ background: lightGray;
+ }
.webBox-ui {
position: absolute;
@@ -137,6 +143,7 @@
transform-origin: top left;
width: 100%;
height: 100%;
+ position: absolute;
.webBox-htmlSpan {
position: absolute;
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 9956cc36b..7ff47107e 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -3,21 +3,20 @@ import { action, computed, IReactionDisposer, observable, ObservableMap, reactio
import { observer } from "mobx-react";
import * as WebRequest from 'web-request';
import { Doc, DocListCast, HeightSym, Opt, WidthSym } from "../../../fields/Doc";
-import { documentSchema } from "../../../fields/documentSchemas";
import { Id } from "../../../fields/FieldSymbols";
import { HtmlField } from "../../../fields/HtmlField";
import { InkTool } from "../../../fields/InkField";
import { List } from "../../../fields/List";
-import { listSpec, makeInterface } from "../../../fields/Schema";
+import { listSpec } from "../../../fields/Schema";
import { ComputedField } from "../../../fields/ScriptField";
-import { Cast, NumCast, StrCast } from "../../../fields/Types";
-import { WebField } from "../../../fields/URLField";
+import { Cast, ImageCast, NumCast, StrCast } from "../../../fields/Types";
+import { ImageField, WebField } from "../../../fields/URLField";
import { TraceMobx } from "../../../fields/util";
import { emptyFunction, getWordAtPoint, OmitKeys, returnFalse, returnOne, setupMoveUpEvents, smoothScroll, Utils } from "../../../Utils";
import { Docs } from "../../documents/Documents";
import { CurrentUserUtils } from "../../util/CurrentUserUtils";
import { KeyCodes } from "../../util/KeyCodes";
-import { Scripting } from "../../util/Scripting";
+import { ScriptingGlobals } from "../../util/ScriptingGlobals";
import { SnappingManager } from "../../util/SnappingManager";
import { undoBatch } from "../../util/UndoManager";
import { MarqueeOptionsMenu } from "../collections/collectionFreeForm";
@@ -36,18 +35,18 @@ import { StyleProp } from "../StyleProvider";
import { DocumentViewProps } from "./DocumentView";
import { FieldView, FieldViewProps } from './FieldView';
import { LinkDocPreview } from "./LinkDocPreview";
+import { VideoBox } from "./VideoBox";
import "./WebBox.scss";
import React = require("react");
+const { CreateImage } = require("./WebBoxRenderer");
const _global = (window /* browser */ || global /* node */) as any;
const htmlToText = require("html-to-text");
-type WebDocument = makeInterface<[typeof documentSchema]>;
-const WebDocument = makeInterface(documentSchema);
-
@observer
-export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps, WebDocument>(WebDocument) {
+export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps>() {
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(WebBox, fieldKey); }
public static openSidebarWidth = 250;
+ public static sidebarResizerWidth = 5;
private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean, hide: boolean) => void);
private _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
private _outerRef: React.RefObject<HTMLDivElement> = React.createRef();
@@ -63,6 +62,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
@observable private _searching: boolean = false;
@observable private _showSidebar = false;
@observable private _scrollTimer: any;
+ @observable private _webPageHasBeenRendered = false;
@observable private _overlayAnnoInfo: Opt<Doc>;
@observable private _marqueeing: number[] | undefined;
@observable private _isAnnotating = false;
@@ -76,6 +76,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
@computed get allAnnotations() { return DocListCast(this.dataDoc[this.annotationKey]); }
@computed get inlineTextAnnotations() { return this.allAnnotations.filter(a => a.textInlineAnnotations); }
@computed get webField() { return Cast(this.dataDoc[this.props.fieldKey], WebField)?.url; }
+ @computed get webThumb() { return ImageCast(this.layoutDoc["thumb-frozen"], ImageCast(this.layoutDoc.thumb))?.url; }
constructor(props: any) {
super(props);
@@ -103,7 +104,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
return true;
}
async componentDidMount() {
- this.props.setContentView?.(this); // this tells the DocumentView that this AudioBox is the "content" of the document. this allows the DocumentView to indirectly call getAnchor() on the AudioBox when making a link.
+ this.props.setContentView?.(this); // this tells the DocumentView that this WebBox is the "content" of the document. this allows the DocumentView to call WebBox relevant methods to configure the UI (eg, show back/forward buttons)
runInAction(() => {
this._annotationKeySuffix = () => this._urlHash + "-annotations";
@@ -111,6 +112,48 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
this.dataDoc[this.fieldKey + "-annotations"] = ComputedField.MakeFunction(`copyField(this["${this.fieldKey}-"+urlHash(this["${this.fieldKey}"]?.url?.toString())+"-annotations"`);
this.dataDoc[this.fieldKey + "-sidebar"] = ComputedField.MakeFunction(`copyField(this["${this.fieldKey}-"+urlHash(this["${this.fieldKey}"]?.url?.toString())+"-sidebar"`);
});
+ reaction(() => this.props.isSelected(),
+ async (selected) => {
+ if (selected) {
+ this._webPageHasBeenRendered = true;
+ setTimeout(action(() => {
+ this._scrollHeight = Math.max(this.scrollHeight, this._iframe?.contentDocument?.body.scrollHeight || 0);
+ if (this._initialScroll !== undefined && this._outerRef.current) {
+ setTimeout(() => {
+ this._outerRef.current!.scrollTop = this._initialScroll!;
+ this._initialScroll = undefined;
+ });
+ }
+ }));
+ } else if (!this.props.isContentActive() &&
+ !this.props.docViewPath().lastElement()?.docView?._pendingDoubleClick && /// don't create a thumbnail when double-clicking to enter lightbox because thumbnail will be empty
+ LightboxView.LightboxDoc !== this.rootDoc) { // don't create a thumbnail if entering Lightbox from maximize either, since thumb will be empty.
+ const imageBitmap = ImageCast(this.layoutDoc["thumb-frozen"])?.url.href;
+ if (this._iframe && !imageBitmap) {
+ var htmlString = this._iframe.contentDocument && new XMLSerializer().serializeToString(this._iframe.contentDocument);
+ if (!htmlString) {
+ htmlString = await (await fetch(Utils.CorsProxy(this.webField!.href))).text();
+ }
+ this.layoutDoc.thumb = undefined;
+ const nativeWidth = NumCast(this.layoutDoc.nativeWidth);
+ CreateImage(
+ this._webUrl.endsWith("/") ? this._webUrl.substring(0, this._webUrl.length - 1) : this._webUrl,
+ this._iframe.contentDocument?.styleSheets ?? [],
+ htmlString,
+ nativeWidth,
+ nativeWidth * this.props.PanelHeight() / this.props.PanelWidth(),
+ NumCast(this.layoutDoc._scrollTop)
+ ).then
+ ((dataUrl: any) => {
+ VideoBox.convertDataUri(dataUrl, this.layoutDoc[Id] + "-thumb" + (new Date()).getTime(), true).then(
+ returnedfilename => setTimeout(action(() => this.layoutDoc.thumb = new ImageField(returnedfilename)), 500));
+ })
+ .catch(function (error: any) {
+ console.error('oops, something went wrong!', error);
+ });
+ }
+ }
+ });
this._disposers.autoHeight = reaction(() => this.layoutDoc._autoHeight,
autoHeight => {
@@ -292,12 +335,6 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
iframe.contentDocument.addEventListener("pointerdown", this.iframeDown);
this._scrollHeight = Math.max(this.scrollHeight, iframe?.contentDocument.body.scrollHeight);
setTimeout(action(() => this._scrollHeight = Math.max(this.scrollHeight, iframe?.contentDocument?.body.scrollHeight || 0)), 5000);
- const initialScroll = this._initialScroll;
- if (initialScroll !== undefined && this._outerRef.current) {
- // bcz: not sure why this happens, but if the webpage isn't ready yet, it's scroll height seems to be limited. So we need to wait tp set scroll location to what we want.
- setTimeout(() => this._outerRef.current!.scrollTop = initialScroll);
- this._initialScroll = undefined;
- }
iframe.setAttribute("enable-annotation", "true");
iframe.contentDocument.addEventListener("click", undoBatch(action((e: MouseEvent) => {
let href = "";
@@ -353,42 +390,46 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
}
}
- @action
- forward = () => {
+ forward = (checkAvailable?: boolean) => {
const future = Cast(this.dataDoc[this.fieldKey + "-future"], listSpec("string"), []);
const history = Cast(this.dataDoc[this.fieldKey + "-history"], listSpec("string"), []);
- if (future.length) {
- const curUrl = this._url;
- this.dataDoc[this.fieldKey + "-history"] = new List<string>([...history, this._url]);
- this.dataDoc[this.fieldKey] = new WebField(new URL(future.pop()!));
- if (this._webUrl === this._url) {
- this._webUrl = curUrl;
- setTimeout(action(() => this._webUrl = this._url));
- } else {
- this._webUrl = this._url;
+ if (checkAvailable) return future.length;
+ runInAction(() => {
+ if (future.length) {
+ const curUrl = this._url;
+ this.dataDoc[this.fieldKey + "-history"] = new List<string>([...history, this._url]);
+ this.dataDoc[this.fieldKey] = new WebField(new URL(future.pop()!));
+ if (this._webUrl === this._url) {
+ this._webUrl = curUrl;
+ setTimeout(action(() => this._webUrl = this._url));
+ } else {
+ this._webUrl = this._url;
+ }
+ return true;
}
- return true;
- }
+ });
return false;
}
- @action
- back = () => {
+ back = (checkAvailable?: boolean) => {
const future = Cast(this.dataDoc[this.fieldKey + "-future"], listSpec("string"));
const history = Cast(this.dataDoc[this.fieldKey + "-history"], listSpec("string"), []);
- if (history.length) {
- const curUrl = this._url;
- if (future === undefined) this.dataDoc[this.fieldKey + "-future"] = new List<string>([this._url]);
- else this.dataDoc[this.fieldKey + "-future"] = new List<string>([...future, this._url]);
- this.dataDoc[this.fieldKey] = new WebField(new URL(history.pop()!));
- if (this._webUrl === this._url) {
- this._webUrl = curUrl;
- setTimeout(action(() => this._webUrl = this._url));
- } else {
- this._webUrl = this._url;
+ if (checkAvailable) return history.length;
+ runInAction(() => {
+ if (history.length) {
+ const curUrl = this._url;
+ if (future === undefined) this.dataDoc[this.fieldKey + "-future"] = new List<string>([this._url]);
+ else this.dataDoc[this.fieldKey + "-future"] = new List<string>([...future, this._url]);
+ this.dataDoc[this.fieldKey] = new WebField(new URL(history.pop()!));
+ if (this._webUrl === this._url) {
+ this._webUrl = curUrl;
+ setTimeout(action(() => this._webUrl = this._url));
+ } else {
+ this._webUrl = this._url;
+ }
+ return true;
}
- return true;
- }
+ });
return false;
}
@@ -452,8 +493,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
<button className="submitUrl" onClick={() => this.submitURL(this._keyInput.current!.value)} onDragOver={e => e.stopPropagation()} onDrop={this.onWebUrlDrop}>
GO
</button>
- <button className="submitUrl" onClick={this.back}> <FontAwesomeIcon icon="caret-left" size="lg" /> </button>
- <button className="submitUrl" onClick={this.forward}> <FontAwesomeIcon icon="caret-right" size="lg" /> </button>
+ <button className="submitUrl" onClick={() => this.back}> <FontAwesomeIcon icon="caret-left" size="lg" /> </button>
+ <button className="submitUrl" onClick={() => this.forward}> <FontAwesomeIcon icon="caret-right" size="lg" /> </button>
</div>
</div>
);
@@ -512,7 +553,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
}
@computed get urlContent() {
- if (this._hackHide) return (null);
+ if (this._hackHide || (this.webThumb && (!this._webPageHasBeenRendered && LightboxView.LightboxDoc !== this.rootDoc))) return (null);
const field = this.dataDoc[this.props.fieldKey];
let view;
if (field instanceof HtmlField) {
@@ -530,6 +571,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
style={{ pointerEvents: this._scrollTimer ? "none" : undefined }} // if we allow pointer events when scrolling is on, then reversing direction does not work smoothly
ref={action((r: HTMLIFrameElement | null) => this._iframe = r)} src={"https://crossorigin.me/https://cs.brown.edu"} />;
}
+ setTimeout(action(() => this._webPageHasBeenRendered = true));
return view;
}
@@ -542,34 +584,37 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
if (!this.layoutDoc._showSidebar) this.toggleSidebar();
return this.addDocumentWrapper(doc, sidebarKey);
}
- sidebarBtnDown = (e: React.PointerEvent) => {
- setupMoveUpEvents(this, e, (e, down, delta) => {
+ @observable _draggingSidebar = false;
+ sidebarBtnDown = (e: React.PointerEvent, onButton: boolean) => { // onButton determines whether the width of the pdf box changes, or just the ratio of the sidebar to the pdf
+ setupMoveUpEvents(this, e, action((e, down, delta) => {
+ this._draggingSidebar = true;
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 + localDelta[0] / (this.props.scaling?.() || 1)) / nativeWidth;
+ const ratio = (curNativeWidth + (onButton ? 1 : -1) * localDelta[0] / (this.props.scaling?.() || 1)) / nativeWidth;
if (ratio >= 1) {
this.layoutDoc.nativeWidth = nativeWidth * ratio;
- this.layoutDoc._width = this.layoutDoc[WidthSym]() + localDelta[0];
+ onButton && (this.layoutDoc._width = this.layoutDoc[WidthSym]() + localDelta[0]);
this.layoutDoc._showSidebar = nativeWidth !== this.layoutDoc._nativeWidth;
}
return false;
- }, emptyFunction, () => this.toggleSidebar());
+ }), action(() => this._draggingSidebar = false), () => this.toggleSidebar());
}
@observable _previewNativeWidth: Opt<number> = undefined;
@observable _previewWidth: Opt<number> = undefined;
toggleSidebar = action((preview: boolean = false) => {
const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + "-nativeWidth"]);
- const ratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? WebBox.openSidebarWidth : 0) + nativeWidth) / nativeWidth;
+ const sideratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? WebBox.openSidebarWidth : 0) + nativeWidth) / nativeWidth;
+ const pdfratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? WebBox.openSidebarWidth + WebBox.sidebarResizerWidth : 0) + nativeWidth) / nativeWidth;
const curNativeWidth = NumCast(this.layoutDoc.nativeWidth, nativeWidth);
if (preview) {
- this._previewNativeWidth = nativeWidth * ratio;
- this._previewWidth = this.layoutDoc[WidthSym]() * nativeWidth * ratio / curNativeWidth;
+ this._previewNativeWidth = nativeWidth * sideratio;
+ this._previewWidth = this.layoutDoc[WidthSym]() * nativeWidth * sideratio / curNativeWidth;
this._showSidebar = true;
}
else {
- this.layoutDoc.nativeWidth = nativeWidth * ratio;
- this.layoutDoc._width = this.layoutDoc[WidthSym]() * nativeWidth * ratio / curNativeWidth;
+ this.layoutDoc.nativeWidth = nativeWidth * pdfratio;
+ this.layoutDoc._width = this.layoutDoc[WidthSym]() * nativeWidth * pdfratio / curNativeWidth;
this.layoutDoc._showSidebar = nativeWidth !== this.layoutDoc._nativeWidth;
}
});
@@ -633,7 +678,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
}
return this.props.styleProvider?.(doc, props, property);
}
- pointerEvents = () => this.props.isContentActive() && this.props.pointerEvents !== "none" && !MarqueeOptionsMenu.Instance.isShown() ? "all" : SnappingManager.GetIsDragging() ? undefined : "none";
+ pointerEvents = () => !this._draggingSidebar && this.props.isContentActive() && this.props.pointerEvents !== "none" && !MarqueeOptionsMenu.Instance.isShown() ? "all" : SnappingManager.GetIsDragging() ? undefined : "none";
render() {
const pointerEvents = this.props.layerProvider?.(this.layoutDoc) === false ? "none" : this.props.pointerEvents ? this.props.pointerEvents as any : undefined;
const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1;
@@ -664,13 +709,17 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
pointerEvents={this._isAnnotating || SnappingManager.GetIsDragging() ? "all" : "none"} />;
return (
<div className="webBox" ref={this._mainCont}
- style={{ pointerEvents: this.pointerEvents() }} >
- <div className={`webBox-container`} style={{ pointerEvents }} onContextMenu={this.specificContextMenu}>
+ style={{ pointerEvents: this.pointerEvents(), display: this.props.thumbShown?.() ? "none" : undefined }} >
+ <div className="webBox-background" onPointerDown={e => this.sidebarBtnDown(e, false)} />
+ <div className="webBox-container" style={{
+ position: "absolute",
+ width: `calc(${100 / scale}% - ${(this.sidebarWidth() + WebBox.sidebarResizerWidth) / scale * (this._previewWidth ? scale : 1)}px)`,
+ transform: `scale(${scale})`,
+ pointerEvents
+ }} onContextMenu={this.specificContextMenu}>
<div className={"webBox-outerContent"} ref={this._outerRef}
style={{
- width: `calc(${100 / scale}% - ${this.sidebarWidth() / scale * (this._previewWidth ? scale : 1)}px)`,
height: `${100 / scale}%`,
- transform: `scale(${scale})`,
pointerEvents
}}
onWheel={e => { e.stopPropagation(); e.preventDefault(); }} // block wheel events from propagating since they're handled by the iframe
@@ -703,6 +752,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
</div >
<SidebarAnnos ref={this._sidebarRef}
{...this.props}
+ whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
fieldKey={this.fieldKey + "-" + this._urlHash}
rootDoc={this.rootDoc}
layoutDoc={this.layoutDoc}
@@ -720,11 +770,11 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
top: StrCast(this.rootDoc._showTitle) === "title" ? 20 : 5,
backgroundColor: this.SidebarShown ? Colors.MEDIUM_BLUE : Colors.BLACK
}}
- onPointerDown={this.sidebarBtnDown} >
+ onPointerDown={e => this.sidebarBtnDown(e, true)} >
<FontAwesomeIcon style={{ color: Colors.WHITE }} icon={"comment-alt"} size="sm" />
</div>
{!this.props.isContentActive() ? (null) : this.searchUI}
</div>);
}
}
-Scripting.addGlobal(function urlHash(url: string) { return WebBox.urlHash(url); }); \ No newline at end of file
+ScriptingGlobals.add(function urlHash(url: string) { return WebBox.urlHash(url); }); \ No newline at end of file
diff --git a/src/client/views/nodes/WebBoxRenderer.js b/src/client/views/nodes/WebBoxRenderer.js
new file mode 100644
index 000000000..08a5746d1
--- /dev/null
+++ b/src/client/views/nodes/WebBoxRenderer.js
@@ -0,0 +1,395 @@
+/**
+ *
+ * @param {StyleSheetList} styleSheets
+ */
+var ForeignHtmlRenderer = function (styleSheets) {
+
+ const self = this;
+
+ /**
+ *
+ * @param {String} binStr
+ */
+ const binaryStringToBase64 = function (binStr) {
+ return new Promise(function (resolve) {
+ const reader = new FileReader();
+ reader.readAsDataURL(binStr);
+ reader.onloadend = function () {
+ resolve(reader.result);
+ }
+ });
+ };
+
+ function prepend(extension) {
+ return window.location.origin + extension;
+ }
+ function CorsProxy(url) {
+ return prepend("/corsProxy/") + encodeURIComponent(url);
+ }
+ /**
+ *
+ * @param {String} url
+ * @returns {Promise}
+ */
+ const getResourceAsBase64 = function (webUrl, inurl) {
+ return new Promise(function (resolve, reject) {
+ const xhr = new XMLHttpRequest();
+ //const url = inurl.startsWith("/") && !inurl.startsWith("//") ? webUrl + inurl : inurl;
+ //const url = CorsProxy(inurl.startsWith("/") && !inurl.startsWith("//") ? webUrl + inurl : inurl);// inurl.startsWith("http") ? CorsProxy(inurl) : inurl;
+ var url = inurl;
+ if (inurl.startsWith("/static")) {
+ url = (new URL(webUrl).origin + inurl);
+ } else
+ if ((inurl.startsWith("/") && !inurl.startsWith("//"))) {
+ url = CorsProxy(new URL(webUrl).origin + inurl);
+ } else if (!inurl.startsWith("http") && !inurl.startsWith("//")) {
+ url = CorsProxy(webUrl + "/" + inurl);
+ }
+ xhr.open("GET", url);
+ xhr.responseType = 'blob';
+
+ xhr.onreadystatechange = async function () {
+ if (xhr.readyState === 4 && xhr.status === 200) {
+ const resBase64 = await binaryStringToBase64(xhr.response);
+
+ resolve(
+ {
+ "resourceUrl": inurl,
+ "resourceBase64": resBase64
+ }
+ );
+ } else if (xhr.readyState === 4) {
+ console.log("COULDN'T FIND: " + (inurl.startsWith("/") ? webUrl + inurl : inurl));
+ resolve(
+ {
+ "resourceUrl": "",
+ "resourceBase64": inurl
+ }
+ );
+ }
+ };
+
+ xhr.send(null);
+ });
+ };
+
+ /**
+ *
+ * @param {String[]} urls
+ * @returns {Promise}
+ */
+ const getMultipleResourcesAsBase64 = function (webUrl, urls) {
+ const promises = [];
+ for (let i = 0; i < urls.length; i++) {
+ promises.push(getResourceAsBase64(webUrl, urls[i]));
+ }
+ return Promise.all(promises);
+ };
+
+ /**
+ *
+ * @param {String} str
+ * @param {Number} startIndex
+ * @param {String} prefixToken
+ * @param {String[]} suffixTokens
+ *
+ * @returns {String|null}
+ */
+ const parseValue = function (str, startIndex, prefixToken, suffixTokens) {
+ const idx = str.indexOf(prefixToken, startIndex);
+ if (idx === -1) {
+ return null;
+ }
+
+ let val = '';
+ for (let i = idx + prefixToken.length; i < str.length; i++) {
+ if (suffixTokens.indexOf(str[i]) !== -1) {
+ break;
+ }
+
+ val += str[i];
+ }
+
+ return {
+ "foundAtIndex": idx,
+ "value": val
+ }
+ };
+
+ /**
+ *
+ * @param {String} cssRuleStr
+ * @returns {String[]}
+ */
+ const getUrlsFromCssString = function (cssRuleStr, selector = "url(", delimiters = [')'], mustEndWithQuote = false) {
+ const urlsFound = [];
+ let searchStartIndex = 0;
+
+ while (true) {
+ const url = parseValue(cssRuleStr, searchStartIndex, selector, delimiters);
+ if (url === null) {
+ break;
+ }
+ searchStartIndex = url.foundAtIndex + url.value.length;
+ if (mustEndWithQuote && url.value[url.value.length - 1] !== '"') continue;
+ const unquoted = removeQuotes(url.value);
+ if (!unquoted /* || (!unquoted.startsWith('http')&& !unquoted.startsWith("/") )*/ || unquoted === 'http://' || unquoted === 'https://') {
+ continue;
+ }
+
+ unquoted && urlsFound.push(unquoted);
+ }
+
+ return urlsFound;
+ };
+
+ /**
+ *
+ * @param {String} html
+ * @returns {String[]}
+ */
+ const getImageUrlsFromFromHtml = function (html) {
+ return getUrlsFromCssString(html, "src=", [' ', '>', '\t'], true);
+ };
+ const getSourceUrlsFromFromHtml = function (html) {
+ return getUrlsFromCssString(html, "source=", [' ', '>', '\t'], true);
+ };
+
+ /**
+ *
+ * @param {String} str
+ * @returns {String}
+ */
+ const removeQuotes = function (str) {
+ return str.replace(/["']/g, "");
+ };
+
+ const escapeRegExp = function (string) {
+ return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
+ };
+
+ /**
+ *
+ * @param {String} contentHtml
+ * @param {Number} width
+ * @param {Number} height
+ *
+ * @returns {Promise<String>}
+ */
+ const buildSvgDataUri = async function (webUrl, contentHtml, width, height, scroll) {
+
+ return new Promise(async function (resolve, reject) {
+
+ /* !! The problems !!
+ * 1. CORS (not really an issue, expect perhaps for images, as this is a general security consideration to begin with)
+ * 2. Platform won't wait for external assets to load (fonts, images, etc.)
+ */
+
+ // copy styles
+ let cssStyles = "";
+ let urlsFoundInCss = [];
+
+ for (let i = 0; i < styleSheets.length; i++) {
+ try {
+ const rules = styleSheets[i].cssRules
+ for (let j = 0; j < rules.length; j++) {
+ const cssRuleStr = rules[j].cssText;
+ urlsFoundInCss.push(...getUrlsFromCssString(cssRuleStr));
+ cssStyles += cssRuleStr;
+ }
+ } catch (e) {
+
+ }
+ }
+
+ // const fetchedResourcesFromStylesheets = await getMultipleResourcesAsBase64(webUrl, urlsFoundInCss);
+ // for (let i = 0; i < fetchedResourcesFromStylesheets.length; i++) {
+ // const r = fetchedResourcesFromStylesheets[i];
+ // if (r.resourceUrl) {
+ // cssStyles = cssStyles.replace(new RegExp(escapeRegExp(r.resourceUrl), "g"), r.resourceBase64);
+ // }
+ // }
+
+ contentHtml = contentHtml.replace(/<source[^>]*>/g, "") // <picture> tags have a <source> which has a srcset field of image refs. instead of converting each, just use the default <img> of the picture
+ .replace(/noscript/g, "div").replace(/<div class="mediaset"><\/div>/g, "") // when scripting isn't available (ie, rendering web pages here), <noscript> tags should become <div>'s. But for Brown CS, there's a layout problem if you leave the empty <mediaset> tag
+ .replace(/<link[^>]*>/g, "") // don't need to keep any linked style sheets because we've already processed all style sheets above
+ .replace(/srcset="([^ "]*)[^"]*"/g, "src=\"$1\""); // instead of converting each item in the srcset to a data url, just convert the first one and use that
+ let urlsFoundInHtml = getImageUrlsFromFromHtml(contentHtml);
+ const fetchedResources = await getMultipleResourcesAsBase64(webUrl, urlsFoundInHtml);
+ for (let i = 0; i < fetchedResources.length; i++) {
+ const r = fetchedResources[i];
+ if (r.resourceUrl) {
+ contentHtml = contentHtml.replace(new RegExp(escapeRegExp(r.resourceUrl), "g"), r.resourceBase64);
+ }
+ }
+
+ const styleElem = document.createElement("style");
+ styleElem.innerHTML = cssStyles.replace("&gt;", ">").replace("&lt;", "<");
+
+ const styleElemString = new XMLSerializer().serializeToString(styleElem).replace(/&gt;/g, ">").replace(/&lt;/g, "<");
+
+ // create DOM element string that encapsulates styles + content
+ const contentRootElem = document.createElement("body");
+ contentRootElem.style.zIndex = "1111";
+ // contentRootElem.style.transform = "scale(0.08)"
+ contentRootElem.innerHTML = styleElemString + contentHtml;
+ contentRootElem.setAttribute("xmlns", "http://www.w3.org/1999/xhtml");
+ //document.body.appendChild(contentRootElem);
+
+ const contentRootElemString = new XMLSerializer().serializeToString(contentRootElem);
+
+ // build SVG string
+ const svg = `<svg xmlns='http://www.w3.org/2000/svg' width='${width}' height='${height}'>
+ <foreignObject x='0' y='${-scroll}' width='${width}' height='${scroll + height}'>
+ ${contentRootElemString}
+ </foreignObject>
+ </svg>`;
+
+ // convert SVG to data-uri
+ const dataUri = `data:image/svg+xml;base64,${window.btoa(unescape(encodeURIComponent(svg)))}`;
+
+ resolve(dataUri);
+ });
+ };
+
+ /**
+ * @param {String} html
+ * @param {Number} width
+ * @param {Number} height
+ *
+ * @return {Promise<Image>}
+ */
+ this.renderToImage = async function (webUrl, html, width, height, scroll) {
+ return new Promise(async function (resolve, reject) {
+ const img = new Image();
+ console.log("BUILDING SVG for:" + webUrl);
+ img.src = await buildSvgDataUri(webUrl, html, width, height, scroll);
+
+ img.onload = function () {
+ console.log("IMAGE SVG created:" + webUrl);
+ resolve(img);
+ };
+ });
+ };
+
+ /**
+ * @param {String} html
+ * @param {Number} width
+ * @param {Number} height
+ *
+ * @return {Promise<Image>}
+ */
+ this.renderToCanvas = async function (webUrl, html, width, height, scroll) {
+ return new Promise(async function (resolve, reject) {
+ const img = await self.renderToImage(webUrl, html, width, height, scroll);
+
+ const canvas = document.createElement('canvas');
+ canvas.width = img.width;
+ canvas.height = img.height;
+
+ const canvasCtx = canvas.getContext('2d');
+ canvasCtx.drawImage(img, 0, 0, img.width, img.height);
+
+ resolve(canvas);
+ });
+ };
+
+ /**
+ * @param {String} html
+ * @param {Number} width
+ * @param {Number} height
+ *
+ * @return {Promise<String>}
+ */
+ this.renderToBase64Png = async function (webUrl, html, width, height, scroll) {
+ return new Promise(async function (resolve, reject) {
+ const canvas = await self.renderToCanvas(webUrl, html, width, height, scroll);
+ resolve(canvas.toDataURL('image/png'));
+ });
+ };
+
+};
+
+
+export function CreateImage(webUrl, styleSheets, html, width, height, scroll) {
+ const val = (new ForeignHtmlRenderer(styleSheets)).renderToBase64Png(webUrl, html.replace(/\n/g, "").replace(/<script((?!\/script).)*<\/script>/g, ""), width, height, scroll);
+ return val;
+}
+
+
+
+var ClipboardUtils = new function () {
+ var permissions = {
+ 'image/bmp': true,
+ 'image/gif': true,
+ 'image/png': true,
+ 'image/jpeg': true,
+ 'image/tiff': true
+ };
+
+ function getType(types) {
+ for (var j = 0; j < types.length; ++j) {
+ var type = types[j];
+ if (permissions[type]) {
+ return type;
+ }
+ }
+ return null;
+ }
+ function getItem(items) {
+ for (var i = 0; i < items.length; ++i) {
+ var item = items[i];
+ if (item) {
+ var type = getType(item.types);
+ if (type) {
+ return item.getType(type);
+ }
+ }
+ }
+ return null;
+ }
+ function loadFile(file, callback) {
+ if (window.FileReader) {
+ var reader = new FileReader();
+ reader.onload = function () {
+ callback(reader.result, null);
+ };
+ reader.onerror = function () {
+ callback(null, 'Incorrect file.');
+ };
+ reader.readAsDataURL(file);
+ } else {
+ callback(null, 'File api is not supported.');
+ }
+ }
+ this.readImage = function (callback) {
+ if (navigator.clipboard) {
+ var promise = navigator.clipboard.read();
+ promise
+ .then(function (items) {
+ var promise = getItem(items);
+ if (promise == null) {
+ callback(null, null);
+ return;
+ }
+ promise
+ .then(function (result) {
+ loadFile(result, callback);
+ })
+ .catch(function (error) {
+ callback(null, 'Reading clipboard error.');
+ });
+ })
+ .catch(function (error) {
+ callback(null, 'Reading clipboard error.');
+ });
+ } else {
+ callback(null, 'Clipboard is not supported.');
+ }
+ };
+};
+
+
+export function pasteImageBitmap(callback) {
+ return ClipboardUtils.readImage(callback);
+} \ No newline at end of file
diff --git a/src/client/views/nodes/button/ButtonScripts.ts b/src/client/views/nodes/button/ButtonScripts.ts
index bb4dd8bc9..f3731b8f9 100644
--- a/src/client/views/nodes/button/ButtonScripts.ts
+++ b/src/client/views/nodes/button/ButtonScripts.ts
@@ -1,14 +1,14 @@
-import { Scripting } from "../../../util/Scripting";
+import { ScriptingGlobals } from "../../../util/ScriptingGlobals";
import { SelectionManager } from "../../../util/SelectionManager";
// toggle: Set overlay status of selected document
-Scripting.addGlobal(function changeView(view: string) {
+ScriptingGlobals.add(function changeView(view: string) {
const selected = SelectionManager.Views().length ? SelectionManager.Views()[0] : undefined;
selected ? selected.Document._viewType = view : console.log("[FontIconBox.tsx] changeView failed");
});
// toggle: Set overlay status of selected document
-Scripting.addGlobal(function toggleOverlay() {
+ScriptingGlobals.add(function toggleOverlay() {
const selected = SelectionManager.Views().length ? SelectionManager.Views()[0] : undefined;
selected ? selected.props.CollectionFreeFormDocumentView?.().float() : console.log("failed");
}); \ No newline at end of file
diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx
index bd103dcf7..ca13590de 100644
--- a/src/client/views/nodes/button/FontIconBox.tsx
+++ b/src/client/views/nodes/button/FontIconBox.tsx
@@ -5,31 +5,30 @@ import { action, computed, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { ColorState, SketchPicker } from 'react-color';
-import { Doc, StrListCast, WidthSym, HeightSym } from '../../../../fields/Doc';
+import { Doc, StrListCast } from '../../../../fields/Doc';
import { InkTool } from '../../../../fields/InkField';
-import { createSchema, makeInterface } from '../../../../fields/Schema';
+import { createSchema } from '../../../../fields/Schema';
import { ScriptField } from '../../../../fields/ScriptField';
-import { BoolCast, Cast, NumCast, StrCast } from '../../../../fields/Types';
+import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
import { WebField } from '../../../../fields/URLField';
+import { Utils } from '../../../../Utils';
import { DocumentType } from '../../../documents/DocumentTypes';
-import { Scripting } from "../../../util/Scripting";
+import { ScriptingGlobals } from "../../../util/ScriptingGlobals";
import { SelectionManager } from '../../../util/SelectionManager';
-import { UndoManager, undoBatch } from '../../../util/UndoManager';
+import { undoBatch, UndoManager } from '../../../util/UndoManager';
import { CollectionViewType } from '../../collections/CollectionView';
import { ContextMenu } from '../../ContextMenu';
import { DocComponent } from '../../DocComponent';
import { EditableView } from '../../EditableView';
import { GestureOverlay } from '../../GestureOverlay';
import { Colors } from '../../global/globalEnums';
-import { SetActiveInkColor, ActiveFillColor, SetActiveFillColor, ActiveInkWidth, ActiveInkColor, SetActiveInkWidth } from '../../InkingStroke';
+import { ActiveFillColor, ActiveInkColor, ActiveInkWidth, SetActiveFillColor, SetActiveInkColor, SetActiveInkWidth } from '../../InkingStroke';
import { StyleProp } from '../../StyleProvider';
import { FieldView, FieldViewProps } from '.././FieldView';
import { RichTextMenu } from '../formattedText/RichTextMenu';
-import { Utils } from '../../../../Utils';
-import { IButtonProps } from './ButtonInterface';
+import { WebBox } from '../WebBox';
import { FontIconBadge } from './FontIconBadge';
import './FontIconBox.scss';
-import { WebBox } from '../WebBox';
const FontIconSchema = createSchema({
icon: "string",
});
@@ -57,11 +56,8 @@ export enum NumButtonType {
export interface ButtonProps extends FieldViewProps {
type?: ButtonType;
}
-
-type FontIconDocument = makeInterface<[typeof FontIconSchema]>;
-const FontIconDocument = makeInterface(FontIconSchema);
@observer
-export class FontIconBox extends DocComponent<ButtonProps, FontIconDocument>(FontIconDocument) {
+export class FontIconBox extends DocComponent<ButtonProps>() {
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(FontIconBox, fieldKey); }
showTemplate = (): void => {
const dragFactory = Cast(this.layoutDoc.dragFactory, Doc, null);
@@ -105,16 +101,11 @@ export class FontIconBox extends DocComponent<ButtonProps, FontIconDocument>(Fon
*/
@computed get numberButton() {
const numBtnType: string = StrCast(this.rootDoc.numBtnType);
- const setValue = (value: number) => {
- // Script for running the toggle
- const script: string = StrCast(this.rootDoc.script) + "(" + value + ")";
- ScriptField.MakeScript(script)?.script.run();
- };
+ const numScript = ScriptCast(this.rootDoc.script);
+ const setValue = (value: number) => numScript?.script.run({ value, _readOnly_: false });
// Script for checking the outcome of the toggle
- const checkScript: string = StrCast(this.rootDoc.script) + "(0, true)";
- const checkResult: number = ScriptField.MakeScript(checkScript)?.script.run().result || 0;
-
+ const checkResult: number = numScript?.script.run({ value: 0, _readOnly_: true }).result || 0;
if (numBtnType === NumButtonType.Slider) {
const dropdown =
@@ -237,34 +228,37 @@ export class FontIconBox extends DocComponent<ButtonProps, FontIconDocument>(Fon
const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color);
const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor);
- const script: string = StrCast(this.rootDoc.script);
+ const script = ScriptCast(this.rootDoc.script);
let noviceList: string[] = [];
let text: string | undefined;
let dropdown = true;
let icon: IconProp = "caret-down";
-
- if (script === 'setView') {
- const selected = SelectionManager.Docs().lastElement();
- if (selected) {
- if (StrCast(selected.type) === DocumentType.COL) {
- text = StrCast(selected._viewType);
+ try {
+ if (script.script.originalScript.startsWith('setView')) {
+ const selected = SelectionManager.Docs().lastElement();
+ if (selected) {
+ if (StrCast(selected.type) === DocumentType.COL) {
+ text = StrCast(selected._viewType);
+ } else {
+ dropdown = false;
+ text = selected.type === DocumentType.RTF ? "Text" : StrCast(selected.type);
+ icon = Doc.toIcon(selected);
+ }
} else {
dropdown = false;
- text = selected.type === DocumentType.RTF ? "Text" : StrCast(selected.type);
- icon = Doc.toIcon(selected);
+ icon = "globe-asia";
+ text = "User Default";
}
- } else {
- dropdown = false;
- icon = "globe-asia";
- text = "User Default";
+ noviceList = [CollectionViewType.Freeform, CollectionViewType.Schema, CollectionViewType.Stacking];
+ } else if (script.script.originalScript.startsWith('setFont')) {
+ const editorView = RichTextMenu.Instance?.TextView?.EditorView;
+ text = StrCast((editorView ? RichTextMenu.Instance : Doc.UserDoc()).fontFamily);
+ noviceList = ["Roboto", "Times New Roman", "Arial", "Georgia",
+ "Comic Sans MS", "Tahoma", "Impact", "Crimson Text"];
}
- noviceList = [CollectionViewType.Freeform, CollectionViewType.Schema, CollectionViewType.Stacking];
- } else if (script === 'setFont') {
- const editorView = RichTextMenu.Instance?.TextView?.EditorView;
- text = StrCast((editorView ? RichTextMenu.Instance : Doc.UserDoc()).fontFamily);
- noviceList = ["Roboto", "Times New Roman", "Arial", "Georgia",
- "Comic Sans MS", "Tahoma", "Impact", "Crimson Text"];
+ } catch (e) {
+ console.log(e);
}
// Get items to place into the list
@@ -272,18 +266,12 @@ export class FontIconBox extends DocComponent<ButtonProps, FontIconDocument>(Fon
if (Doc.UserDoc().noviceMode && !noviceList.includes(value)) {
return;
}
- const click = () => {
- const s = ScriptField.MakeScript(script + '("' + value + '")');
- if (s) {
- s.script.run().result;
- }
- };
return <div className="list-item" key={`${value}`}
style={{
- fontFamily: script === 'setFont' ? value : undefined,
+ fontFamily: script.script.originalScript.startsWith('setFont') ? value : undefined,
backgroundColor: value === text ? Colors.LIGHT_BLUE : undefined
}}
- onClick={click}>
+ onClick={() => script.script.run({ value }).result}>
{value[0].toUpperCase() + value.slice(1)}
</div>;
});
@@ -319,15 +307,12 @@ export class FontIconBox extends DocComponent<ButtonProps, FontIconDocument>(Fon
}
@observable colorPickerClosed: boolean = true;
- @computed get colorScript() {
- const script = StrCast(this.rootDoc.script);
- return ScriptField.MakeScript(script + '(colValue, checkResult)', { colValue: "string", checkResult: "boolean" });
- }
+ @computed get colorScript() { return ScriptCast(this.rootDoc.script); }
colorPicker = (curColor: string) => {
const change = (value: ColorState) => {
const s = this.colorScript;
- s && undoBatch(() => s.script.run({ colValue: Utils.colorString(value), checkResult: false }).result)();
+ s && undoBatch(() => s.script.run({ value: Utils.colorString(value), _readOnly_: false }).result)();
};
const presets = ['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505',
'#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B',
@@ -343,7 +328,7 @@ export class FontIconBox extends DocComponent<ButtonProps, FontIconDocument>(Fon
@computed get colorButton() {
const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color);
const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor);
- const curColor = this.colorScript?.script.run({ colValue: undefined, checkResult: true }).result ?? "transparent";
+ const curColor = this.colorScript?.script.run({ value: undefined, _readOnly_: true }).result ?? "transparent";
const label = !this.label || !Doc.UserDoc()._showLabel ? (null) :
<div className="fontIconBox-label" style={{ color, backgroundColor, position: "absolute" }}>
@@ -439,52 +424,34 @@ export class FontIconBox extends DocComponent<ButtonProps, FontIconDocument>(Fon
@computed get editableText() {
// Script for running the toggle
- const script: string = StrCast(this.rootDoc.script);
-
- // Script for checking the outcome of the toggle
- const checkScript: string = StrCast(this.rootDoc.script) + "('', true)";
-
+ const script = ScriptCast(this.rootDoc.script);
// Function to run the script
- const checkResult = ScriptField.MakeScript(checkScript)?.script.run().result;
+ const checkResult = script?.script.run({ value: "", _readOnly_: true }).result;
- const setValue = (value: string, shiftDown?: boolean): boolean => {
- ScriptField.MakeScript(script + "('" + value + "')")?.script.run();
- return true;
- };
+ const setValue = (value: string, shiftDown?: boolean): boolean => script?.script.run({ value, _readOnly_: false }).result;
return (
<div className="menuButton editableText">
<FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={"lock"} />
<div style={{ width: "calc(100% - .875em)", paddingLeft: "4px" }}>
- <EditableView GetValue={() => checkResult} SetValue={setValue} contents={checkResult} />
+ <EditableView GetValue={() => script?.script.run({ value: "", _readOnly_: true }).result} SetValue={setValue} contents={checkResult} />
</div>
</div>
);
}
-
render() {
const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color);
const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor);
-
const label = !this.label || !Doc.UserDoc()._showLabel ? (null) :
- <div className="fontIconBox-label" style={{ color: color, backgroundColor: backgroundColor, position: "absolute" }}>
+ <div className="fontIconBox-label" style={{ color, backgroundColor, position: "absolute" }}>
{this.label}
</div>;
const menuLabel = !this.label || !Doc.UserDoc()._showMenuLabel ? (null) :
- <div className="fontIconBox-label" style={{ color: color, backgroundColor: "transparent" }}>
+ <div className="fontIconBox-label" style={{ color, backgroundColor: "transparent" }}>
{this.label}
</div>;
- const buttonProps: IButtonProps = {
- type: this.type,
- rootDoc: this.rootDoc,
- label: label,
- backgroundColor: backgroundColor,
- icon: this.icon,
- color: color
- };
-
const buttonText = StrCast(this.rootDoc.buttonText);
// TODO:glr Add label of button type
@@ -493,7 +460,7 @@ export class FontIconBox extends DocComponent<ButtonProps, FontIconDocument>(Fon
switch (this.type) {
case ButtonType.TextButton:
button = (
- <div className={`menuButton ${this.type}`} style={{ color: color, backgroundColor: backgroundColor, opacity: 1, gridAutoColumns: `${NumCast(this.rootDoc._height)} auto` }}>
+ <div className={`menuButton ${this.type}`} style={{ color, backgroundColor, opacity: 1, gridAutoColumns: `${NumCast(this.rootDoc._height)} auto` }}>
<FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={this.icon} color={color} />
{buttonText ?
<div className="button-text">
@@ -522,7 +489,7 @@ export class FontIconBox extends DocComponent<ButtonProps, FontIconDocument>(Fon
break;
case ButtonType.ToolButton:
button = (
- <div className={`menuButton ${this.type}`} style={{ opacity: 1, backgroundColor: backgroundColor, color: color }}>
+ <div className={`menuButton ${this.type}`} style={{ opacity: 1, backgroundColor, color }}>
<FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={this.icon} color={color} />
{label}
</div>
@@ -534,7 +501,7 @@ export class FontIconBox extends DocComponent<ButtonProps, FontIconDocument>(Fon
break;
case ButtonType.ClickButton:
button = (
- <div className={`menuButton ${this.type}`} style={{ color: color, backgroundColor: backgroundColor, opacity: 1 }}>
+ <div className={`menuButton ${this.type}`} style={{ color, backgroundColor, opacity: 1 }}>
<FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={this.icon} color={color} />
{label}
</div>
@@ -544,7 +511,7 @@ export class FontIconBox extends DocComponent<ButtonProps, FontIconDocument>(Fon
const trailsIcon = <img src={`/assets/${"presTrails.png"}`}
style={{ width: 30, height: 30, filter: `invert(${color === Colors.DARK_GRAY ? "0%" : "100%"})` }} />;
button = (
- <div className={`menuButton ${this.type}`} style={{ color: color, backgroundColor: backgroundColor }}>
+ <div className={`menuButton ${this.type}`} style={{ color, backgroundColor }}>
{this.icon === "pres-trail" ? trailsIcon : <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={this.icon} color={color} />}
{menuLabel}
<FontIconBadge collection={Cast(this.rootDoc.watchedDocuments, Doc, null)} />
@@ -564,14 +531,14 @@ export class FontIconBox extends DocComponent<ButtonProps, FontIconDocument>(Fon
// toggle: Set overlay status of selected document
-Scripting.addGlobal(function setView(view: string) {
+ScriptingGlobals.add(function setView(view: string) {
const selected = SelectionManager.Docs().lastElement();
selected ? selected._viewType = view : console.log("[FontIconBox.tsx] changeView failed");
});
// toggle: Set overlay status of selected document
-Scripting.addGlobal(function setBackgroundColor(color?: string, checkResult?: boolean) {
+ScriptingGlobals.add(function setBackgroundColor(color?: string, checkResult?: boolean) {
const selected = SelectionManager.Docs().lastElement();
if (checkResult) {
return selected?._backgroundColor ?? "transparent";
@@ -580,7 +547,7 @@ Scripting.addGlobal(function setBackgroundColor(color?: string, checkResult?: bo
});
// toggle: Set overlay status of selected document
-Scripting.addGlobal(function setHeaderColor(color?: string, checkResult?: boolean) {
+ScriptingGlobals.add(function setHeaderColor(color?: string, checkResult?: boolean) {
if (checkResult) {
return Doc.SharingDoc().userColor;
}
@@ -590,7 +557,7 @@ Scripting.addGlobal(function setHeaderColor(color?: string, checkResult?: boolea
});
// toggle: Set overlay status of selected document
-Scripting.addGlobal(function toggleOverlay(checkResult?: boolean) {
+ScriptingGlobals.add(function toggleOverlay(checkResult?: boolean) {
const selected = SelectionManager.Views().length ? SelectionManager.Views()[0] : undefined;
if (checkResult && selected) {
if (NumCast(selected.Document.z) >= 1) return Colors.MEDIUM_BLUE;
@@ -612,7 +579,7 @@ Scripting.addGlobal(function toggleOverlay(checkResult?: boolean) {
**/
// toggle: Set overlay status of selected document
-Scripting.addGlobal(function setFont(font: string, checkResult?: boolean) {
+ScriptingGlobals.add(function setFont(font: string, checkResult?: boolean) {
SelectionManager.Docs().map(doc => doc._fontFamily = font);
const editorView = RichTextMenu.Instance.TextView?.EditorView;
if (checkResult) {
@@ -622,7 +589,7 @@ Scripting.addGlobal(function setFont(font: string, checkResult?: boolean) {
else Doc.UserDoc().fontFamily = font;
});
-Scripting.addGlobal(function getActiveTextInfo(info: "family" | "size" | "color" | "highlight") {
+ScriptingGlobals.add(function getActiveTextInfo(info: "family" | "size" | "color" | "highlight") {
const editorView = RichTextMenu.Instance.TextView?.EditorView;
const style = editorView?.state && RichTextMenu.Instance.getActiveFontStylesOnSelection();
switch (info) {
@@ -633,7 +600,7 @@ Scripting.addGlobal(function getActiveTextInfo(info: "family" | "size" | "color"
}
});
-Scripting.addGlobal(function setAlignment(align: "left" | "right" | "center", checkResult?: boolean) {
+ScriptingGlobals.add(function setAlignment(align: "left" | "right" | "center", checkResult?: boolean) {
const editorView = RichTextMenu.Instance?.TextView?.EditorView;
if (checkResult) {
return (editorView ? RichTextMenu.Instance.textAlign : Doc.UserDoc().textAlign) === align ? Colors.MEDIUM_BLUE : "transparent";
@@ -642,7 +609,7 @@ Scripting.addGlobal(function setAlignment(align: "left" | "right" | "center", ch
else Doc.UserDoc().textAlign = align;
});
-Scripting.addGlobal(function setBulletList(mapStyle: "bullet" | "decimal", checkResult?: boolean) {
+ScriptingGlobals.add(function setBulletList(mapStyle: "bullet" | "decimal", checkResult?: boolean) {
const editorView = RichTextMenu.Instance?.TextView?.EditorView;
if (checkResult) {
const active = editorView?.state && RichTextMenu.Instance.getActiveListStyle();
@@ -657,8 +624,8 @@ Scripting.addGlobal(function setBulletList(mapStyle: "bullet" | "decimal", check
});
// toggle: Set overlay status of selected document
-Scripting.addGlobal(function setFontColor(color?: string, checkResult?: boolean) {
- const editorView = RichTextMenu.Instance.TextView?.EditorView;
+ScriptingGlobals.add(function setFontColor(color?: string, checkResult?: boolean) {
+ const editorView = RichTextMenu.Instance?.TextView?.EditorView;
if (checkResult) {
return editorView ? RichTextMenu.Instance.fontColor : Doc.UserDoc().fontColor;
@@ -669,7 +636,7 @@ Scripting.addGlobal(function setFontColor(color?: string, checkResult?: boolean)
});
// toggle: Set overlay status of selected document
-Scripting.addGlobal(function setFontHighlight(color?: string, checkResult?: boolean) {
+ScriptingGlobals.add(function setFontHighlight(color?: string, checkResult?: boolean) {
const selected = SelectionManager.Docs().lastElement();
const editorView = RichTextMenu.Instance.TextView?.EditorView;
@@ -686,18 +653,18 @@ Scripting.addGlobal(function setFontHighlight(color?: string, checkResult?: bool
});
// toggle: Set overlay status of selected document
-Scripting.addGlobal(function setFontSize(size: string | number, checkResult?: boolean) {
- if (typeof size === "number") size = size.toString();
- if (size && Number(size).toString() === size) size += "px";
- const editorView = RichTextMenu.Instance.TextView?.EditorView;
+ScriptingGlobals.add(function setFontSize(size: string | number, checkResult?: boolean) {
+ const editorView = RichTextMenu.Instance?.TextView?.EditorView;
if (checkResult) {
return (editorView ? RichTextMenu.Instance.fontSize : StrCast(Doc.UserDoc().fontSize, "10px")).replace("px", "");
}
+ if (typeof size === "number") size = size.toString();
+ if (size && Number(size).toString() === size) size += "px";
if (editorView) RichTextMenu.Instance.setFontSize(size);
else Doc.UserDoc()._fontSize = size;
});
-Scripting.addGlobal(function toggleBold(checkResult?: boolean) {
+ScriptingGlobals.add(function toggleBold(checkResult?: boolean) {
const editorView = RichTextMenu.Instance?.TextView?.EditorView;
if (checkResult) {
return (editorView ? RichTextMenu.Instance.bold : Doc.UserDoc().fontWeight === "bold") ? Colors.MEDIUM_BLUE : "transparent";
@@ -706,7 +673,7 @@ Scripting.addGlobal(function toggleBold(checkResult?: boolean) {
else Doc.UserDoc().fontWeight = Doc.UserDoc().fontWeight === "bold" ? undefined : "bold";
});
-Scripting.addGlobal(function toggleUnderline(checkResult?: boolean) {
+ScriptingGlobals.add(function toggleUnderline(checkResult?: boolean) {
const editorView = RichTextMenu.Instance?.TextView?.EditorView;
if (checkResult) {
return (editorView ? RichTextMenu.Instance.underline : Doc.UserDoc().textDecoration === "underline") ? Colors.MEDIUM_BLUE : "transparent";
@@ -715,7 +682,7 @@ Scripting.addGlobal(function toggleUnderline(checkResult?: boolean) {
else Doc.UserDoc().textDecoration = Doc.UserDoc().textDecoration === "underline" ? undefined : "underline";
});
-Scripting.addGlobal(function toggleItalic(checkResult?: boolean) {
+ScriptingGlobals.add(function toggleItalic(checkResult?: boolean) {
const editorView = RichTextMenu.Instance?.TextView?.EditorView;
if (checkResult) {
return (editorView ? RichTextMenu.Instance.italics : Doc.UserDoc().fontStyle === "italics") ? Colors.MEDIUM_BLUE : "transparent";
@@ -733,7 +700,7 @@ Scripting.addGlobal(function toggleItalic(checkResult?: boolean) {
* setStrokeColor
**/
-Scripting.addGlobal(function setActiveInkTool(tool: string, checkResult?: boolean) {
+ScriptingGlobals.add(function setActiveInkTool(tool: string, checkResult?: boolean) {
if (checkResult) {
return ((Doc.UserDoc().activeInkTool === tool && !GestureOverlay.Instance?.InkShape) || GestureOverlay.Instance?.InkShape === tool) ?
Colors.MEDIUM_BLUE : "transparent";
@@ -759,7 +726,7 @@ Scripting.addGlobal(function setActiveInkTool(tool: string, checkResult?: boolea
});
// toggle: Set overlay status of selected document
-Scripting.addGlobal(function setFillColor(color?: string, checkResult?: boolean) {
+ScriptingGlobals.add(function setFillColor(color?: string, checkResult?: boolean) {
const selected = SelectionManager.Docs().lastElement();
if (checkResult) {
if (selected?.type === DocumentType.INK) {
@@ -771,7 +738,7 @@ Scripting.addGlobal(function setFillColor(color?: string, checkResult?: boolean)
SelectionManager.Docs().filter(doc => doc.type === DocumentType.INK).map(doc => doc.fillColor = color);
});
-Scripting.addGlobal(function setStrokeWidth(width: number, checkResult?: boolean) {
+ScriptingGlobals.add(function setStrokeWidth(width: number, checkResult?: boolean) {
if (checkResult) {
const selected = SelectionManager.Docs().lastElement();
if (selected?.type === DocumentType.INK) {
@@ -784,7 +751,7 @@ Scripting.addGlobal(function setStrokeWidth(width: number, checkResult?: boolean
});
// toggle: Set overlay status of selected document
-Scripting.addGlobal(function setStrokeColor(color?: string, checkResult?: boolean) {
+ScriptingGlobals.add(function setStrokeColor(color?: string, checkResult?: boolean) {
if (checkResult) {
const selected = SelectionManager.Docs().lastElement();
if (selected?.type === DocumentType.INK) {
@@ -800,7 +767,7 @@ Scripting.addGlobal(function setStrokeColor(color?: string, checkResult?: boolea
/** WEB
* webSetURL
**/
-Scripting.addGlobal(function webSetURL(url: string, checkResult?: boolean) {
+ScriptingGlobals.add(function webSetURL(url: string, checkResult?: boolean) {
const selected = SelectionManager.Views().lastElement();
if (selected?.rootDoc.type === DocumentType.WEB) {
if (checkResult) {
@@ -810,24 +777,26 @@ Scripting.addGlobal(function webSetURL(url: string, checkResult?: boolean) {
//selected.rootDoc.data = new WebField(url);
}
});
-Scripting.addGlobal(function webForward() {
- const selected = SelectionManager.Views().lastElement();
- if (selected?.rootDoc.type === DocumentType.WEB) {
- (selected.ComponentView as WebBox).forward();
+ScriptingGlobals.add(function webForward(checkResult?: boolean) {
+ const selected = (SelectionManager.Views().lastElement()?.ComponentView as WebBox);
+ if (checkResult) {
+ return selected?.forward(checkResult) ? undefined : "lightGray";
}
+ selected?.forward();
});
-Scripting.addGlobal(function webBack() {
- const selected = SelectionManager.Views().lastElement();
- if (selected?.rootDoc.type === DocumentType.WEB) {
- (selected.ComponentView as WebBox).back();
+ScriptingGlobals.add(function webBack(checkResult?: boolean) {
+ const selected = (SelectionManager.Views().lastElement()?.ComponentView as WebBox);
+ if (checkResult) {
+ return selected?.back(checkResult) ? undefined : "lightGray";
}
+ selected?.back();
});
/** Schema
* toggleSchemaPreview
**/
-Scripting.addGlobal(function toggleSchemaPreview(checkResult?: boolean) {
+ScriptingGlobals.add(function toggleSchemaPreview(checkResult?: boolean) {
const selected = SelectionManager.Docs().lastElement();
if (checkResult && selected) {
const result: boolean = NumCast(selected.schemaPreviewWidth) > 0;
@@ -846,7 +815,7 @@ Scripting.addGlobal(function toggleSchemaPreview(checkResult?: boolean) {
/** STACK
* groupBy
*/
-Scripting.addGlobal(function setGroupBy(key: string, checkResult?: boolean) {
+ScriptingGlobals.add(function setGroupBy(key: string, checkResult?: boolean) {
SelectionManager.Docs().map(doc => doc._fontFamily = key);
const editorView = RichTextMenu.Instance.TextView?.EditorView;
if (checkResult) {
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 311d52afa..6192b6829 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -12,13 +12,11 @@ import { EditorState, NodeSelection, Plugin, TextSelection, Transaction } from "
import { EditorView } from "prosemirror-view";
import { DateField } from '../../../../fields/DateField';
import { AclAdmin, AclEdit, AclSelfEdit, DataSym, Doc, DocListCast, DocListCastAsync, Field, ForceServerWrite, HeightSym, Opt, UpdatingFromServer, WidthSym, AclAugment } from "../../../../fields/Doc";
-import { documentSchema } from '../../../../fields/documentSchemas';
import { Id } from '../../../../fields/FieldSymbols';
import { InkTool } from '../../../../fields/InkField';
import { PrefetchProxy } from '../../../../fields/Proxy';
import { RichTextField } from "../../../../fields/RichTextField";
import { RichTextUtils } from '../../../../fields/RichTextUtils';
-import { makeInterface } from "../../../../fields/Schema";
import { Cast, DateCast, NumCast, ScriptCast, StrCast } from "../../../../fields/Types";
import { GetEffectiveAcl, TraceMobx } from '../../../../fields/util';
import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, OmitKeys, returnZero, setupMoveUpEvents, smoothScroll, Utils } from '../../../../Utils';
@@ -77,13 +75,10 @@ export interface FormattedTextBoxProps {
}
export const GoogleRef = "googleDocId";
-type RichTextDocument = makeInterface<[typeof documentSchema]>;
-const RichTextDocument = makeInterface(documentSchema);
-
type PullHandler = (exportState: Opt<GoogleApiClientUtils.Docs.ImportResult>, dataDoc: Doc) => void;
@observer
-export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProps & FormattedTextBoxProps), RichTextDocument>(RichTextDocument) {
+export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProps & FormattedTextBoxProps)>() {
public static LayoutString(fieldStr: string) { return FieldView.LayoutString(FormattedTextBox, fieldStr); }
public static blankState = () => EditorState.create(FormattedTextBox.Instance.config);
public static Instance: FormattedTextBox;
@@ -645,7 +640,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
} else if (!this.rootDoc.isTemplateDoc) {
const title = StrCast(this.rootDoc.title);
this.rootDoc.title = "text";
- this.rootDoc.layout = (this.layoutDoc as Doc).layout as string;
+ this.rootDoc.layout = this.layoutDoc.layout as string;
this.rootDoc.title = this.layoutDoc.isTemplateForField as string;
this.rootDoc.isTemplateDoc = false;
this.rootDoc.isTemplateForField = "";
@@ -1130,13 +1125,13 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
},
dispatchTransaction: this.dispatchTransaction,
nodeViews: {
- dashComment(node, view, getPos) { return new DashDocCommentView(node, view, getPos); },
- dashDoc(node, view, getPos) { return new DashDocView(node, view, getPos, self); },
- dashField(node, view, getPos) { return new DashFieldView(node, view, getPos, self); },
- equation(node, view, getPos) { return new EquationView(node, view, getPos, self); },
- summary(node, view, getPos) { return new SummaryView(node, view, getPos); },
- ordered_list(node, view, getPos) { return new OrderedListView(); },
- footnote(node, view, getPos) { return new FootnoteView(node, view, getPos); }
+ dashComment(node: any, view: any, getPos: any) { return new DashDocCommentView(node, view, getPos); },
+ dashDoc(node: any, view: any, getPos: any) { return new DashDocView(node, view, getPos, self); },
+ dashField(node: any, view: any, getPos: any) { return new DashFieldView(node, view, getPos, self); },
+ equation(node: any, view: any, getPos: any) { return new EquationView(node, view, getPos, self); },
+ summary(node: any, view: any, getPos: any) { return new SummaryView(node, view, getPos); },
+ ordered_list(node: any, view: any, getPos: any) { return new OrderedListView(); },
+ footnote(node: any, view: any, getPos: any) { return new FootnoteView(node, view, getPos); }
},
clipboardTextSerializer: this.clipboardTextSerializer,
handlePaste: this.handlePaste,
@@ -1423,7 +1418,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
this.dataDoc[this.fieldKey + "-translation"] = result1 + "\r\n\r\n" + result[0];
}), 1000);
});
- } catch (e) { console.log(e.message); }
+ } catch (e: any) { console.log(e.message); }
this._lastText = curText;
}
}
diff --git a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
index 76a5675de..c76eda859 100644
--- a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
+++ b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
@@ -106,7 +106,7 @@ export function buildKeymap<S extends Schema<any>>(schema: S, props: any, mapKey
bind("Mod-U", toggleEditableMark(schema.marks.underline));
//Commands for lists
- bind("Ctrl-i", (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => canEdit(state) && wrapInList(schema.nodes.ordered_list)(state, dispatch as any));
+ bind("Ctrl-i", (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => canEdit(state) && wrapInList(schema.nodes.ordered_list)(state as any, dispatch as any));
bind("Tab", (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => {
/// bcz; Argh!! replace layotuTEmpalteString with a onTab prop conditionally handles Tab);
@@ -125,7 +125,7 @@ export function buildKeymap<S extends Schema<any>>(schema: S, props: any, mapKey
dispatch(tx3);
})) { // couldn't sink into an existing list, so wrap in a new one
const newstate = state.applyTransaction(state.tr.setSelection(TextSelection.create(state.doc, range!.start, range!.end)));
- if (!wrapInList(schema.nodes.ordered_list)(newstate.state, (tx2: Transaction) => {
+ if (!wrapInList(schema.nodes.ordered_list)(newstate.state as any, (tx2: Transaction) => {
const tx3 = updateBullets(tx2, schema);
// when promoting to a list, assume list will format things so don't copy the stored marks.
marks && tx3.ensureMarks([...marks]);
@@ -160,14 +160,14 @@ export function buildKeymap<S extends Schema<any>>(schema: S, props: any, mapKey
});
//Commands to modify BlockType
- bind("Ctrl->", (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => canEdit((state) && wrapIn(schema.nodes.blockquote)(state, dispatch as any)));
- bind("Alt-\\", (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => canEdit(state) && setBlockType(schema.nodes.paragraph)(state, dispatch as any));
- bind("Shift-Ctrl-\\", (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => canEdit(state) && setBlockType(schema.nodes.code_block)(state, dispatch as any));
+ bind("Ctrl->", (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => canEdit((state) && wrapIn(schema.nodes.blockquote)(state as any, dispatch as any)));
+ bind("Alt-\\", (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => canEdit(state) && setBlockType(schema.nodes.paragraph)(state as any, dispatch as any));
+ bind("Shift-Ctrl-\\", (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => canEdit(state) && setBlockType(schema.nodes.code_block)(state as any, dispatch as any));
bind("Ctrl-m", (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => canEdit(state) && dispatch(state.tr.replaceSelectionWith(schema.nodes.equation.create({ fieldKey: "math" + Utils.GenerateGuid() }))));
for (let i = 1; i <= 6; i++) {
- bind("Shift-Ctrl-" + i, (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => canEdit(state) && setBlockType(schema.nodes.heading, { level: i })(state, dispatch as any));
+ bind("Shift-Ctrl-" + i, (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => canEdit(state) && setBlockType(schema.nodes.heading, { level: i })(state as any, dispatch as any));
}
//Command to create a horizontal break line
@@ -197,13 +197,13 @@ export function buildKeymap<S extends Schema<any>>(schema: S, props: any, mapKey
bind("Backspace", (state: EditorState<S>, dispatch: (tx: Transaction<Schema<any, any>>) => void) => {
if (!canEdit(state)) return true;
- if (!deleteSelection(state, (tx: Transaction<Schema<any, any>>) => {
+ if (!deleteSelection(state, (tx: Transaction<S>) => {
dispatch(updateBullets(tx, schema));
})) {
- if (!joinBackward(state, (tx: Transaction<Schema<any, any>>) => {
+ if (!joinBackward(state, (tx: Transaction<S>) => {
dispatch(updateBullets(tx, schema));
})) {
- if (!selectNodeBackward(state, (tx: Transaction<Schema<any, any>>) => {
+ if (!selectNodeBackward(state, (tx: Transaction<S>) => {
dispatch(updateBullets(tx, schema));
})) {
return false;
@@ -225,14 +225,14 @@ export function buildKeymap<S extends Schema<any>>(schema: S, props: any, mapKey
const depth = trange ? liftTarget(trange) : undefined;
const split = path.length > 5 && !path[path.length - 3].textContent && path[path.length - 6].type !== schema.nodes.list_item;
if (split && trange && depth !== undefined && depth !== null) {
- dispatch(state.tr.lift(trange, depth));
+ dispatch(state.tr.lift(trange, depth) as any);
return true;
}
const marks = state.storedMarks || (state.selection.$to.parentOffset && state.selection.$from.marks());
const cr = state.selection.$from.node().textContent.endsWith("\n");
- if (cr || !newlineInCode(state, dispatch)) {
- if (!splitListItem(schema.nodes.list_item)(state, (tx2: Transaction) => {
+ if (cr || !newlineInCode(state, dispatch as any)) {
+ if (!splitListItem(schema.nodes.list_item)(state as any, (tx2: Transaction) => {
const tx3 = updateBullets(tx2, schema);
marks && tx3.ensureMarks([...marks]);
marks && tx3.setStoredMarks([...marks]);
diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts
index 711136469..bafae84dc 100644
--- a/src/client/views/nodes/formattedText/RichTextRules.ts
+++ b/src/client/views/nodes/formattedText/RichTextRules.ts
@@ -34,13 +34,9 @@ export class RichTextRules {
wrappingInputRule(
/^1\.\s$/,
schema.nodes.ordered_list,
- () => {
- return ({ mapStyle: "decimal", bulletStyle: 1 });
- },
- (match: any, node: any) => {
- return node.childCount + node.attrs.order === +match[1];
- },
- (type: any) => ({ type: type, attrs: { mapStyle: "decimal", bulletStyle: 1 } })
+ () => ({ mapStyle: "decimal", bulletStyle: 1 }),
+ (match: any, node: any) => node.childCount + node.attrs.order === +match[1],
+ ((type: any) => ({ type: type, attrs: { mapStyle: "decimal", bulletStyle: 1 } })) as any
),
// A. create alphabetical ordered list
@@ -55,20 +51,16 @@ export class RichTextRules {
(match: any, node: any) => {
return node.childCount + node.attrs.order === +match[1];
},
- (type: any) => ({ type: type, attrs: { mapStyle: "multi", bulletStyle: 1 } })
+ ((type: any) => ({ type: type, attrs: { mapStyle: "multi", bulletStyle: 1 } })) as any
),
// * + - create bullet list
wrappingInputRule(/^\s*([-+*])\s$/, schema.nodes.ordered_list,
// match => {
- () => {
- return ({ mapStyle: "bullet" });
- // return ({ order: +match[1] })
- },
- (match: any, node: any) => {
- return node.childCount + node.attrs.order === +match[1];
- },
- (type: any) => ({ type: type, attrs: { mapStyle: "bullet" } })),
+ () => ({ mapStyle: "bullet" }), // ({ order: +match[1] })
+ (match: any, node: any) => node.childCount + node.attrs.order === +match[1],
+ ((type: any) => ({ type: type, attrs: { mapStyle: "bullet" } })) as any
+ ),
// ``` create code block
textblockTypeInputRule(/^```$/, schema.nodes.code_block),
@@ -221,7 +213,7 @@ export class RichTextRules {
tr.deleteRange(start, end).replaceSelectionWith(newNode); // replace insertion with a footnote.
return tr.setSelection(new NodeSelection( // select the footnote node to open its display
tr.doc.resolve( // get the location of the footnote node by subtracting the nodesize of the footnote from the current insertion point anchor (which will be immediately after the footnote node)
- tr.selection.anchor - tr.selection.$anchor.nodeBefore!.nodeSize)));
+ tr.selection.anchor - (tr.selection.$anchor.nodeBefore?.nodeSize || 0))));
}),
// activate a style by name using prefix '%<color name>'
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 2370b7e16..2e312ee51 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -6,11 +6,10 @@ import { observer } from "mobx-react";
import { ColorState, SketchPicker } from "react-color";
import { Bounce, Fade, Flip, LightSpeed, Roll, Rotate, Zoom } from 'react-reveal';
import { Doc, DocListCast, DocListCastAsync, FieldResult } from "../../../../fields/Doc";
-import { documentSchema } from "../../../../fields/documentSchemas";
import { InkTool } from "../../../../fields/InkField";
import { List } from "../../../../fields/List";
import { PrefetchProxy } from "../../../../fields/Proxy";
-import { listSpec, makeInterface } from "../../../../fields/Schema";
+import { listSpec } from "../../../../fields/Schema";
import { ScriptField } from "../../../../fields/ScriptField";
import { BoolCast, Cast, NumCast, StrCast } from "../../../../fields/Types";
import { emptyFunction, returnFalse, returnOne, returnTrue } from '../../../../Utils';
@@ -18,7 +17,7 @@ import { Docs } from "../../../documents/Documents";
import { DocumentType } from "../../../documents/DocumentTypes";
import { CurrentUserUtils } from "../../../util/CurrentUserUtils";
import { DocumentManager } from "../../../util/DocumentManager";
-import { Scripting } from "../../../util/Scripting";
+import { ScriptingGlobals } from "../../../util/ScriptingGlobals";
import { SelectionManager } from "../../../util/SelectionManager";
import { undoBatch, UndoManager } from "../../../util/UndoManager";
import { CollectionDockingView } from "../../collections/CollectionDockingView";
@@ -39,11 +38,8 @@ export class PinProps {
hidePresBox?: boolean;
}
-type PresBoxSchema = makeInterface<[typeof documentSchema]>;
-const PresBoxDocument = makeInterface(documentSchema);
-
@observer
-export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>(PresBoxDocument) {
+export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PresBox, fieldKey); }
/**
@@ -2461,7 +2457,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
</div>;
}
}
-Scripting.addGlobal(function lookupPresBoxField(container: Doc, field: string, data: Doc) {
+ScriptingGlobals.add(function lookupPresBoxField(container: Doc, field: string, data: Doc) {
if (field === 'indexInPres') return DocListCast(container[StrCast(container.presentationFieldKey)]).indexOf(data);
if (field === 'presCollapsedHeight') return container._viewType === CollectionViewType.Stacking ? 35 : 31;
if (field === 'presStatus') return container.presStatus;
diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx
index 238d025dc..a4ec559f5 100644
--- a/src/client/views/nodes/trails/PresElementBox.tsx
+++ b/src/client/views/nodes/trails/PresElementBox.tsx
@@ -3,11 +3,10 @@ import { Tooltip } from "@material-ui/core";
import { action, computed, IReactionDisposer, observable, reaction } from "mobx";
import { observer } from "mobx-react";
import { DataSym, Doc, Opt } from "../../../../fields/Doc";
-import { documentSchema } from '../../../../fields/documentSchemas';
import { Id } from "../../../../fields/FieldSymbols";
-import { createSchema, makeInterface } from '../../../../fields/Schema';
import { Cast, NumCast, StrCast } from "../../../../fields/Types";
-import { emptyFunction, returnFalse, returnTrue, setupMoveUpEvents, emptyPath, returnEmptyDoclist } from "../../../../Utils";
+import { emptyFunction, returnEmptyDoclist, returnFalse, returnTrue, setupMoveUpEvents } from "../../../../Utils";
+import { DocUtils } from "../../../documents/Documents";
import { DocumentType } from "../../../documents/DocumentTypes";
import { CurrentUserUtils } from "../../../util/CurrentUserUtils";
import { DocumentManager } from "../../../util/DocumentManager";
@@ -16,36 +15,20 @@ import { Transform } from "../../../util/Transform";
import { undoBatch } from "../../../util/UndoManager";
import { ViewBoxBaseComponent } from '../../DocComponent';
import { EditableView } from "../../EditableView";
+import { Colors } from "../../global/globalEnums";
import { DocumentView, DocumentViewProps } from "../../nodes/DocumentView";
import { FieldView, FieldViewProps } from '../../nodes/FieldView';
-import { PresBox } from "./PresBox";
-import { Colors } from "../../global/globalEnums";
import { StyleProp } from "../../StyleProvider";
+import { PresBox } from "./PresBox";
import "./PresElementBox.scss";
-import React = require("react");
-import { DocUtils } from "../../../documents/Documents";
import { PresMovement } from "./PresEnums";
-
-export const presSchema = createSchema({
- presentationTargetDoc: Doc,
- presBox: Doc,
- presZoomButton: "boolean",
- presNavButton: "boolean",
- presHideTillShownButton: "boolean",
- presFadeButton: "boolean",
- presHideAfterButton: "boolean",
- presGroupButton: "boolean",
- presExpandInlineButton: "boolean"
-});
-
-type PresDocument = makeInterface<[typeof presSchema, typeof documentSchema]>;
-const PresDocument = makeInterface(presSchema, documentSchema);
+import React = require("react");
/**
* This class models the view a document added to presentation will have in the presentation.
* It involves some functionality for its buttons and options.
*/
@observer
-export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDocument>(PresDocument) {
+export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PresElementBox, fieldKey); }
_heightDisposer: IReactionDisposer | undefined;