From 96de4bf18d5721d2b7957d7adb8ad3393462c4d1 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Fri, 31 Jan 2020 11:04:58 -0500 Subject: lint --- src/client/views/nodes/ImageBox.tsx | 1 + 1 file changed, 1 insertion(+) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 33c694c6e..382ca526d 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -67,6 +67,7 @@ const uploadIcons = { @observer export class ImageBox extends DocAnnotatableComponent(ImageDocument) { + protected multiTouchDisposer?: import("../../util/InteractionUtils").InteractionUtils.MultiTouchEventDisposer | undefined; public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ImageBox, fieldKey); } private _imgRef: React.RefObject = React.createRef(); private _dropDisposer?: DragManager.DragDropDisposer; -- cgit v1.2.3-70-g09d2 From 693665069c170983bd76336b804ec73870642fe3 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 1 Feb 2020 16:25:10 -0500 Subject: simplified Presentations a bit by using templates --- .../views/collections/CollectionDockingView.tsx | 15 ++-- src/client/views/nodes/DocumentContentsView.tsx | 7 +- src/client/views/nodes/ImageBox.tsx | 6 +- src/client/views/nodes/PresBox.tsx | 54 +++++++------- .../views/presentationview/PresElementBox.tsx | 85 ++++++++++++---------- src/new_fields/Doc.ts | 16 ++-- 6 files changed, 97 insertions(+), 86 deletions(-) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 159a1cded..e691788ad 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -35,6 +35,7 @@ import { ComputedField } from '../../../new_fields/ScriptField'; import { InteractionUtils } from '../../util/InteractionUtils'; import { TraceMobx } from '../../../new_fields/util'; import { Scripting } from '../../util/Scripting'; +import { PresElementBox } from '../presentationview/PresElementBox'; library.add(faFile); const _global = (window /* browser */ || global /* node */) as any; @@ -326,7 +327,7 @@ export class CollectionDockingView extends React.Component void = () => { if (this._containerRef.current) { this.reactionDisposer = reaction( - () => StrCast(this.props.Document.dockingConfig), + () => this.props.Document.dockingConfig, () => { if (!this._goldenLayout || this._ignoreStateChange !== JSON.stringify(this._goldenLayout.toConfig())) { // Because this is in a set timeout, if this component unmounts right after mounting, @@ -643,15 +644,9 @@ export class DockedFrameRenderer extends React.Component { //add this new doc to props.Document const curPres = Cast(CurrentUserUtils.UserDocument.curPresentation, Doc) as Doc; if (curPres) { - const pinDoc = Docs.Create.PresElementBoxDocument({ backgroundColor: "transparent", _xMargin: 5 }); - Doc.GetProto(pinDoc).presentationTargetDoc = doc; - Doc.GetProto(pinDoc).title = ComputedField.MakeFunction('(this.presentationTargetDoc instanceof Doc) && this.presentationTargetDoc.title?.toString()'); - const data = Cast(curPres.data, listSpec(Doc)); - if (data) { - data.push(pinDoc); - } else { - curPres.data = new List([pinDoc]); - } + const pinDoc = Doc.MakeAlias(doc); + pinDoc.presentationTargetDoc = doc; + Doc.AddDocToList(curPres, "data", pinDoc); if (!DocumentManager.Instance.getDocumentView(curPres)) { this.addDocTab(curPres, undefined, "onRight"); } diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 0b01e6471..3b9015994 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -81,6 +81,11 @@ export class DocumentContentsView extends React.Component 7 || !this.layout) ? (null) : + return (this.props.renderDepth > 7 || !this.layout || !this.layoutDoc) ? (null) : console.log(err)); } else if (this.Document._nativeHeight !== cachedNativeSize.width || this.Document._nativeWidth !== cachedNativeSize.height) { !(this.Document[StrCast(this.props.Document.layoutKey)] instanceof Doc) && setTimeout(() => { - this.Document._nativeWidth = cachedNativeSize.width; - this.Document._nativeHeight = cachedNativeSize.height; + if (!(this.Document[StrCast(this.props.Document.layoutKey)] instanceof Doc)) { + this.Document._nativeWidth = cachedNativeSize.width; + this.Document._nativeHeight = cachedNativeSize.height; + } }, 0); } } diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index 8d53f45a6..c661b7f4e 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -2,23 +2,22 @@ import React = require("react"); import { library } from '@fortawesome/fontawesome-svg-core'; import { faArrowLeft, faArrowRight, faEdit, faMinus, faPlay, faPlus, faStop, faTimes } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { action, computed, reaction, IReactionDisposer } from "mobx"; +import { action, computed, IReactionDisposer, reaction } from "mobx"; import { observer } from "mobx-react"; import { Doc, DocListCast, DocListCastAsync } from "../../../new_fields/Doc"; import { listSpec } from "../../../new_fields/Schema"; +import { ComputedField } from "../../../new_fields/ScriptField"; import { Cast, FieldValue, NumCast } from "../../../new_fields/Types"; import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; +import { Docs } from "../../documents/Documents"; import { DocumentManager } from "../../util/DocumentManager"; import { undoBatch } from "../../util/UndoManager"; -import { CollectionViewType } from "../collections/CollectionView"; import { CollectionDockingView } from "../collections/CollectionDockingView"; -import { CollectionView } from "../collections/CollectionView"; +import { CollectionView, CollectionViewType } from "../collections/CollectionView"; import { ContextMenu } from "../ContextMenu"; import { FieldView, FieldViewProps } from './FieldView'; import "./PresBox.scss"; -import { DocumentType } from "../../documents/DocumentTypes"; -import { Docs } from "../../documents/Documents"; -import { ComputedField } from "../../../new_fields/ScriptField"; +import { presSchema } from "../presentationview/PresElementBox"; library.add(faArrowLeft); library.add(faArrowRight); @@ -32,28 +31,18 @@ library.add(faEdit); @observer export class PresBox extends React.Component { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PresBox, fieldKey); } - _docListChangedReaction: IReactionDisposer | undefined; componentDidMount() { - this._docListChangedReaction = reaction(() => { - const value = FieldValue(Cast(this.props.Document[this.props.fieldKey], listSpec(Doc))); - return value ? value.slice() : value; - }, () => { - const value = FieldValue(Cast(this.props.Document[this.props.fieldKey], listSpec(Doc))); - if (value) { - value.forEach((item, i) => { - if (item instanceof Doc && item.type !== DocumentType.PRESELEMENT) { - const pinDoc = Docs.Create.PresElementBoxDocument({ backgroundColor: "transparent", _xMargin: 5 }); - Doc.GetProto(pinDoc).presentationTargetDoc = item; - Doc.GetProto(pinDoc).title = ComputedField.MakeFunction('this.presentationTargetDoc?.title?.toString()'); - value.splice(i, 1, pinDoc); - } - }); - } - }); - } - - componentWillUnmount() { - this._docListChangedReaction && this._docListChangedReaction(); + const userDoc = CurrentUserUtils.UserDocument; + let presTemp = Cast(userDoc.presentationTemplate, Doc); + if (presTemp instanceof Promise) { + presTemp.then(presTemp => this.props.Document.childLayout = presTemp); + } + else if (presTemp === undefined) { + presTemp = userDoc.presentationTemplate = Docs.Create.PresElementBoxDocument({ backgroundColor: "transparent", _xMargin: 5, isTemplateDoc: true, isTemplateForField: "data" }); + } + else { + this.props.Document.childLayout = presTemp; + } } @computed get childDocs() { return DocListCast(this.props.Document[this.props.fieldKey]); } @@ -282,6 +271,13 @@ export class PresBox extends React.Component { } } + addDocument = (doc: Doc) => { + const newPinDoc = Doc.MakeAlias(doc); + newPinDoc.presentationTargetDoc = doc; + return Doc.AddDocToList(this.props.Document, this.props.fieldKey, newPinDoc); + } + + //The function that resets the presentation by removing every action done by it. It also //stops the presentaton. @action @@ -342,7 +338,7 @@ export class PresBox extends React.Component { doc.presBox = this.props.Document; doc.presBoxKey = this.props.fieldKey; doc.collapsedHeight = hgt; - doc._height = ComputedField.MakeFunction("this.collapsedHeight + Number(this.embedOpen ? 100:0)"); + doc._nativeWidth = doc._nativeHeight = undefined; const curScale = NumCast(doc.viewScale, null); if (curScale === undefined) { doc.viewScale = 1; @@ -373,7 +369,7 @@ export class PresBox extends React.Component { {this.props.Document.inOverlay ? (null) :
- +
} diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx index dad55e1fd..afc88833e 100644 --- a/src/client/views/presentationview/PresElementBox.tsx +++ b/src/client/views/presentationview/PresElementBox.tsx @@ -2,7 +2,7 @@ import { library } from '@fortawesome/fontawesome-svg-core'; import { faFile as fileRegular } from '@fortawesome/free-regular-svg-icons'; import { faArrowDown, faArrowUp, faFile as fileSolid, faFileDownload, faLocationArrow, faSearch } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { action, computed } from "mobx"; +import { action, computed, reaction, IReactionDisposer } from "mobx"; import { observer } from "mobx-react"; import { Doc, DocListCast } from "../../../new_fields/Doc"; import { documentSchema } from '../../../new_fields/documentSchemas'; @@ -14,7 +14,7 @@ import { DocumentType } from "../../documents/DocumentTypes"; import { Transform } from "../../util/Transform"; import { CollectionViewType } from '../collections/CollectionView'; import { ContentFittingDocumentView } from '../nodes/ContentFittingDocumentView'; -import { DocComponent } from '../DocComponent'; +import { DocComponent, DocExtendableComponent } from '../DocComponent'; import { FieldView, FieldViewProps } from '../nodes/FieldView'; import "./PresElementBox.scss"; import React = require("react"); @@ -46,13 +46,23 @@ const PresDocument = makeInterface(presSchema, documentSchema); * It involves some functionality for its buttons and options. */ @observer -export class PresElementBox extends DocComponent(PresDocument) { +export class PresElementBox extends DocExtendableComponent(PresDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PresElementBox, fieldKey); } - @computed get indexInPres() { return DocListCast(this.presentationDoc[this.Document.presBoxKey || ""]).indexOf(this.props.Document); } - @computed get presentationDoc() { return Cast(this.Document.presBox, Doc) as Doc; } - @computed get targetDoc() { return this.Document.presentationTargetDoc as Doc; } - @computed get currentIndex() { return NumCast(this.presentationDoc.selectedDoc); } + _heightDisposer: IReactionDisposer | undefined; + @computed get indexInPres() { return this.originalLayout?.presBoxKey ? DocListCast(this.presentationDoc[StrCast(this.originalLayout?.presBoxKey)]).indexOf(this.originalLayout) : 0; } + @computed get presentationDoc() { return Cast(this.originalLayout?.presBox, Doc) as Doc; } + @computed get originalLayout() { return this.props.Document.expandedTemplate as Doc; } + @computed get targetDoc() { return this.originalLayout?.presentationTargetDoc as Doc; } + @computed get currentIndex() { return NumCast(this.presentationDoc?.selectedDoc); } + + componentDidMount() { + this._heightDisposer = reaction(() => [this.originalLayout.embedOpen, this.originalLayout.collapsedHeight], + params => this.originalLayout._height = NumCast(params[1]) + (Number(params[0]) ? 100 : 0), { fireImmediately: true }); + } + componentWillUnmount() { + this._heightDisposer?.(); + } /** * The function that is called on click to turn Hiding document till press option on/off. @@ -61,8 +71,8 @@ export class PresElementBox extends DocComponent(P @action onHideDocumentUntilPressClick = (e: React.MouseEvent) => { e.stopPropagation(); - this.Document.hideTillShownButton = !this.Document.hideTillShownButton; - if (!this.Document.hideTillShownButton) { + this.originalLayout.hideTillShownButton = !this.originalLayout.hideTillShownButton; + if (!this.originalLayout.hideTillShownButton) { if (this.indexInPres >= this.currentIndex && this.targetDoc) { this.targetDoc.opacity = 1; } @@ -81,13 +91,13 @@ export class PresElementBox extends DocComponent(P @action onHideDocumentAfterPresentedClick = (e: React.MouseEvent) => { e.stopPropagation(); - this.Document.hideAfterButton = !this.Document.hideAfterButton; - if (!this.Document.hideAfterButton) { + this.originalLayout.hideAfterButton = !this.originalLayout.hideAfterButton; + if (!this.originalLayout.hideAfterButton) { if (this.indexInPres <= this.currentIndex && this.targetDoc) { this.targetDoc.opacity = 1; } } else { - if (this.Document.fadeButton) this.Document.fadeButton = false; + if (this.originalLayout.fadeButton) this.originalLayout.fadeButton = false; if (this.presentationDoc.presStatus && this.indexInPres < this.currentIndex && this.targetDoc) { this.targetDoc.opacity = 0; } @@ -102,13 +112,13 @@ export class PresElementBox extends DocComponent(P @action onFadeDocumentAfterPresentedClick = (e: React.MouseEvent) => { e.stopPropagation(); - this.Document.fadeButton = !this.Document.fadeButton; - if (!this.Document.fadeButton) { + this.originalLayout.fadeButton = !this.originalLayout.fadeButton; + if (!this.originalLayout.fadeButton) { if (this.indexInPres <= this.currentIndex && this.targetDoc) { this.targetDoc.opacity = 1; } } else { - this.Document.hideAfterButton = false; + this.originalLayout.hideAfterButton = false; if (this.presentationDoc.presStatus && (this.indexInPres < this.currentIndex) && this.targetDoc) { this.targetDoc.opacity = 0.5; } @@ -121,11 +131,11 @@ export class PresElementBox extends DocComponent(P @action onNavigateDocumentClick = (e: React.MouseEvent) => { e.stopPropagation(); - this.Document.navButton = !this.Document.navButton; - if (this.Document.navButton) { - this.Document.showButton = false; + this.originalLayout.navButton = !this.originalLayout.navButton; + if (this.originalLayout.navButton) { + this.originalLayout.showButton = false; if (this.currentIndex === this.indexInPres) { - this.props.focus(this.props.Document); + this.props.focus(this.originalLayout); } } } @@ -137,13 +147,13 @@ export class PresElementBox extends DocComponent(P onZoomDocumentClick = (e: React.MouseEvent) => { e.stopPropagation(); - this.Document.showButton = !this.Document.showButton; - if (!this.Document.showButton) { - this.props.Document.viewScale = 1; + this.originalLayout.showButton = !this.originalLayout.showButton; + if (!this.originalLayout.showButton) { + this.originalLayout.viewScale = 1; } else { - this.Document.navButton = false; + this.originalLayout.navButton = false; if (this.currentIndex === this.indexInPres) { - this.props.focus(this.props.Document); + this.props.focus(this.originalLayout); } } } @@ -157,7 +167,7 @@ export class PresElementBox extends DocComponent(P * presentation element. */ renderEmbeddedInline = () => { - if (!this.Document.embedOpen || !this.targetDoc) { + if (!this.originalLayout.embedOpen || !this.targetDoc) { return (null); } @@ -170,7 +180,8 @@ export class PresElementBox extends DocComponent(P width: propDocWidth === 0 ? "auto" : propDocWidth * scale(), }}> (P const treecontainer = this.props.ContainingCollectionDoc?._viewType === CollectionViewType.Tree; const className = "presElementBox-item" + (this.currentIndex === this.indexInPres ? " presElementBox-selected" : ""); const pbi = "presElementBox-interaction"; - return ( + return !this.originalLayout ? (null) : (
{ this.props.focus(this.props.Document); e.stopPropagation(); }}> + onClick={e => { this.props.focus(this.originalLayout); e.stopPropagation(); }}> {treecontainer ? (null) : <> - {`${this.indexInPres + 1}. ${this.Document.title}`} + {`${this.indexInPres + 1}. ${this.targetDoc?.title}`} - +
} - - - - - - - + + + + + + +
{this.renderEmbeddedInline()} diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 5f78636a9..0624d6698 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -445,8 +445,8 @@ export namespace Doc { // between the two. If so, the layoutDoc is expanded into a new document that inherits the properties // of the original layout while allowing for individual layout properties to be overridden in the expanded layout. // - export function expandTemplateLayout(templateLayoutDoc: Doc, dataDoc?: Doc) { - if (!WillExpandTemplateLayout(templateLayoutDoc, dataDoc) || !dataDoc) return templateLayoutDoc; + export function expandTemplateLayout(templateLayoutDoc: Doc, targetDoc?: Doc) { + if (!WillExpandTemplateLayout(templateLayoutDoc, targetDoc) || !targetDoc) return templateLayoutDoc; const templateField = StrCast(templateLayoutDoc.isTemplateForField); // the field that the template renders // First it checks if an expanded layout already exists -- if so it will be stored on the dataDoc @@ -455,13 +455,15 @@ export namespace Doc { // saves it on the data doc indexed by the template layout's id. // const expandedLayoutFieldKey = templateField + "-layout[" + templateLayoutDoc[Id] + "]"; - const expandedTemplateLayout = dataDoc?.[expandedLayoutFieldKey]; + const expandedTemplateLayout = targetDoc?.[expandedLayoutFieldKey]; if (expandedTemplateLayout === undefined) { setTimeout(() => { - if (!dataDoc[expandedLayoutFieldKey]) { + if (!targetDoc[expandedLayoutFieldKey]) { const newLayoutDoc = Doc.MakeDelegate(templateLayoutDoc, undefined, "[" + templateLayoutDoc.title + "]"); - dataDoc[expandedLayoutFieldKey] = newLayoutDoc; - newLayoutDoc.resolvedDataDoc = dataDoc; + newLayoutDoc.expandedTemplate = targetDoc; + targetDoc[expandedLayoutFieldKey] = newLayoutDoc; + const dataDoc = Doc.GetProto(targetDoc); + newLayoutDoc.resolvedDataDoc = targetDoc; if (dataDoc[templateField] === undefined && templateLayoutDoc[templateField] instanceof List && Cast(templateLayoutDoc[templateField], listSpec(Doc), []).length) { dataDoc[templateField] = ComputedField.MakeFunction(`ObjectField.MakeCopy(templateLayoutDoc["${templateField}"] as List)`, { templateLayoutDoc: Doc.name }, { templateLayoutDoc: templateLayoutDoc }); } @@ -474,7 +476,7 @@ export namespace Doc { // if the childDoc is a template for a field, then this will return the expanded layout with its data doc. // otherwise, it just returns the childDoc export function GetLayoutDataDocPair(containerDoc: Doc, containerDataDoc: Opt, childDoc: Doc) { - const resolvedDataDoc = containerDataDoc === containerDoc || !containerDataDoc ? undefined : Doc.GetDataDoc(containerDataDoc); + const resolvedDataDoc = containerDataDoc === containerDoc || !containerDataDoc ? undefined : containerDataDoc; return { layout: Doc.expandTemplateLayout(childDoc, resolvedDataDoc), data: resolvedDataDoc }; } export function CreateDocumentExtensionForField(doc: Doc, fieldKey: string) { -- cgit v1.2.3-70-g09d2 From 8597134b6ada1e57ae08d49e24c00d11f728ba90 Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 6 Feb 2020 16:04:04 -0500 Subject: restored isBackground for documents that don't want to respond to anything. --- src/client/util/DragManager.ts | 4 ++-- .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 1 + src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 1 + src/client/views/nodes/ImageBox.scss | 5 ++--- src/client/views/nodes/ImageBox.tsx | 3 ++- 5 files changed, 8 insertions(+), 6 deletions(-) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index b0dd90947..e572f0fcb 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -15,7 +15,7 @@ import { listSpec } from "../../new_fields/Schema"; import { Scripting } from "./Scripting"; import { convertDropDataToButtons } from "./DropConverter"; -export type dropActionType = "alias" | "copy" | "move" | undefined; +export type dropActionType = "alias" | "copy" | undefined; export function SetupDrag( _reference: React.RefObject, docFunc: () => Doc | Promise | undefined, @@ -198,7 +198,7 @@ export namespace DragManager { ); e.docDragData?.droppedDocuments.forEach((drop: Doc, i: number) => Cast(dragData.draggedDocuments[i].removeDropProperties, listSpec("string"), []).map(prop => { - drop[prop] = "move"; + drop[prop] = undefined; }) ); }; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 1ac0d28f5..f2c4cda34 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -126,6 +126,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @undoBatch @action drop = (e: Event, de: DragManager.DropEvent) => { + if (this.props.Document.isBackground) return false; const xf = this.getTransform(); const xfo = this.getTransformOverlay(); const [xp, yp] = xf.transformPoint(de.x, de.y); diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 2a11267d4..f484b6115 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -88,6 +88,7 @@ export class CollectionFreeFormDocumentView extends DocComponent {!this.props.fitToBox ? Date: Fri, 7 Feb 2020 15:17:06 -0500 Subject: fixed imageresize issue --- src/client/views/nodes/ImageBox.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 1951fcc1a..896ac1685 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -257,7 +257,7 @@ export class ImageBox extends DocAnnotatableComponent console.log(err)); - } else if (this.Document._nativeHeight !== cachedNativeSize.width || this.Document._nativeWidth !== cachedNativeSize.height) { + } else if (this.Document._nativeWidth !== cachedNativeSize.width || this.Document._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; -- cgit v1.2.3-70-g09d2 From 4af6916f1f68b879e11e38b4d2a3f9a0708ac979 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Tue, 11 Feb 2020 06:21:39 -0500 Subject: factored out image resizing, fixed back button, importer script, tooltips on range sliders --- src/client/documents/Documents.ts | 21 +- src/client/util/SettingsManager.scss | 2 +- .../views/collections/CollectionTimeView.scss | 17 +- .../views/collections/CollectionTimeView.tsx | 12 +- src/client/views/nodes/ImageBox.tsx | 2 +- src/client/views/nodes/SliderBox-components.tsx | 10 +- src/client/views/nodes/SliderBox.tsx | 27 +- src/scraping/buxton/final/BuxtonImporter.ts | 180 ++++---- src/scraping/buxton/final/json/buxton.json | 490 ++++++++++----------- src/server/DashUploadUtils.ts | 108 +++-- 10 files changed, 447 insertions(+), 422 deletions(-) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 027d7129e..49d1820f5 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -355,13 +355,18 @@ export namespace Docs { _LODdisable: true }); Networking.FetchFromServer("/buxton").then(response => { - const parentProto = Doc.GetProto(parent); - parentProto.data = new List(); const devices = JSON.parse(response); if (!Array.isArray(devices)) { - alert("Improper Buxton import formatting!"); + if ("error" in devices) { + loading.title = devices.error; + } else { + console.log(devices); + alert("The importer returned an unexpected import format. Check the console."); + } return; } + const parentProto = Doc.GetProto(parent); + parentProto.data = new List(); devices.forEach(device => { const { __images } = device; delete device.__images; @@ -370,9 +375,9 @@ export namespace Docs { const constructed = __images.map(relative => Utils.prepend(relative)); const deviceImages = constructed.map((url, i) => ImageDocument(url, { title: `image${i}.${extname(url)}` })); const doc = StackingDocument(deviceImages, { title: device.title, _LODdisable: true }); - const protoDoc = Doc.GetProto(doc); - protoDoc.hero = new ImageField(constructed[0]); - Docs.Get.DocumentHierarchyFromJson(device, undefined, protoDoc); + const deviceProto = Doc.GetProto(doc); + deviceProto.hero = new ImageField(constructed[0]); + Docs.Get.DocumentHierarchyFromJson(device, undefined, deviceProto); Doc.AddDocToList(parentProto, "data", doc); } }); @@ -507,10 +512,6 @@ export namespace Docs { return doc; } - export function IconDocument(icon: string, options: DocumentOptions = {}) { - return InstanceFromProto(Prototypes.get(DocumentType.ICON), new IconField(icon), options); - } - export function PdfDocument(url: string, options: DocumentOptions = {}) { return InstanceFromProto(Prototypes.get(DocumentType.PDF), new PdfField(new URL(url)), options); } diff --git a/src/client/util/SettingsManager.scss b/src/client/util/SettingsManager.scss index 7a0fb0741..6513cb223 100644 --- a/src/client/util/SettingsManager.scss +++ b/src/client/util/SettingsManager.scss @@ -1,6 +1,6 @@ @import "../views/globalCssVariables"; -.dialogue-box { +.settings-interface { background-color: whitesmoke !important; color: grey; width: 450px; diff --git a/src/client/views/collections/CollectionTimeView.scss b/src/client/views/collections/CollectionTimeView.scss index 02ef4e2d2..2dffb3ea0 100644 --- a/src/client/views/collections/CollectionTimeView.scss +++ b/src/client/views/collections/CollectionTimeView.scss @@ -1,21 +1,26 @@ -.collectionTimeView, .collectionTimeView-pivot { +.collectionTimeView, +.collectionTimeView-pivot { display: flex; flex-direction: row; position: absolute; height: 100%; width: 100%; overflow: hidden; + .collectionTimeView-backBtn { background: green; display: inline; margin-right: 20px; } + .collectionFreeform-customText { text-align: left; } + .collectionFreeform-customDiv { position: absolute; } + .collectionTimeView-thumb { position: absolute; width: 30px; @@ -28,14 +33,17 @@ border-radius: 9px; opacity: 0.25; } + .collectionTimeView-thumb-min { - margin-left:25%; + margin-left: 25%; } + .collectionTimeView-thumb-max { - margin-left:75%; + margin-left: 75%; } + .collectionTimeView-thumb-mid { - margin-left:50%; + margin-left: 50%; } .collectionTimeView-flyout { @@ -118,6 +126,7 @@ left: -10px; } } + .collectionTimeView-pivot { .collectionFreeform-customText { text-align: center; diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index db176d0bc..808144c18 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -46,7 +46,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { this.props.Document._fitToBox = true; } if (!this.props.Document.onViewDefClick) { - this.props.Document.onViewDefDivClick = ScriptField.MakeScript("pivotColumnClick(this,payload)", { payload: "any" }) + this.props.Document.onViewDefDivClick = ScriptField.MakeScript("pivotColumnClick(this,payload)", { payload: "any" }); } } @@ -164,7 +164,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { typeof (pair.layout[fieldKey]) === "string").map(fieldKey => keySet.add(fieldKey))); Array.from(keySet).map(fieldKey => docItems.push({ description: ":" + fieldKey, event: () => this.props.Document._pivotField = fieldKey, icon: "compress-arrows-alt" })); - docItems.push({ description: ":(null)", event: () => this.props.Document._pivotField = undefined, icon: "compress-arrows-alt" }) + docItems.push({ description: ":(null)", event: () => this.props.Document._pivotField = undefined, icon: "compress-arrows-alt" }); ContextMenu.Instance.addItem({ description: "Pivot Fields ...", subitems: docItems, icon: "eye" }); const pt = this.props.ScreenToLocalTransform().inverse().transformPoint(x, y); ContextMenu.Instance.displayMenu(x, y, ":"); @@ -282,9 +282,9 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { const layoutItems: ContextMenuProps[] = []; const doc = this.props.Document; - layoutItems.push({ description: "Force Timeline", event: () => { doc._forceRenderEngine = "timeline" }, icon: "compress-arrows-alt" }); - layoutItems.push({ description: "Force Pivot", event: () => { doc._forceRenderEngine = "pivot" }, icon: "compress-arrows-alt" }); - layoutItems.push({ description: "Auto Time/Pivot layout", event: () => { doc._forceRenderEngine = undefined }, icon: "compress-arrows-alt" }); + layoutItems.push({ description: "Force Timeline", event: () => { doc._forceRenderEngine = "timeline"; }, icon: "compress-arrows-alt" }); + layoutItems.push({ description: "Force Pivot", event: () => { doc._forceRenderEngine = "pivot"; }, icon: "compress-arrows-alt" }); + layoutItems.push({ description: "Auto Time/Pivot layout", event: () => { doc._forceRenderEngine = undefined; }, icon: "compress-arrows-alt" }); layoutItems.push({ description: "Sync with presentation", event: () => CollectionTimeView.SyncTimelineToPresentation(doc), icon: "compress-arrows-alt" }); ContextMenu.Instance.addItem({ description: "Pivot/Time Options ...", subitems: layoutItems, icon: "eye" }); @@ -331,7 +331,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
-
); diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index a7c1990e9..4f50be5b0 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -651,8 +651,7 @@ export class PDFViewer extends DocAnnotatableComponent + ContainingCollectionDoc={this.props.ContainingCollectionView?.props.Document}>
; } diff --git a/src/new_fields/documentSchemas.ts b/src/new_fields/documentSchemas.ts index 1707524cb..aac6d4e3e 100644 --- a/src/new_fields/documentSchemas.ts +++ b/src/new_fields/documentSchemas.ts @@ -10,22 +10,24 @@ export const documentSchema = createSchema({ title: "string", // document title (can be on either data document or layout) dropAction: "string", // override specifying what should happen when this document is dropped (can be "alias" or "copy") childDropAction: "string", // specify the override for what should happen when the child of a collection is dragged from it and dropped (can be "alias" or "copy") - _nativeWidth: "number", // native width of document which determines how much document contents are scaled when the document's width is set - _nativeHeight: "number", // " - _width: "number", // width of document in its container's coordinate system - _height: "number", // " + _nativeWidth: "number", // native width of document which determines how much document contents are scaled when the document's width is set + _nativeHeight: "number", // " + _width: "number", // width of document in its container's coordinate system + _height: "number", // " _freeformLayoutEngine: "string",// the string ID for the layout engine to use to layout freeform view documents - _LODdisable: "boolean", // whether to disbale LOD switching for CollectionFreeFormViews + _LODdisable: "boolean", // whether to disbale LOD switching for CollectionFreeFormViews _pivotField: "string", // specifies which field should be used as the timeline/pivot axis + _replacedChrome: "string", // what the default chrome is replaced with. Currently only supports the value of 'replaced' for PresBox's. + _chromeStatus: "string", // determines the state of the collection chrome. values allowed are 'replaced', 'enabled', 'disabled', 'collapsed' color: "string", // foreground color of document backgroundColor: "string", // background color of document opacity: "number", // opacity of document - creationDate: DateField, // when the document was created + creationDate: DateField, // when the document was created links: listSpec(Doc), // computed (readonly) list of links associated with this document removeDropProperties: listSpec("string"), // properties that should be removed from the alias/copy/etc of this document when it is dropped onClick: ScriptField, // script to run when document is clicked (can be overriden by an onClick prop) - onPointerDown: ScriptField, // script to run when document is clicked (can be overriden by an onClick prop) - onPointerUp: ScriptField, // script to run when document is clicked (can be overriden by an onClick prop) + onPointerDown: ScriptField, // script to run when document is clicked (can be overriden by an onClick prop) + onPointerUp: ScriptField, // script to run when document is clicked (can be overriden by an onClick prop) onDragStart: ScriptField, // script to run when document is dragged (without being selected). the script should return the Doc to be dropped. dragFactory: Doc, // the document that serves as the "template" for the onDragStart script. ie, to drag out copies of the dragFactory document. ignoreAspect: "boolean", // whether aspect ratio should be ignored when laying out or manipulating the document @@ -36,7 +38,7 @@ export const documentSchema = createSchema({ treeViewOpen: "boolean", // flag denoting whether the documents sub-tree (contents) is visible or hidden treeViewExpandedView: "string", // name of field whose contents are being displayed as the document's subtree preventTreeViewOpen: "boolean", // ignores the treeViewOpen flag (for allowing a view to not be slaved to other views of the document) - currentTimecode: "number", // current play back time of a temporal document (video / audio) + currentTimecode: "number", // current play back time of a temporal document (video / audio) maximizeLocation: "string", // flag for where to place content when following a click interaction (e.g., onRight, inPlace, inTab) lockedPosition: "boolean", // whether the document can be moved (dragged) lockedTransform: "boolean", // whether the document can be panned/zoomed diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 3a2a0f513..0185017ec 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -48,7 +48,7 @@ export class CurrentUserUtils { // setup the "creator" buttons for the sidebar-- eg. the default set of draggable document creation tools static setupCreatorButtons(doc: Doc, buttons?: string[]) { const notes = CurrentUserUtils.setupNoteTypes(doc); - const emptyPresentation = Docs.Create.PresDocument(new List(), { title: "Presentation", _viewType: CollectionViewType.Stacking, _chromeStatus: "enabled", showTitle: "title", boxShadow: "0 0" }); + const emptyPresentation = Docs.Create.PresDocument(new List(), { title: "Presentation", _viewType: CollectionViewType.Stacking, _chromeStatus: "replaced", showTitle: "title", boxShadow: "0 0" }); const emptyCollection = Docs.Create.FreeformDocument([], { _nativeWidth: undefined, _nativeHeight: undefined, _LODdisable: true, _width: 150, _height: 100, title: "freeform" }); doc.noteTypes = Docs.Create.TreeDocument(notes, { title: "Note Types", _height: 75 }); doc.activePen = doc; @@ -270,7 +270,7 @@ export class CurrentUserUtils { // the initial presentation Doc to use static setupDefaultPresentation(doc: Doc) { - doc.curPresentation = Docs.Create.PresDocument(new List(), { title: "Presentation", _viewType: CollectionViewType.Stacking, _chromeStatus: "enabled", showTitle: "title", boxShadow: "0 0" }); + doc.curPresentation = Docs.Create.PresDocument(new List(), { title: "Presentation", _viewType: CollectionViewType.Stacking, _chromeStatus: "replaced", showTitle: "title", boxShadow: "0 0" }); } static setupMobileUploads(doc: Doc) { -- cgit v1.2.3-70-g09d2 From ec5c878fb4c5f7e03fdd214c0841cf2ebf983e8c Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Tue, 11 Feb 2020 15:48:06 -0500 Subject: refactored image upload data response format, google docs working for specific interactions --- .../util/Import & Export/DirectoryImportBox.tsx | 4 +- src/client/util/RichTextSchema.tsx | 1 + src/client/views/collections/CollectionSubView.tsx | 8 +- src/client/views/nodes/DocumentView.tsx | 4 +- src/client/views/nodes/ImageBox.tsx | 4 +- src/new_fields/RichTextUtils.ts | 30 ++--- src/scraping/buxton/final/json/buxton.json | 130 ++++++++++----------- src/server/ApiManagers/DownloadManager.ts | 2 +- src/server/DashUploadUtils.ts | 37 ++++-- src/server/apis/google/GooglePhotosUploadUtils.ts | 3 +- 10 files changed, 121 insertions(+), 102 deletions(-) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/util/Import & Export/DirectoryImportBox.tsx b/src/client/util/Import & Export/DirectoryImportBox.tsx index 071015193..d04f56e57 100644 --- a/src/client/util/Import & Export/DirectoryImportBox.tsx +++ b/src/client/util/Import & Export/DirectoryImportBox.tsx @@ -120,8 +120,8 @@ export default class DirectoryImportBox extends React.Component runInAction(() => this.completed += batch.length); }); - await Promise.all(uploads.map(async ({ name, type, clientAccessPath, exifData }) => { - const path = Utils.prepend(clientAccessPath); + await Promise.all(uploads.map(async ({ name, type, accessPaths, exifData }) => { + const path = Utils.prepend(accessPaths.agnostic.client); const document = await Docs.Get.DocumentFromType(type, path, { _width: 300, title: name }); const { data, error } = exifData; if (document) { diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index f12b3632c..3cf0561dc 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -133,6 +133,7 @@ export const nodes: { [index: string]: NodeSpec } = { inline: true, attrs: { src: {}, + agnostic: { default: null }, width: { default: 100 }, alt: { default: null }, title: { default: null }, diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 293a8491a..20941493f 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -232,8 +232,8 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { const split = img.split("src=\"")[1].split("\"")[0]; let source = split; if (split.startsWith("data:image") && split.includes("base64")) { - const [{ clientAccessPath }] = await Networking.PostToServer("/uploadRemoteImage", { sources: [split] }); - source = Utils.prepend(clientAccessPath); + const [{ accessPaths }] = await Networking.PostToServer("/uploadRemoteImage", { sources: [split] }); + source = Utils.prepend(accessPaths.agnostic.client); } const doc = Docs.Create.ImageDocument(source, { ...options, _width: 300 }); ImageUtils.ExtractExif(doc); @@ -312,9 +312,9 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { const dropFileName = file ? file.name : "-empty-"; promises.push(Networking.PostFormDataToServer("/uploadFormData", formData).then(results => { results.map(action((result: any) => { - const { clientAccessPath, nativeWidth, nativeHeight, contentSize } = result; + const { accessPaths, nativeWidth, nativeHeight, contentSize } = result; const full = { ...options, _width: 300, title: dropFileName }; - const pathname = Utils.prepend(clientAccessPath); + const pathname = Utils.prepend(accessPaths.agnostic.client); Docs.Get.DocumentFromType(type, pathname, full).then(doc => { if (doc) { const proto = Doc.GetProto(doc); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index e4ab3e746..5c5a87cb9 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -277,7 +277,7 @@ export class DocumentView extends DocComponent(Docu } preventDefault && e.preventDefault(); } - }) + }); buttonClick = async (altKey: boolean, ctrlKey: boolean) => { const linkDocs = DocListCast(this.props.Document.links); @@ -636,7 +636,7 @@ export class DocumentView extends DocComponent(Docu if (StrCast(tempDoc.title) === layout) { foundLayout = tempDoc; } - }) + }); DocumentView. makeCustomViewClicked(this.props.Document, this.props.DataDoc, Docs.Create.StackingDocument, layout, foundLayout); } else { diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index db9800de4..c0e102195 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -321,12 +321,12 @@ export class ImageBox extends DocAnnotatableComponent this.uploadIcon = loading); - const [{ clientAccessPath }] = await Networking.PostToServer("/uploadRemoteImage", { sources: [primary] }); + const [{ accessPaths }] = await Networking.PostToServer("/uploadRemoteImage", { sources: [primary] }); dataDoc.originalUrl = primary; let succeeded = true; let data: ImageField | undefined; try { - data = new ImageField(Utils.prepend(clientAccessPath)); + data = new ImageField(Utils.prepend(accessPaths.agnostic.client)); } catch { succeeded = false; } diff --git a/src/new_fields/RichTextUtils.ts b/src/new_fields/RichTextUtils.ts index 016bcc4ca..7c1fc39d8 100644 --- a/src/new_fields/RichTextUtils.ts +++ b/src/new_fields/RichTextUtils.ts @@ -114,6 +114,7 @@ export namespace RichTextUtils { width: number; title: string; url: string; + agnostic: string; } const parseInlineObjects = async (document: docs_v1.Schema$Document): Promise> => { @@ -135,17 +136,17 @@ export namespace RichTextUtils { for (let i = 0; i < objects.length; i++) { const object = objects[i]; - const { clientAccessPath } = uploads[i]; + const { accessPaths } = uploads[i]; + const { agnostic, _m } = accessPaths; const embeddedObject = object.inlineObjectProperties!.embeddedObject!; const size = embeddedObject.size!; const width = size.width!.magnitude!; - const ext = extname(clientAccessPath); - const url = Utils.prepend(clientAccessPath.replace(ext, "_m" + ext)); inlineObjectMap.set(object.objectId!, { title: embeddedObject.title || `Imported Image from ${document.title}`, width, - url + url: Utils.prepend(_m.client), + agnostic: Utils.prepend(agnostic.client) }); } } @@ -267,19 +268,19 @@ export namespace RichTextUtils { }; const imageNode = (schema: any, image: ImageTemplate, textNote: Doc) => { - const { url: src, width } = image; + const { url: src, width, agnostic } = image; let docid: string; - const guid = Utils.GenerateDeterministicGuid(src); + const guid = Utils.GenerateDeterministicGuid(agnostic); const backingDocId = StrCast(textNote[guid]); if (!backingDocId) { - const backingDoc = Docs.Create.ImageDocument(src, { _width: 300, _height: 300 }); + const backingDoc = Docs.Create.ImageDocument(agnostic, { _width: 300, _height: 300 }); DocumentView.makeCustomViewClicked(backingDoc, undefined, Docs.Create.FreeformDocument); docid = backingDoc[Id]; textNote[guid] = docid; } else { docid = backingDocId; } - return schema.node("image", { src, width, docid, float: null, location: "onRight" }); + return schema.node("image", { src, agnostic, width, docid, float: null, location: "onRight" }); }; const textNode = (schema: any, run: docs_v1.Schema$TextRun) => { @@ -435,7 +436,7 @@ export namespace RichTextUtils { const width = attrs.width; requests.push(await EncodeImage({ startIndex: position + nodeSize - 1, - uri: attrs.src, + uri: attrs.agnostic, width: Number(typeof width === "string" ? width.replace("px", "") : width) })); } @@ -498,15 +499,18 @@ export namespace RichTextUtils { }; }; - const EncodeImage = async (information: ImageInformation) => { - const source = [Docs.Create.ImageDocument(information.uri)]; + const EncodeImage = async ({ uri, width, startIndex }: ImageInformation) => { + if (!uri) { + return {}; + } + const source = [Docs.Create.ImageDocument(uri)]; const baseUrls = await GooglePhotos.Transactions.UploadThenFetch(source); if (baseUrls) { return { insertInlineImage: { uri: baseUrls[0], - objectSize: { width: { magnitude: information.width, unit: "PT" } }, - location: { index: information.startIndex } + objectSize: { width: { magnitude: width, unit: "PT" } }, + location: { index: startIndex } } }; } diff --git a/src/scraping/buxton/final/json/buxton.json b/src/scraping/buxton/final/json/buxton.json index 5c2e2c90c..16b28916b 100644 --- a/src/scraping/buxton/final/json/buxton.json +++ b/src/scraping/buxton/final/json/buxton.json @@ -18,9 +18,9 @@ "3DCad_Brochure.jpg" ], "__images": [ - "/files/images/buxton/upload_19ce4ebd-f207-4724-b8bf-610c8e1cf322.png", - "/files/images/buxton/upload_4dde8de0-f1ec-4ffb-b7cc-57b8c4ae6c94.png", - "/files/images/buxton/upload_825e8ed8-063c-428b-917d-eb62ea218f05.png" + "/files/images/buxton/upload_793981b0-d7da-45d1-a643-596cc3834166.png", + "/files/images/buxton/upload_6259e28a-055e-4b02-b547-e72c5e6fa3c0.png", + "/files/images/buxton/upload_4f4fb80f-467a-41e7-9bf5-1b1f377b2ec4.png" ], "title": "3Dconnexion CadMan 3D Motion Controller", "company": "3Dconnexion", @@ -63,11 +63,11 @@ "SpaceMouse_Plus_Info_Sheet.jpg" ], "__images": [ - "/files/images/buxton/upload_f84cb54e-9bdb-4fbc-9503-6cfa8ddd65be.jpg", - "/files/images/buxton/upload_506b5361-a9fd-4440-a19b-5b4af461878a.png", - "/files/images/buxton/upload_60380383-3603-4624-98cf-50a0d4afe4c9.png", - "/files/images/buxton/upload_2fad6fb2-f1e1-4fe3-915b-33586f05fcad.png", - "/files/images/buxton/upload_effcd815-49eb-4cd4-82cf-2519e58eb729.png" + "/files/images/buxton/upload_4a6cbfa8-964b-41d3-9f24-7d1aed22cd79.jpg", + "/files/images/buxton/upload_8c33d572-07da-4599-944c-eb2370b16a63.png", + "/files/images/buxton/upload_9afc5cca-6208-4944-a0f6-1c3fcd41fdcf.png", + "/files/images/buxton/upload_74e79798-9c9e-4c54-b42f-5813f218bc63.png", + "/files/images/buxton/upload_2bea6876-dc4e-4681-a1d3-433caec163c1.png" ], "title": "3Dconnexion Magellan/SpaceMouse Plus", "company": "3Dconnexion", @@ -114,13 +114,13 @@ "SpaceBall_5000_Data_Sheet.jpg" ], "__images": [ - "/files/images/buxton/upload_81972990-8cad-4299-926a-fe5d49711a80.jpg", - "/files/images/buxton/upload_04103620-72e4-431f-b34f-61d0f158277a.png", - "/files/images/buxton/upload_9bfe7c5a-1c5e-46e3-8f8d-4e0eec3e38e3.png", - "/files/images/buxton/upload_77da85f5-6575-4a8d-acb6-52f2df3307b0.png", - "/files/images/buxton/upload_1c041a33-b258-42d1-b9f2-d610a4838fb3.jpg", - "/files/images/buxton/upload_841f0d98-27d7-4298-a71d-c5cba72a262a.jpg", - "/files/images/buxton/upload_0e0eaf99-f8bb-4f02-ad46-651cd67c13b1.jpg" + "/files/images/buxton/upload_94e39580-5cca-46e9-ae49-ab6cd2fe3cad.jpg", + "/files/images/buxton/upload_eacee8a5-9849-4401-9c38-aa46fc0f517b.png", + "/files/images/buxton/upload_9b0b1f35-ac7c-4160-8806-8d243223872b.png", + "/files/images/buxton/upload_cf0c6e39-9ae6-48ce-90bd-d9f335503439.png", + "/files/images/buxton/upload_b4285b9f-26cd-4de5-8e37-c4e563c3e7f6.jpg", + "/files/images/buxton/upload_5b6ff31b-81b2-4a74-8591-27730c24225b.jpg", + "/files/images/buxton/upload_64dcea06-3b35-4979-bf40-5dfa5d4668b1.jpg" ], "title": "3Dconnexion Spaceball 5000", "company": "3Dconnexion", @@ -171,13 +171,13 @@ "SpaceNavigator_Press_Release.jpg" ], "__images": [ - "/files/images/buxton/upload_b44ec511-334e-46c0-a315-63d90fac8117.jpg", - "/files/images/buxton/upload_734ae360-faaf-4c78-89b4-a3f120fe233e.png", - "/files/images/buxton/upload_d20bbf6a-7310-407a-8b85-c607e9cf7f73.png", - "/files/images/buxton/upload_e9236600-dd5f-4805-92ca-805d5a301aa1.jpg", - "/files/images/buxton/upload_c85c977d-ef99-44be-b55c-8e8dde124e83.png", - "/files/images/buxton/upload_a6034d66-7de6-4d4b-bd64-ea95cc00ae8a.png", - "/files/images/buxton/upload_07415a65-964a-4936-aa6e-79861e8ebcbf.png" + "/files/images/buxton/upload_73511beb-f2bf-4f28-a1ea-64ef52a00426.jpg", + "/files/images/buxton/upload_4e088fb4-e5ff-4a1b-ba88-5f4575c86fe3.png", + "/files/images/buxton/upload_876a9921-3eb1-4c35-99e3-b82924fb88c4.png", + "/files/images/buxton/upload_d23c2886-c2b9-4558-9bfb-966aca7be20e.jpg", + "/files/images/buxton/upload_aef9171b-2e19-4fcb-b2dc-2281e89d498b.png", + "/files/images/buxton/upload_bbdaf252-1689-4680-8b19-ec5e79088e44.png", + "/files/images/buxton/upload_4cf49440-cf6b-484d-8391-3a2b0fae2b7e.png" ], "title": "3Dconnexion SpaceNavigator ", "company": "3Dconnexion", @@ -222,12 +222,12 @@ "3M_2006_Catalogue_p18.jpg" ], "__images": [ - "/files/images/buxton/upload_52b83c2a-5fe4-42aa-a488-5667b0a5beae.jpg", - "/files/images/buxton/upload_e05d8710-d82b-4f3b-8940-3745db1c855c.jpg", - "/files/images/buxton/upload_557c6fc7-04a3-4698-acde-4e53ceb6793c.jpg", - "/files/images/buxton/upload_d9723beb-bfe3-4556-b17d-aedf2db59777.jpg", - "/files/images/buxton/upload_5cb15815-3cab-406f-bf95-f9410997b4f4.jpg", - "/files/images/buxton/upload_a7fc91e0-7672-4f81-a8f3-66072997bd44.jpg" + "/files/images/buxton/upload_02df5121-8eff-452c-a52b-a44238afc06d.jpg", + "/files/images/buxton/upload_169aa4ee-4c34-43a2-8302-48bb3b7a01b6.jpg", + "/files/images/buxton/upload_a4d11c27-e4fa-4912-96da-3d971ec49ca0.jpg", + "/files/images/buxton/upload_7e9e1862-72e7-4f0d-8451-36de8c1bbe9c.jpg", + "/files/images/buxton/upload_76fa705f-2470-439c-acf6-03482d7a9570.jpg", + "/files/images/buxton/upload_7b6dd2c9-b88f-4958-a4d0-94bb42172e26.jpg" ], "title": "3M EM500 Ergonomic Mouse", "company": "3M", @@ -268,13 +268,13 @@ "Abaton_ProPoint_Brochure.jpg" ], "__images": [ - "/files/images/buxton/upload_f6f038a9-3583-4d21-9a43-f762e1df0b52.jpg", - "/files/images/buxton/upload_ad5f2bbd-66be-4dde-afe4-60e353a63f74.jpg", - "/files/images/buxton/upload_2e384260-5d2b-47a4-9508-028462a5a1e7.jpg", - "/files/images/buxton/upload_4dfcd3af-f06d-4c3e-8dff-7c43acd79a16.jpg", - "/files/images/buxton/upload_19eea9af-abec-4617-8b8d-fcb6637420de.jpg", - "/files/images/buxton/upload_89702b8a-fcb5-426d-b5af-c58e62d1c8ff.jpg", - "/files/images/buxton/upload_44419996-994e-471c-8dc7-cda22b00ac24.jpg" + "/files/images/buxton/upload_37169968-d329-40c5-9483-6bc198edc43c.jpg", + "/files/images/buxton/upload_64731ea4-a3aa-43ec-a56d-d4f6ecba7cf0.jpg", + "/files/images/buxton/upload_c41feac8-3b98-4d85-b9c7-79b3482a0695.jpg", + "/files/images/buxton/upload_5f67807b-f61b-4816-b93f-6d88c95b2418.jpg", + "/files/images/buxton/upload_a3e3cab8-48ab-43c2-bed9-5cc0ce68928d.jpg", + "/files/images/buxton/upload_4c3ac379-6703-4c87-a4a0-ca450a1151d2.jpg", + "/files/images/buxton/upload_8df14dc0-d75d-41f0-9e70-a221598d3df3.jpg" ], "title": "Abaton ProPoint Optical Trackball", "company": "Abaton", @@ -305,8 +305,8 @@ "Active_Book_Brochure_p1.jpg" ], "__images": [ - "/files/images/buxton/upload_2159da7b-9ebd-41ed-8b60-9eb36a6c6685.jpg", - "/files/images/buxton/upload_6d470914-fc41-4151-858b-f945807e62a2.png" + "/files/images/buxton/upload_9c8aa6a2-570f-4915-b840-504c8531c341.jpg", + "/files/images/buxton/upload_fbb7ad12-2a5d-4f76-89a9-ec30d7260031.png" ], "title": "Active Book Company Active Book Prototype", "company": "Active Book Company", @@ -342,11 +342,11 @@ "Adesso_ACK-540PW_June 21_2003.jpg" ], "__images": [ - "/files/images/buxton/upload_189469a3-1133-4a4f-8720-19c04f29684e.jpg", - "/files/images/buxton/upload_73f5d066-f9b5-41ce-9ce3-e27253ef51e7.jpg", - "/files/images/buxton/upload_498e5cbd-d65e-4b01-bed2-bcb2723ffee5.jpg", - "/files/images/buxton/upload_97ee9d03-07e0-448c-89f6-6ac61948de68.jpg", - "/files/images/buxton/upload_661e7387-dcd7-4ca1-8493-2e94f8803ef7.jpg" + "/files/images/buxton/upload_967656ff-44d7-4693-bcb0-dc0eab204413.jpg", + "/files/images/buxton/upload_9ffd4ccb-8ca5-4926-8fa2-38277b2ccfb6.jpg", + "/files/images/buxton/upload_22399981-f8c0-46e0-953c-89f7eb043ad2.jpg", + "/files/images/buxton/upload_15ad02a9-123f-4e7e-94c5-d959076520f0.jpg", + "/files/images/buxton/upload_8905097a-3568-4d37-9ad3-126a0e429f12.jpg" ], "title": "Adesso ACK-540PB PS/2 Mini PS/2 Touchpad Keyboard", "company": "Adesso", @@ -405,17 +405,17 @@ "Adesso_KP_Mouse_11_Product.JPG" ], "__images": [ - "/files/images/buxton/upload_0a127e30-9014-4300-bade-07945fba940f.jpg", - "/files/images/buxton/upload_ca20611c-9061-4e56-9d72-4c4a3c798d3f.jpg", - "/files/images/buxton/upload_12b46021-eeef-47f0-9e55-ca9e9b76f9e4.jpg", - "/files/images/buxton/upload_5e86ad07-77af-4d3e-a82e-eaa9cafdbbe4.jpg", - "/files/images/buxton/upload_4be64833-53e9-4216-b7ec-d521e0b87933.jpg", - "/files/images/buxton/upload_7cb731b5-5c52-47e0-a33b-c113530478f2.jpg", - "/files/images/buxton/upload_b20407b3-3578-4fa5-8f16-e0bf729e4daa.jpg", - "/files/images/buxton/upload_bee2fcb8-702a-46aa-9ec3-eb9b50ef1ba7.jpg", - "/files/images/buxton/upload_0ee0f6d5-34fc-41f3-9c8e-cf462dbcc40b.jpg", - "/files/images/buxton/upload_8f442582-b901-4a38-8df6-5a9b3195df9f.jpg", - "/files/images/buxton/upload_3f96763c-c3af-46a7-8831-3206c8bc460e.jpg" + "/files/images/buxton/upload_5bc99192-0935-4f6d-8d6c-a2218d55b359.jpg", + "/files/images/buxton/upload_52a6212e-c79d-4ec6-86a0-a3ca4ea54387.jpg", + "/files/images/buxton/upload_997acb64-0e08-4af2-b0e3-0b86a18bace5.jpg", + "/files/images/buxton/upload_00586980-0a08-43e1-9721-c2f5dcd1079e.jpg", + "/files/images/buxton/upload_3f695b11-dc1d-4d54-abec-eacfac80bdc7.jpg", + "/files/images/buxton/upload_161f1420-9594-4dca-ba62-1ca32e9a2028.jpg", + "/files/images/buxton/upload_a8b4ea6e-f1f8-47db-a796-72f566e60e6f.jpg", + "/files/images/buxton/upload_b6365e4e-4656-4bbf-aec6-feb920be6df9.jpg", + "/files/images/buxton/upload_1a0e9061-39e1-4dec-8add-5cc1abd110b5.jpg", + "/files/images/buxton/upload_d9bba544-f2b1-4a15-81e5-0d10e60d7881.jpg", + "/files/images/buxton/upload_56d486df-d7bb-44b0-80ad-c41c63590bae.jpg" ], "title": "Adesso 2-in-1 Optical Keypad Calculator Mouse AKP-170", "company": "Adesso Inc", @@ -477,18 +477,18 @@ "NB75D_Mouse_Manual.jpg" ], "__images": [ - "/files/images/buxton/upload_dae8f950-38bf-4fdf-8db0-153e3cae9cae.jpg", - "/files/images/buxton/upload_3e054d83-d01f-4d3d-aad2-fa8ee1d22a97.jpg", - "/files/images/buxton/upload_e9c2ddb0-0684-4bb4-a88c-5ee8074e456e.jpg", - "/files/images/buxton/upload_9c829a69-7d45-4d25-b906-98153aa03001.jpg", - "/files/images/buxton/upload_4faa425c-a100-4ce4-869c-a6c6705779ee.jpg", - "/files/images/buxton/upload_ed20ac31-69f6-45b8-b8e0-b8ad829ba002.jpg", - "/files/images/buxton/upload_f3d3d8f5-01cf-4cd1-9d1c-0a11a8c3e239.jpg", - "/files/images/buxton/upload_af1fa3b6-4537-416a-b626-34bed1154f35.jpg", - "/files/images/buxton/upload_5127f377-b697-4ad7-9fb3-fd6f82017c3c.jpg", - "/files/images/buxton/upload_061ae6a2-e083-492a-bc8a-826c4be00790.jpg", - "/files/images/buxton/upload_32e91966-7f1b-4cd7-858b-9cdb63affd13.jpg", - "/files/images/buxton/upload_ccc9de21-b047-4f9c-89c6-08fb3d206c7a.jpg" + "/files/images/buxton/upload_2db5c520-b370-4f03-8481-908e42428466.jpg", + "/files/images/buxton/upload_b28643eb-57a0-4602-b7cc-c41d553628b9.jpg", + "/files/images/buxton/upload_2478a89a-4eea-4e4c-af83-ecd292f44f3d.jpg", + "/files/images/buxton/upload_113d7356-f550-4491-849d-f69087c73918.jpg", + "/files/images/buxton/upload_44c40c44-ade6-499d-951c-4b436131e66e.jpg", + "/files/images/buxton/upload_d91f9756-09bc-447f-8f04-dc78344a5f11.jpg", + "/files/images/buxton/upload_b8c51011-5f93-43f3-85aa-b611a3b3cf93.jpg", + "/files/images/buxton/upload_483544a3-c3f7-4c8f-a236-def10d32f4f0.jpg", + "/files/images/buxton/upload_ea048294-3f57-42c3-b5b4-27062a5755dc.jpg", + "/files/images/buxton/upload_8eb1b9b1-9ca3-49c8-9bd4-7302a9c1f07e.jpg", + "/files/images/buxton/upload_029aa1d6-056d-4cf0-8eaf-b23b3d0e4317.jpg", + "/files/images/buxton/upload_3acc0955-da14-4a53-ac58-2e494e04ca78.jpg" ], "title": "A4 Tech BatteryFREE Wireless Optical Mouse Model NB-75D", "company": "A4Tech", diff --git a/src/server/ApiManagers/DownloadManager.ts b/src/server/ApiManagers/DownloadManager.ts index fad5e6789..01d2dfcad 100644 --- a/src/server/ApiManagers/DownloadManager.ts +++ b/src/server/ApiManagers/DownloadManager.ts @@ -254,7 +254,7 @@ async function writeHierarchyRecursive(file: Archiver.Archiver, hierarchy: Hiera // and dropped in the browser and thus hosted remotely) so we upload it // to our server and point the zip file to it, so it can bundle up the bytes const information = await DashUploadUtils.UploadImage(result); - path = information instanceof Error ? "" : information.serverAccessPaths[SizeSuffix.Original]; + path = information instanceof Error ? "" : information.accessPaths[SizeSuffix.Original].server; } // write the file specified by the path to the directory in the // zip file given by the prefix. diff --git a/src/server/DashUploadUtils.ts b/src/server/DashUploadUtils.ts index 83a0064e8..0f1758c26 100644 --- a/src/server/DashUploadUtils.ts +++ b/src/server/DashUploadUtils.ts @@ -61,13 +61,16 @@ export namespace DashUploadUtils { const type = "content-type"; export interface ImageUploadInformation { - clientAccessPath: string; - serverAccessPaths: { [key: string]: string }; + accessPaths: AccessPathInfo; exifData: EnrichedExifData; contentSize?: number; contentType?: string; } + export interface AccessPathInfo { + [suffix: string]: { client: string, server: string }; + } + const { imageFormats, videoFormats, applicationFormats } = AcceptibleMedia; export async function upload(file: File): Promise { @@ -94,7 +97,7 @@ export namespace DashUploadUtils { } console.log(red(`Ignoring unsupported file (${name}) with upload type (${type}).`)); - return { clientAccessPath: undefined }; + return { accessPaths: undefined }; } async function UploadPdf(absolutePath: string) { @@ -213,29 +216,40 @@ export namespace DashUploadUtils { }; }; - export async function MoveParsedFile(absolutePath: string, destination: Directory): Promise<{ clientAccessPath: Opt }> { - return new Promise<{ clientAccessPath: Opt }>(resolve => { + export async function MoveParsedFile(absolutePath: string, destination: Directory): Promise> { + return new Promise>(resolve => { const filename = basename(absolutePath); const destinationPath = serverPathToFile(destination, filename); rename(absolutePath, destinationPath, error => { - resolve({ clientAccessPath: error ? undefined : clientPathToFile(destination, filename) }); + resolve(error ? undefined : { + agnostic: getAccessPaths(destination, filename) + }); }); }); } + function getAccessPaths(directory: Directory, fileName: string) { + return { + client: clientPathToFile(directory, fileName), + server: serverPathToFile(directory, fileName) + }; + } + export const UploadInspectedImage = async (metadata: InspectionResults, filename?: string, prefix = "", cleanUp = true): Promise => { const { requestable, source, ...remaining } = metadata; const extension = `.${remaining.contentType.split("/")[1].toLowerCase()}`; const resolved = filename || `${prefix}upload_${Utils.GenerateGuid()}${extension}`; + const { images } = Directory; const information: ImageUploadInformation = { - clientAccessPath: clientPathToFile(Directory.images, resolved), - serverAccessPaths: {}, + accessPaths: { + agnostic: getAccessPaths(images, resolved) + }, ...remaining }; const outputPath = pathToDirectory(Directory.images); const writtenFiles = await outputResizedImages(() => request(requestable), outputPath, resolved, extension); for (const suffix of Object.keys(writtenFiles)) { - information.serverAccessPaths[suffix] = serverPathToFile(Directory.images, writtenFiles[suffix]); + information.accessPaths[suffix] = getAccessPaths(images, writtenFiles[suffix]); } if (isLocal().test(source) && cleanUp) { unlinkSync(source); @@ -270,10 +284,9 @@ export namespace DashUploadUtils { export async function outputResizedImages(readStreamSource: () => ReadStreamLike | Promise, outputPath: string, fileName: string, ext: string) { const writtenFiles: { [suffix: string]: string } = {}; for (const { resizer, suffix } of resizers(ext)) { - const resizedPath = path.resolve(outputPath, InjectSize(fileName, suffix)); - writtenFiles[suffix] = resizedPath; + const resolved = writtenFiles[suffix] = InjectSize(fileName, suffix); await new Promise(async (resolve, reject) => { - const writeStream = createWriteStream(resizedPath); + const writeStream = createWriteStream(path.resolve(outputPath, resolved)); let readStream: ReadStreamLike; const source = readStreamSource(); if (source instanceof Promise) { diff --git a/src/server/apis/google/GooglePhotosUploadUtils.ts b/src/server/apis/google/GooglePhotosUploadUtils.ts index 8ae63caa3..d305eed0a 100644 --- a/src/server/apis/google/GooglePhotosUploadUtils.ts +++ b/src/server/apis/google/GooglePhotosUploadUtils.ts @@ -84,6 +84,7 @@ export namespace GooglePhotosUploadUtils { if (!DashUploadUtils.validateExtension(url)) { return undefined; } + const body = await request(url, { encoding: null }); // returns a readable stream with the unencoded binary image data const parameters = { method: 'POST', uri: prepend('uploads'), @@ -92,7 +93,7 @@ export namespace GooglePhotosUploadUtils { 'X-Goog-Upload-File-Name': filename || path.basename(url), 'X-Goog-Upload-Protocol': 'raw' }, - body: await request(url, { encoding: null }) // returns a readable stream with the unencoded binary image data + body }; return new Promise((resolve, reject) => request(parameters, (error, _response, body) => { if (error) { -- cgit v1.2.3-70-g09d2 From 553fb2a11aa638c35192a1a2f7da99729867e542 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 13 Feb 2020 22:30:32 -0500 Subject: starting a broad cleanup of code. trying to make standard doc field names be more regular --- src/client/documents/Documents.ts | 15 ++-- src/client/util/DragManager.ts | 1 - src/client/util/RichTextRules.ts | 3 +- src/client/views/MainView.tsx | 7 +- .../views/collections/CollectionCarouselView.scss | 1 + .../views/collections/CollectionCarouselView.tsx | 1 - .../views/collections/CollectionLinearView.tsx | 10 +-- src/client/views/collections/CollectionSubView.tsx | 5 +- .../views/collections/CollectionTreeView.tsx | 35 ++++----- src/client/views/collections/CollectionView.tsx | 5 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 3 +- .../views/nodes/ContentFittingDocumentView.tsx | 24 +----- src/client/views/nodes/DocumentView.tsx | 36 ++------- src/client/views/nodes/FormattedTextBox.tsx | 11 --- src/client/views/nodes/ImageBox.tsx | 9 ++- src/new_fields/Doc.ts | 90 +++++++++------------- src/new_fields/documentSchemas.ts | 12 ++- .../authentication/models/current_user_utils.ts | 8 +- 18 files changed, 96 insertions(+), 180 deletions(-) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 8304c2a7f..adcdf260d 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -22,7 +22,6 @@ import { ImageField, VideoField, AudioField, PdfField, WebField, YoutubeField } import { HtmlField } from "../../new_fields/HtmlField"; import { List } from "../../new_fields/List"; import { Cast, NumCast } from "../../new_fields/Types"; -import { IconField } from "../../new_fields/IconField"; import { listSpec } from "../../new_fields/Schema"; import { DocServer } from "../DocServer"; import { dropActionType } from "../util/DragManager"; @@ -53,7 +52,6 @@ import { InkingStroke } from "../views/InkingStroke"; import { InkField } from "../../new_fields/InkField"; import { InkingControl } from "../views/InkingControl"; import { RichTextField } from "../../new_fields/RichTextField"; -import { Networking } from "../Network"; import { extname } from "path"; import { MessageStore } from "../../server/Message"; const requestImageSize = require('../util/request-image-size'); @@ -92,7 +90,6 @@ export interface DocumentOptions { scale?: number; isDisplayPanel?: boolean; // whether the panel functions as GoldenLayout "stack" used to display documents forceActive?: boolean; - preventTreeViewOpen?: boolean; // ignores the treeViewOpen Doc flag which allows a treeViewItem's expande/collapse state to be independent of other views of the same document in the tree view layout?: string | Doc; hideHeadings?: boolean; // whether stacking view column headings should be hidden isTemplateForField?: string; // the field key for which the containing document is a rendering template @@ -109,7 +106,6 @@ export interface DocumentOptions { curPage?: number; currentTimecode?: number; // the current timecode of a time-based document (e.g., current time of a video) value is in seconds displayTimecode?: number; // the time that a document should be displayed (e.g., time an annotation should be displayed on a video) - documentText?: string; borderRounding?: string; boxShadow?: string; sectionFilter?: string; // field key used to determine headings for sections in stacking and masonry views @@ -124,15 +120,16 @@ export interface DocumentOptions { onChildClick?: ScriptField; // script given to children of a collection to execute when they are clicked onPointerDown?: ScriptField; onPointerUp?: ScriptField; + dropConverter?: ScriptField; // script to run when documents are dropped on this Document. dragFactory?: Doc; // document to create when dragging with a suitable onDragStart script onDragStart?: ScriptField; //script to execute at start of drag operation -- e.g., when a "creator" button is dragged this script generates a different document to drop - clipboard?: Doc; //script to execute at start of drag operation -- e.g., when a "creator" button is dragged this script generates a different document to drop + clipboard?: Doc; icon?: string; sourcePanel?: Doc; // panel to display in 'targetContainer' as the result of a button onClick script targetContainer?: Doc; // document whose proto will be set to 'panel' as the result of a onClick click script - dropConverter?: ScriptField; // script to run when documents are dropped on this Document. strokeWidth?: number; color?: string; + treeViewPreventOpen?: boolean; // ignores the treeViewOpen Doc flag which allows a treeViewItem's expand/collapse state to be independent of other views of the same document in the tree view treeViewHideTitle?: boolean; // whether to hide the title of a tree view treeViewHideHeaderFields?: boolean; // whether to hide the drop down options for tree view items. treeViewOpen?: boolean; // whether this document is expanded in a tree view @@ -141,9 +138,9 @@ export interface DocumentOptions { limitHeight?: number; // maximum height for newly created (eg, from pasting) text documents // [key: string]: Opt; pointerHack?: boolean; // for buttons, allows onClick handler to fire onPointerDown - isExpanded?: boolean; // is linear view expanded - textTransform?: string; // is linear view expanded - letterSpacing?: string; // is linear view expanded + linearViewIsExpanded?: boolean; // is linear view expanded + textTransform?: string; + letterSpacing?: string; } class EmptyBox { diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index e572f0fcb..2877d5fd7 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -134,7 +134,6 @@ export namespace DragManager { embedDoc?: boolean; moveDocument?: MoveFunction; isSelectionMove?: boolean; // indicates that an explicitly selected Document is being dragged. this will suppress onDragStart scripts - applyAsTemplate?: boolean; } export class LinkDragData { constructor(linkSourceDoc: Doc) { diff --git a/src/client/util/RichTextRules.ts b/src/client/util/RichTextRules.ts index 6b8762a5e..de0f46202 100644 --- a/src/client/util/RichTextRules.ts +++ b/src/client/util/RichTextRules.ts @@ -121,8 +121,7 @@ export class RichTextRules { new InputRule( new RegExp(/##$/), (state, match, start, end) => { - const schemaDoc = Doc.GetDataDoc(this.Document); - const textDoc = Doc.GetProto(Cast(schemaDoc[DataSym], Doc, null)!); + const textDoc = this.Document[DataSym]; const numInlines = NumCast(textDoc.inlineTextCount); textDoc.inlineTextCount = numInlines + 1; const inlineFieldKey = "inline" + numInlines; // which field on the text document this annotation will write to diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 401a4b15c..192f3b8fb 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -482,12 +482,13 @@ export class MainView extends React.Component { return new Transform(-translateX, -translateY, 1 / scale); } @computed get docButtons() { - if (CurrentUserUtils.UserDocument?.expandingButtons instanceof Doc) { + const expandingBtns = Doc.UserDoc()?.expandingButtons; + if (expandingBtns instanceof Doc) { return
+ style={{ height: !expandingBtns.linearViewIsExpanded ? "42px" : undefined }} > this.props.Document[HeightSym]() + this.childDocs.length + (this.props.Document.isExpanded ? 1 : 0), - () => this.props.Document._width = 5 + (this.props.Document.isExpanded ? this.childDocs.length * (this.props.Document[HeightSym]()) : 10), + this._widthDisposer = reaction(() => this.props.Document[HeightSym]() + this.childDocs.length + (this.props.Document.linearViewIsExpanded ? 1 : 0), + () => this.props.Document._width = 5 + (this.props.Document.linearViewIsExpanded ? this.childDocs.length * (this.props.Document[HeightSym]()) : 10), { fireImmediately: true } ); @@ -84,8 +84,8 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) { const guid = Utils.GenerateGuid(); return
- this.props.Document.isExpanded = this.addMenuToggle.current!.checked)} /> + this.props.Document.linearViewIsExpanded = this.addMenuToggle.current!.checked)} />
@@ -97,7 +97,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) { return
(schemaCtor: (doc: Doc) => T) { const docDragData = de.complete.docDragData; (this.props.Document.dropConverter instanceof ScriptField) && this.props.Document.dropConverter.script.run({ dragData: docDragData }); /// bcz: check this - if (docDragData && !docDragData.applyAsTemplate) { + if (docDragData) { if (de.altKey && docDragData.draggedDocuments.length) { this.childDocs.map(doc => { doc.layout_fromParent = docDragData.draggedDocuments[0]; @@ -253,7 +253,8 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { } }); } else { - const htmlDoc = Docs.Create.HtmlDocument(html, { ...options, title: "-web page-", _width: 300, _height: 300, documentText: text }); + const htmlDoc = Docs.Create.HtmlDocument(html, { ...options, title: "-web page-", _width: 300, _height: 300 }); + Doc.GetProto(htmlDoc)["data-text"] = text; this.props.addDocument(htmlDoc); } return; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index e91c3cc49..a160dcc62 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -61,7 +61,7 @@ export interface TreeViewProps { parentKey: string; active: (outsideReaction?: boolean) => boolean; treeViewHideHeaderFields: () => boolean; - preventTreeViewOpen: boolean; + treeViewPreventOpen: boolean; renderedIds: string[]; onCheckedClick?: ScriptField; } @@ -84,7 +84,7 @@ library.add(faPlus, faMinus); * * special fields: * treeViewOpen : flag denoting whether the documents sub-tree (contents) is visible or hidden - * preventTreeViewOpen : ignores the treeViewOpen flag (for allowing a view to not be slaved to other views of the document) + * treeViewPreventOpen : ignores the treeViewOpen flag (for allowing a view to not be slaved to other views of the document) * treeViewExpandedView : name of field whose contents are being displayed as the document's subtree */ class TreeView extends React.Component { @@ -96,8 +96,8 @@ class TreeView extends React.Component { get defaultExpandedView() { return this.childDocs ? this.fieldKey : StrCast(this.props.document.defaultExpandedView, "fields"); } @observable _overrideTreeViewOpen = false; // override of the treeViewOpen field allowing the display state to be independent of the document's state - set treeViewOpen(c: boolean) { if (this.props.preventTreeViewOpen) this._overrideTreeViewOpen = c; else this.props.document.treeViewOpen = this._overrideTreeViewOpen = c; } - @computed get treeViewOpen() { return (!this.props.preventTreeViewOpen && BoolCast(this.props.document.treeViewOpen)) || this._overrideTreeViewOpen; } + set treeViewOpen(c: boolean) { if (this.props.treeViewPreventOpen) this._overrideTreeViewOpen = c; else this.props.document.treeViewOpen = this._overrideTreeViewOpen = c; } + @computed get treeViewOpen() { return (!this.props.treeViewPreventOpen && BoolCast(this.props.document.treeViewOpen)) || this._overrideTreeViewOpen; } @computed get treeViewExpandedView() { return StrCast(this.props.document.treeViewExpandedView, this.defaultExpandedView); } @computed get MAX_EMBED_HEIGHT() { return NumCast(this.props.document.maxEmbedHeight, 300); } @computed get dataDoc() { return this.templateDataDoc ? this.templateDataDoc : this.props.document; } @@ -179,8 +179,7 @@ class TreeView extends React.Component { SetValue={undoBatch((value: string) => Doc.SetInPlace(this.props.document, key, value, false) || true)} OnFillDown={undoBatch((value: string) => { Doc.SetInPlace(this.props.document, key, value, false); - const layoutDoc = this.props.document.layout_custom instanceof Doc ? Doc.ApplyTemplate(Doc.GetProto(this.props.document.layout_custom)) : undefined; - const doc = layoutDoc || Docs.Create.FreeformDocument([], { title: "", x: 0, y: 0, _width: 100, _height: 25, templates: new List([Templates.Title.Layout]) }); + const doc = Docs.Create.FreeformDocument([], { title: "", x: 0, y: 0, _width: 100, _height: 25, templates: new List([Templates.Title.Layout]) }); EditableView.loadId = doc[Id]; return this.props.addDocument(doc); })} @@ -291,7 +290,7 @@ class TreeView extends React.Component { contentElement = TreeView.GetChildElements(contents instanceof Doc ? [contents] : DocListCast(contents), this.props.treeViewId, doc, undefined, key, this.props.containingCollection, this.props.prevSibling, addDoc, remDoc, this.move, this.props.dropAction, this.props.addDocTab, this.props.pinToPres, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active, - this.props.panelWidth, this.props.ChromeHeight, this.props.renderDepth, this.props.treeViewHideHeaderFields, this.props.preventTreeViewOpen, + this.props.panelWidth, this.props.ChromeHeight, this.props.renderDepth, this.props.treeViewHideHeaderFields, this.props.treeViewPreventOpen, [...this.props.renderedIds, doc[Id]], this.props.libraryPath, this.props.onCheckedClick); } else { contentElement = { TreeView.GetChildElements(docs, this.props.treeViewId, Doc.Layout(this.props.document), this.templateDataDoc, expandKey, this.props.containingCollection, this.props.prevSibling, addDoc, remDoc, this.move, this.props.dropAction, this.props.addDocTab, this.props.pinToPres, this.props.ScreenToLocalTransform, - this.props.outerXf, this.props.active, this.props.panelWidth, this.props.ChromeHeight, this.props.renderDepth, this.props.treeViewHideHeaderFields, this.props.preventTreeViewOpen, + this.props.outerXf, this.props.active, this.props.panelWidth, this.props.ChromeHeight, this.props.renderDepth, this.props.treeViewHideHeaderFields, this.props.treeViewPreventOpen, [...this.props.renderedIds, this.props.document[Id]], this.props.libraryPath, this.props.onCheckedClick)} ; } else if (this.treeViewExpandedView === "fields") { @@ -464,7 +463,7 @@ class TreeView extends React.Component { ChromeHeight: undefined | (() => number), renderDepth: number, treeViewHideHeaderFields: () => boolean, - preventTreeViewOpen: boolean, + treeViewPreventOpen: boolean, renderedIds: string[], libraryPath: Doc[] | undefined, onCheckedClick: ScriptField | undefined @@ -574,7 +573,7 @@ class TreeView extends React.Component { parentKey={key} active={active} treeViewHideHeaderFields={treeViewHideHeaderFields} - preventTreeViewOpen={preventTreeViewOpen} + treeViewPreventOpen={treeViewPreventOpen} renderedIds={renderedIds} />; }); } @@ -601,8 +600,7 @@ export class CollectionTreeView extends CollectionSubView(Document) { @action remove = (document: Document): boolean => { - const targetDataDoc = this.props.Document && !this.props.Document.isTemplateForField ? this.props.Document : Doc.GetProto(this.props.Document[DataSym] as Doc); - const children = Cast(targetDataDoc[this.props.fieldKey], listSpec(Doc), []); + const children = Cast(this.props.Document[DataSym][this.props.fieldKey], listSpec(Doc), []); if (children.indexOf(document) !== -1) { children.splice(children.indexOf(document), 1); return true; @@ -611,10 +609,8 @@ export class CollectionTreeView extends CollectionSubView(Document) { } @action addDoc = (doc: Document, relativeTo: Opt, before?: boolean): boolean => { - const doAddDoc = () => { - const targetDataDoc = this.props.Document && !this.props.Document.isTemplateForField ? this.props.Document : Doc.GetProto(this.props.Document[DataSym] as Doc); - Doc.AddDocToList(targetDataDoc, this.props.fieldKey, doc, relativeTo, before, false, false, false); - }; + const doAddDoc = () => + Doc.AddDocToList(this.props.Document[DataSym], this.props.fieldKey, doc, relativeTo, before, false, false, false); if (this.props.Document.resolvedDataDoc instanceof Promise) { this.props.Document.resolvedDataDoc.then(resolved => doAddDoc()); } else { @@ -637,7 +633,7 @@ export class CollectionTreeView extends CollectionSubView(Document) { ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15); } else { const layoutItems: ContextMenuProps[] = []; - layoutItems.push({ description: (this.props.Document.preventTreeViewOpen ? "Persist" : "Abandon") + "Treeview State", event: () => this.props.Document.preventTreeViewOpen = !this.props.Document.preventTreeViewOpen, icon: "paint-brush" }); + layoutItems.push({ description: (this.props.Document.treeViewPreventOpen ? "Persist" : "Abandon") + "Treeview State", event: () => this.props.Document.treeViewPreventOpen = !this.props.Document.treeViewPreventOpen, icon: "paint-brush" }); layoutItems.push({ description: (this.props.Document.treeViewHideHeaderFields ? "Show" : "Hide") + " Header Fields", event: () => this.props.Document.treeViewHideHeaderFields = !this.props.Document.treeViewHideHeaderFields, icon: "paint-brush" }); layoutItems.push({ description: (this.props.Document.treeViewHideTitle ? "Show" : "Hide") + " Title", event: () => this.props.Document.treeViewHideTitle = !this.props.Document.treeViewHideTitle, icon: "paint-brush" }); ContextMenu.Instance.addItem({ description: "Treeview Options ...", subitems: layoutItems, icon: "eye" }); @@ -733,8 +729,7 @@ export class CollectionTreeView extends CollectionSubView(Document) { SetValue={undoBatch((value: string) => Doc.SetInPlace(this.dataDoc, "title", value, false) || true)} OnFillDown={undoBatch((value: string) => { Doc.SetInPlace(this.dataDoc, "title", value, false); - const layoutDoc = this.props.Document.layout_custom instanceof Doc ? Doc.ApplyTemplate(Doc.GetProto(this.props.Document.layout_custom)) : undefined; - const doc = layoutDoc || Docs.Create.FreeformDocument([], { title: "", x: 0, y: 0, _width: 100, _height: 25, templates: new List([Templates.Title.Layout]) }); + const doc = Docs.Create.FreeformDocument([], { title: "", x: 0, y: 0, _width: 100, _height: 25, templates: new List([Templates.Title.Layout]) }); EditableView.loadId = doc[Id]; this.addDoc(doc, this.childDocs.length ? this.childDocs[0] : undefined, true); })} />)} @@ -744,7 +739,7 @@ export class CollectionTreeView extends CollectionSubView(Document) { TreeView.GetChildElements(this.childDocs, this.props.Document, this.props.Document, this.props.DataDoc, this.props.fieldKey, this.props.ContainingCollectionDoc, undefined, addDoc, this.remove, moveDoc, dropAction, this.props.addDocTab, this.props.pinToPres, this.props.ScreenToLocalTransform, this.outerXf, this.props.active, this.props.PanelWidth, this.props.ChromeHeight, this.props.renderDepth, () => BoolCast(this.props.Document.treeViewHideHeaderFields), - BoolCast(this.props.Document.preventTreeViewOpen), [], this.props.LibraryPath, ScriptCast(this.props.Document.onCheckedClick)) + BoolCast(this.props.Document.treeViewPreventOpen), [], this.props.LibraryPath, ScriptCast(this.props.Document.onCheckedClick)) }
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index ad39b69d8..39ce4d6e8 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -133,7 +133,7 @@ export class CollectionView extends Touchable { @action.bound addDocument(doc: Doc): boolean { - const targetDataDoc = this.props.Document.resolvedDataDoc && !this.props.Document.isTemplateForField ? this.props.Document : Doc.GetProto(this.props.Document[DataSym]); + const targetDataDoc = this.props.Document[DataSym]; targetDataDoc[this.props.fieldKey] = new List([...DocListCast(targetDataDoc[this.props.fieldKey]), doc]); // DocAddToList may write to targetdataDoc's parent ... we don't want this. should really change GetProto to GetDataDoc and test for resolvedDataDoc there // Doc.AddDocToList(targetDataDoc, this.props.fieldKey, doc); targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now())); @@ -145,8 +145,7 @@ export class CollectionView extends Touchable { removeDocument(doc: Doc): boolean { const docView = DocumentManager.Instance.getDocumentView(doc, this.props.ContainingCollectionView); docView && SelectionManager.DeselectDoc(docView); - const targetDataDoc = this.props.Document.resolvedDataDoc && !this.props.Document.isTemplateForField ? this.props.Document : Doc.GetProto(this.props.Document[DataSym]); - const value = Cast(targetDataDoc[this.props.fieldKey], listSpec(Doc), []); + const value = Cast(this.props.Document[DataSym][this.props.fieldKey], listSpec(Doc), []); let index = value.reduce((p, v, i) => (v instanceof Doc && v === doc) ? i : p, -1); index = index !== -1 ? index : value.reduce((p, v, i) => (v instanceof Doc && Doc.AreProtosEqual(v, doc)) ? i : p, -1); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 7f1817a15..e1854fc2d 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1074,7 +1074,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { // this.Document.fitH = this.contentBounds && (this.contentBounds.b - this.contentBounds.y); // if isAnnotationOverlay is set, then children will be stored in the extension document for the fieldKey. // otherwise, they are stored in fieldKey. All annotations to this document are stored in the extension document - // let lodarea = this.Document[WidthSym]() * this.Document[HeightSym]() / this.props.ScreenToLocalTransform().Scale / this.props.ScreenToLocalTransform().Scale; return
- {!this.Document._LODdisable && !this.props.active() && !this.props.isAnnotationOverlay && !this.props.annotationsKey && this.props.renderDepth > 0 ? // && this.props.CollectionView && lodarea < NumCast(this.Document.LODarea, 100000) ? + {!this.Document._LODdisable && !this.props.active() && !this.props.isAnnotationOverlay && !this.props.annotationsKey && this.props.renderDepth > 0 ? this.placeholder : this.marqueeView}
; diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx index 671f5b96e..5c449026e 100644 --- a/src/client/views/nodes/ContentFittingDocumentView.tsx +++ b/src/client/views/nodes/ContentFittingDocumentView.tsx @@ -1,19 +1,17 @@ import React = require("react"); -import { action, computed } from "mobx"; +import { computed } from "mobx"; import { observer } from "mobx-react"; import "react-table/react-table.css"; import { Doc, Opt } from "../../../new_fields/Doc"; -import { ComputedField, ScriptField } from "../../../new_fields/ScriptField"; +import { ScriptField } from "../../../new_fields/ScriptField"; import { NumCast, StrCast } from "../../../new_fields/Types"; +import { TraceMobx } from "../../../new_fields/util"; import { emptyFunction, returnEmptyString, returnOne } from "../../../Utils"; -import { DragManager } from "../../util/DragManager"; import { Transform } from "../../util/Transform"; -import { undoBatch } from "../../util/UndoManager"; +import { CollectionView } from "../collections/CollectionView"; import '../DocumentDecorations.scss'; import { DocumentView } from "../nodes/DocumentView"; import "./ContentFittingDocumentView.scss"; -import { CollectionView } from "../collections/CollectionView"; -import { TraceMobx } from "../../../new_fields/util"; interface ContentFittingDocumentViewProps { Document?: Doc; @@ -55,20 +53,6 @@ export class ContentFittingDocumentView extends React.Component this.scaling; - @undoBatch - @action - drop = (e: Event, de: DragManager.DropEvent) => { - const docDragData = de.complete.docDragData; - if (docDragData) { - this.props.childDocs && this.props.childDocs.map(otherdoc => { - const target = Doc.GetProto(otherdoc); - target.layout = ComputedField.MakeFunction("this.image_data[0]"); - target.layout_custom = Doc.MakeDelegate(docDragData.draggedDocuments[0]); - }); - e.stopPropagation(); - } - return true; - } private PanelWidth = () => this.panelWidth; private PanelHeight = () => this.panelHeight;; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 48df1ea33..e9b4f9f7f 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -92,7 +92,6 @@ export class DocumentView extends DocComponent(Docu private _downY: number = 0; private _lastTap: number = 0; private _doubleTap = false; - private _hitTemplateDrag = false; private _mainCont = React.createRef(); private _dropDisposer?: DragManager.DragDropDisposer; private _gestureEventDisposer?: GestureUtils.GestureEventDisposer; @@ -196,14 +195,13 @@ export class DocumentView extends DocComponent(Docu !this.props.dontRegisterView && DocumentManager.Instance.DocumentViews.splice(DocumentManager.Instance.DocumentViews.indexOf(this), 1); } - startDragging(x: number, y: number, dropAction: dropActionType, applyAsTemplate?: boolean) { + startDragging(x: number, y: number, dropAction: dropActionType) { if (this._mainCont.current) { const dragData = new DragManager.DocumentDragData([this.props.Document]); const [left, top] = this.props.ScreenToLocalTransform().scale(this.props.ContentScaling()).inverse().transformPoint(0, 0); dragData.offset = this.props.ScreenToLocalTransform().scale(this.props.ContentScaling()).transformDirection(x - left, y - top); dragData.dropAction = dropAction; dragData.moveDocument = this.props.moveDocument;// this.Document.onDragStart ? undefined : this.props.moveDocument; - dragData.applyAsTemplate = applyAsTemplate; dragData.dragDivName = this.props.dragDivName; this.props.Document.sourceContext = this.props.ContainingCollectionDoc; // bcz: !! shouldn't need this ... use search find the document's context dynamically DragManager.StartDocumentDrag([this._mainCont.current], dragData, x, y, { hideSource: !dropAction && !this.Document.onDragStart }); @@ -257,8 +255,8 @@ export class DocumentView extends DocComponent(Docu let preventDefault = true; if (this._doubleTap && this.props.renderDepth && !this.onClickHandler?.script) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click const fullScreenAlias = Doc.MakeAlias(this.props.Document); - if (StrCast(fullScreenAlias.layoutKey) !== "layout_custom" && fullScreenAlias.layout_custom !== undefined) { - fullScreenAlias.layoutKey = "layout_custom"; + if (StrCast(fullScreenAlias.layoutKey) !== "layout_fullScreen" && fullScreenAlias.layout_fullScreen) { + fullScreenAlias.layoutKey = "layout_fullScreen"; } this.props.addDocTab(fullScreenAlias, undefined, "inTab"); SelectionManager.DeselectAll(); @@ -323,7 +321,7 @@ export class DocumentView extends DocComponent(Docu if (Math.abs(this._downX - touch.clientX) > 3 || Math.abs(this._downY - touch.clientY) > 3) { if (!e.altKey && (!this.topMost || this.Document.onDragStart || this.Document.onClick)) { this.cleanUpInteractions(); - this.startDragging(this._downX, this._downY, this.Document.dropAction ? this.Document.dropAction as any : e.ctrlKey || e.altKey ? "alias" : undefined, this._hitTemplateDrag); + this.startDragging(this._downX, this._downY, this.Document.dropAction ? this.Document.dropAction as any : e.ctrlKey || e.altKey ? "alias" : undefined); } } e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document' however it does mark the event as cancelBubble=true which we test for in the move event handlers @@ -434,14 +432,6 @@ export class DocumentView extends DocComponent(Docu if (!e.nativeEvent.cancelBubble || this.onClickHandler || this.Document.onDragStart) { this._downX = e.clientX; this._downY = e.clientY; - this._hitTemplateDrag = false; - // this whole section needs to move somewhere else. We're trying to initiate a special "template" drag where - // this document is the template and we apply it to whatever we drop it on. - for (let element = (e.target as any); element && !this._hitTemplateDrag; element = element.parentElement) { - if (element.className && element.className.toString() === "collectionViewBaseChrome-collapse") { - this._hitTemplateDrag = true; - } - } if ((this.active || this.Document.onDragStart || this.onClickHandler) && !e.ctrlKey && (e.button === 0 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) && @@ -470,7 +460,7 @@ export class DocumentView extends DocComponent(Docu if (!e.altKey && (!this.topMost || this.Document.onDragStart || this.onClickHandler) && (e.buttons === 1 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE))) { document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); - this.startDragging(this._downX, this._downY, this.props.ContainingCollectionDoc?.childDropAction ? this.props.ContainingCollectionDoc?.childDropAction : this.Document.dropAction ? this.Document.dropAction as any : e.ctrlKey || e.altKey ? "alias" : undefined, this._hitTemplateDrag); + this.startDragging(this._downX, this._downY, this.props.ContainingCollectionDoc?.childDropAction ? this.props.ContainingCollectionDoc?.childDropAction : this.Document.dropAction ? this.Document.dropAction as any : e.ctrlKey || e.altKey ? "alias" : undefined); } } e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document' however it does mark the event as cancelBubble=true which we test for in the move event handlers @@ -556,17 +546,6 @@ export class DocumentView extends DocComponent(Docu } } - @undoBatch - makeSelBtnClicked = (): void => { - if (this.Document.isButton || this.Document.onClick || this.Document.ignoreClick) { - this.Document.isButton = false; - this.Document.ignoreClick = false; - this.Document.onClick = undefined; - } else { - this.props.Document.isButton = "Selector"; - } - } - @undoBatch @action drop = async (e: Event, de: DragManager.DropEvent) => { @@ -578,10 +557,6 @@ export class DocumentView extends DocComponent(Docu DocUtils.MakeLink({ doc: de.complete.annoDragData.annotationDocument }, { doc: this.props.Document, ctx: this.props.ContainingCollectionDoc }, `Link from ${StrCast(de.complete.annoDragData.annotationDocument.title)}`); } - if (de.complete.docDragData && de.complete.docDragData.applyAsTemplate) { - Doc.ApplyTemplateTo(de.complete.docDragData.draggedDocuments[0], this.props.Document, "layout_custom", undefined); - e.stopPropagation(); - } if (de.complete.linkDragData) { e.stopPropagation(); // const docs = await SearchUtil.Search(`data_l:"${destDoc[Id]}"`, true); @@ -697,7 +672,6 @@ export class DocumentView extends DocComponent(Docu onClicks.push({ description: "Toggle Detail", event: () => this.Document.onClick = ScriptField.MakeScript(`toggleDetail(this, "${this.props.Document.layoutKey}")`), icon: "window-restore" }); onClicks.push({ description: this.Document.ignoreClick ? "Select" : "Do Nothing", event: () => this.Document.ignoreClick = !this.Document.ignoreClick, icon: this.Document.ignoreClick ? "unlock" : "lock" }); onClicks.push({ description: this.Document.isButton || this.Document.onClick ? "Remove Click Behavior" : "Follow Link", event: this.makeBtnClicked, icon: "concierge-bell" }); - onClicks.push({ description: this.props.Document.isButton ? "Remove Select Link Behavior" : "Select Link", event: this.makeSelBtnClicked, icon: "concierge-bell" }); onClicks.push({ description: "Edit onClick Script", icon: "edit", event: (obj: any) => ScriptBox.EditButtonScript("On Button Clicked ...", this.props.Document, "onClick", obj.x, obj.y) }); !existingOnClick && cm.addItem({ description: "OnClick...", subitems: onClicks, icon: "hand-point-right" }); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 7fbee8881..2fb61f9db 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -250,17 +250,6 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & Doc.GetProto(this.dataDoc)[this.props.fieldKey] = new RichTextField(draggedDoc.data.Data, draggedDoc.data.Text); e.stopPropagation(); } - // apply as template when dragging with Meta - } else if (draggedDoc && draggedDoc.type === DocumentType.TEXT && !Doc.AreProtosEqual(draggedDoc, this.props.Document) && de.metaKey) { - draggedDoc.isTemplateDoc = true; - let newLayout = Doc.Layout(draggedDoc); - if (typeof (draggedDoc.layout) === "string") { - newLayout = Doc.MakeDelegate(draggedDoc); - newLayout.layout = StrCast(newLayout.layout).replace(/fieldKey={'[^']*'}/, `fieldKey={'${this.props.fieldKey}'}`); - } - this.Document.layout_custom = newLayout; - this.Document.layoutKey = "layout_custom"; - e.stopPropagation(); // embed document when dragging with a userDropAction or an embedDoc flag set } else if (de.complete.docDragData.userDropAction || de.complete.docDragData.embedDoc) { const target = de.complete.docDragData.droppedDocuments[0]; diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index c0e102195..364bce7a8 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -92,10 +92,11 @@ export class ImageBox extends DocAnnotatableComponent Cast(target[SelfProxy].proto, Doc) || null, // TODO this might be able to replace the proto logic in getter has: (target, key) => key in target.__fields, - ownKeys: target => Object.keys(target.__allfields), + ownKeys: target => { + let obj = {} as any; + Object.assign(obj, target.___fields); + runInAction(() => obj.__LAYOUT__ = target.__LAYOUT__); + return Object.keys(obj) + }, getOwnPropertyDescriptor: (target, prop) => { if (prop.toString() === "__LAYOUT__") { return Reflect.getOwnPropertyDescriptor(target, prop); @@ -140,17 +144,7 @@ export class Doc extends RefField { [key: string]: FieldResult; @serializable(alias("fields", map(autoObject(), { afterDeserialize: afterDocDeserialize }))) - private get __fields() { - return this.___fields; - } - private get __allfields() { - let obj = {} as any; - Object.assign(obj, this.___fields); - runInAction(() => obj.__LAYOUT__ = this.__LAYOUT__); - return obj; - } - - + private get __fields() { return this.___fields; } private set __fields(value) { this.___fields = value; for (const key in value) { @@ -168,18 +162,19 @@ export class Doc extends RefField { private [UpdatingFromServer]: boolean = false; private [Update] = (diff: any) => { - if (this[UpdatingFromServer]) { - return; - } - DocServer.UpdateField(this[Id], diff); + !this[UpdatingFromServer] && DocServer.UpdateField(this[Id], diff); } private [Self] = this; private [SelfProxy]: any; public [WidthSym] = () => NumCast(this[SelfProxy]._width); public [HeightSym] = () => NumCast(this[SelfProxy]._height); - public get [DataSym]() { return Cast(Doc.Layout(this[SelfProxy]).resolvedDataDoc, Doc, null) || this[SelfProxy]; } public get [LayoutSym]() { return this[SelfProxy].__LAYOUT__; } + public get [DataSym]() { + const self = this[SelfProxy]; + return self.resolvedDataDoc && !self.isTemplateForField ? self : + Doc.GetProto(Cast(Doc.Layout(self).resolvedDataDoc, Doc, null) || self); + } @computed get __LAYOUT__() { const templateLayoutDoc = Cast(Doc.LayoutField(this[SelfProxy]), Doc, null); if (templateLayoutDoc) { @@ -195,12 +190,8 @@ export class Doc extends RefField { return undefined; } - [ToScriptString]() { - return "invalid"; - } - [ToString]() { - return "Doc"; - } + [ToScriptString]() { return "invalid"; } + [ToString]() { return "Doc"; } private [CachedUpdates]: { [key: string]: () => void | Promise } = {}; public static CurrentUserEmail: string = ""; @@ -287,8 +278,7 @@ export namespace Doc { export function Get(doc: Doc, key: string, ignoreProto: boolean = false): FieldResult { try { - const self = doc[Self]; - return getField(self, key, ignoreProto); + return getField(doc[Self], key, ignoreProto); } catch { return doc; } @@ -357,13 +347,12 @@ export namespace Doc { return r || r2 || r3 || r4; } - // gets the document's prototype or returns the document if it is a prototype - export function GetProto(doc: Doc) { - return doc && (Doc.GetT(doc, "isPrototype", "boolean", true) ? doc : (doc.proto || doc)); - } - export function GetDataDoc(doc: Doc): Doc { - const proto = Doc.GetProto(doc); - return proto === doc ? proto : Doc.GetDataDoc(proto); + // Gets the data document for the document. Note: this is mis-named -- it does not specifically + // return the doc's proto, but rather recursively searches through the proto inheritance chain + // and returns the document who's proto is undefined or whose proto is marked as a base prototype ('isPrototype'). + export function GetProto(doc: Doc): Doc { + const proto = doc && (Doc.GetT(doc, "isPrototype", "boolean", true) ? doc : (doc.proto || doc)); + return proto === doc ? proto : Doc.GetProto(proto); } export function allKeys(doc: Doc): string[] { @@ -443,11 +432,6 @@ export namespace Doc { return bounds; } - export function MakeTitled(title: string) { - const doc = new Doc(); - doc.title = title; - return doc; - } export function MakeAlias(doc: Doc, id?: string) { const alias = !GetT(doc, "isPrototype", "boolean", true) ? Doc.MakeCopy(doc, undefined, id) : Doc.MakeDelegate(doc, id); const layout = Doc.LayoutField(alias); @@ -488,7 +472,7 @@ export namespace Doc { if (templateLayoutDoc.resolvedDataDoc instanceof Promise) { expandedTemplateLayout = undefined; - } else if (templateLayoutDoc.resolvedDataDoc === Doc.GetDataDoc(targetDoc)) { + } else if (templateLayoutDoc.resolvedDataDoc === Doc.GetProto(targetDoc)) { expandedTemplateLayout = templateLayoutDoc; } else if (expandedTemplateLayout === undefined) { setTimeout(action(() => { @@ -497,7 +481,7 @@ export namespace Doc { newLayoutDoc.lockedPosition = true; newLayoutDoc.expandedTemplate = targetDoc; targetDoc[expandedLayoutFieldKey] = newLayoutDoc; - const dataDoc = Doc.GetDataDoc(targetDoc); + const dataDoc = Doc.GetProto(targetDoc); newLayoutDoc.resolvedDataDoc = dataDoc; if (dataDoc[templateField] === undefined && templateLayoutDoc[templateField] instanceof List && Cast(templateLayoutDoc[templateField], listSpec(Doc), []).length) { dataDoc[templateField] = ComputedField.MakeFunction(`ObjectField.MakeCopy(templateLayoutDoc["${templateField}"] as List)`, { templateLayoutDoc: Doc.name }, { templateLayoutDoc: templateLayoutDoc }); @@ -660,10 +644,6 @@ export namespace Doc { // assign the template field doc a delegate of any extension document that was previously used to render the template field (since extension doc's carry rendering informatino) Doc.Layout(templateField)[metadataFieldKey + "_ext"] = Doc.MakeDelegate(templateField[templateFieldLayoutString?.split("'")[1] + "_ext"] as Doc); - if (templateField.backgroundColor !== templateDoc?.defaultBackgroundColor) { - templateField.defaultBackgroundColor = templateField.backgroundColor; - } - return true; } @@ -716,26 +696,26 @@ export namespace Doc { export function SetUserDoc(doc: Doc) { manager._user_doc = doc; } export function IsBrushed(doc: Doc) { return computedFn(function IsBrushed(doc: Doc) { - return brushManager.BrushedDoc.has(doc) || brushManager.BrushedDoc.has(Doc.GetDataDoc(doc)); + return brushManager.BrushedDoc.has(doc) || brushManager.BrushedDoc.has(Doc.GetProto(doc)); })(doc); } // don't bother memoizing (caching) the result if called from a non-reactive context. (plus this avoids a warning message) export function IsBrushedDegreeUnmemoized(doc: Doc) { - return brushManager.BrushedDoc.has(doc) ? 2 : brushManager.BrushedDoc.has(Doc.GetDataDoc(doc)) ? 1 : 0; + return brushManager.BrushedDoc.has(doc) ? 2 : brushManager.BrushedDoc.has(Doc.GetProto(doc)) ? 1 : 0; } export function IsBrushedDegree(doc: Doc) { return computedFn(function IsBrushDegree(doc: Doc) { - return brushManager.BrushedDoc.has(doc) ? 2 : brushManager.BrushedDoc.has(Doc.GetDataDoc(doc)) ? 1 : 0; + return Doc.IsBrushedDegreeUnmemoized(doc); })(doc); } export function BrushDoc(doc: Doc) { brushManager.BrushedDoc.set(doc, true); - brushManager.BrushedDoc.set(Doc.GetDataDoc(doc), true); + brushManager.BrushedDoc.set(Doc.GetProto(doc), true); return doc; } export function UnBrushDoc(doc: Doc) { brushManager.BrushedDoc.delete(doc); - brushManager.BrushedDoc.delete(Doc.GetDataDoc(doc)); + brushManager.BrushedDoc.delete(Doc.GetProto(doc)); return doc; } @@ -748,14 +728,14 @@ export namespace Doc { document.removeEventListener("pointerdown", linkFollowUnhighlight); } - let dt = 0; + let _lastDate = 0; export function linkFollowHighlight(destDoc: Doc, dataAndDisplayDocs = true) { linkFollowUnhighlight(); Doc.HighlightDoc(destDoc, dataAndDisplayDocs); document.removeEventListener("pointerdown", linkFollowUnhighlight); document.addEventListener("pointerdown", linkFollowUnhighlight); - const x = dt = Date.now(); - window.setTimeout(() => dt === x && linkFollowUnhighlight(), 5000); + const lastDate = _lastDate = Date.now(); + window.setTimeout(() => _lastDate === lastDate && linkFollowUnhighlight(), 5000); } export class HighlightBrush { @@ -763,18 +743,18 @@ export namespace Doc { } const highlightManager = new HighlightBrush(); export function IsHighlighted(doc: Doc) { - return highlightManager.HighlightedDoc.get(doc) || highlightManager.HighlightedDoc.get(Doc.GetDataDoc(doc)); + return highlightManager.HighlightedDoc.get(doc) || highlightManager.HighlightedDoc.get(Doc.GetProto(doc)); } export function HighlightDoc(doc: Doc, dataAndDisplayDocs = true) { runInAction(() => { highlightManager.HighlightedDoc.set(doc, true); - dataAndDisplayDocs && highlightManager.HighlightedDoc.set(Doc.GetDataDoc(doc), true); + dataAndDisplayDocs && highlightManager.HighlightedDoc.set(Doc.GetProto(doc), true); }); } export function UnHighlightDoc(doc: Doc) { runInAction(() => { highlightManager.HighlightedDoc.set(doc, false); - highlightManager.HighlightedDoc.set(Doc.GetDataDoc(doc), false); + highlightManager.HighlightedDoc.set(Doc.GetProto(doc), false); }); } export function UnhighlightAll() { diff --git a/src/new_fields/documentSchemas.ts b/src/new_fields/documentSchemas.ts index 81f073855..3cc05d3d5 100644 --- a/src/new_fields/documentSchemas.ts +++ b/src/new_fields/documentSchemas.ts @@ -4,12 +4,13 @@ import { Doc } from "./Doc"; import { DateField } from "./DateField"; export const documentSchema = createSchema({ - layout: "string", // this is the native layout string for the document. templates can be added using other fields and setting layoutKey below (see layout_custom as an example) + type: "string", // enumerated type of document -- should be template-specific (ie, start with an '_') + layout: "string", // this is the native layout string for the document. templates can be added using other fields and setting layoutKey below layoutKey: "string", // holds the field key for the field that actually holds the current lyoat - layout_custom: Doc, // used to hold a custom layout (there's nothing special about this field .. any field could hold a custom layout that can be selected by setting 'layoutKey') title: "string", // document title (can be on either data document or layout) dropAction: "string", // override specifying what should happen when this document is dropped (can be "alias" or "copy") childDropAction: "string", // specify the override for what should happen when the child of a collection is dragged from it and dropped (can be "alias" or "copy") + _autoHeight: "boolean", // whether the height of the document should be computed automatically based on its contents _nativeWidth: "number", // native width of document which determines how much document contents are scaled when the document's width is set _nativeHeight: "number", // " _width: "number", // width of document in its container's coordinate system @@ -27,20 +28,18 @@ export const documentSchema = createSchema({ opacity: "number", // opacity of document creationDate: DateField, // when the document was created links: listSpec(Doc), // computed (readonly) list of links associated with this document - removeDropProperties: listSpec("string"), // properties that should be removed from the alias/copy/etc of this document when it is dropped onClick: ScriptField, // script to run when document is clicked (can be overriden by an onClick prop) onPointerDown: ScriptField, // script to run when document is clicked (can be overriden by an onClick prop) onPointerUp: ScriptField, // script to run when document is clicked (can be overriden by an onClick prop) onDragStart: ScriptField, // script to run when document is dragged (without being selected). the script should return the Doc to be dropped. dragFactory: Doc, // the document that serves as the "template" for the onDragStart script. ie, to drag out copies of the dragFactory document. + removeDropProperties: listSpec("string"), // properties that should be removed from the alias/copy/etc of this document when it is dropped ignoreAspect: "boolean", // whether aspect ratio should be ignored when laying out or manipulating the document - autoHeight: "boolean", // whether the height of the document should be computed automatically based on its contents isTemplateForField: "string",// when specifies a field key, then the containing document is a template that renders the specified field isBackground: "boolean", // whether document is a background element and ignores input events (can only selet with marquee) - type: "string", // enumerated type of document treeViewOpen: "boolean", // flag denoting whether the documents sub-tree (contents) is visible or hidden treeViewExpandedView: "string", // name of field whose contents are being displayed as the document's subtree - preventTreeViewOpen: "boolean", // ignores the treeViewOpen flag (for allowing a view to not be slaved to other views of the document) + treeViewPreventOpen: "boolean", // ignores the treeViewOpen flag (for allowing a view to not be slaved to other views of the document) currentTimecode: "number", // current play back time of a temporal document (video / audio) maximizeLocation: "string", // flag for where to place content when following a click interaction (e.g., onRight, inPlace, inTab) lockedPosition: "boolean", // whether the document can be moved (dragged) @@ -57,7 +56,6 @@ export const documentSchema = createSchema({ fitToBox: "boolean", // whether freeform view contents should be zoomed/panned to fill the area of the document view xPadding: "number", // pixels of padding on left/right of collectionfreeformview contents when fitToBox is set yPadding: "number", // pixels of padding on left/right of collectionfreeformview contents when fitToBox is set - LODarea: "number", // area (width*height) where CollectionFreeFormViews switch from a label to rendering contents letterSpacing: "string", textTransform: "string" }); diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 45875d455..32c375bd7 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -139,7 +139,7 @@ export class CurrentUserUtils { static setupThumbDoc(userDoc: Doc) { if (!userDoc.thumbDoc) { userDoc.thumbDoc = Docs.Create.LinearDocument(CurrentUserUtils.setupThumbButtons(userDoc), { - _width: 100, _height: 50, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", title: "buttons", _autoHeight: true, _yMargin: 5, isExpanded: true, backgroundColor: "white" + _width: 100, _height: 50, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", title: "buttons", _autoHeight: true, _yMargin: 5, linearViewIsExpanded: true, backgroundColor: "white" }); } return userDoc.thumbDoc; @@ -181,12 +181,12 @@ export class CurrentUserUtils { }); doc.documents = Docs.Create.TreeDocument([], { - title: "DOCUMENTS", _height: 42, forceActive: true, boxShadow: "0 0", preventTreeViewOpen: true, lockedPosition: true, backgroundColor: "#eeeeee" + title: "DOCUMENTS", _height: 42, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: true, lockedPosition: true, backgroundColor: "#eeeeee" }); // setup Recently Closed library item doc.recentlyClosed = Docs.Create.TreeDocument([], { - title: "RECENTLY CLOSED", _height: 75, forceActive: true, boxShadow: "0 0", preventTreeViewOpen: true, lockedPosition: true, backgroundColor: "#eeeeee" + title: "RECENTLY CLOSED", _height: 75, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: true, lockedPosition: true, backgroundColor: "#eeeeee" }); return Docs.Create.ButtonDocument({ @@ -255,7 +255,7 @@ export class CurrentUserUtils { { _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, dropAction: "alias", onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: slideTemplate, removeDropProperties: new List(["dropAction"]), title: "presentation slide", icon: "sticky-note" }); doc.expandingButtons = Docs.Create.LinearDocument([doc.undoBtn as Doc, doc.redoBtn as Doc, doc.slidesBtn as Doc], { title: "expanding buttons", _gridGap: 5, _xMargin: 5, _yMargin: 5, _height: 42, _width: 100, boxShadow: "0 0", - backgroundColor: "black", preventTreeViewOpen: true, forceActive: true, lockedPosition: true, + backgroundColor: "black", treeViewPreventOpen: true, forceActive: true, lockedPosition: true, dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }) }); -- cgit v1.2.3-70-g09d2 From 2ae91501a3195da9dcbc02e180b108983cd1d8af Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 16 Feb 2020 21:47:28 -0500 Subject: got rid of unneeded ignoreAspect field. other cleanup. --- src/client/util/RichTextSchema.tsx | 2 +- src/client/views/DocumentDecorations.tsx | 9 ++------- src/client/views/collections/CollectionDockingView.tsx | 8 ++++---- .../views/collections/CollectionMasonryViewFieldRow.tsx | 3 ++- src/client/views/collections/CollectionStackingView.tsx | 6 +++--- src/client/views/collections/CollectionView.tsx | 17 ----------------- .../views/nodes/CollectionFreeFormDocumentView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 15 +++++---------- src/client/views/nodes/ImageBox.tsx | 2 +- src/client/views/nodes/PDFBox.tsx | 4 ++-- src/new_fields/Doc.ts | 3 +-- src/new_fields/documentSchemas.ts | 1 - 12 files changed, 22 insertions(+), 50 deletions(-) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 3a3bcd1ad..656215368 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -723,7 +723,7 @@ export class DashDocView { const { scale, translateX, translateY } = Utils.GetScreenTransform(this._outer); return new Transform(-translateX, -translateY, 1).scale(1 / this.contentScaling() / scale); } - contentScaling = () => NumCast(this._dashDoc!._nativeWidth) > 0 && !this._dashDoc!.ignoreAspect ? this._dashDoc![WidthSym]() / NumCast(this._dashDoc!._nativeWidth) : 1; + contentScaling = () => NumCast(this._dashDoc!._nativeWidth) > 0 ? this._dashDoc![WidthSym]() / NumCast(this._dashDoc!._nativeWidth) : 1; outerFocus = (target: Doc) => this._textBox.props.focus(this._textBox.props.Document); // ideally, this would scroll to show the focus target constructor(node: any, view: any, getPos: any, tbox: FormattedTextBox) { this._textBox = tbox; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 5fc14e716..cc7388a61 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -283,17 +283,12 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> const actualdH = Math.max(height + (dH * scale), 20); doc.x = (doc.x || 0) + dX * (actualdW - width); doc.y = (doc.y || 0) + dY * (actualdH - height); - const fixedAspect = e.ctrlKey || (!layoutDoc.ignoreAspect && nwidth && nheight); - if (fixedAspect && e.ctrlKey && layoutDoc.ignoreAspect) { - layoutDoc.ignoreAspect = false; - layoutDoc._nativeWidth = nwidth = layoutDoc._width || 0; - layoutDoc._nativeHeight = nheight = layoutDoc._height || 0; - } + const fixedAspect = e.ctrlKey || (nwidth && nheight); if (fixedAspect && (!nwidth || !nheight)) { layoutDoc._nativeWidth = nwidth = layoutDoc._width || 0; layoutDoc._nativeHeight = nheight = layoutDoc._height || 0; } - if (nwidth > 0 && nheight > 0 && !layoutDoc.ignoreAspect) { + if (nwidth > 0 && nheight > 0) { if (Math.abs(dW) > Math.abs(dH)) { if (!fixedAspect) { layoutDoc._nativeWidth = actualdW / (layoutDoc._width || 1) * (layoutDoc._nativeWidth || 0); diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 6abfb59c3..bf0333d55 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -678,8 +678,8 @@ export class DockedFrameRenderer extends React.Component { panelWidth = () => this.layoutDoc && this.layoutDoc.maxWidth ? Math.min(Math.max(NumCast(this.layoutDoc._width), NumCast(this.layoutDoc._nativeWidth)), this._panelWidth) : this._panelWidth; panelHeight = () => this._panelHeight; - nativeWidth = () => !this.layoutDoc!.ignoreAspect && !this.layoutDoc!._fitWidth ? NumCast(this.layoutDoc!._nativeWidth) || this._panelWidth : 0; - nativeHeight = () => !this.layoutDoc!.ignoreAspect && !this.layoutDoc!._fitWidth ? NumCast(this.layoutDoc!._nativeHeight) || this._panelHeight : 0; + nativeWidth = () => !this.layoutDoc!._fitWidth ? NumCast(this.layoutDoc!._nativeWidth) || this._panelWidth : 0; + nativeHeight = () => !this.layoutDoc!._fitWidth ? NumCast(this.layoutDoc!._nativeHeight) || this._panelHeight : 0; contentScaling = () => { if (this.layoutDoc!.type === DocumentType.PDF) { @@ -705,8 +705,8 @@ export class DockedFrameRenderer extends React.Component { } return Transform.Identity(); } - get previewPanelCenteringOffset() { return this.nativeWidth() && !this.layoutDoc!.ignoreAspect ? (this._panelWidth - this.nativeWidth() * this.contentScaling()) / 2 : 0; } - get widthpercent() { return this.nativeWidth() && !this.layoutDoc!.ignoreAspect ? `${(this.nativeWidth() * this.contentScaling()) / this.panelWidth() * 100}%` : undefined; } + get previewPanelCenteringOffset() { return this.nativeWidth() ? (this._panelWidth - this.nativeWidth() * this.contentScaling()) / 2 : 0; } + get widthpercent() { return this.nativeWidth() ? `${(this.nativeWidth() * this.contentScaling()) / this.panelWidth() * 100}%` : undefined; } addDocTab = (doc: Doc, dataDoc: Opt, location: string, libraryPath?: Doc[]) => { SelectionManager.DeselectAll(); diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx index f3dd7c733..c9b7ca221 100644 --- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx +++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx @@ -259,7 +259,8 @@ export class CollectionMasonryViewFieldRow extends React.Component "", diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index a9cefae6a..ad9dc8f7c 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -185,7 +185,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { if (!d) return 0; const layoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.()); const nw = NumCast(layoutDoc._nativeWidth); - return Math.min(nw && !d.ignoreAspect && !this.props.Document.fillColumn ? d[WidthSym]() : Number.MAX_VALUE, this.columnWidth / this.numGroupColumns); + return Math.min(nw && !this.props.Document.fillColumn ? d[WidthSym]() : Number.MAX_VALUE, this.columnWidth / this.numGroupColumns); } getDocHeight(d?: Doc) { if (!d) return 0; @@ -193,9 +193,9 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { const nw = NumCast(layoutDoc._nativeWidth); const nh = NumCast(layoutDoc._nativeHeight); let wid = this.columnWidth / (this.isStackingView ? this.numGroupColumns : 1); - if (!layoutDoc.ignoreAspect && !layoutDoc._fitWidth && nw && nh) { + if (!layoutDoc._fitWidth && nw && nh) { const aspect = nw && nh ? nh / nw : 1; - if (!(!layoutDoc.ignoreAspect && this.props.Document.fillColumn)) wid = Math.min(layoutDoc[WidthSym](), wid); + if (!(this.props.Document.fillColumn)) wid = Math.min(layoutDoc[WidthSym](), wid); return wid * aspect; } return layoutDoc._fitWidth ? !nh ? this.props.PanelHeight() - 2 * this.yMargin : diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 48294f9c2..52a18fb99 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -90,11 +90,9 @@ export interface CollectionRenderProps { export class CollectionView extends Touchable { public static LayoutString(fieldStr: string) { return FieldView.LayoutString(CollectionView, fieldStr); } - private _reactionDisposer: IReactionDisposer | undefined; private _isChildActive = false; //TODO should this be observable? @observable private _isLightboxOpen = false; @observable private _curLightboxImg = 0; - @observable private _collapsed = true; @observable private static _safeMode = false; public static SetSafeMode(safeMode: boolean) { this._safeMode = safeMode; } @@ -111,20 +109,6 @@ export class CollectionView extends Touchable { return viewField; } - componentDidMount = () => { - this._reactionDisposer = reaction(() => StrCast(this.props.Document._chromeStatus), - () => { - // chrome status is one of disabled, collapsed, or visible. this determines initial state from document - // chrome status may also be view-mode, in reference to stacking view's toggle mode. it is essentially disabled mode, but prevents the toggle button from showing up on the left sidebar. - const chromeStatus = this.props.Document._chromeStatus; - if (chromeStatus && (chromeStatus === "disabled" || chromeStatus === "collapsed" || chromeStatus === "replaced")) { - runInAction(() => this._collapsed = true); - } - }); - } - - componentWillUnmount = () => this._reactionDisposer && this._reactionDisposer(); - // bcz: Argh? What's the height of the collection chromes?? chromeHeight = () => (this.props.Document._chromeStatus === "enabled" ? -60 : 0); @@ -198,7 +182,6 @@ export class CollectionView extends Touchable { @action private collapse = (value: boolean) => { - this._collapsed = value; this.props.Document._chromeStatus = value ? "collapsed" : "enabled"; } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 53d17b580..eaab4086c 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -60,7 +60,7 @@ export class CollectionFreeFormDocumentView extends DocComponent this.nativeWidth > 0 && !this.props.Document.ignoreAspect && !this.props.fitToBox ? this.width / this.nativeWidth : 1; + contentScaling = () => this.nativeWidth > 0 && !this.props.fitToBox ? this.width / this.nativeWidth : 1; panelWidth = () => (this.dataProvider?.width || this.props.PanelWidth()); panelHeight = () => (this.dataProvider?.height || this.props.PanelHeight()); getTransform = (): Transform => this.props.ScreenToLocalTransform() diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index b4ec09aee..330410a92 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -364,18 +364,12 @@ export class DocumentView extends DocComponent(Docu const actualdH = Math.max(height + (dH * scale), 20); doc.x = (doc.x || 0) + dX * (actualdW - width); doc.y = (doc.y || 0) + dY * (actualdH - height); - const fixedAspect = e.ctrlKey || (!layoutDoc.ignoreAspect && nwidth && nheight); - if (fixedAspect && e.ctrlKey && layoutDoc.ignoreAspect) { - layoutDoc.ignoreAspect = false; - - layoutDoc._nativeWidth = nwidth = layoutDoc._width || 0; - layoutDoc._nativeHeight = nheight = layoutDoc._height || 0; - } + const fixedAspect = e.ctrlKey || (nwidth && nheight); if (fixedAspect && (!nwidth || !nheight)) { layoutDoc._nativeWidth = nwidth = layoutDoc._width || 0; layoutDoc._nativeHeight = nheight = layoutDoc._height || 0; } - if (nwidth > 0 && nheight > 0 && !layoutDoc.ignoreAspect) { + if (nwidth > 0 && nheight > 0) { if (Math.abs(dW) > Math.abs(dH)) { if (!fixedAspect) { layoutDoc._nativeWidth = actualdW / (layoutDoc._width || 1) * (layoutDoc._nativeWidth || 0); @@ -546,10 +540,11 @@ export class DocumentView extends DocComponent(Docu } @undoBatch - public static unfreezeNativeDimensions = action((layoutDoc: Doc): void => { + @action + public static unfreezeNativeDimensions(layoutDoc: Doc) { layoutDoc._nativeWidth = undefined; layoutDoc._nativeHeight = undefined; - }); + } toggleNativeDimensions = () => { if (this.Document._nativeWidth || this.Document._nativeHeight) { diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 364bce7a8..5b5768d54 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -375,7 +375,7 @@ export class ImageBox extends DocAnnotatableComponent
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index e1c5fd27f..a2aec699f 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -52,7 +52,7 @@ export class PDFBox extends DocAnnotatableComponent this._initialScale = this.props.ScreenToLocalTransform().Scale; const nw = this.Document._nativeWidth = NumCast(this.dataDoc[this.props.fieldKey + "-nativeWidth"], NumCast(this.Document._nativeWidth, 927)); const nh = this.Document._nativeHeight = NumCast(this.dataDoc[this.props.fieldKey + "-nativeHeight"], NumCast(this.Document._nativeHeight, 1200)); - !this.Document._fitWidth && !this.Document.ignoreAspect && (this.Document._height = this.Document[WidthSym]() * (nh / nw)); + !this.Document._fitWidth && (this.Document._height = this.Document[WidthSym]() * (nh / nw)); const backup = "oldPath"; const { Document } = this.props; @@ -93,7 +93,7 @@ export class PDFBox extends DocAnnotatableComponent this.dataDoc[this.props.fieldKey + "-numPages"] = np; this.dataDoc[this.props.fieldKey + "-nativeWidth"] = this.Document._nativeWidth = nw * 96 / 72; this.dataDoc[this.props.fieldKey + "-nativeHeight"] = this.Document._nativeHeight = nh * 96 / 72; - !this.Document._fitWidth && !this.Document.ignoreAspect && (this.Document._height = this.Document[WidthSym]() * (nh / nw)); + !this.Document._fitWidth && (this.Document._height = this.Document[WidthSym]() * (nh / nw)); } public search(string: string, fwd: boolean) { this._pdfViewer && this._pdfViewer.search(string, fwd); } diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index a722f552e..48890ac8d 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -840,8 +840,7 @@ export namespace Doc { export function freezeNativeDimensions(layoutDoc: Doc, width: number, height: number): void { layoutDoc._autoHeight = false; - layoutDoc.ignoreAspect = false; - if (!layoutDoc.ignoreAspect && !layoutDoc._nativeWidth) { + if (!layoutDoc._nativeWidth) { layoutDoc._nativeWidth = NumCast(layoutDoc._width, width); layoutDoc._nativeHeight = NumCast(layoutDoc._height, height); } diff --git a/src/new_fields/documentSchemas.ts b/src/new_fields/documentSchemas.ts index 3cc05d3d5..f3726cb5a 100644 --- a/src/new_fields/documentSchemas.ts +++ b/src/new_fields/documentSchemas.ts @@ -34,7 +34,6 @@ export const documentSchema = createSchema({ onDragStart: ScriptField, // script to run when document is dragged (without being selected). the script should return the Doc to be dropped. dragFactory: Doc, // the document that serves as the "template" for the onDragStart script. ie, to drag out copies of the dragFactory document. removeDropProperties: listSpec("string"), // properties that should be removed from the alias/copy/etc of this document when it is dropped - ignoreAspect: "boolean", // whether aspect ratio should be ignored when laying out or manipulating the document isTemplateForField: "string",// when specifies a field key, then the containing document is a template that renders the specified field isBackground: "boolean", // whether document is a background element and ignores input events (can only selet with marquee) treeViewOpen: "boolean", // flag denoting whether the documents sub-tree (contents) is visible or hidden -- cgit v1.2.3-70-g09d2 From 6d7f56cead95b1ab59a62ccc21ee52491386a655 Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 18 Feb 2020 14:00:06 -0500 Subject: cleaned up context menu ordering --- src/client/views/DocumentDecorations.tsx | 4 +- src/client/views/collections/CollectionView.tsx | 13 +++-- .../collectionFreeForm/CollectionFreeFormView.tsx | 1 + src/client/views/nodes/DocumentView.tsx | 61 +++++++++++----------- src/client/views/nodes/FormattedTextBox.tsx | 3 +- src/client/views/nodes/ImageBox.tsx | 2 +- 6 files changed, 46 insertions(+), 38 deletions(-) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 8e4598339..07cc1d984 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -171,7 +171,9 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> } @action onSettingsClick = (e: PointerEvent): void => { if (e.button === 0 && !e.altKey && !e.ctrlKey) { - this.simulateMouseClick(SelectionManager.SelectedDocuments()[0].ContentDiv!.children[0].children[0], e.clientX, e.clientY + 30, e.screenX, e.screenY + 30); + let child = SelectionManager.SelectedDocuments()[0].ContentDiv!.children[0]; + while (child.children.length && child.className !== "jsx-parser") child = child.children[0]; + this.simulateMouseClick(child.children[0], e.clientX, e.clientY + 30, e.screenX, e.screenY + 30); } } diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 52a18fb99..79fd7d792 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -236,15 +236,20 @@ export class CollectionView extends Touchable { } !existing && ContextMenu.Instance.addItem({ description: "Layout...", subitems: layoutItems, icon: "hand-point-right" }); - const more = ContextMenu.Instance.findByDescription("More..."); - const moreItems = more && "subitems" in more ? more.subitems : []; - moreItems.push({ description: "Export Image Hierarchy", icon: "columns", event: () => ImageUtils.ExportHierarchyToFileSystem(this.props.Document) }); - !more && ContextMenu.Instance.addItem({ description: "More...", subitems: moreItems, icon: "hand-point-right" }); + const open = ContextMenu.Instance.findByDescription("Open..."); + const openItems = open && "subitems" in open ? open.subitems : []; + !open && ContextMenu.Instance.addItem({ description: "Open...", subitems: openItems, icon: "hand-point-right" }); const existingOnClick = ContextMenu.Instance.findByDescription("OnClick..."); const onClicks = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : []; onClicks.push({ description: "Edit onChildClick script", icon: "edit", event: (obj: any) => ScriptBox.EditButtonScript("On Child Clicked...", this.props.Document, "onChildClick", obj.x, obj.y) }); !existingOnClick && ContextMenu.Instance.addItem({ description: "OnClick...", subitems: onClicks, icon: "hand-point-right" }); + + const more = ContextMenu.Instance.findByDescription("More..."); + const moreItems = more && "subitems" in more ? more.subitems : []; + moreItems.push({ description: "Export Image Hierarchy", icon: "columns", event: () => ImageUtils.ExportHierarchyToFileSystem(this.props.Document) }); + !more && ContextMenu.Instance.addItem({ description: "More...", subitems: moreItems, icon: "hand-point-right" }); + } } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 59c3033e9..fa8a203b4 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -965,6 +965,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { // } onContextMenu = (e: React.MouseEvent) => { + if (this.props.children && this.props.annotationsKey) return; const layoutItems: ContextMenuProps[] = []; layoutItems.push({ description: "reset view", event: () => { this.props.Document._panX = this.props.Document._panY = 0; this.props.Document.scale = 1; }, icon: "compress-arrows-alt" }); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 5062f193e..229e7fa45 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -628,22 +628,37 @@ export class DocumentView extends DocComponent(Docu } e.preventDefault(); + const cm = ContextMenu.Instance; const templateDoc = Cast(this.props.Document[StrCast(this.props.Document.layoutKey)], Doc, null); - const cm = ContextMenu.Instance; - const subitems: ContextMenuProps[] = []; - subitems.push({ description: "Open Full Screen", event: () => CollectionDockingView.Instance && CollectionDockingView.Instance.OpenFullScreen(this, this.props.LibraryPath), icon: "desktop" }); - subitems.push({ description: "Open Tab ", event: () => this.props.addDocTab(this.props.Document, this.props.DataDoc, "inTab", this.props.LibraryPath), icon: "folder" }); - subitems.push({ description: "Open Right ", event: () => this.props.addDocTab(this.props.Document, this.props.DataDoc, "onRight", this.props.LibraryPath), icon: "caret-square-right" }); - subitems.push({ description: "Open Alias Tab ", event: () => this.props.addDocTab(Doc.MakeAlias(this.props.Document), this.props.DataDoc, "inTab"), icon: "folder" }); - subitems.push({ description: "Open Alias Right", event: () => this.props.addDocTab(Doc.MakeAlias(this.props.Document), this.props.DataDoc, "onRight"), icon: "caret-square-right" }); - subitems.push({ description: "Open Fields ", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), undefined, "onRight"), icon: "layer-group" }); - templateDoc && subitems.push({ description: "Open Template ", event: () => this.props.addDocTab(templateDoc, undefined, "onRight"), icon: "eye" }); - subitems.push({ description: "Open Repl", icon: "laptop-code", event: () => OverlayView.Instance.addWindow(, { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" }) }); - cm.addItem({ description: "Open...", subitems: subitems, icon: "external-link-alt" }); - - - const existingOnClick = ContextMenu.Instance.findByDescription("OnClick..."); + const existing = cm.findByDescription("Layout..."); + const layoutItems: ContextMenuProps[] = existing && "subitems" in existing ? existing.subitems : []; + layoutItems.push({ description: this.Document.isBackground ? "As Foreground" : "As Background", event: this.makeBackground, icon: this.Document.lockedPosition ? "unlock" : "lock" }); + layoutItems.push({ description: "Make View of Metadata Field", event: () => Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.DataDoc), icon: "concierge-bell" }); + + layoutItems.push({ description: `${this.Document._chromeStatus !== "disabled" ? "Hide" : "Show"} Chrome`, event: () => this.Document._chromeStatus = (this.Document._chromeStatus !== "disabled" ? "disabled" : "enabled"), icon: "project-diagram" }); + layoutItems.push({ description: `${this.Document._autoHeight ? "Variable Height" : "Auto Height"}`, event: () => this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight, icon: "plus" }); + layoutItems.push({ description: !this.Document._nativeWidth || !this.Document._nativeHeight ? "Freeze" : "Unfreeze", event: this.toggleNativeDimensions, icon: "snowflake" }); + layoutItems.push({ description: this.Document.lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.Document.lockedPosition) ? "unlock" : "lock" }); + layoutItems.push({ description: this.Document.lockedTransform ? "Unlock Transform" : "Lock Transform", event: this.toggleLockTransform, icon: BoolCast(this.Document.lockedTransform) ? "unlock" : "lock" }); + layoutItems.push({ description: "Center View", event: () => this.props.focus(this.props.Document, false), icon: "crosshairs" }); + layoutItems.push({ description: "Zoom to Document", event: () => this.props.focus(this.props.Document, true), icon: "search" }); + !existing && cm.addItem({ description: "Layout...", subitems: layoutItems, icon: "compass" }); + + const open = ContextMenu.Instance.findByDescription("Open..."); + const openItems: ContextMenuProps[] = open && "subitems" in open ? open.subitems : []; + openItems.push({ description: "Open Full Screen", event: () => CollectionDockingView.Instance && CollectionDockingView.Instance.OpenFullScreen(this, this.props.LibraryPath), icon: "desktop" }); + openItems.push({ description: "Open Tab ", event: () => this.props.addDocTab(this.props.Document, this.props.DataDoc, "inTab", this.props.LibraryPath), icon: "folder" }); + openItems.push({ description: "Open Right ", event: () => this.props.addDocTab(this.props.Document, this.props.DataDoc, "onRight", this.props.LibraryPath), icon: "caret-square-right" }); + openItems.push({ description: "Open Alias Tab ", event: () => this.props.addDocTab(Doc.MakeAlias(this.props.Document), this.props.DataDoc, "inTab"), icon: "folder" }); + openItems.push({ description: "Open Alias Right", event: () => this.props.addDocTab(Doc.MakeAlias(this.props.Document), this.props.DataDoc, "onRight"), icon: "caret-square-right" }); + openItems.push({ description: "Open Fields ", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), undefined, "onRight"), icon: "layer-group" }); + templateDoc && openItems.push({ description: "Open Template ", event: () => this.props.addDocTab(templateDoc, undefined, "onRight"), icon: "eye" }); + openItems.push({ description: "Open Repl", icon: "laptop-code", event: () => OverlayView.Instance.addWindow(, { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" }) }); + !open && cm.addItem({ description: "Open...", subitems: openItems, icon: "external-link-alt" }); + + + const existingOnClick = cm.findByDescription("OnClick..."); const onClicks: ContextMenuProps[] = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : []; onClicks.push({ description: "Enter Portal", event: this.makeIntoPortal, icon: "window-restore" }); onClicks.push({ description: "Toggle Detail", event: () => this.Document.onClick = ScriptField.MakeScript(`toggleDetail(this, "${this.props.Document.layoutKey}")`), icon: "window-restore" }); @@ -657,24 +672,10 @@ export class DocumentView extends DocComponent(Docu funcs.push({ description: "Drag an Alias", icon: "edit", event: () => this.Document.dragFactory && (this.Document.onDragStart = ScriptField.MakeFunction('getAlias(this.dragFactory)')) }); funcs.push({ description: "Drag a Copy", icon: "edit", event: () => this.Document.dragFactory && (this.Document.onDragStart = ScriptField.MakeFunction('getCopy(this.dragFactory, true)')) }); funcs.push({ description: "Drag Document", icon: "edit", event: () => this.Document.onDragStart = undefined }); - ContextMenu.Instance.addItem({ description: "OnDrag...", subitems: funcs, icon: "asterisk" }); + cm.addItem({ description: "OnDrag...", subitems: funcs, icon: "asterisk" }); } - const existing = ContextMenu.Instance.findByDescription("Layout..."); - const layoutItems: ContextMenuProps[] = existing && "subitems" in existing ? existing.subitems : []; - layoutItems.push({ description: this.Document.isBackground ? "As Foreground" : "As Background", event: this.makeBackground, icon: this.Document.lockedPosition ? "unlock" : "lock" }); - layoutItems.push({ description: "Make View of Metadata Field", event: () => Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.DataDoc), icon: "concierge-bell" }); - - layoutItems.push({ description: `${this.Document._chromeStatus !== "disabled" ? "Hide" : "Show"} Chrome`, event: () => this.Document._chromeStatus = (this.Document._chromeStatus !== "disabled" ? "disabled" : "enabled"), icon: "project-diagram" }); - layoutItems.push({ description: `${this.Document._autoHeight ? "Variable Height" : "Auto Height"}`, event: () => this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight, icon: "plus" }); - layoutItems.push({ description: !this.Document._nativeWidth || !this.Document._nativeHeight ? "Freeze" : "Unfreeze", event: this.toggleNativeDimensions, icon: "snowflake" }); - layoutItems.push({ description: this.Document.lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.Document.lockedPosition) ? "unlock" : "lock" }); - layoutItems.push({ description: this.Document.lockedTransform ? "Unlock Transform" : "Lock Transform", event: this.toggleLockTransform, icon: BoolCast(this.Document.lockedTransform) ? "unlock" : "lock" }); - layoutItems.push({ description: "Center View", event: () => this.props.focus(this.props.Document, false), icon: "crosshairs" }); - layoutItems.push({ description: "Zoom to Document", event: () => this.props.focus(this.props.Document, true), icon: "search" }); - !existing && cm.addItem({ description: "Layout...", subitems: layoutItems, icon: "compass" }); - - const more = ContextMenu.Instance.findByDescription("More..."); + const more = cm.findByDescription("More..."); const moreItems: ContextMenuProps[] = more && "subitems" in more ? more.subitems : []; if (!ClientUtils.RELEASE) { diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 26711259c..fd288f720 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -990,7 +990,6 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & } richTextMenuPlugin() { - const self = FormattedTextBox; return new Plugin({ view(newView) { RichTextMenu.Instance.changeView(newView); @@ -1091,7 +1090,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & return (
+ return
Date: Wed, 19 Feb 2020 14:40:34 -0500 Subject: chome display set to 'none' when not 'enabled'. fixed template expansion bug. --- src/client/views/MainView.tsx | 4 ++-- src/client/views/collections/CollectionView.tsx | 9 ++++----- .../views/collections/CollectionViewChromes.scss | 3 ++- .../views/collections/CollectionViewChromes.tsx | 7 +++++-- src/client/views/nodes/ImageBox.tsx | 2 +- src/new_fields/Doc.ts | 21 ++------------------- 6 files changed, 16 insertions(+), 30 deletions(-) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 1849ec250..cc75a68fe 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -454,11 +454,11 @@ export class MainView extends React.Component { {this.docButtons}
; } - //`${StrCast(sidebar.backgroundColor, this.darkScheme ? "dimGray" : "black")}` }} > + @computed get mainContent() { const sidebar = this.userDoc && this.userDoc.sidebarContainer; return !this.userDoc || !(sidebar instanceof Doc) ? (null) : ( -
+
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 95f9fa62f..157229ec8 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -109,9 +109,6 @@ export class CollectionView extends Touchable { return viewField; } - // bcz: Argh? What's the height of the collection chromes?? - chromeHeight = () => (this.props.Document._chromeStatus === "enabled" ? -60 : 0); - active = (outsideReaction?: boolean) => this.props.isSelected(outsideReaction) || BoolCast(this.props.Document.forceActive) || this._isChildActive || this.props.renderDepth === 0; whenActiveChanged = (isActive: boolean) => { this.props.whenActiveChanged(this._isChildActive = isActive); }; @@ -128,15 +125,17 @@ export class CollectionView extends Touchable { @action.bound removeDocument(doc: Doc): boolean { + const targetDataDoc = this.props.Document[DataSym]; const docView = DocumentManager.Instance.getDocumentView(doc, this.props.ContainingCollectionView); docView && SelectionManager.DeselectDoc(docView); - const value = Cast(this.props.Document[DataSym][this.props.fieldKey], listSpec(Doc), []); + const value = DocListCast(targetDataDoc[this.props.fieldKey]); let index = value.reduce((p, v, i) => (v instanceof Doc && v === doc) ? i : p, -1); index = index !== -1 ? index : value.reduce((p, v, i) => (v instanceof Doc && Doc.AreProtosEqual(v, doc)) ? i : p, -1); ContextMenu.Instance.clearItems(); if (index !== -1) { value.splice(index, 1); + targetDataDoc[this.props.fieldKey] = new List(value); return true; } return false; @@ -162,7 +161,7 @@ export class CollectionView extends Touchable { } private SubViewHelper = (type: CollectionViewType, renderProps: CollectionRenderProps) => { - const props: SubCollectionViewProps = { ...this.props, ...renderProps, ChromeHeight: this.chromeHeight, CollectionView: this, annotationsKey: "" }; + const props: SubCollectionViewProps = { ...this.props, ...renderProps, CollectionView: this, annotationsKey: "" }; switch (type) { case CollectionViewType.Schema: return (); case CollectionViewType.Docking: return (); diff --git a/src/client/views/collections/CollectionViewChromes.scss b/src/client/views/collections/CollectionViewChromes.scss index 517f467b7..0c96a662c 100644 --- a/src/client/views/collections/CollectionViewChromes.scss +++ b/src/client/views/collections/CollectionViewChromes.scss @@ -2,7 +2,8 @@ @import '~js-datepicker/dist/datepicker.min.css'; .collectionViewChrome-cont { - position: relative; + position: absolute; + width:100%; opacity: 0.9; z-index: 9001; transition: top .5s; diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index 0378c818c..49a9e8200 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -257,6 +257,8 @@ export class CollectionViewBaseChrome extends React.Component { + const collapsed = this.props.CollectionView.props.Document._chromeStatus !== "enabled"; + if (collapsed) return null; switch (this.props.type) { case CollectionViewType.Stacking: return (); case CollectionViewType.Schema: return (); @@ -368,7 +370,7 @@ export class CollectionViewBaseChrome extends React.Component -
+
-
+
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index ba09a02a3..bb421d315 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -96,7 +96,7 @@ export class ImageBox extends DocAnnotatableComponent, childDoc: Doc) { const existingResolvedDataDoc = childDoc[DataSym] !== Doc.GetProto(childDoc)[DataSym] && childDoc[DataSym]; - const resolvedDataDoc = existingResolvedDataDoc || (containerDataDoc === containerDoc || !containerDataDoc || (!childDoc.isTemplateDoc && !childDoc.isTemplateForField) ? undefined : containerDataDoc); + const resolvedDataDoc = existingResolvedDataDoc || (Doc.AreProtosEqual(containerDataDoc, containerDoc) || !containerDataDoc || (!childDoc.isTemplateDoc && !childDoc.isTemplateForField) ? undefined : containerDataDoc); return { layout: Doc.expandTemplateLayout(childDoc, resolvedDataDoc), data: resolvedDataDoc }; } - export function CreateDocumentExtensionForField(doc: Doc, fieldKey: string) { - let proto: Doc | undefined = doc; - while (proto && !Doc.IsPrototype(proto) && proto.proto) { - proto = proto.proto; - } - let docExtensionForField = ((proto || doc)[fieldKey + "_ext"] as Doc); - if (!docExtensionForField) { - docExtensionForField = new Doc(doc[Id] + fieldKey, true); - docExtensionForField.title = fieldKey + ".ext"; // courtesy field--- shouldn't be needed except maybe for debugging - docExtensionForField.extendsDoc = doc; // this is used by search to map field matches on the extension doc back to the document it extends. - docExtensionForField.extendsField = fieldKey; // this can be used by search to map matches on the extension doc back to the field that was extended. - docExtensionForField.type = DocumentType.EXTENSION; - (proto || doc)[fieldKey + "_ext"] = new PrefetchProxy(docExtensionForField); - } - return docExtensionForField; - } export function Overwrite(doc: Doc, overwrite: Doc, copyProto: boolean = false): Doc { Object.keys(doc).forEach(key => { -- cgit v1.2.3-70-g09d2 From 59e947ad4bd885c4bbf511a19eba64f672a3d76d Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 22 Feb 2020 12:14:27 -0500 Subject: added option to update image native size --- src/client/views/collections/CollectionSubView.tsx | 4 ++-- src/client/views/nodes/ImageBox.tsx | 13 +++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 27a1c6367..6ad187e5c 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -334,8 +334,8 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { const proto = Doc.GetProto(doc); proto.fileUpload = basename(pathname).replace("upload_", "").replace(/\.[a-z0-9]*$/, ""); if (Upload.isImageInformation(result)) { - proto["data-nativeWidth"] = result.nativeWidth; - proto["data-nativeHeight"] = result.nativeHeight; + proto["data-nativeWidth"] = (result.nativeWidth > result.nativeHeight) ? 400 * result.nativeWidth / result.nativeHeight : 400; + proto["data-nativeHeight"] = (result.nativeWidth > result.nativeHeight) ? 400 : 400 / (result.nativeWidth / result.nativeHeight); proto.contentSize = result.contentSize; } generatedDocuments.push(doc); diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index bb421d315..99000a0a9 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -160,6 +160,19 @@ export class ImageBox extends DocAnnotatableComponent Utils.CopyText(field.url.href), icon: "expand-arrows-alt" }); funcs.push({ description: "Rotate", event: this.rotate, icon: "expand-arrows-alt" }); + funcs.push({ + description: "Reset Native Dimensions", event: action(() => { + const curNW = NumCast(this.dataDoc[this.props.fieldKey + "-nativeWidth"]); + const curNH = NumCast(this.dataDoc[this.props.fieldKey + "-nativeHeight"]); + if (this.props.PanelWidth() / this.props.PanelHeight() > curNW / curNH) { + this.dataDoc[this.props.fieldKey + "-nativeWidth"] = this.props.PanelHeight() * curNW / curNH; + this.dataDoc[this.props.fieldKey + "-nativeHeight"] = this.props.PanelHeight(); + } else { + this.dataDoc[this.props.fieldKey + "-nativeWidth"] = this.props.PanelWidth(); + this.dataDoc[this.props.fieldKey + "-nativeHeight"] = this.props.PanelWidth() * curNH / curNW; + } + }), icon: "expand-arrows-alt" + }); const existingAnalyze = ContextMenu.Instance.findByDescription("Analyzers..."); const modes: ContextMenuProps[] = existingAnalyze && "subitems" in existingAnalyze ? existingAnalyze.subitems : []; -- cgit v1.2.3-70-g09d2 From 5c139f0001cd10e5699a716c1e64d2c2c0b2d800 Mon Sep 17 00:00:00 2001 From: bob Date: Fri, 28 Feb 2020 12:17:03 -0500 Subject: allowing different text templates to be the default. fixing transparency. removing audio by default from notes. --- src/client/documents/Documents.ts | 5 +++- src/client/util/Import & Export/ImageUtils.ts | 2 +- src/client/util/RichTextSchema.tsx | 8 ++--- src/client/views/InkingControl.tsx | 3 +- src/client/views/TemplateMenu.tsx | 5 ++++ .../collectionFreeForm/CollectionFreeFormView.tsx | 4 +-- .../collections/collectionFreeForm/MarqueeView.tsx | 3 +- src/client/views/nodes/DocumentView.tsx | 6 ++-- src/client/views/nodes/FormattedTextBox.scss | 2 +- src/client/views/nodes/FormattedTextBox.tsx | 34 +++++++++++++--------- src/client/views/nodes/ImageBox.tsx | 19 ++++++------ src/new_fields/documentSchemas.ts | 13 +++++---- 12 files changed, 63 insertions(+), 41 deletions(-) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index a0b8a6382..aab44f668 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -77,6 +77,8 @@ export interface DocumentOptions { _gridGap?: number; // gap between items in masonry view _xMargin?: number; // gap between left edge of document and start of masonry/stacking layouts _yMargin?: number; // gap between top edge of dcoument and start of masonry/stacking layouts + _xPadding?: number; + _yPadding?: number; _itemIndex?: number; // which item index the carousel viewer is showing _showSidebar?: boolean; //whether an annotationsidebar should be displayed for text docuemnts x?: number; @@ -174,7 +176,7 @@ export namespace Docs { const TemplateMap: TemplateMap = new Map([ [DocumentType.TEXT, { layout: { view: FormattedTextBox, dataField: data }, - options: { _height: 150 } + options: { _height: 150, _xMargin: 10, _yMargin: 10 } }], [DocumentType.HIST, { layout: { view: HistogramBox, dataField: data }, @@ -407,6 +409,7 @@ export namespace Docs { const delegateKeys = ["x", "y", "layoutKey", "_width", "_height", "_panX", "_panY", "_viewType", "_nativeWidth", "_nativeHeight", "dropAction", "childDropAction", "_annotationOn", "_chromeStatus", "_forceActive", "_autoHeight", "_fitWidth", "_LODdisable", "_itemIndex", "_showSidebar", "_showTitle", "_showCaption", "_showTitleHover", "_backgroundColor", + "_xMargin", "_yMargin", "_xPadding", "_yPadding", "_color", "isButton", "isBackground", "removeDropProperties", "treeViewOpen"]; /** diff --git a/src/client/util/Import & Export/ImageUtils.ts b/src/client/util/Import & Export/ImageUtils.ts index ff909cc6b..ab8c73d15 100644 --- a/src/client/util/Import & Export/ImageUtils.ts +++ b/src/client/util/Import & Export/ImageUtils.ts @@ -24,7 +24,7 @@ export namespace ImageUtils { const proto = Doc.GetProto(document); proto["data-nativeWidth"] = nativeWidth; proto["data-nativeHeight"] = nativeHeight; - proto.contentSize = contentSize; + proto.contentSize = contentSize ? contentSize : undefined; return data !== undefined; }; diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index a56aac9b1..4a80a1af8 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -910,11 +910,11 @@ export class DashFieldView { } e.preventDefault(); } - if (e.key === "Enter" && e.ctrlKey) { - Doc.addEnumerationToTextField(self._textBoxDoc, node.attrs.fieldKey, [Docs.Create.TextDocument(self._fieldSpan.innerText, { title: self._fieldSpan.innerText })]); - e.preventDefault(); - } else if (e.key === "Enter") { + if (e.key === "Enter") { e.preventDefault(); + if (e.ctrlKey) { + Doc.addEnumerationToTextField(self._textBoxDoc, node.attrs.fieldKey, [Docs.Create.TextDocument(self._fieldSpan.innerText, { title: self._fieldSpan.innerText })]); + } let newText = self._fieldSpan.innerText.startsWith(":=") ? ":=-computed-" : self._fieldSpan.innerText; // look for a document whose id === the fieldKey being displayed. If there's a match, then that document // holds the different enumerated values for the field in the titles of its collected documents. diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx index 374c2df27..5cd3c265d 100644 --- a/src/client/views/InkingControl.tsx +++ b/src/client/views/InkingControl.tsx @@ -29,8 +29,7 @@ export class InkingControl { if (number < 0) { number = 0xFFFFFFFF + number + 1; } - - return number.toString(16).toUpperCase(); + return (number < 16 ? "0" : "") + number.toString(16).toUpperCase(); } @undoBatch diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index 595c3817e..5029b4074 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -61,6 +61,10 @@ export class TemplateMenu extends React.Component { DocumentView.FloatDoc(topDocView, ex, ey); } + toggleAudio = (e: React.ChangeEvent): void => { + this.props.docViews.map(dv => dv.props.Document._showAudio = e.target.checked); + } + @undoBatch @action toggleTemplate = (event: React.ChangeEvent, template: Template): void => { @@ -102,6 +106,7 @@ export class TemplateMenu extends React.Component { const templateMenu: Array = []; this.props.templates.forEach((checked, template) => templateMenu.push()); + templateMenu.push(); templateMenu.push(); templateMenu.push(); this._addedKeys && Array.from(this._addedKeys).map(layout => diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 4458c7dcf..ca8d5e18b 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -51,8 +51,8 @@ export const panZoomSchema = createSchema({ arrangeInit: ScriptField, useClusters: "boolean", fitToBox: "boolean", - xPadding: "number", // pixels of padding on left/right of collectionfreeformview contents when fitToBox is set - yPadding: "number", // pixels of padding on left/right of collectionfreeformview contents when fitToBox is set + _xPadding: "number", // pixels of padding on left/right of collectionfreeformview contents when fitToBox is set + _yPadding: "number", // pixels of padding on left/right of collectionfreeformview contents when fitToBox is set panTransformType: "string", scrollHeight: "number", fitX: "number", diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index b1cca027d..b8e9acf85 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -18,6 +18,7 @@ import MarqueeOptionsMenu from "./MarqueeOptionsMenu"; import "./MarqueeView.scss"; import React = require("react"); import { CollectionView } from "../CollectionView"; +import { FormattedTextBox } from "../../nodes/FormattedTextBox"; interface MarqueeViewProps { getContainerTransform: () => Transform; @@ -104,7 +105,7 @@ export class MarqueeView extends React.Component 48 && e.keyCode <= 57) { const notes = DocListCast((CurrentUserUtils.UserDocument.noteTypes as Doc).data); const text = Docs.Create.TextDocument("", { _width: 200, _height: 100, x: x, y: y, _autoHeight: true, title: "-typed text-" }); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 06ca9b5f4..7683ad269 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -909,17 +909,19 @@ export class DocumentView extends DocComponent(Docu render() { if (!(this.props.Document instanceof Doc)) return (null); const backgroundColor = StrCast(this.layoutDoc._backgroundColor) || StrCast(this.layoutDoc.backgroundColor) || StrCast(this.Document.backgroundColor) || this.props.backgroundColor?.(this.Document); + const finalColor = this.layoutDoc.type === DocumentType.FONTICON || this.layoutDoc._viewType === CollectionViewType.Linear ? undefined : backgroundColor; const fullDegree = Doc.isBrushedHighlightedDegree(this.props.Document); const borderRounding = this.layoutDoc.borderRounding; const localScale = fullDegree; + console.log("Background = " + this.props.Document.title + " " + finalColor); const highlightColors = Cast(Doc.UserDoc().activeWorkspace, Doc, null)?.darkScheme ? ["transparent", "#65350c", "#65350c", "yellow", "magenta", "cyan", "orange"] : ["transparent", "maroon", "maroon", "yellow", "magenta", "cyan", "orange"]; const highlightStyles = ["solid", "dashed", "solid", "solid", "solid", "solid", "solid"]; let highlighting = fullDegree && this.layoutDoc.type !== DocumentType.FONTICON && this.layoutDoc._viewType !== CollectionViewType.Linear; highlighting = highlighting && this.props.focus !== emptyFunction; // bcz: hack to turn off highlighting onsidebar panel documents. need to flag a document as not highlightable in a more direct way - return
Doc.BrushDoc(this.props.Document)} onPointerLeave={e => Doc.UnBrushDoc(this.props.Document)} style={{ @@ -931,7 +933,7 @@ export class DocumentView extends DocComponent(Docu outline: highlighting && !borderRounding ? `${highlightColors[fullDegree]} ${highlightStyles[fullDegree]} ${localScale}px` : "solid 0px", border: highlighting && borderRounding ? `${highlightStyles[fullDegree]} ${highlightColors[fullDegree]} ${localScale}px` : undefined, boxShadow: this.props.Document.isTemplateForField ? "black 0.2vw 0.2vw 0.8vw" : undefined, - background: this.layoutDoc.type === DocumentType.FONTICON || this.layoutDoc._viewType === CollectionViewType.Linear ? undefined : backgroundColor, + background: finalColor, width: "100%", height: "100%", opacity: this.Document.opacity diff --git a/src/client/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss index c203ca0c3..db2bb751f 100644 --- a/src/client/views/nodes/FormattedTextBox.scss +++ b/src/client/views/nodes/FormattedTextBox.scss @@ -95,8 +95,8 @@ .formattedTextBox-inner-rounded, .formattedTextBox-inner { - padding: 10px 10px; height: 100%; + white-space: pre-wrap; } // .menuicon { diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index a320cff75..3567dbbd5 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -375,12 +375,15 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & toggleSidebar = () => this._sidebarMovement < 5 && (this.props.Document.sidebarWidthPercent = StrCast(this.props.Document.sidebarWidthPercent, "0%") === "0%" ? "25%" : "0%"); + public static DefaultLayout: Doc | string | undefined; specificContextMenu = (e: React.MouseEvent): void => { const funcs: ContextMenuProps[] = []; + this.props.Document.isTemplateDoc && funcs.push({ description: "Make Default Layout", event: async () => FormattedTextBox.DefaultLayout = this.props.Document.proto as Doc, icon: "eye" }); + funcs.push({ description: "Reset Default Layout", event: () => FormattedTextBox.DefaultLayout = undefined, icon: "eye" }); !this.props.Document.expandedTemplate && funcs.push({ description: "Make Template", event: () => { this.props.Document.isTemplateDoc = true; Doc.AddDocToList(Cast(Doc.UserDoc().noteTypes, Doc, null), "data", this.props.Document); }, icon: "eye" }); - funcs.push({ description: "Toggle Sidebar", event: () => { e.stopPropagation(); this.props.Document._showSidebar = !this.props.Document._showSidebar; }, icon: "expand-arrows-alt" }); - funcs.push({ description: "Record Bullet", event: () => { e.stopPropagation(); this.recordBullet(); }, icon: "expand-arrows-alt" }); - funcs.push({ description: "Toggle Menubar", event: () => { e.stopPropagation(); this.toggleMenubar(); }, icon: "expand-arrows-alt" }); + funcs.push({ description: "Toggle Sidebar", event: () => this.props.Document._showSidebar = !this.props.Document._showSidebar, icon: "expand-arrows-alt" }); + funcs.push({ description: "Record Bullet", event: () => this.recordBullet(), icon: "expand-arrows-alt" }); + funcs.push({ description: "Toggle Menubar", event: () => this.toggleMenubar(), icon: "expand-arrows-alt" }); ["My Text", "Text from Others", "Todo Items", "Important Items", "Ignore Items", "Disagree Items", "By Recent Minute", "By Recent Hour"].forEach(option => funcs.push({ description: (FormattedTextBox._highlights.indexOf(option) === -1 ? "Highlight " : "Unhighlight ") + option, event: () => { @@ -1125,7 +1128,11 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & onPointerLeave={action(() => this._entered = false)} >
-
+
{!this.props.Document._showSidebar ? (null) : this.sidebarWidthPercent === "0%" ?
this.toggleSidebar()} /> : @@ -1152,15 +1159,16 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
this.toggleSidebar()} />
} -
{ - this._recording ? this.stopDictation(true) : this.recordDictation(); - setTimeout(() => this._editorView!.focus(), 500); - e.stopPropagation(); - }} > - -
+ {!this.props.Document._showAudio ? (null) : +
{ + this._recording ? this.stopDictation(true) : this.recordDictation(); + setTimeout(() => this._editorView!.focus(), 500); + e.stopPropagation(); + }} > + +
}
); } diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 99000a0a9..c46191270 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -407,15 +407,16 @@ export class ImageBox extends DocAnnotatableComponent
}
-
- -
+ {!this.props.Document._showAudio ? (null) : +
+ +
} {this.considerDownloadIcon} {this.considerGooglePhotosLink()} diff --git a/src/new_fields/documentSchemas.ts b/src/new_fields/documentSchemas.ts index f3726cb5a..7006163e0 100644 --- a/src/new_fields/documentSchemas.ts +++ b/src/new_fields/documentSchemas.ts @@ -15,9 +15,14 @@ export const documentSchema = createSchema({ _nativeHeight: "number", // " _width: "number", // width of document in its container's coordinate system _height: "number", // " - _showCaption: "string", // whether editable caption text is overlayed at the bottom of the document - _showTitle: "string", // the fieldkey whose contents should be displayed at the top of the document - _showTitleHover: "string", // the showTitle should be shown only on hover + _xPadding: "number", // pixels of padding on left/right of collectionfreeformview contents when fitToBox is set + _yPadding: "number", // pixels of padding on top/bottom of collectionfreeformview contents when fitToBox is set + _xMargin: "number", // margin added on left/right of most documents to add separation from their container + _yMargin: "number", // margin added on top/bottom of most documents to add separation from their container + _showCaption: "string", // whether editable caption text is overlayed at the bottom of the document + _showTitle: "string", // the fieldkey whose contents should be displayed at the top of the document + _showTitleHover: "string", // the showTitle should be shown only on hover + _showAudio: "boolean", // whether to show the audio record icon on documents _freeformLayoutEngine: "string",// the string ID for the layout engine to use to layout freeform view documents _LODdisable: "boolean", // whether to disbale LOD switching for CollectionFreeFormViews _pivotField: "string", // specifies which field should be used as the timeline/pivot axis @@ -53,8 +58,6 @@ export const documentSchema = createSchema({ strokeWidth: "number", fontSize: "string", fitToBox: "boolean", // whether freeform view contents should be zoomed/panned to fill the area of the document view - xPadding: "number", // pixels of padding on left/right of collectionfreeformview contents when fitToBox is set - yPadding: "number", // pixels of padding on left/right of collectionfreeformview contents when fitToBox is set letterSpacing: "string", textTransform: "string" }); -- cgit v1.2.3-70-g09d2 From 4eaec2585a4f38a826707f2cf850d287276d9b14 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 10 Mar 2020 00:39:30 -0400 Subject: fixed up iconifying of different document types. fixed selection to not select toolbar tabs. fixed outline-like document creation in tree views. --- src/client/documents/Documents.ts | 1 + src/client/views/DocumentDecorations.tsx | 1 + .../views/collections/CollectionTreeView.tsx | 6 +++-- src/client/views/nodes/DocumentView.tsx | 28 ++++++++++++++++------ src/client/views/nodes/ImageBox.tsx | 2 +- src/new_fields/Doc.ts | 2 +- .../authentication/models/current_user_utils.ts | 16 +++++++++---- 7 files changed, 40 insertions(+), 16 deletions(-) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 901b3684f..131a48a2b 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -114,6 +114,7 @@ export interface DocumentOptions { lockedTransform?: boolean; // lock the panx,pany and scale parameters of the document so that it be panned/zoomed opacity?: number; defaultBackgroundColor?: string; + dontSelect?: boolean; // whether document decorations should be displayed when the document is selected isBackground?: boolean; isButton?: boolean; columnWidth?: number; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 2ec170ddb..c4abc935f 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -69,6 +69,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> get Bounds(): { x: number, y: number, b: number, r: number } { return SelectionManager.SelectedDocuments().reduce((bounds, documentView) => { if (documentView.props.renderDepth === 0 || + documentView.props.Document.dontSelect || Doc.AreProtosEqual(documentView.props.Document, CurrentUserUtils.UserDocument)) { return bounds; } diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 54ad2ad48..4757e5a53 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -185,8 +185,10 @@ class TreeView extends React.Component { })} OnFillDown={undoBatch((value: string) => { Doc.SetInPlace(this.props.document, key, value, false); - const doc = Docs.Create.FreeformDocument([], { title: "", x: 0, y: 0, _width: 100, _height: 25, templates: new List([Templates.Title.Layout]) }); - EditableView.loadId = doc[Id]; + const doc = Docs.Create.FreeformDocument([], { title: "-", x: 0, y: 0, _width: 100, _height: 25, templates: new List([Templates.Title.Layout]) }); + //EditableView.loadId = doc[Id]; + this.props.document.editTitle = undefined; + doc.editTitle = true; return this.props.addDocument(doc); })} onClick={() => { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index dc529b79b..bf5f936d1 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -281,6 +281,7 @@ export class DocumentView extends DocComponent(Docu (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD)) { e.stopPropagation(); let preventDefault = true; + this.props.bringToFront(this.props.Document); if (this._doubleTap && this.props.renderDepth && !this.onClickHandler?.script) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click const fullScreenAlias = Doc.MakeAlias(this.props.Document); if (StrCast(fullScreenAlias.layoutKey) !== "layout_fullScreen" && fullScreenAlias.layout_fullScreen) { @@ -291,7 +292,10 @@ export class DocumentView extends DocComponent(Docu Doc.UnBrushDoc(this.props.Document); } else if (this.onClickHandler?.script) { SelectionManager.DeselectAll(); - UndoManager.RunInBatch(() => this.onClickHandler!.script.run({ this: this.Document.isTemplateForField && this.props.DataDoc ? this.props.DataDoc : this.props.Document, containingCollection: this.props.ContainingCollectionDoc, shiftKey: e.shiftKey }, console.log) && this.select(false), "on click"); + UndoManager.RunInBatch(() => this.onClickHandler!.script.run({ + this: this.Document.isTemplateForField && this.props.DataDoc ? this.props.DataDoc : this.props.Document, // try this.props.Document.expandedTemplate || this.props.Document + containingCollection: this.props.ContainingCollectionDoc, shiftKey: e.shiftKey + }, console.log) && !BoolCast(this.props.Document.dontSelect) && this.select(false), "on click"); } else if (this.Document.type === DocumentType.BUTTON) { UndoManager.RunInBatch(() => ScriptBox.EditButtonScript("On Button Clicked ...", this.props.Document, "onClick", e.clientX, e.clientY), "on button click"); } else if (this.Document.isButton) { @@ -633,13 +637,23 @@ export class DocumentView extends DocComponent(Docu if (custom) { DocumentView.makeNativeViewClicked(this.props.Document); + const imgView = Cast(Doc.UserDoc().iconView, Doc, null); + const iconImgView = Cast(Doc.UserDoc().iconImageView, Doc, null); + const iconColView = Cast(Doc.UserDoc().iconColView, Doc, null); + const iconViews = [imgView, iconImgView, iconColView]; + const expandingButtons = DocListCast(Cast(Doc.UserDoc().expandingButtons, Doc, null)?.data); + const allTemplates = iconViews.concat(expandingButtons); let foundLayout: Opt; - DocListCast(Cast(Doc.UserDoc().expandingButtons, Doc, null)?.data)?.concat([Cast(Doc.UserDoc().iconView, Doc, null)]). - map(btnDoc => (btnDoc.dragFactory as Doc) || btnDoc).filter(doc => doc.isTemplateDoc).forEach(tempDoc => { - if (StrCast(tempDoc.title) === layout) { - foundLayout = tempDoc; - } - }); + allTemplates.map(btnDoc => (btnDoc.dragFactory as Doc) || btnDoc).filter(doc => doc.isTemplateDoc).forEach(tempDoc => { + if (StrCast(tempDoc.title) === this.props.Document.type + "_" + layout) { + foundLayout = tempDoc; + } + }); + !foundLayout && allTemplates.map(btnDoc => (btnDoc.dragFactory as Doc) || btnDoc).filter(doc => doc.isTemplateDoc).forEach(tempDoc => { + if (StrCast(tempDoc.title) === layout) { + foundLayout = tempDoc; + } + }); DocumentView. makeCustomViewClicked(this.props.Document, this.props.DataDoc, Docs.Create.StackingDocument, layout, foundLayout); } else { diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index e5848614c..6ae32a1d6 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -258,7 +258,7 @@ export class ImageBox extends DocAnnotatableComponent 0.05 || imgPath !== cachedImgPath) { (!this.layoutDoc.isTemplateDoc || this.dataDoc !== this.layoutDoc) && requestImageSize(imgPath).then((inquiredSize: any) => { const rotation = NumCast(this.dataDoc[this.props.fieldKey + "-rotation"]) % 180; const rotatedNativeSize = rotation === 90 || rotation === 270 ? { height: inquiredSize.width, width: inquiredSize.height } : inquiredSize; diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 4a6ff8e42..c7caa853a 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -792,7 +792,7 @@ export namespace Doc { export function setNativeView(doc: any) { const prevLayout = StrCast(doc.layoutKey).split("_")[1]; const deiconify = prevLayout === "icon" && StrCast(doc.deiconifyLayout) ? "layout_" + StrCast(doc.deiconifyLayout) : ""; - doc.deiconifyLayout = undefined; + prevLayout === "icon" && (doc.deiconifyLayout = undefined); if (StrCast(doc.title).endsWith("_" + prevLayout) && deiconify) doc.title = StrCast(doc.title).replace("_" + prevLayout, deiconify); else doc.title = undefined; doc.layoutKey = deiconify || "layout"; diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 5d93f208a..15f626af4 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -11,7 +11,7 @@ import { listSpec } from "../../../new_fields/Schema"; import { ScriptField, ComputedField } from "../../../new_fields/ScriptField"; import { Cast, PromiseValue, StrCast } from "../../../new_fields/Types"; import { Utils } from "../../../Utils"; -import { nullAudio } from "../../../new_fields/URLField"; +import { nullAudio, ImageField } from "../../../new_fields/URLField"; import { DragManager } from "../../../client/util/DragManager"; import { InkingControl } from "../../../client/views/InkingControl"; import { Scripting } from "../../../client/util/Scripting"; @@ -194,7 +194,7 @@ export class CurrentUserUtils { }); return Docs.Create.ButtonDocument({ - _width: 35, _height: 25, title: "Tools", fontSize: 10, targetContainer: sidebarContainer, + _width: 35, _height: 25, title: "Tools", fontSize: 10, targetContainer: sidebarContainer, dontSelect: true, letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)", sourcePanel: Docs.Create.StackingDocument([dragCreators, color], { _width: 500, lockedPosition: true, _chromeStatus: "disabled", title: "tools stack" @@ -220,7 +220,7 @@ export class CurrentUserUtils { }); return Docs.Create.ButtonDocument({ - _width: 50, _height: 25, title: "Library", fontSize: 10, + _width: 50, _height: 25, title: "Library", fontSize: 10, dontSelect: true, letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)", sourcePanel: Docs.Create.TreeDocument([doc.workspaces as Doc, doc.documents as Doc, Docs.Prototypes.MainLinkDocument(), doc, doc.recentlyClosed as Doc], { title: "Library", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, dropAction: "alias", lockedPosition: true, boxShadow: "0 0", dontRegisterChildren: true @@ -233,7 +233,7 @@ export class CurrentUserUtils { // setup the Search button which will display the search panel. static setupSearchPanel(sidebarContainer: Doc) { return Docs.Create.ButtonDocument({ - _width: 50, _height: 25, title: "Search", fontSize: 10, + _width: 50, _height: 25, title: "Search", fontSize: 10, dontSelect: true, letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)", sourcePanel: Docs.Create.QueryDocument({ title: "search stack", ignoreClick: true @@ -275,9 +275,15 @@ export class CurrentUserUtils { descriptionTemplate.isTemplateDoc = makeTemplate(descriptionTemplate, true, "descriptionView"); const iconDoc = Docs.Create.TextDocument("", { title: "icon", _width: 150, _height: 30, isTemplateDoc: true, onClick: ScriptField.MakeScript("setNativeView(this)") }); - Doc.GetProto(iconDoc).data = new RichTextField('{"doc":{"type":"doc","content":[{"type":"paragraph","attrs":{"align":null,"color":null,"id":null,"indent":null,"inset":null,"lineSpacing":null,"paddingBottom":null,"paddingTop":null},"content":[{"type":"dashField","attrs":{"fieldKey":"title","docid":""}}]}]},"selection":{"type":"text","anchor":2,"head":2},"storedMarks":[]}', ""); + Doc.GetProto(iconDoc).icon = new RichTextField('{"doc":{"type":"doc","content":[{"type":"paragraph","attrs":{"align":null,"color":null,"id":null,"indent":null,"inset":null,"lineSpacing":null,"paddingBottom":null,"paddingTop":null},"content":[{"type":"dashField","attrs":{"fieldKey":"title","docid":""}}]}]},"selection":{"type":"text","anchor":2,"head":2},"storedMarks":[]}', ""); doc.isTemplateDoc = makeTemplate(iconDoc); doc.iconView = new PrefetchProxy(iconDoc); + const imgIconDoc = Docs.Create.ImageDocument("http://www.cs.brown.edu/~bcz/face.gif", { title: "data", _width: 50, isTemplateDoc: true, onClick: ScriptField.MakeScript("setNativeView(this)") }); + doc.isTemplateDoc = makeTemplate(imgIconDoc, true, "image_icon"); + doc.iconImageView = new PrefetchProxy(imgIconDoc); + const colIconDoc = Docs.Create.TreeDocument([], { title: "data", _width: 180, _height: 80, isTemplateDoc: true, onClick: ScriptField.MakeScript("setNativeView(this)") }); + doc.isTemplateDoc = makeTemplate(colIconDoc, true, "collection_icon"); + doc.iconColView = new PrefetchProxy(colIconDoc); doc.undoBtn = Docs.Create.FontIconDocument( { _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, dropAction: "alias", onClick: ScriptField.MakeScript("undo()"), removeDropProperties: new List(["dropAction"]), title: "undo button", icon: "undo-alt" }); -- cgit v1.2.3-70-g09d2 From 1693e9daf1657c1fc45afa3fa14f0a0df0e01e13 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 17 Mar 2020 16:12:49 -0400 Subject: fixes for typing url in web box. fixes for dropping imags from proxied document. possible fix for updateing image width/height --- src/client/views/collections/CollectionSubView.tsx | 12 +++++--- src/client/views/nodes/ImageBox.tsx | 35 ++++++++++++---------- src/client/views/nodes/WebBox.tsx | 6 ++-- src/server/server_Initialization.ts | 2 +- 4 files changed, 31 insertions(+), 24 deletions(-) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index b995fc7d5..2d6777a4e 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -234,7 +234,9 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { if (!html.startsWith(" 1 && tags[1].startsWith("img") ? tags[1] : ""; + let img = tags[0].startsWith("img") ? tags[0] : tags.length > 1 && tags[1].startsWith("img") ? tags[1] : ""; + const cors = img.includes("corsProxy") ? img.match(/http.*corsProxy\//)![0] : ""; + img = cors ? img.replace(cors, "") : img; if (img) { const split = img.split("src=\"")[1].split("\"")[0]; let source = split; @@ -242,9 +244,11 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { const [{ accessPaths }] = await Networking.PostToServer("/uploadRemoteImage", { sources: [split] }); source = Utils.prepend(accessPaths.agnostic.client); } - const doc = Docs.Create.ImageDocument(source, { ...options, _width: 300 }); - ImageUtils.ExtractExif(doc); - addDocument(doc); + if (source.startsWith("http")) { + const doc = Docs.Create.ImageDocument(source, { ...options, _width: 300 }); + ImageUtils.ExtractExif(doc); + addDocument(doc); + } return; } else { const path = window.location.origin + "/doc/"; diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 6ae32a1d6..f870a5df4 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -258,22 +258,27 @@ export class ImageBox extends DocAnnotatableComponent 0.05 || imgPath !== cachedImgPath) { - (!this.layoutDoc.isTemplateDoc || this.dataDoc !== this.layoutDoc) && requestImageSize(imgPath).then((inquiredSize: any) => { - const rotation = NumCast(this.dataDoc[this.props.fieldKey + "-rotation"]) % 180; - const rotatedNativeSize = rotation === 90 || rotation === 270 ? { height: inquiredSize.width, width: inquiredSize.height } : inquiredSize; - const rotatedAspect = rotatedNativeSize.height / rotatedNativeSize.width; - const docAspect = this.Document[HeightSym]() / this.Document[WidthSym](); - setTimeout(action(() => { - 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.props.fieldKey + "-nativeWidth"] = this.Document._nativeWidth = rotatedNativeSize.width; - this.dataDoc[this.props.fieldKey + "-nativeHeight"] = this.Document._nativeHeight = rotatedNativeSize.height; - } - this.dataDoc[this.props.fieldKey + "-imgPath"] = imgPath; - }), 0); - }) - .catch((err: any) => console.log(err)); + if (!this.layoutDoc.isTemplateDoc || this.dataDoc !== this.layoutDoc) { + requestImageSize(imgPath).then((inquiredSize: any) => { + const rotation = NumCast(this.dataDoc[this.props.fieldKey + "-rotation"]) % 180; + const rotatedNativeSize = rotation === 90 || rotation === 270 ? { height: inquiredSize.width, width: inquiredSize.height } : inquiredSize; + const rotatedAspect = rotatedNativeSize.height / rotatedNativeSize.width; + setTimeout(action(() => { + 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.props.fieldKey + "-nativeWidth"] = this.Document._nativeWidth = rotatedNativeSize.width; + this.dataDoc[this.props.fieldKey + "-nativeHeight"] = this.Document._nativeHeight = rotatedNativeSize.height; + } + this.dataDoc[this.props.fieldKey + "-imgPath"] = imgPath; + }), 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; + } } else if (this.Document._nativeWidth !== cachedNativeSize.width || this.Document._nativeHeight !== cachedNativeSize.height) { !(this.Document[StrCast(this.props.Document.layoutKey)] instanceof Doc) && setTimeout(() => { if (!(this.Document[StrCast(this.props.Document.layoutKey)] instanceof Doc)) { diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 24cb08c4c..557adfc03 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -81,14 +81,12 @@ export class WebBox extends DocAnnotatableComponent @action submitURL = () => { - const script = KeyValueBox.CompileKVPScript(`new WebField("${this.url}")`); - if (!script) return; - KeyValueBox.ApplyKVPScript(this.props.Document, "data", script); + this.dataDoc[this.props.fieldKey] = new WebField(new URL(this.url)); } @action setURL() { - const urlField: FieldResult = Cast(this.props.Document.data, WebField); + const urlField: FieldResult = Cast(this.dataDoc[this.props.fieldKey], WebField); if (urlField) this.url = urlField.url.toString(); else this.url = ""; } diff --git a/src/server/server_Initialization.ts b/src/server/server_Initialization.ts index 76cb22521..7b2228831 100644 --- a/src/server/server_Initialization.ts +++ b/src/server/server_Initialization.ts @@ -129,7 +129,7 @@ function registerCorsProxy(server: express.Express) { // if the referer is a cors page and the cors() route (I think) redirected to /corsProxy/ and the requested url path was relative, // then we redirect again to the cors referer and just add the relative path. if (!requrl.startsWith("http") && req.originalUrl.startsWith("/corsProxy") && referer?.includes("corsProxy")) { - res.redirect(referer + requrl); + res.redirect(referer + (referer.endsWith("/") ? "" : "/") + requrl); } else { req.pipe(request(requrl)).on("response", res => { -- cgit v1.2.3-70-g09d2 From 85a67ff30d86fa51b4534f717d3857aa23b732d1 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 19 Mar 2020 12:04:32 -0400 Subject: added screen capture doc --- src/client/documents/DocumentTypes.ts | 3 +- src/client/documents/Documents.ts | 9 + src/client/views/collections/CollectionSubView.tsx | 2 +- src/client/views/nodes/DocumentContentsView.tsx | 3 +- src/client/views/nodes/ImageBox.tsx | 27 ++- src/client/views/nodes/ScreenshotBox.scss | 46 +++++ src/client/views/nodes/ScreenshotBox.tsx | 193 +++++++++++++++++++++ src/client/views/nodes/VideoBox.tsx | 17 +- src/client/views/nodes/WebBox.scss | 7 +- src/client/views/nodes/WebBox.tsx | 9 +- .../authentication/models/current_user_utils.ts | 3 +- 11 files changed, 296 insertions(+), 23 deletions(-) create mode 100644 src/client/views/nodes/ScreenshotBox.scss create mode 100644 src/client/views/nodes/ScreenshotBox.tsx (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts index e3ce8e798..5ec1cfdb4 100644 --- a/src/client/documents/DocumentTypes.ts +++ b/src/client/documents/DocumentTypes.ts @@ -27,5 +27,6 @@ export enum DocumentType { DOCULINK = "doculink", PDFANNO = "pdfanno", INK = "ink", - DOCUMENT = "document" + DOCUMENT = "document", + SCREENSHOT = "screenshot", } \ No newline at end of file diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 131a48a2b..b5cffaddd 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -58,6 +58,7 @@ import { MessageStore } from "../../server/Message"; import { ContextMenuProps } from "../views/ContextMenuItem"; import { ContextMenu } from "../views/ContextMenu"; import { LinkBox } from "../views/nodes/LinkBox"; +import { ScreenshotBox } from "../views/nodes/ScreenshotBox"; const requestImageSize = require('../util/request-image-size'); const path = require('path'); @@ -277,6 +278,10 @@ export namespace Docs { [DocumentType.INK, { layout: { view: InkingStroke, dataField: data }, options: { backgroundColor: "transparent" } + }], + [DocumentType.SCREENSHOT, { + layout: { view: ScreenshotBox, dataField: data }, + options: {} }] ]); @@ -522,6 +527,10 @@ export namespace Docs { return InstanceFromProto(Prototypes.get(DocumentType.WEBCAM), "", options); } + export function ScreenshotDocument(url: string, options: DocumentOptions = {}) { + return InstanceFromProto(Prototypes.get(DocumentType.SCREENSHOT), "", options); + } + export function AudioDocument(url: string, options: DocumentOptions = {}) { const instance = InstanceFromProto(Prototypes.get(DocumentType.AUDIO), new AudioField(new URL(url)), options); Doc.GetProto(instance).backgroundColor = ComputedField.MakeFunction("this._audioState === 'playing' ? 'green':'gray'"); diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 2d6777a4e..97177855f 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -316,7 +316,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { const item = e.dataTransfer.items[i]; if (item.kind === "string" && item.type.includes("uri")) { const stringContents = await new Promise(resolve => item.getAsString(resolve)); - const type = (await rp.head(Utils.CorsProxy(stringContents)))["content-type"]; + const type = "html";// (await rp.head(Utils.CorsProxy(stringContents)))["content-type"]; if (type) { const doc = await Docs.Get.DocumentFromType(type, stringContents, options); doc && generatedDocuments.push(doc); diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index f121ba3e0..239f414fd 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -29,6 +29,7 @@ import { ColorBox } from "./ColorBox"; import { DashWebRTCVideo } from "../webcam/DashWebRTCVideo"; import { DocuLinkBox } from "./DocuLinkBox"; import { PresElementBox } from "../presentationview/PresElementBox"; +import { ScreenshotBox } from "./ScreenshotBox"; import { VideoBox } from "./VideoBox"; import { WebBox } from "./WebBox"; import { InkingStroke } from "../InkingStroke"; @@ -99,7 +100,7 @@ export class DocumentContentsView extends React.Component Utils.CopyText(field.url.href), icon: "expand-arrows-alt" }); funcs.push({ description: "Rotate", event: this.rotate, icon: "expand-arrows-alt" }); funcs.push({ - description: "Reset Native Dimensions", event: action(() => { + description: "Reset Native Dimensions", event: action(async () => { const curNW = NumCast(this.dataDoc[this.props.fieldKey + "-nativeWidth"]); const curNH = NumCast(this.dataDoc[this.props.fieldKey + "-nativeHeight"]); if (this.props.PanelWidth() / this.props.PanelHeight() > curNW / curNH) { diff --git a/src/client/views/nodes/ScreenshotBox.scss b/src/client/views/nodes/ScreenshotBox.scss new file mode 100644 index 000000000..4aaccb472 --- /dev/null +++ b/src/client/views/nodes/ScreenshotBox.scss @@ -0,0 +1,46 @@ +.screenshotBox { + pointer-events: all; + transform-origin: top left; + background: white; + color: black; + // .screenshotBox-viewer { + // opacity: 0.99; // hack! overcomes some kind of Chrome weirdness where buttons (e.g., snapshot) disappear at some point as the video is resized larger + // } + // .inkingCanvas-paths-markers { + // opacity : 0.4; // we shouldn't have to do this, but since chrome crawls to a halt with z-index unset in videoBox-content, this is a workaround + // } +} + +.screenshotBox-content, .screenshotBox-content-interactive, .screenshotBox-cont-fullScreen { + width: 100%; + z-index: -1; // 0; // logically this should be 0 (or unset) which would give us transparent brush strokes over videos. However, this makes Chrome crawl to a halt + position: absolute; +} + +.screenshotBox-content, .screenshotBox-content-interactive, .screenshotBox-content-fullScreen { + height: Auto; +} + +.screenshotBox-content-interactive, .screenshotBox-content-fullScreen { + pointer-events: all; +} + +.screenshotBox-snapshot{ + color : white; + top :25px; + right : 25px; + position: absolute; + background-color:rgba(50, 50, 50, 0.2); + transform-origin: left top; + pointer-events:all; +} + +.screenshotBox-recorder{ + color : white; + top :25px; + right : 50px; + position: absolute; + background-color:rgba(50, 50, 50, 0.2); + transform-origin: left top; + pointer-events:all; +} diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx new file mode 100644 index 000000000..de9e521f6 --- /dev/null +++ b/src/client/views/nodes/ScreenshotBox.tsx @@ -0,0 +1,193 @@ +import React = require("react"); +import { library } from "@fortawesome/fontawesome-svg-core"; +import { faVideo } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { action, computed, IReactionDisposer, observable, runInAction } from "mobx"; +import { observer } from "mobx-react"; +import * as rp from 'request-promise'; +import { documentSchema, positionSchema } from "../../../new_fields/documentSchemas"; +import { makeInterface } from "../../../new_fields/Schema"; +import { ScriptField } from "../../../new_fields/ScriptField"; +import { Cast, StrCast } from "../../../new_fields/Types"; +import { VideoField } from "../../../new_fields/URLField"; +import { emptyFunction, returnFalse, returnOne, Utils } from "../../../Utils"; +import { Docs, DocUtils } from "../../documents/Documents"; +import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; +import { ContextMenu } from "../ContextMenu"; +import { ContextMenuProps } from "../ContextMenuItem"; +import { DocAnnotatableComponent } from "../DocComponent"; +import { InkingControl } from "../InkingControl"; +import { FieldView, FieldViewProps } from './FieldView'; +import "./ScreenshotBox.scss"; +const path = require('path'); + +type ScreenshotDocument = makeInterface<[typeof documentSchema, typeof positionSchema]>; +const ScreenshotDocument = makeInterface(documentSchema, positionSchema); + +library.add(faVideo); + +@observer +export class ScreenshotBox extends DocAnnotatableComponent(ScreenshotDocument) { + private _reactionDisposer?: IReactionDisposer; + private _videoRef: HTMLVideoElement | null = null; + public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ScreenshotBox, fieldKey); } + + public get player(): HTMLVideoElement | null { + return this._videoRef; + } + + videoLoad = () => { + 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; + } + + @action public Snapshot() { + const width = this.Document._width || 0; + const height = this.Document._height || 0; + const canvas = document.createElement('canvas'); + canvas.width = 640; + canvas.height = 640 * (this.Document._nativeHeight || 0) / (this.Document._nativeWidth || 1); + const ctx = canvas.getContext('2d');//draw image to canvas. scale to target dimensions + if (ctx) { + ctx.rect(0, 0, canvas.width, canvas.height); + ctx.fillStyle = "blue"; + ctx.fill(); + this._videoRef && ctx.drawImage(this._videoRef, 0, 0, canvas.width, canvas.height); + } + + if (this._videoRef) { + //convert to desired file format + const dataUrl = canvas.toDataURL('image/png'); // can also use 'image/png' + // if you want to preview the captured image, + const filename = path.basename(encodeURIComponent("screenshot" + Utils.GenerateGuid().replace(/\..*$/, "").replace(" ", "_"))); + ScreenshotBox.convertDataUri(dataUrl, filename).then(returnedFilename => { + setTimeout(() => { + if (returnedFilename) { + const imageSummary = Docs.Create.ImageDocument(Utils.prepend(returnedFilename), { + x: (this.Document.x || 0) + width, y: (this.Document.y || 0), + _width: 150, _height: height / width * 150, title: "--screenshot--" + }); + this.props.addDocument?.(imageSummary); + } + }, 500); + }); + } + } + + componentDidMount() { + } + + componentWillUnmount() { + this._reactionDisposer && this._reactionDisposer(); + } + + @action + setVideoRef = (vref: HTMLVideoElement | null) => { + this._videoRef = vref; + } + + public static async convertDataUri(imageUri: string, returnedFilename: string) { + try { + const posting = Utils.prepend("/uploadURI"); + const returnedUri = await rp.post(posting, { + body: { + uri: imageUri, + name: returnedFilename + }, + json: true, + }); + return returnedUri; + + } catch (e) { + console.log(e); + } + } + @observable _screenCapture = false; + specificContextMenu = (e: React.MouseEvent): void => { + const field = Cast(this.dataDoc[this.props.fieldKey], VideoField); + if (field) { + const url = field.url.href; + const subitems: ContextMenuProps[] = []; + subitems.push({ description: "Take Snapshot", event: () => this.Snapshot(), icon: "expand-arrows-alt" }); + subitems.push({ + description: "Screen Capture", event: (async () => { + runInAction(() => this._screenCapture = !this._screenCapture); + this._videoRef!.srcObject = !this._screenCapture ? undefined : await (navigator.mediaDevices as any).getDisplayMedia({ video: true }); + }), icon: "expand-arrows-alt" + }); + ContextMenu.Instance.addItem({ description: "Screenshot Funcs...", subitems: subitems, icon: "video" }); + } + } + + @computed get content() { + const interactive = InkingControl.Instance.selectedTool || !this.props.isSelected() ? "" : "-interactive"; + const style = "videoBox-content" + interactive; + return ; + } + + toggleRecording = action(async () => { + this._screenCapture = !this._screenCapture; + this._videoRef!.srcObject = !this._screenCapture ? undefined : await (navigator.mediaDevices as any).getDisplayMedia({ video: true }); + }) + + private get uIButtons() { + return ([ +
+ +
, +
+ +
]); + } + + onSnapshot = (e: React.PointerEvent) => { + this.Snapshot(); + e.stopPropagation(); + e.preventDefault(); + } + + + contentFunc = () => [this.content]; + render() { + return (
+
+ + {this.contentFunc} + +
+ {this.uIButtons} +
); + } +} \ No newline at end of file diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 439f2d85f..24b66d8f7 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -195,6 +195,7 @@ export class VideoBox extends DocAnnotatableComponent { const field = Cast(this.dataDoc[this.props.fieldKey], VideoField); if (field) { @@ -203,6 +204,12 @@ export class VideoBox extends DocAnnotatableComponent { Utils.CopyText(url); }, icon: "expand-arrows-alt" }); subitems.push({ description: "Toggle Show Controls", event: action(() => VideoBox._showControls = !VideoBox._showControls), icon: "expand-arrows-alt" }); subitems.push({ description: "Take Snapshot", event: () => this.Snapshot(), icon: "expand-arrows-alt" }); + subitems.push({ + description: "Screen Capture", event: (async () => { + runInAction(() => this._screenCapture = !this._screenCapture); + this._videoRef!.srcObject = !this._screenCapture ? undefined : await (navigator.mediaDevices as any).getDisplayMedia({ video: true }); + }), icon: "expand-arrows-alt" + }); ContextMenu.Instance.addItem({ description: "Video Funcs...", subitems: subitems, icon: "video" }); } } @@ -212,8 +219,14 @@ export class VideoBox extends DocAnnotatableComponentLoading
: -
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index a6cbabf42..85926e393 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -565,7 +565,8 @@ export namespace Doc { } else if (cfield instanceof ComputedField) { copy[key] = ComputedField.MakeFunction(cfield.script.originalScript); } else if (field instanceof ObjectField) { - copy[key] = key.includes("layout[") && doc[key] instanceof Doc ? Doc.MakeCopy(doc[key] as Doc, false) : ObjectField.MakeCopy(field); + copy[key] = key.includes("layout[") && doc[key] instanceof Doc ? Doc.MakeCopy(doc[key] as Doc, false) : + doc[key] instanceof Doc ? doc[key] : ObjectField.MakeCopy(field); } else if (field instanceof Promise) { debugger; //This shouldn't happend... } else { -- cgit v1.2.3-70-g09d2 From b4958eac84339dd7a88c964a9c52e89481048f55 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 2 Apr 2020 19:39:03 -0400 Subject: supported uploads of images ending with .webp --- src/client/views/collections/CollectionView.tsx | 6 +++--- src/client/views/nodes/ImageBox.tsx | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index b6ce2f3a9..df1770ffe 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -429,9 +429,9 @@ export class CollectionView extends Touchable { Document={facetCollection} backgroundColor={this.filterBackground} fieldKey={`${this.props.fieldKey}-filter`} - moveDocument={(doc: Doc) => false} - removeDocument={(doc: Doc) => false} - addDocument={(doc: Doc) => false} /> + moveDocument={returnFalse} + removeDocument={returnFalse} + addDocument={returnFalse} />
; } diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index e710b3075..00057055f 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -225,7 +225,7 @@ export class ImageBox extends DocAnnotatableComponent