From d165aad7c31395db6cff8d5029e4638534f609e3 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 9 Apr 2020 02:43:50 -0400 Subject: from last --- src/client/views/nodes/ScriptingBox.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx index 93956592f..f930c6692 100644 --- a/src/client/views/nodes/ScriptingBox.tsx +++ b/src/client/views/nodes/ScriptingBox.tsx @@ -46,9 +46,8 @@ export class ScriptingBox extends DocAnnotatableComponent e.messageText).join("\n") : ""; - return ScriptCast(this.dataDoc[this.props.fieldKey]); + return this.dataDoc[this.props.fieldKey] = result.compiled ? new ScriptField(result) : undefined; } @action -- cgit v1.2.3-70-g09d2 From c38cd3c24c254aec3cfad1e7d8c31d8f584e96f0 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 9 Apr 2020 11:52:11 -0400 Subject: added initial script template (onClick) for script behaviors --- src/client/documents/Documents.ts | 6 ++++-- src/client/util/DropConverter.ts | 4 +--- src/client/util/Scripting.ts | 4 ++-- src/client/views/nodes/DocumentView.tsx | 2 +- src/client/views/nodes/ScriptingBox.tsx | 2 ++ src/server/authentication/models/current_user_utils.ts | 16 ++++++++++------ 6 files changed, 20 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 5eca71ca9..d07e20b89 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -509,8 +509,10 @@ export namespace Docs { return InstanceFromProto(Prototypes.get(DocumentType.PRES), initial, options); } - export function ScriptingDocument(options: DocumentOptions = {}) { - return InstanceFromProto(Prototypes.get(DocumentType.SCRIPTING), "", options); + export function ScriptingDocument(script: Opt, options: DocumentOptions = {}, fieldKey?: string) { + const res = InstanceFromProto(Prototypes.get(DocumentType.SCRIPTING), script, options); + fieldKey && res.proto instanceof Doc && ((res.proto as Doc).layout = ScriptingBox.LayoutString(fieldKey)); + return res; } export function VideoDocument(url: string, options: DocumentOptions = {}) { diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts index d572e64a6..eb4d3a9b0 100644 --- a/src/client/util/DropConverter.ts +++ b/src/client/util/DropConverter.ts @@ -52,10 +52,8 @@ export function convertDropDataToButtons(data: DragManager.DocumentDragData) { // bcz: isButtonBar is intended to allow a collection of linear buttons to be dropped and nested into another collection of buttons... it's not being used yet, and isn't very elegant if (!doc.onDragStart && !doc.isButtonBar) { const layoutDoc = doc.layout instanceof Doc && doc.layout.isTemplateForField ? doc.layout : doc; - if (layoutDoc.type === DocumentType.COL || layoutDoc.type === DocumentType.RTF || layoutDoc.type === DocumentType.IMG) { + if (layoutDoc.type !== DocumentType.FONTICON) { !layoutDoc.isTemplateDoc && makeTemplate(layoutDoc); - } else { - (layoutDoc.layout instanceof Doc) && !data.userDropAction; } layoutDoc.isTemplateDoc = true; dbox = Docs.Create.FontIconDocument({ diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts index 57d22eaf8..12628273b 100644 --- a/src/client/util/Scripting.ts +++ b/src/client/util/Scripting.ts @@ -41,9 +41,9 @@ export interface CompileError { export type CompileResult = CompiledScript | CompileError; export function isCompileError(toBeDetermined: CompileResult): toBeDetermined is CompileError { if ((toBeDetermined as CompileError).errors) { - return true + return true; } - return false + return false; } export namespace Scripting { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 867405d54..fba924d9e 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -309,7 +309,7 @@ export class DocumentView extends DocComponent(Docu } else if (this.Document.isLinkButton) { DocListCast(this.props.Document.links).length && this.followLinkClick(e.altKey, e.ctrlKey, e.shiftKey); } else { - if ((this.props.Document.onDragStart || this.props.Document.isTemplateForField) && !(e.ctrlKey || e.button > 0)) { + if ((this.props.Document.onDragStart || (this.props.Document.rootDocument && this.props.Document.isTemplateForField)) && !(e.ctrlKey || e.button > 0)) { // onDragStart implies a button doc that we don't want to select when clicking. RootDocument & isTEmplaetForField implies we're clicking on part of a template instance and we want to select the whole template, not the part stopPropagate = false; // don't stop propagation for field templates -- want the selection to propagate up to the root document of the template } else { SelectionManager.SelectDoc(this, e.ctrlKey); diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx index f930c6692..309ee3620 100644 --- a/src/client/views/nodes/ScriptingBox.tsx +++ b/src/client/views/nodes/ScriptingBox.tsx @@ -38,6 +38,8 @@ export class ScriptingBox extends DocAnnotatableComponent { const params = this.compileParams.reduce((o: ScriptParam, p: string) => { o[p] = "any"; return o; }, {} as ScriptParam); diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 37b680765..33a1f1173 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -80,7 +80,7 @@ export class CurrentUserUtils { { title: "record", icon: "microphone", ignoreClick: true, drag: `Docs.Create.AudioDocument("${nullAudio}", { _width: 200, title: "ready to record audio" })` }, { title: "clickable button", icon: "bolt", ignoreClick: true, drag: 'Docs.Create.ButtonDocument({ _width: 150, _height: 50, title: "Button" })' }, { title: "presentation", icon: "tv", click: 'openOnRight(Doc.UserDoc().curPresentation = getCopy(this.dragFactory, true))', drag: `Doc.UserDoc().curPresentation = getCopy(this.dragFactory,true)`, dragFactory: emptyPresentation }, - { title: "script", icon: "terminal", ignoreClick: true, drag: 'Docs.Create.ScriptingDocument({ _width: 200, _height: 250 title: "untitled script" })' }, + { title: "script", icon: "terminal", ignoreClick: true, drag: 'Docs.Create.ScriptingDocument(undefined, { _width: 200, _height: 250 title: "untitled script" })' }, { title: "import folder", icon: "cloud-upload-alt", ignoreClick: true, drag: 'Docs.Create.DirectoryImportDocument({ title: "Directory Import", _width: 400, _height: 400 })' }, { title: "mobile view", icon: "phone", ignoreClick: true, drag: 'Doc.UserDoc().activeMobile' }, { title: "use pen", icon: "pen-nib", click: 'activatePen(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this,2, this.backgroundColor)', backgroundColor: "blue", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc }, @@ -319,7 +319,7 @@ export class CurrentUserUtils { doc.queryBtn = ficon({ onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: queryTemplate, removeDropProperties: new List(["dropAction"]), title: "query view", icon: "sticky-note" }); doc.templateButtons = blist({ title: "template buttons", ignoreClick: true }, [doc.slidesBtn as Doc, doc.descriptionBtn as Doc, doc.queryBtn as Doc]); doc.expandingButtons = blist({ title: "expanding buttons", ignoreClick: true }, [doc.undoBtn as Doc, doc.redoBtn as Doc, doc.templateButtons as Doc]); - doc.templateDocs = new PrefetchProxy(Docs.Create.TreeDocument([doc.noteTypes as Doc, doc.templateButtons as Doc], { + doc.templateDocs = new PrefetchProxy(Docs.Create.TreeDocument([doc.noteTypes as Doc, doc.templateButtons as Doc, doc.clickFuncs as Doc], { title: "template layouts", _xPadding: 0, dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }) })); @@ -341,10 +341,12 @@ export class CurrentUserUtils { } static setupChildClicks(doc: Doc) { - const openInTarget = Docs.Create.TextDocument("", { title: "On Child Clicked (open in target)" }); - const text = "docCast(thisContainer.target).then((target) => { target && docCast(this.source).then((source) => { target.proto.data = new List([source || this]); } ); } )"; - openInTarget.script = ScriptField.MakeScript(text, { thisContainer: Doc.name }); + const openInTarget = Docs.Create.ScriptingDocument(ScriptField.MakeScript( + "docCast(thisContainer.target).then((target) => { target && docCast(this.source).then((source) => { target.proto.data = new List([source || this]); } ); } )", + { target: Doc.name }), { title: "On Child Clicked (open in target)", _width: 300, _height: 200 }); + const onClick = Docs.Create.ScriptingDocument(ScriptField.MakeScript("console.log('click')"), { title: "onClick", isTemplateDoc: true, isTemplateForField: "onClick", _width: 300, _height: 200 }, "onClick"); doc.childClickFuncs = Docs.Create.TreeDocument([openInTarget], { title: "on Child Click function templates" }); + doc.clickFuncs = Docs.Create.TreeDocument([onClick], { title: "onClick funcs" }); } static updateUserDocument(doc: Doc) { @@ -352,12 +354,12 @@ export class CurrentUserUtils { new InkingControl(); (doc.iconTypes === undefined) && CurrentUserUtils.setupDefaultIconTypes(doc); (doc.noteTypes === undefined) && CurrentUserUtils.setupDefaultDocTemplates(doc); + (doc.childClickFuncs === undefined) && CurrentUserUtils.setupChildClicks(doc); (doc.optionalRightCollection === undefined) && CurrentUserUtils.setupMobileUploads(doc); (doc.overlays === undefined) && CurrentUserUtils.setupOverlays(doc); (doc.expandingButtons === undefined) && CurrentUserUtils.setupExpandingButtons(doc); (doc.curPresentation === undefined) && CurrentUserUtils.setupDefaultPresentation(doc); (doc.sidebarButtons === undefined) && CurrentUserUtils.setupSidebarButtons(doc); - (doc.childClickFuncs === undefined) && CurrentUserUtils.setupChildClicks(doc); // this is equivalent to using PrefetchProxies to make sure all the childClickFuncs have been retrieved. PromiseValue(Cast(doc.childClickFuncs, Doc)).then(func => func && PromiseValue(func.data).then(DocListCast)); @@ -365,6 +367,8 @@ export class CurrentUserUtils { PromiseValue(Cast(doc.recentlyClosed, Doc)).then(recent => recent && PromiseValue(recent.data).then(DocListCast)); // this is equivalent to using PrefetchProxies to make sure all the sidebarButtons and noteType internal Doc's have been retrieved. PromiseValue(Cast(doc.noteTypes, Doc)).then(noteTypes => noteTypes && PromiseValue(noteTypes.data).then(DocListCast)); + PromiseValue(Cast(doc.clickFuncs, Doc)).then(func => func && PromiseValue(func.data).then(DocListCast)); + PromiseValue(Cast(doc.childClickFuncs, Doc)).then(func => func && PromiseValue(func.data).then(DocListCast)); PromiseValue(Cast(doc.sidebarButtons, Doc)).then(stackingDoc => { stackingDoc && PromiseValue(Cast(stackingDoc.data, listSpec(Doc))).then(sidebarButtons => { sidebarButtons && sidebarButtons.map((sidebarBtn, i) => { -- cgit v1.2.3-70-g09d2 From 43a6467b2fbeb5adb90c4d6efdde0c137925cda0 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 9 Apr 2020 12:19:37 -0400 Subject: from last --- src/client/views/nodes/FormattedTextBox.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 836d95830..5bcb89f0a 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -911,7 +911,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & this.doLinkOnDeselect(); FormattedTextBox._downEvent = true; FormattedTextBoxComment.textBox = this; - if (this.props.onClick && e.button === 0) { + if (this.props.onClick && e.button === 0 && !this.props.isSelected(false)) { e.preventDefault(); } if (e.button === 0 && this.active(true) && !e.altKey && !e.ctrlKey && !e.metaKey) { -- cgit v1.2.3-70-g09d2 From 8bca5882b39c21560c29cb97c2770a7a78384018 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 9 Apr 2020 15:41:44 -0400 Subject: starting cleanup --- src/client/documents/Documents.ts | 2 +- src/client/util/RichTextSchema.tsx | 2 - src/client/views/DocComponent.tsx | 22 +++++++- src/client/views/nodes/DocumentView.tsx | 2 +- src/client/views/nodes/FormattedTextBox.tsx | 2 +- src/client/views/nodes/ImageBox.tsx | 64 ++++++++++----------- src/client/views/nodes/ScreenshotBox.tsx | 1 - src/client/views/nodes/VideoBox.tsx | 66 ++++++++++------------ .../views/presentationview/PresElementBox.tsx | 4 +- 9 files changed, 84 insertions(+), 81 deletions(-) (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index d07e20b89..88179afd9 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -260,7 +260,7 @@ export namespace Docs { }], [DocumentType.RECOMMENDATION, { layout: { view: RecommendationsBox, dataField: data }, - options: { width: 200, height: 200 }, + options: { _width: 200, _height: 200 }, }], [DocumentType.WEBCAM, { layout: { view: DashWebRTCVideo, dataField: data } diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index de2707d36..3e6cbce56 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -959,8 +959,6 @@ export class DashFieldView { if (self._options?.length && !self._dashDoc[self._fieldKey]) { self._dashDoc[self._fieldKey] = StrCast(self._options[0].title); } - // NOTE: if the field key starts with "@", then the actual field key is stored in the field 'fieldKey' (removing the @). - self._fieldKey = self._fieldKey.startsWith("@") ? StrCast(tbox.props.Document[StrCast(self._fieldKey).substring(1)]) : self._fieldKey; this._labelSpan.innerHTML = `${self._fieldKey}: `; const fieldVal = Cast(this._dashDoc?.[self._fieldKey], "boolean", null); this._fieldCheck.style.display = (fieldVal === true || fieldVal === false) ? "inline-block" : "none"; diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index bbba2712e..325f7c042 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -18,7 +18,10 @@ export function DocComponent

(schemaCtor: (doc: D class Component extends Touchable

{ //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then @computed get Document(): T { return schemaCtor(this.props.Document); } - @computed get layoutDoc() { return PositionDocument(Doc.Layout(this.props.Document, this.props.LayoutDoc?.())); } + // This is the "The Document" -- it encapsulates, data, layout, and any templates + @computed get rootDoc() { return Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document; } + // This is the rendering data of a document -- it may be "The Document", or it may be some template document that holds the rendering info + @computed get layoutDoc() { return Doc.Layout(this.props.Document); } protected multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer; } return Component; @@ -37,8 +40,13 @@ export function DocExtendableComponent

(schemaCt class Component extends Touchable

{ //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then @computed get Document(): T { return schemaCtor(this.props.Document); } + // This is the "The Document" -- it encapsulates, data, layout, and any templates + @computed get rootDoc() { return Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document; } + // This is the rendering data of a document -- it may be "The Document", or it may be some template document that holds the rendering info @computed get layoutDoc() { return Doc.Layout(this.props.Document); } - @computed get dataDoc() { return (this.props.DataDoc && (this.props.Document.isTemplateForField || this.props.Document.isTemplateDoc) ? this.props.DataDoc : Cast(this.props.Document.resolvedDataDoc, Doc, null) || Doc.GetProto(this.props.Document)) as Doc; } + // This is the data part of a document -- ie, the data that is constant across all views of the document + @computed get dataDoc() { return this.props.DataDoc && (this.props.Document.isTemplateForField || this.props.Document.isTemplateDoc) ? this.props.DataDoc : this.props.Document[DataSym]; } + active = (outsideReaction?: boolean) => !this.props.Document.isBackground && ((this.props.Document.forceActive && this.props.rootSelected(outsideReaction)) || this.props.isSelected(outsideReaction) || this.props.renderDepth === 0);// && !InkingControl.Instance.selectedTool; // bcz: inking state shouldn't affect static tools protected multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer; } @@ -62,9 +70,17 @@ export function DocAnnotatableComponent

(schema @observable _isChildActive = false; //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then @computed get Document(): T { return schemaCtor(this.props.Document); } - @computed get layoutDoc() { return Doc.Layout(this.props.Document); } + + // This is the "The Document" -- it encapsulates, data, layout, and any templates + @computed get rootDoc() { return Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document; } + // This is the rendering data of a document -- it may be "The Document", or it may be some template document that holds the rendering info + @computed get layoutDoc() { return schemaCtor(Doc.Layout(this.props.Document)); } + // This is the data part of a document -- ie, the data that is constant across all views of the document @computed get dataDoc() { return this.props.DataDoc && (this.props.Document.isTemplateForField || this.props.Document.isTemplateDoc) ? this.props.DataDoc : this.props.Document[DataSym]; } + // key where data is stored + @computed get fieldKey() { return this.props.fieldKey; } + protected multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer; _annotationKey: string = "annotations"; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index fba924d9e..f0290f887 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -298,7 +298,7 @@ export class DocumentView extends DocComponent(Docu SelectionManager.DeselectAll(); const func = () => this.onClickHandler!.script.run({ this: this.props.Document, - self: Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document, + self: this.rootDoc, thisContainer: this.props.ContainingCollectionDoc, shiftKey: e.shiftKey }, console.log); if (this.props.Document !== Doc.UserDoc().undoBtn && this.props.Document !== Doc.UserDoc().redoBtn) { diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 5bcb89f0a..4cccfc966 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -850,7 +850,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & } } - const selectOnLoad = (Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document)[Id] === FormattedTextBox.SelectOnLoad; + const selectOnLoad = this.rootDoc[Id] === FormattedTextBox.SelectOnLoad; if (selectOnLoad && !this.props.dontRegisterView) { FormattedTextBox.SelectOnLoad = ""; this.props.select(false); diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 325d759ad..651171294 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -79,10 +79,6 @@ export class ImageBox extends DocAnnotatableComponent { @@ -146,19 +142,19 @@ export class ImageBox extends DocAnnotatableComponent { - const nw = NumCast(this.Document[this.fieldKey + "-nativeWidth"]); - const nh = NumCast(this.Document[this.fieldKey + "-nativeHeight"]); - const w = this.Document._width; - const h = this.Document._height; + const nw = NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"]); + const nh = NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"]); + const w = this.layoutDoc._width; + const h = this.layoutDoc._height; this.dataDoc[this.fieldKey + "-rotation"] = (NumCast(this.dataDoc[this.fieldKey + "-rotation"]) + 90) % 360; this.dataDoc[this.fieldKey + "-nativeWidth"] = nh; this.dataDoc[this.fieldKey + "-nativeHeight"] = nw; - this.Document._width = h; - this.Document._height = w; + this.layoutDoc._width = h; + this.layoutDoc._height = w; }); specificContextMenu = (e: React.MouseEvent): void => { - const field = Cast(this.Document[this.fieldKey], ImageField); + const field = Cast(this.dataDoc[this.fieldKey], ImageField); if (field) { const funcs: ContextMenuProps[] = []; funcs.push({ description: "Copy path", event: () => Utils.CopyText(field.url.href), icon: "expand-arrows-alt" }); @@ -258,7 +254,7 @@ export class ImageBox extends DocAnnotatableComponent 0.05) { if (!this.layoutDoc.isTemplateDoc || this.dataDoc !== this.layoutDoc) { @@ -267,22 +263,22 @@ export class ImageBox extends DocAnnotatableComponent { - if (this.Document[WidthSym]() && (!cachedNativeSize.width || !cachedNativeSize.height || Math.abs(1 - docAspect / rotatedAspect) > 0.1)) { - this.Document._height = this.Document[WidthSym]() * rotatedAspect; - this.dataDoc[this.fieldKey + "-nativeWidth"] = this.Document._nativeWidth = rotatedNativeSize.width; - this.dataDoc[this.fieldKey + "-nativeHeight"] = this.Document._nativeHeight = rotatedNativeSize.height; + if (this.layoutDoc[WidthSym]() && (!cachedNativeSize.width || !cachedNativeSize.height || Math.abs(1 - docAspect / rotatedAspect) > 0.1)) { + this.layoutDoc._height = this.layoutDoc[WidthSym]() * rotatedAspect; + this.dataDoc[this.fieldKey + "-nativeWidth"] = this.layoutDoc._nativeWidth = rotatedNativeSize.width; + this.dataDoc[this.fieldKey + "-nativeHeight"] = this.layoutDoc._nativeHeight = rotatedNativeSize.height; } }), 0); }).catch((err: any) => console.log(err)); } else if (Math.abs(1 - docAspect / cachedAspect) > 0.1) { - this.Document._width = this.Document[WidthSym]() || cachedNativeSize.width; - this.Document._height = this.Document[WidthSym]() * cachedAspect; + this.layoutDoc._width = this.layoutDoc[WidthSym]() || cachedNativeSize.width; + this.layoutDoc._height = this.layoutDoc[WidthSym]() * cachedAspect; } - } else if (this.Document._nativeWidth !== cachedNativeSize.width || this.Document._nativeHeight !== cachedNativeSize.height) { + } else if (this.layoutDoc._nativeWidth !== cachedNativeSize.width || this.layoutDoc._nativeHeight !== cachedNativeSize.height) { !(this.Document[StrCast(this.props.Document.layoutKey)] instanceof Doc) && setTimeout(() => { if (!(this.Document[StrCast(this.props.Document.layoutKey)] instanceof Doc)) { - this.Document._nativeWidth = cachedNativeSize.width; - this.Document._nativeHeight = cachedNativeSize.height; + this.layoutDoc._nativeWidth = cachedNativeSize.width; + this.layoutDoc._nativeHeight = cachedNativeSize.height; } }, 0); } @@ -311,7 +307,7 @@ export class ImageBox extends DocAnnotatableComponent this.recordAudioAnnotation(); considerGooglePhotosLink = () => { - const remoteUrl = this.Document.googlePhotosUrl; + const remoteUrl = this.dataDoc.googlePhotosUrl; return !remoteUrl ? (null) : ( { - const tags = this.Document.googlePhotosTags; + const tags = this.dataDoc.googlePhotosTags; return !tags ? (null) : (); } @@ -372,25 +368,23 @@ export class ImageBox extends DocAnnotatableComponent 20) { - const alts = DocListCast(this.dataDoc[this.fieldKey + "-alternates"]); - const altpaths = alts.filter(doc => doc.data instanceof ImageField).map(doc => this.choosePath((doc.data as ImageField).url)); - const field = this.dataDoc[this.fieldKey]; // if (w < 100 && this._smallRetryCount < 10) this._curSuffix = "_s"; // else if (w < 600 && this._mediumRetryCount < 10) this._curSuffix = "_m"; // else if (this._largeRetryCount < 10) this._curSuffix = "_l"; - if (field instanceof ImageField) paths = [this.choosePath(field.url)]; - paths.push(...altpaths); - return paths; + @computed get paths() { + const field = Cast(this.dataDoc[this.fieldKey], ImageField, null); // retrieve the primary image URL that is being rendered from the data doc + const alts = DocListCast(this.dataDoc[this.fieldKey + "-alternates"]); // retrieve alternate documents that may be rendered as alternate images + const altpaths = alts.map(doc => Cast(doc[Doc.LayoutFieldKey(doc)], ImageField, null)?.url.href).filter(url => url); // access the primary layout data of the alternate documents + const paths = field ? [this.choosePath(field.url), ...altpaths] : altpaths; + return paths.length ? paths : [Utils.CorsProxy("http://www.cs.brown.edu/~bcz/noImage.png")]; } @computed get content() { TraceMobx(); - const srcpath = this.paths[NumCast(this.props.Document.curPage, 0)]; + const srcpath = this.paths[0]; const fadepath = this.paths[Math.min(1, this.paths.length - 1)]; const { nativeWidth, nativeHeight } = this.nativeSize; const rotation = NumCast(this.dataDoc[this.fieldKey + "-rotation"]); @@ -401,7 +395,7 @@ export class ImageBox extends DocAnnotatableComponent + return

}
- {!this.props.Document._showAudio ? (null) : + {!this.layoutDoc._showAudio ? (null) :
{ const aspect = this.player!.videoWidth / this.player!.videoHeight; - const nativeWidth = (this.Document._nativeWidth || 0); - const nativeHeight = (this.Document._nativeHeight || 0); - if (!nativeWidth || !nativeHeight) { - if (!this.Document._nativeWidth) this.Document._nativeWidth = this.player!.videoWidth; - this.Document._nativeHeight = (this.Document._nativeWidth || 0) / aspect; - this.Document._height = (this.Document._width || 0) / aspect; - } - if (!this.Document.duration) this.Document.duration = this.player!.duration; + this.layoutDoc._nativeWidth = this.player!.videoWidth; + this.layoutDoc._nativeHeight = (this.layoutDoc._nativeWidth || 0) / aspect; + this.layoutDoc._height = (this.layoutDoc._width || 0) / aspect; + this.dataDoc[this.fieldKey + "-" + "duration"] = this.player!.duration; } @action public Play = (update: boolean = true) => { @@ -90,7 +86,7 @@ export class VideoBox extends DocAnnotatableComponent { if (returnedFilename) { const url = this.choosePath(Utils.prepend(returnedFilename)); const imageSummary = Docs.Create.ImageDocument(url, { - x: (this.Document.x || 0) + width, y: (this.Document.y || 0), - _width: 150, _height: height / width * 150, title: "--snapshot" + (this.Document.currentTimecode || 0) + " image-" + x: (this.layoutDoc.x || 0) + width, y: (this.layoutDoc.y || 0), displayTimecode: this.layoutDoc.currentTimecode || 0, + _width: 150, _height: height / width * 150, title: "--snapshot" + (this.layoutDoc.currentTimecode || 0) + " image-" }); imageSummary.isLinkButton = true; this.props.addDocument && this.props.addDocument(imageSummary); - DocUtils.MakeLink({ doc: imageSummary }, { doc: this.props.Document }, "video snapshot"); + DocUtils.MakeLink({ doc: imageSummary }, { doc: this.rootDoc }, "video snapshot"); } }); } @@ -142,8 +138,8 @@ export class VideoBox extends DocAnnotatableComponent { - this.player && (this.Document.currentTimecode = this.player.currentTime); - this._youtubePlayer && (this.Document.currentTimecode = this._youtubePlayer.getCurrentTime()); + this.player && (this.layoutDoc.currentTimecode = this.player.currentTime); + this._youtubePlayer && (this.layoutDoc.currentTimecode = this._youtubePlayer.getCurrentTime()); } componentDidMount() { @@ -151,12 +147,12 @@ export class VideoBox extends DocAnnotatableComponent this._fullScreen = vref.webkitDisplayingFullscreen); this._reactionDisposer && this._reactionDisposer(); - this._reactionDisposer = reaction(() => this.Document.currentTimecode || 0, + this._reactionDisposer = reaction(() => (this.layoutDoc.currentTimecode || 0), time => !this._playing && (vref.currentTime = time), { fireImmediately: true }); } } @@ -215,7 +211,7 @@ export class VideoBox extends DocAnnotatableComponentLoading
: @@ -259,7 +255,7 @@ export class VideoBox extends DocAnnotatableComponent { this._reactionDisposer && this._reactionDisposer(); this._youtubeReactionDisposer && this._youtubeReactionDisposer(); - this._reactionDisposer = reaction(() => this.Document.currentTimecode, () => !this._playing && this.Seek(this.Document.currentTimecode || 0)); + this._reactionDisposer = reaction(() => this.layoutDoc.currentTimecode, () => !this._playing && this.Seek((this.layoutDoc.currentTimecode || 0))); this._youtubeReactionDisposer = reaction(() => [this.props.isSelected(), DocumentDecorations.Instance.Interacting, InkingControl.Instance.selectedTool], () => { const interactive = InkingControl.Instance.selectedTool === InkTool.None && this.props.isSelected(true) && !DocumentDecorations.Instance.Interacting; iframe.style.pointerEvents = interactive ? "all" : "none"; @@ -274,7 +270,7 @@ export class VideoBox extends DocAnnotatableComponent {"" + Math.round(curTime)} {" " + Math.round((curTime - Math.trunc(curTime)) * 100)} @@ -316,7 +312,7 @@ export class VideoBox extends DocAnnotatableComponent { this._isResetClick += Math.abs(e.movementX) + Math.abs(e.movementY); - this.Seek(Math.max(0, (this.Document.currentTimecode || 0) + Math.sign(e.movementX) * 0.0333)); + this.Seek(Math.max(0, (this.layoutDoc.currentTimecode || 0) + Math.sign(e.movementX) * 0.0333)); e.stopImmediatePropagation(); } @@ -324,22 +320,22 @@ export class VideoBox extends DocAnnotatableComponent { document.removeEventListener("pointermove", this.onResetMove, true); document.removeEventListener("pointerup", this.onResetUp, true); - this._isResetClick < 10 && (this.Document.currentTimecode = 0); + this._isResetClick < 10 && (this.layoutDoc.currentTimecode = 0); } @computed get youtubeContent() { this._youtubeIframeId = VideoBox._youtubeIframeCounter++; this._youtubeContentCreated = this._forceCreateYouTubeIFrame ? true : true; const style = "videoBox-content-YouTube" + (this._fullScreen ? "-fullScreen" : ""); - const start = untracked(() => Math.round(this.Document.currentTimecode || 0)); + const start = untracked(() => Math.round((this.layoutDoc.currentTimecode || 0))); return