From 462580bf70ff563dbfe33a84b8cd015e637cdf7e Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 22 Mar 2024 11:41:22 -0400 Subject: make ink stroke labels visible always for closed gesture strokes. --- .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index b2fb5848e..01d379b96 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -647,7 +647,8 @@ export class CollectionFreeFormView extends CollectionSubView Date: Sat, 23 Mar 2024 21:13:38 -0400 Subject: fixed linking to parts of a template. fixed highlting part of a template when following a link to it. --- .../collectionFreeForm/CollectionFreeFormView.tsx | 12 +++++++++--- src/fields/Doc.ts | 3 ++- 2 files changed, 11 insertions(+), 4 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 01d379b96..1fd453e96 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -314,7 +314,7 @@ export class CollectionFreeFormView extends CollectionSubView pair.layout).includes(anchor)) return; const xfToCollection = options?.docTransform ?? Transform.Identity(); const savedState = { panX: NumCast(this.Document[this.panXFieldKey]), panY: NumCast(this.Document[this.panYFieldKey]), scale: options?.willZoomCentered ? this.Document[this.scaleFieldKey] : undefined }; const cantTransform = this.fitContentsToBox || ((this.Document.isGroup || this.layoutDoc._lockedTransform) && !LightboxView.LightboxDoc); @@ -335,6 +335,7 @@ export class CollectionFreeFormView extends CollectionSubView> => new Promise>(res => { if (doc.hidden && this._lightboxDoc !== doc) options.didMove = !(doc.hidden = false); + if (doc === this.Document) return res(this.DocumentView?.()); const findDoc = (finish: (dv: DocumentView) => void) => DocumentManager.Instance.AddViewRenderedCb(doc, dv => finish(dv)); findDoc(dv => res(dv)); }); @@ -1262,7 +1263,7 @@ export class CollectionFreeFormView extends CollectionSubView pair.layout)?.includes(doc)) { if (doc.hidden) doc.hidden = false; return true; } @@ -1405,7 +1406,12 @@ export class CollectionFreeFormView extends CollectionSubView { // create an anchor that saves information about the current state of the freeform view (pan, zoom, view type) - const anchor = Docs.Create.ConfigDocument({ title: 'ViewSpec - ' + StrCast(this.layoutDoc._type_collection), layout_unrendered: true, presentation_transition: 500, annotationOn: this.Document }); + const anchor = Docs.Create.ConfigDocument({ + title: 'ViewSpec - ' + StrCast(this.layoutDoc._type_collection), + layout_unrendered: true, + presentation_transition: 500, + annotationOn: this.Document, + }); PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), pannable: !this.Document.isGroup, type_collection: true, filters: true } }, this.Document); if (addAsAnnotation) { diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 4b40d11b9..246828709 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -1279,7 +1279,8 @@ export namespace Doc { highlightedDocs.add(doc); doc[Highlight] = true; doc[Animation] = presentation_effect; - if (dataAndDisplayDocs) { + if (dataAndDisplayDocs && !doc.resolvedDataDoc) { + // if doc is a layout template then we don't want to highlight the proto since that will be the entire template, not just the specific layout field highlightedDocs.add(doc[DocData]); doc[DocData][Highlight] = true; } -- cgit v1.2.3-70-g09d2 From b420caf2c7ecd386cae2cc550904522474b541aa Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 26 Mar 2024 22:34:10 -0400 Subject: added empty image tool and click on empty image to select from filesystem. fixed following links in lightbox and showing links to stackedTimelines. fixed embedding docs into text. fixed not resizing text boxes that also show up in pivot view. prevent context menu from going off top of screen. fixed freeform clustering colors and click to type. fixed links to stackedTimeline marks, and titles for marks. made title editing from doc deco and header use same syntax as keyValue. fixed marquee selection on webBoxes. turn off transitions in freeformdocview after timeout. enabled iconifying templates to propagate to "offspring". fixes images in templates. don't show headr on schema views. --- src/client/documents/Documents.ts | 52 ++++++++-------- src/client/util/DocumentManager.ts | 4 +- src/client/views/ContextMenu.tsx | 6 +- src/client/views/DocumentDecorations.tsx | 71 ++++++++-------------- src/client/views/FieldsDropdown.tsx | 1 - src/client/views/LightboxView.tsx | 2 + src/client/views/MarqueeAnnotator.tsx | 19 ++++-- src/client/views/ObservableReactComponent.tsx | 3 +- src/client/views/PropertiesView.tsx | 2 +- src/client/views/StyleProvider.tsx | 6 +- .../collections/CollectionStackedTimeline.tsx | 13 ++-- .../CollectionFreeFormLayoutEngines.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 11 ++-- .../collections/collectionFreeForm/MarqueeView.tsx | 4 +- .../collectionSchema/SchemaTableCell.tsx | 2 +- src/client/views/global/globalScripts.ts | 4 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 24 ++++++-- src/client/views/nodes/DocumentContentsView.tsx | 7 ++- src/client/views/nodes/DocumentView.tsx | 35 +++++++---- src/client/views/nodes/FieldView.tsx | 1 + src/client/views/nodes/ImageBox.tsx | 55 +++++++++++++---- src/client/views/nodes/KeyValueBox.tsx | 2 +- src/client/views/nodes/LabelBox.tsx | 2 +- src/client/views/nodes/LinkBox.tsx | 47 ++++++++++---- src/client/views/nodes/VideoBox.tsx | 5 +- src/client/views/nodes/WebBox.tsx | 65 ++++++++++++++------ .../views/nodes/formattedText/FormattedTextBox.tsx | 17 ++++-- src/client/views/nodes/trails/PresBox.tsx | 2 +- src/fields/Doc.ts | 29 +++++---- src/fields/PresField.ts | 6 -- src/fields/RichTextField.ts | 7 --- 31 files changed, 311 insertions(+), 195 deletions(-) delete mode 100644 src/fields/PresField.ts (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 17cb6fef8..b63c5e429 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -1017,8 +1017,8 @@ export namespace Docs { } export function ImageDocument(url: string | ImageField, options: DocumentOptions = {}, overwriteDoc?: Doc) { - const imgField = url instanceof ImageField ? url : new ImageField(url); - return InstanceFromProto(Prototypes.get(DocumentType.IMG), imgField, { title: basename(imgField.url.href), ...options }, undefined, undefined, undefined, overwriteDoc); + const imgField = url instanceof ImageField ? url : url ? new ImageField(url) : undefined; + return InstanceFromProto(Prototypes.get(DocumentType.IMG), imgField, { title: basename(imgField?.url.href ?? '-no image-'), ...options }, undefined, undefined, undefined, overwriteDoc); } export function PresDocument(options: DocumentOptions = {}) { @@ -1950,6 +1950,31 @@ export namespace DocUtils { return dd; } + export function assignImageInfo(result: Upload.FileInformation, proto: Doc) { + if (Upload.isImageInformation(result)) { + const maxNativeDim = Math.min(Math.max(result.nativeHeight, result.nativeWidth), defaultNativeImageDim); + const exifRotation = StrCast((result.exifData?.data as any)?.Orientation).toLowerCase(); + proto['data-nativeOrientation'] = result.exifData?.data?.image?.Orientation ?? (exifRotation.includes('rotate 90') || exifRotation.includes('rotate 270') ? 5 : undefined); + proto['data_nativeWidth'] = result.nativeWidth < result.nativeHeight ? (maxNativeDim * result.nativeWidth) / result.nativeHeight : maxNativeDim; + proto['data_nativeHeight'] = result.nativeWidth < result.nativeHeight ? maxNativeDim : maxNativeDim / (result.nativeWidth / result.nativeHeight); + if (NumCast(proto['data-nativeOrientation']) >= 5) { + proto['data_nativeHeight'] = result.nativeWidth < result.nativeHeight ? (maxNativeDim * result.nativeWidth) / result.nativeHeight : maxNativeDim; + proto['data_nativeWidth'] = result.nativeWidth < result.nativeHeight ? maxNativeDim : maxNativeDim / (result.nativeWidth / result.nativeHeight); + } + proto.data_exif = JSON.stringify(result.exifData?.data); + proto.data_contentSize = result.contentSize; + // exif gps data coordinates are stored in DMS (Degrees Minutes Seconds), the following operation converts that to decimal coordinates + const latitude = result.exifData?.data?.GPSLatitude; + const latitudeDirection = result.exifData?.data?.GPSLatitudeRef; + const longitude = result.exifData?.data?.GPSLongitude; + const longitudeDirection = result.exifData?.data?.GPSLongitudeRef; + if (latitude !== undefined && longitude !== undefined && latitudeDirection !== undefined && longitudeDirection !== undefined) { + proto.latitude = ConvertDMSToDD(latitude[0], latitude[1], latitude[2], latitudeDirection); + proto.longitude = ConvertDMSToDD(longitude[0], longitude[1], longitude[2], longitudeDirection); + } + } + } + async function processFileupload(generatedDocuments: Doc[], name: string, type: string, result: Error | Upload.FileInformation, options: DocumentOptions, overwriteDoc?: Doc) { if (result instanceof Error) { alert(`Upload failed: ${result.message}`); @@ -1961,28 +1986,7 @@ export namespace DocUtils { if (doc) { const proto = Doc.GetProto(doc); proto.text = result.rawText; - if (Upload.isImageInformation(result)) { - const maxNativeDim = Math.min(Math.max(result.nativeHeight, result.nativeWidth), defaultNativeImageDim); - const exifRotation = StrCast((result.exifData?.data as any)?.Orientation).toLowerCase(); - proto['data-nativeOrientation'] = result.exifData?.data?.image?.Orientation ?? (exifRotation.includes('rotate 90') || exifRotation.includes('rotate 270') ? 5 : undefined); - proto['data_nativeWidth'] = result.nativeWidth < result.nativeHeight ? (maxNativeDim * result.nativeWidth) / result.nativeHeight : maxNativeDim; - proto['data_nativeHeight'] = result.nativeWidth < result.nativeHeight ? maxNativeDim : maxNativeDim / (result.nativeWidth / result.nativeHeight); - if (NumCast(proto['data-nativeOrientation']) >= 5) { - proto['data_nativeHeight'] = result.nativeWidth < result.nativeHeight ? (maxNativeDim * result.nativeWidth) / result.nativeHeight : maxNativeDim; - proto['data_nativeWidth'] = result.nativeWidth < result.nativeHeight ? maxNativeDim : maxNativeDim / (result.nativeWidth / result.nativeHeight); - } - proto.data_exif = JSON.stringify(result.exifData?.data); - proto.data_contentSize = result.contentSize; - // exif gps data coordinates are stored in DMS (Degrees Minutes Seconds), the following operation converts that to decimal coordinates - const latitude = result.exifData?.data?.GPSLatitude; - const latitudeDirection = result.exifData?.data?.GPSLatitudeRef; - const longitude = result.exifData?.data?.GPSLongitude; - const longitudeDirection = result.exifData?.data?.GPSLongitudeRef; - if (latitude !== undefined && longitude !== undefined && latitudeDirection !== undefined && longitudeDirection !== undefined) { - proto.latitude = ConvertDMSToDD(latitude[0], latitude[1], latitude[2], latitudeDirection); - proto.longitude = ConvertDMSToDD(longitude[0], longitude[1], longitude[2], longitudeDirection); - } - } + !(result instanceof Error) && DocUtils.assignImageInfo(result, proto); if (Upload.isVideoInformation(result)) { proto.data_duration = result.duration; } diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index a38a330da..40d28c690 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -59,7 +59,7 @@ export class DocumentManager { private _viewRenderedCbs: { doc: Doc; func: (dv: DocumentView) => any }[] = []; public AddViewRenderedCb = (doc: Opt, func: (dv: DocumentView) => any) => { if (doc) { - const dv = this.getDocumentView(doc); + const dv = LightboxView.LightboxDoc ? this.getLightboxDocumentView(doc) : this.getDocumentView(doc); this._viewRenderedCbs.push({ doc, func }); if (dv) { this.callAddViewFuncs(dv); @@ -262,7 +262,7 @@ export class DocumentManager { return res(this.getDocumentView(docContextPath[0])!); } options.didMove = true; - docContextPath.some(doc => TabDocView.Activate(doc)) || DocumentViewInternal.addDocTabFunc(docContextPath[0], options.openLocation ?? OpenWhere.addRight); + (!LightboxView.LightboxDoc && docContextPath.some(doc => TabDocView.Activate(doc))) || DocumentViewInternal.addDocTabFunc(docContextPath[0], options.openLocation ?? OpenWhere.addRight); this.AddViewRenderedCb(docContextPath[0], dv => res(dv)); })); if (options.openLocation === OpenWhere.lightbox) { diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index 8f4e43978..ca877b93e 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -218,11 +218,12 @@ export class ContextMenu extends ObservableReactComponent<{}> { this._width = DivWidth(r); this._height = DivHeight(r); } + this._searchRef.current?.focus(); })} style={{ display: this._display ? '' : 'none', left: this.pageX, - ...(this._yRelativeToTop ? { top: this.pageY } : { bottom: this.pageY }), + ...(this._yRelativeToTop ? { top: Math.max(0, this.pageY) } : { bottom: this.pageY }), background: SettingsManager.userBackgroundColor, color: SettingsManager.userColor, }}> @@ -265,7 +266,8 @@ export class ContextMenu extends ObservableReactComponent<{}> { const item = this.flatItems[this._selectedIndex]; if (item) { item.event({ x: this.pageX, y: this.pageY }); - } else if (this._searchString.startsWith(this._defaultPrefix)) { + } else { + //if (this._searchString.startsWith(this._defaultPrefix)) { this._defaultItem?.(this._searchString.substring(this._defaultPrefix.length)); } this.closeMenu(); diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 2fb9f0fc1..4d9b93896 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -34,6 +34,7 @@ import { Colors } from './global/globalEnums'; import { DocumentView, OpenWhereMod } from './nodes/DocumentView'; import { ImageBox } from './nodes/ImageBox'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; +import { KeyValueBox } from './nodes/KeyValueBox'; interface DocumentDecorationsProps { PanelWidth: number; @@ -57,7 +58,7 @@ export class DocumentDecorations extends ObservableReactComponent { - if (this._accumulatedTitle.startsWith('#') || this._accumulatedTitle.startsWith('=')) { + if (this._accumulatedTitle.startsWith('$')) { this._titleControlString = this._accumulatedTitle; - } else if (this._titleControlString.startsWith('#')) { + } else if (this._titleControlString.startsWith('$')) { if (this._accumulatedTitle.startsWith('-->#')) { SelectionManager.Docs.forEach(doc => (doc[DocData].onViewMounted = ScriptField.MakeScript(`updateTagsCollection(this)`))); } @@ -131,26 +132,7 @@ export class DocumentDecorations extends ObservableReactComponent')) { - const title = titleField.toString().replace(/\.?/, ''); - const curKey = Doc.LayoutFieldKey(d.Document); - if (curKey !== title) { - if (title) { - if (d.dataDoc[title] === undefined || d.dataDoc[title] instanceof RichTextField || typeof d.dataDoc[title] === 'string') { - d.Document.layout_fieldKey = `layout_${title}`; - d.Document[`layout_${title}`] = FormattedTextBox.LayoutString(title); - d.Document[`${title}_nativeWidth`] = d.Document[`${title}_nativeHeight`] = 0; - } - } else { - d.Document.layout_fieldKey = undefined; - } - } - } else { - Doc.SetInPlace(d.Document, titleFieldKey, titleField, true); - } + KeyValueBox.SetField(d.Document, titleFieldKey, this._accumulatedTitle); }), 'edit title' ); @@ -181,7 +163,8 @@ export class DocumentDecorations extends ObservableReactComponent this.onBackgroundMove(true, e), emptyFunction, action(e => { - !this._editingTitle && (this._accumulatedTitle = this._titleControlString.startsWith('#') ? this.selectionTitle : this._titleControlString); + const selected = SelectionManager.Views.length === 1 ? SelectionManager.Docs[0] : undefined; + !this._editingTitle && (this._accumulatedTitle = this._titleControlString.startsWith('$') ? (selected && Field.toKeyValueString(selected, this._titleControlString.substring(1))) || '-unset-' : this._titleControlString); this._editingTitle = true; this._keyinput.current && setTimeout(this._keyinput.current.focus); }) @@ -622,11 +605,8 @@ export class DocumentDecorations extends ObservableReactComponent { - this._editingTitle = false; - !hideTitle && this.titleBlur(); - })} - onChange={action(e => !hideTitle && (this._accumulatedTitle = e.target.value))} - onKeyDown={hideTitle ? emptyFunction : this.titleEntered} - onPointerDown={e => e.stopPropagation()} - /> + <> + {r - x < 150 ? null : {this._titleControlString + ':'}} + { + this._editingTitle = false; + !hideTitle && this.titleBlur(); + })} + onChange={action(e => !hideTitle && (this._accumulatedTitle = e.target.value))} + onKeyDown={hideTitle ? emptyFunction : this.titleEntered} + onPointerDown={e => e.stopPropagation()} + /> + ) : (
{hideTitle ? null : ( diff --git a/src/client/views/FieldsDropdown.tsx b/src/client/views/FieldsDropdown.tsx index 5638d34c6..6a5c2cb4c 100644 --- a/src/client/views/FieldsDropdown.tsx +++ b/src/client/views/FieldsDropdown.tsx @@ -61,7 +61,6 @@ export class FieldsDropdown extends ObservableReactComponent filteredOptions.push(pair[0])); const options = filteredOptions.sort().map(facet => ({ value: facet, label: facet })); - console.log(options); return ( } + {Doc.noviceMode ? null : } {templateMenu} { + onKeyDown = (e: KeyboardEvent) => { //make textbox and add it to this collection // tslint:disable-next-line:prefer-const const cm = ContextMenu.Instance; @@ -311,7 +311,7 @@ export class MarqueeView extends ObservableReactComponent { ? DocCast(linkDoc.link_anchor_2) : DocCast(linkDoc.link_anchor_1) : LinkManager.getOppositeAnchor(linkDoc, sourceDoc) || - LinkManager.getOppositeAnchor(linkDoc, Cast(linkDoc.link_anchor_2, Doc, null).annotationOn === sourceDoc ? Cast(linkDoc.link_anchor_2, Doc, null) : Cast(linkDoc.link_anchor_1, Doc, null)); + LinkManager.getOppositeAnchor(linkDoc, Cast(linkDoc.link_anchor_2, Doc, null)?.annotationOn === sourceDoc ? Cast(linkDoc.link_anchor_2, Doc, null) : Cast(linkDoc.link_anchor_1, Doc, null)); return !destDoc || !sourceDoc ? null : ( () { _height: 300, backgroundColor: 'white', }); - this._props.addDocument?.(graph); + const link = DocUtils.MakeLink(this.Document, graph, { link_relationship: 'function', link_description: 'input' }); + //this._props.addDocument?.(graph); + link && this._props.addDocument?.(link); e.stopPropagation(); } if (e.key === 'Backspace' && !this.dataDoc.text) this._props.removeDocument?.(this.Document); diff --git a/src/client/views/nodes/FunctionPlotBox.tsx b/src/client/views/nodes/FunctionPlotBox.tsx index 2e7a2120e..67445e552 100644 --- a/src/client/views/nodes/FunctionPlotBox.tsx +++ b/src/client/views/nodes/FunctionPlotBox.tsx @@ -7,12 +7,13 @@ import { List } from '../../../fields/List'; import { listSpec } from '../../../fields/Schema'; import { Cast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; -import { Docs } from '../../documents/Documents'; +import { DocUtils, Docs } from '../../documents/Documents'; import { DragManager } from '../../util/DragManager'; import { undoBatch } from '../../util/UndoManager'; import { ViewBoxAnnotatableComponent } from '../DocComponent'; import { FieldView, FieldViewProps } from './FieldView'; import { PinProps, PresBox } from './trails'; +import { LinkManager } from '../../util/LinkManager'; @observer export class FunctionPlotBox extends ViewBoxAnnotatableComponent() { @@ -33,7 +34,7 @@ export class FunctionPlotBox extends ViewBoxAnnotatableComponent componentDidMount() { this._props.setContentViewBox?.(this); reaction( - () => [DocListCast(this.dataDoc[this.fieldKey]).map(doc => doc?.text), this.layoutDoc.width, this.layoutDoc.height, this.layoutDoc.xRange, this.layoutDoc.yRange], + () => [this.graphFuncs, this.layoutDoc.width, this.layoutDoc.height, this.layoutDoc.xRange, this.layoutDoc.yRange], () => this.createGraph() ); } @@ -45,11 +46,17 @@ export class FunctionPlotBox extends ViewBoxAnnotatableComponent if (addAsAnnotation) this.addDocument(anchor); return anchor; }; + @computed get graphFuncs() { + const links = LinkManager.Instance.getAllRelatedLinks(this.Document) + .map(d => LinkManager.getOppositeAnchor(d, this.Document)) + .filter(d => d) + .map(d => d!); + return links.concat(DocListCast(this.dataDoc[this.fieldKey])).map(doc => StrCast(doc.text, 'x^2').replace(/\\frac\{(.*)\}\{(.*)\}/, '($1/$2)')); + } createGraph = (ele?: HTMLDivElement) => { this._plotEle = ele || this._plotEle; const width = this._props.PanelWidth(); const height = this._props.PanelHeight(); - const fns = DocListCast(this.dataDoc.data).map(doc => StrCast(doc.text, 'x^2').replace(/\\frac\{(.*)\}\{(.*)\}/, '($1/$2)')); try { this._plotEle.children.length && this._plotEle.removeChild(this._plotEle.children[0]); this._plot = functionPlot({ @@ -59,7 +66,7 @@ export class FunctionPlotBox extends ViewBoxAnnotatableComponent xAxis: { domain: Cast(this.layoutDoc.xRange, listSpec('number'), [-10, 10]) }, yAxis: { domain: Cast(this.layoutDoc.yRange, listSpec('number'), [-1, 9]) }, grid: true, - data: fns.map(fn => ({ + data: this.graphFuncs.map(fn => ({ fn, // derivative: { fn: "2 * x", updateOnMouseMove: true } })), @@ -72,7 +79,14 @@ export class FunctionPlotBox extends ViewBoxAnnotatableComponent @undoBatch drop = (e: Event, de: DragManager.DropEvent) => { if (de.complete.docDragData?.droppedDocuments.length) { - const added = de.complete.docDragData.droppedDocuments.reduce((res, doc) => res && Doc.AddDocToList(this.dataDoc, this._props.fieldKey, doc), true); + const added = de.complete.docDragData.droppedDocuments.reduce((res, doc) => { + ///const ret = res && Doc.AddDocToList(this.dataDoc, this._props.fieldKey, doc); + if (res) { + const link = DocUtils.MakeLink(doc, this.Document, { link_relationship: 'function', link_description: 'input' }); + link && this._props.addDocument?.(link); + } + return res; + }, true); !added && e.preventDefault(); e.stopPropagation(); // prevent parent Doc from registering new position so that it snaps back into place return added; @@ -104,7 +118,7 @@ export class FunctionPlotBox extends ViewBoxAnnotatableComponent {this.theGraph}
() { public static LayoutString(fieldKey: string = 'link') { return FieldView.LayoutString(LinkBox, fieldKey); } - _disposer: IReactionDisposer | undefined; + _disposers: { [name: string]: IReactionDisposer } = {}; @observable _forceAnimate: number = 0; // forces xArrow to animate when a transition animation is detected on something that affects an anchor @observable _hide = false; // don't render if anchor is not visible since that breaks xAnchor @@ -40,11 +40,15 @@ export class LinkBox extends ViewBoxBaseComponent() { return DocumentManager.Instance.getDocumentView(anchor, this.DocumentView?.().containerViewPath?.().lastElement()); }; componentWillUnmount() { - this._disposer?.(); + Object.keys(this._disposers).forEach(key => this._disposers[key]()); } componentDidMount() { this._props.setContentViewBox?.(this); - this._disposer = reaction( + this._disposers.deleting = reaction( + () => !this.anchor1 || !this.anchor2, + empty => empty && this._props.removeDocument?.(this.Document) + ); + this._disposers.dragging = reaction( () => ({ drag: SnappingManager.IsDragging }), ({ drag }) => { !LightboxView.Contains(this.DocumentView?.()) && diff --git a/src/client/views/nodes/LinkDescriptionPopup.tsx b/src/client/views/nodes/LinkDescriptionPopup.tsx index 1645d0813..2a96ce458 100644 --- a/src/client/views/nodes/LinkDescriptionPopup.tsx +++ b/src/client/views/nodes/LinkDescriptionPopup.tsx @@ -69,8 +69,10 @@ export class LinkDescriptionPopup extends React.Component<{}> { }}> e.stopPropagation()} - onKeyPress={e => e.key === 'Enter' && this.onDismiss(true)} + onKeyDown={e => { + e.key === 'Enter' && this.onDismiss(true); + e.stopPropagation(); + }} value={this.description} placeholder={this.description || '(Optional) Enter link description...'} onChange={e => this.descriptionChanged(e)} diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx index d9d0dbe3e..8c65fd34e 100644 --- a/src/client/views/nodes/ScriptingBox.tsx +++ b/src/client/views/nodes/ScriptingBox.tsx @@ -670,7 +670,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent() const definedParameters = !this.compileParams.length ? null : (
{this.compileParams.map((parameter, i) => ( -
e.key === 'Enter' && this._overlayDisposer?.()}> +
e.key === 'Enter' && this._overlayDisposer?.()}> () {!this.compileParams.length || !this.paramsNames ? null : (
{this.paramsNames.map((parameter: string, i: number) => ( -
e.key === 'Enter' && this._overlayDisposer?.()}> +
e.key === 'Enter' && this._overlayDisposer?.()}>
{`${parameter}:${this.paramsTypes[i]} = `}
{this.paramsTypes[i] === 'boolean' ? this.renderEnum(parameter, [true, false]) : null} diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx index 5b03e2236..8802a032f 100644 --- a/src/client/views/nodes/formattedText/DashFieldView.tsx +++ b/src/client/views/nodes/formattedText/DashFieldView.tsx @@ -1,6 +1,6 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; -import { action, computed, IReactionDisposer, makeObservable, observable, reaction, trace } from 'mobx'; +import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction, trace } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import * as ReactDOM from 'react-dom/client'; @@ -22,15 +22,20 @@ import { OpenWhere } from '../DocumentView'; import './DashFieldView.scss'; import { FormattedTextBox } from './FormattedTextBox'; import { DocData } from '../../../../fields/DocSymbols'; +import { NodeSelection, TextSelection } from 'prosemirror-state'; export class DashFieldView { dom: HTMLDivElement; // container for label and value root: any; node: any; tbox: FormattedTextBox; + @observable expanded = false; + Expanded = () => this.expanded; unclickable = () => !this.tbox._props.rootSelected?.() && this.node.marks.some((m: any) => m.type === this.tbox.EditorView?.state.schema.marks.linkAnchor && m.attrs.noPreview); constructor(node: any, view: any, getPos: any, tbox: FormattedTextBox) { + makeObservable(this); + const self = this; this.node = node; this.tbox = tbox; this.dom = document.createElement('div'); @@ -38,11 +43,26 @@ export class DashFieldView { this.dom.style.height = node.attrs.height; this.dom.style.position = 'relative'; this.dom.style.display = 'inline-block'; - this.dom.onkeypress = function (e: any) { + const tBox = this.tbox; + this.dom.onkeypress = function (e: KeyboardEvent) { e.stopPropagation(); }; - this.dom.onkeydown = function (e: any) { + this.dom.onkeydown = function (e: KeyboardEvent) { e.stopPropagation(); + if (e.key === 'Tab') { + e.preventDefault(); + const editor = tbox.EditorView; + if (editor) { + const state = editor.state; + for (var i = state.selection.to; i < state.doc.content.size; i++) { + if (state.doc.nodeAt(i)?.type.name === state.schema.nodes.dashField.name) { + editor.dispatch(state.tr.setSelection(new NodeSelection(state.doc.resolve(i)))); + return; + } + } + tBox.setFocus(state.selection.to + 1); + } + } }; this.dom.onkeyup = function (e: any) { e.stopPropagation(); @@ -51,6 +71,8 @@ export class DashFieldView { e.stopPropagation(); }; + this.expanded = node.attrs.expanded; + this.root = ReactDOM.createRoot(this.dom); this.root.render( @@ -77,9 +99,11 @@ export class DashFieldView { }); } deselectNode() { + runInAction(() => (this.expanded = false)); this.dom.classList.remove('ProseMirror-selectednode'); } selectNode() { + setTimeout(() => runInAction(() => (this.expanded = true)), 100); this.dom.classList.add('ProseMirror-selectednode'); } } @@ -92,7 +116,7 @@ interface IDashFieldViewInternal { width: number; height: number; editable: boolean; - expanded: boolean; + expanded: () => boolean; dataDoc: boolean; node: any; getPos: any; @@ -106,7 +130,7 @@ export class DashFieldViewInternal extends ObservableReactComponent(); @observable _dashDoc: Doc | undefined = undefined; - @observable _expanded = this._props.expanded; + @observable _expanded = this._props.expanded(); constructor(props: IDashFieldViewInternal) { super(props); @@ -132,7 +156,7 @@ export class DashFieldViewInternal extends ObservableReactComponent this._expanded && this._props.editable; + isRowActive = () => (this._props.expanded() || this._expanded) && this._props.editable; finishEdit = action(() => { if (this._expanded) { @@ -155,7 +179,7 @@ export class DashFieldViewInternal extends ObservableReactComponent ({ value: facet, label: facet })); @@ -239,13 +263,13 @@ export class DashFieldViewInternal extends ObservableReactComponent )} {this._props.fieldKey.startsWith('#') ? null : this.fieldValueContent} - {!this.values.length ? null : ( - {this.values.map(val => ( ))} - )} + )} */}
); } diff --git a/src/client/views/nodes/formattedText/EquationView.tsx b/src/client/views/nodes/formattedText/EquationView.tsx index b786c5ffb..b90653acc 100644 --- a/src/client/views/nodes/formattedText/EquationView.tsx +++ b/src/client/views/nodes/formattedText/EquationView.tsx @@ -8,6 +8,7 @@ import { StrCast } from '../../../../fields/Types'; import './DashFieldView.scss'; import EquationEditor from './EquationEditor'; import { FormattedTextBox } from './FormattedTextBox'; +import { DocData } from '../../../../fields/DocSymbols'; export class EquationView { dom: HTMLDivElement; // container for label and value @@ -88,7 +89,6 @@ export class EquationViewInternal extends React.Component } e.stopPropagation(); }} - onKeyPress={e => e.stopPropagation()} style={{ position: 'relative', display: 'inline-block', @@ -96,12 +96,11 @@ export class EquationViewInternal extends React.Component height: this.props.height, background: 'white', borderRadius: '10%', - bottom: 3, }}> ) => { + onKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter') { DocServer.GetRefField(this.idToAdd).then( action((field: any) => { @@ -168,7 +168,7 @@ class Viewer extends React.Component { render() { return ( <> - +
{this.fields.map((field, index) => ( false}> -- cgit v1.2.3-70-g09d2 From 82a74549a6b1c942fabaf8396c450b70d65e81dd Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 28 Mar 2024 23:28:11 -0400 Subject: fixed following link to pdf text selection with highlights. fixed hide key/value in dashfieldView. fixed selecting dashFieldView nodes. --- src/client/documents/Documents.ts | 25 +- src/client/util/CurrentUserUtils.ts | 4 +- src/client/views/MarqueeAnnotator.tsx | 1 + src/client/views/SidebarAnnos.tsx | 4 +- .../CollectionFreeFormLayoutEngines.tsx | 2 +- src/client/views/nodes/MapBox/MapBox.tsx | 791 +++++---------------- src/client/views/nodes/MapBox/MapPushpinBox.tsx | 4 +- .../views/nodes/RecordingBox/RecordingView.scss | 322 ++++----- .../views/nodes/formattedText/DashFieldView.tsx | 70 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 32 +- .../views/nodes/formattedText/RichTextRules.ts | 3 +- src/client/views/nodes/formattedText/nodes_rts.ts | 1 + 12 files changed, 445 insertions(+), 814 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index b63c5e429..b3d14bc22 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -1,6 +1,7 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { action, reaction, runInAction } from 'mobx'; import { basename } from 'path'; +import { OmitKeys, Utils } from '../../Utils'; import { DateField } from '../../fields/DateField'; import { Doc, DocListCast, Field, LinkedTo, Opt, StrListCast, updateCachedAcls } from '../../fields/Doc'; import { DocData, Initializing } from '../../fields/DocSymbols'; @@ -13,30 +14,29 @@ import { SchemaHeaderField } from '../../fields/SchemaHeaderField'; import { ComputedField, ScriptField } from '../../fields/ScriptField'; import { BoolCast, Cast, DocCast, FieldValue, NumCast, ScriptCast, StrCast } from '../../fields/Types'; import { AudioField, CsvField, ImageField, PdfField, VideoField, WebField, YoutubeField } from '../../fields/URLField'; -import { inheritParentAcls, SharingPermissions } from '../../fields/util'; +import { SharingPermissions, inheritParentAcls } from '../../fields/util'; import { Upload } from '../../server/SharedMediaTypes'; -import { OmitKeys, Utils } from '../../Utils'; -import { YoutubeBox } from '../apis/youtube/YoutubeBox'; import { DocServer } from '../DocServer'; import { Networking } from '../Network'; +import { YoutubeBox } from '../apis/youtube/YoutubeBox'; import { DragManager, dropActionType } from '../util/DragManager'; import { FollowLinkScript } from '../util/LinkFollower'; import { LinkManager } from '../util/LinkManager'; import { ScriptingGlobals } from '../util/ScriptingGlobals'; -import { undoable, UndoManager } from '../util/UndoManager'; -import { CollectionDockingView } from '../views/collections/CollectionDockingView'; -import { DimUnit } from '../views/collections/collectionMulticolumn/CollectionMulticolumnView'; -import { CollectionView } from '../views/collections/CollectionView'; +import { UndoManager, undoable } from '../util/UndoManager'; import { ContextMenu } from '../views/ContextMenu'; import { ContextMenuProps } from '../views/ContextMenuItem'; import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, ActiveIsInkMask, InkingStroke } from '../views/InkingStroke'; +import { CollectionDockingView } from '../views/collections/CollectionDockingView'; +import { CollectionView } from '../views/collections/CollectionView'; +import { DimUnit } from '../views/collections/collectionMulticolumn/CollectionMulticolumnView'; import { AudioBox, media_state } from '../views/nodes/AudioBox'; import { ComparisonBox } from '../views/nodes/ComparisonBox'; import { DataVizBox } from '../views/nodes/DataVizBox/DataVizBox'; +import { OpenWhere } from '../views/nodes/DocumentView'; import { EquationBox } from '../views/nodes/EquationBox'; import { FieldViewProps } from '../views/nodes/FieldView'; import { FontIconBox } from '../views/nodes/FontIconBox/FontIconBox'; -import { FormattedTextBox } from '../views/nodes/formattedText/FormattedTextBox'; import { FunctionPlotBox } from '../views/nodes/FunctionPlotBox'; import { ImageBox } from '../views/nodes/ImageBox'; import { KeyValueBox } from '../views/nodes/KeyValueBox'; @@ -52,14 +52,14 @@ import { RecordingBox } from '../views/nodes/RecordingBox/RecordingBox'; import { ScreenshotBox } from '../views/nodes/ScreenshotBox'; import { ScriptingBox } from '../views/nodes/ScriptingBox'; import { TaskCompletionBox } from '../views/nodes/TaskCompletedBox'; -import { PresBox } from '../views/nodes/trails/PresBox'; -import { PresElementBox } from '../views/nodes/trails/PresElementBox'; import { VideoBox } from '../views/nodes/VideoBox'; import { WebBox } from '../views/nodes/WebBox'; +import { CalendarBox } from '../views/nodes/calendarBox/CalendarBox'; +import { FormattedTextBox } from '../views/nodes/formattedText/FormattedTextBox'; +import { PresBox } from '../views/nodes/trails/PresBox'; +import { PresElementBox } from '../views/nodes/trails/PresElementBox'; import { SearchBox } from '../views/search/SearchBox'; import { CollectionViewType, DocumentType } from './DocumentTypes'; -import { CalendarBox } from '../views/nodes/calendarBox/CalendarBox'; -import { OpenWhere } from '../views/nodes/DocumentView'; const { default: { DFLT_IMAGE_NATIVE_DIM } } = require('../views/global/globalCssVariables.module.scss'); // prettier-ignore const defaultNativeImageDim = Number(DFLT_IMAGE_NATIVE_DIM.replace('px', '')); @@ -204,6 +204,7 @@ export class DocumentOptions { overlayX?: NUMt = new NumInfo('horizontal coordinate in overlay view', false); overlayY?: NUMt = new NumInfo('vertical coordinate in overlay view', false); text?: RTFt = new RtfInfo('plain or rich text', true); + text_html?: STRt = new StrInfo('plain text or html', true); _dimMagnitude?: NUMt = new NumInfo("magnitude of collectionMulti{row,col} element's width or height", false); _dimUnit?: DIMt = new DimInfo("units of collectionMulti{row,col} element's width or height - 'px' or '*' for pixels or relative units"); latitude?: NUMt = new NumInfo('latitude coordinate', false); diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 11f6c82ec..f4599f04a 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -321,9 +321,9 @@ export class CurrentUserUtils { {type:"text",text:" "}, {type:"text",text:"Minerals in my tap water"}, {type:"text",text:"\n \"Calcium\" : "}, - {type:"dashField",attrs:{fieldKey:"calcium",docId:"","hideKey":false,editable:true}}, + {type:"dashField",attrs:{fieldKey:"calcium",docId:"",hideKey:false,hideValue:false,editable:true}}, {type:"text",text:"\n \"Potassium\" : "}, - {type:"dashField",attrs:{fieldKey:"pot",docId:"",hideKey:false,editable:true}}, + {type:"dashField",attrs:{fieldKey:"pot",docId:"",hideKey:false,hideValue:false,editable:true}}, {type:"text",text:"\n \"Magnesium\" : 10.01"} ]} ]}, diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx index c29474fcd..0b68fd59e 100644 --- a/src/client/views/MarqueeAnnotator.tsx +++ b/src/client/views/MarqueeAnnotator.tsx @@ -89,6 +89,7 @@ export class MarqueeAnnotator extends ObservableReactComponent, pivotDoc: Do y: -y + (pivotAxisWidth - hgt) / 2, width: wid, height: hgt, + backgroundColor: StrCast(layoutDoc.backgroundColor), pair: { layout: doc }, replica: val.replicas[i], }); diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx index 927e6fad4..36dad2747 100644 --- a/src/client/views/nodes/MapBox/MapBox.tsx +++ b/src/client/views/nodes/MapBox/MapBox.tsx @@ -6,7 +6,7 @@ import { IconButton, Size, Type } from 'browndash-components'; import * as d3 from 'd3'; import { Feature, FeatureCollection, GeoJsonProperties, Geometry, LineString, Position } from 'geojson'; import mapboxgl, { LngLat, LngLatBoundsLike, MapLayerMouseEvent } from 'mapbox-gl'; -import { IReactionDisposer, ObservableMap, action, autorun, computed, makeObservable, observable, reaction, runInAction } from 'mobx'; +import { IReactionDisposer, ObservableMap, action, autorun, computed, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { CirclePicker, ColorResult } from 'react-color'; @@ -14,7 +14,6 @@ import { Layer, MapProvider, MapRef, Map as MapboxMap, Marker, Source, ViewState import { MarkerEvent } from 'react-map-gl/dist/esm/types'; import { Utils, emptyFunction, setupMoveUpEvents } from '../../../../Utils'; import { Doc, DocListCast, Field, LinkedTo, Opt } from '../../../../fields/Doc'; -import { DocCss, Highlight } from '../../../../fields/DocSymbols'; import { DocCast, NumCast, StrCast } from '../../../../fields/Types'; import { DocumentType } from '../../../documents/DocumentTypes'; import { DocUtils, Docs } from '../../../documents/Documents'; @@ -28,7 +27,7 @@ import { SidebarAnnos } from '../../SidebarAnnos'; import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm'; import { Colors } from '../../global/globalEnums'; import { DocumentView } from '../DocumentView'; -import { FocusViewOptions, FieldView, FieldViewProps } from '../FieldView'; +import { FieldView, FieldViewProps, FocusViewOptions } from '../FieldView'; import { FormattedTextBox } from '../formattedText/FormattedTextBox'; import { PinProps, PresBox } from '../trails'; import { fastSpeedIcon, mediumSpeedIcon, slowSpeedIcon } from './AnimationSpeedIcons'; @@ -53,7 +52,6 @@ import { MarkerIcons } from './MarkerIcons'; * A map marker is considered a document that contains a collection with stacking view of documents, it has a lat, lng location, which is passed to Maps API's custom marker (red pin) to be rendered on the google maps */ -const bingApiKey = process.env.BING_MAPS; // if you're running local, get a Bing Maps api key here: https://www.bingmapsportal.com/ and then add it to the .env file in the Dash-Web root directory as: _CLIENT_BING_MAPS= const MAPBOX_ACCESS_TOKEN = 'pk.eyJ1IjoiemF1bHRhdmFuZ2FyIiwiYSI6ImNscHgwNDd1MDA3MXIydm92ODdianp6cGYifQ.WFAqbhwxtMHOWSPtu0l2uQ'; const MAPBOX_FORWARD_GEOCODE_BASE_URL = 'https://api.mapbox.com/geocoding/v5/mapbox.places/'; @@ -66,72 +64,69 @@ type PopupInfo = { description: string; }; -// export type GeocoderControlProps = Omit & { -// mapboxAccessToken: string; -// marker?: Omit; -// position: ControlPosition; - -// onResult: (...args: any[]) => void; -// }; - -type MapMarker = { - longitude: number; - latitude: number; -}; - -/** - * Consider integrating later: allows for drawing, circling, making shapes on map - */ -// const drawingManager = new window.google.maps.drawing.DrawingManager({ -// drawingControl: true, -// drawingControlOptions: { -// position: google.maps.ControlPosition.TOP_RIGHT, -// drawingModes: [ -// google.maps.drawing.OverlayType.MARKER, -// // currently we are not supporting the following drawing mode on map, a thought for future development -// google.maps.drawing.OverlayType.CIRCLE, -// google.maps.drawing.OverlayType.POLYLINE, -// ], -// }, -// }); - @observer export class MapBox extends ViewBoxAnnotatableComponent() implements ViewBoxInterface { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(MapBox, fieldKey); } - private _dragRef = React.createRef(); + private _unmounting = false; private _sidebarRef = React.createRef(); private _ref: React.RefObject = React.createRef(); private _mapRef: React.RefObject = React.createRef(); private _disposers: { [key: string]: IReactionDisposer } = {}; - private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean, hide: boolean, doc: Opt) => void); constructor(props: FieldViewProps) { super(props); makeObservable(this); } - @observable private _savedAnnotations = new ObservableMap(); - @computed get allSidebarDocs() { - return DocListCast(this.dataDoc[this.SidebarKey]); - } + @observable _featuresFromGeocodeResults: any[] = []; + @observable _savedAnnotations = new ObservableMap(); + @observable _selectedPinOrRoute: Doc | undefined = undefined; // The pin that is selected + @observable _mapReady = false; + @observable _isAnimating: boolean = false; + @observable _routeToAnimate: Doc | undefined = undefined; + @observable _animationPhase: number = 0; + @observable _finishedFlyTo: boolean = false; + @observable _frameId: number | null = null; + @observable _animationUtility: AnimationUtility | null = null; + @observable _settingsOpen: boolean = false; + @observable _mapStyle: string = 'mapbox://styles/mapbox/standard'; + @observable _showTerrain: boolean = true; + @observable _currentPopup: PopupInfo | undefined = undefined; + @observable _isStreetViewAnimation: boolean = false; + @observable _animationSpeed: AnimationSpeed = AnimationSpeed.MEDIUM; + @observable _animationLineColor: string = '#ffff00'; + @observable _temporaryRouteSource: FeatureCollection = { type: 'FeatureCollection', features: [] }; + @observable _dynamicRouteFeature: Feature = { + type: 'Feature', + properties: {}, + geometry: { type: 'LineString', coordinates: [] }, + }; + + @observable path: turf.helpers.Feature = { + type: 'Feature', + geometry: { type: 'LineString', coordinates: [] }, + properties: {}, + }; + // this list contains pushpins and configs - @computed get allAnnotations() { - return DocListCast(this.dataDoc[this.annotationKey]); - } - @computed get allPushpins() { - return this.allAnnotations.filter(anno => anno.type === DocumentType.PUSHPIN); - } - @computed get allRoutes() { - return this.allAnnotations.filter(anno => anno.type === DocumentType.MAPROUTE); + @computed get allAnnotations() { return DocListCast(this.dataDoc[this.annotationKey]); } //prettier-ignore + @computed get allSidebarDocs() { return DocListCast(this.dataDoc[this.SidebarKey]); } //prettier-ignore + @computed get allPushpins() { return this.allAnnotations.filter(anno => anno.type === DocumentType.PUSHPIN); } //prettier-ignore + @computed get allRoutes() { return this.allAnnotations.filter(anno => anno.type === DocumentType.MAPROUTE); } //prettier-ignore + @computed get SidebarShown() { return this.layoutDoc._layout_showSidebar ? true : false; } //prettier-ignore + @computed get sidebarWidthPercent() { return StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%'); } //prettier-ignore + @computed get SidebarKey() { return this.fieldKey + '_sidebar'; } //prettier-ignore + @computed get sidebarColor() { + return StrCast(this.layoutDoc.sidebar_color, StrCast(this.layoutDoc[this._props.fieldKey + '_backgroundColor'], '#e4e4e4')); } @computed get updatedRouteCoordinates(): Feature { - if (this.routeToAnimate?.routeCoordinates) { - const originalCoordinates: Position[] = JSON.parse(StrCast(this.routeToAnimate.routeCoordinates)); + if (this._routeToAnimate?.routeCoordinates) { + const originalCoordinates: Position[] = JSON.parse(StrCast(this._routeToAnimate.routeCoordinates)); // const index = Math.floor(this.animationPhase * originalCoordinates.length); - const index = this.animationPhase * (originalCoordinates.length - 1); // Calculate the fractional index - console.log('Animation phase', this.animationPhase); + const index = this._animationPhase * (originalCoordinates.length - 1); // Calculate the fractional index + console.log('Animation phase', this._animationPhase); const startIndex = Math.floor(index); const endIndex = Math.ceil(index); let feature: Feature; @@ -147,7 +142,7 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem feature = { type: 'Feature', properties: { - routeTitle: StrCast(this.routeToAnimate.title), + routeTitle: StrCast(this._routeToAnimate.title), }, geometry: geometry, }; @@ -158,9 +153,7 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem const fraction = index - startIndex; const interpolator = d3.interpolateArray(startCoord, endCoord); - const interpolatedCoord = interpolator(fraction); - const coordinates = originalCoordinates.slice(0, startIndex + 1).concat([interpolatedCoord]); geometry = { @@ -170,14 +163,14 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem feature = { type: 'Feature', properties: { - routeTitle: StrCast(this.routeToAnimate.title), + routeTitle: StrCast(this._routeToAnimate.title), }, geometry: geometry, }; } autorun(() => { - const animationUtil = this.animationUtility; + const animationUtil = this._animationUtility; const concattedCoordinates = geometry.coordinates.concat(originalCoordinates.slice(endIndex)); const newFeature: Feature = { type: 'Feature', @@ -204,11 +197,7 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem }; } @computed get selectedRouteCoordinates(): Position[] { - let coordinates: Position[] = []; - if (this.routeToAnimate?.routeCoordinates) { - coordinates = JSON.parse(StrCast(this.routeToAnimate.routeCoordinates)); - } - return coordinates; + return !this._routeToAnimate?.routeCoordinates ? [] : JSON.parse(StrCast(this._routeToAnimate.routeCoordinates)); } @computed get allRoutesGeoJson(): FeatureCollection { @@ -233,29 +222,14 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem }; } - @computed get SidebarShown() { - return this.layoutDoc._layout_showSidebar ? true : false; - } - @computed get sidebarWidthPercent() { - return StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%'); - } - @computed get sidebarColor() { - return StrCast(this.layoutDoc.sidebar_color, StrCast(this.layoutDoc[this._props.fieldKey + '_backgroundColor'], '#e4e4e4')); - } - @computed get SidebarKey() { - return this.fieldKey + '_sidebar'; - } - componentDidMount() { this._unmounting = false; this._props.setContentViewBox?.(this); } - _unmounting = false; - componentWillUnmount(): void { + componentWillUnmount() { this._unmounting = true; this.deselectPinOrRoute(); - this._rerenderTimeout && clearTimeout(this._rerenderTimeout); Object.keys(this._disposers).forEach(key => this._disposers[key]?.()); } @@ -269,7 +243,7 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem if (!this.layoutDoc._layout_showSidebar) this.toggleSidebar(); const docs = doc instanceof Doc ? [doc] : doc; docs.forEach(doc => { - let existingPin = this.allPushpins.find(pin => pin.latitude === doc.latitude && pin.longitude === doc.longitude) ?? this.selectedPinOrRoute; + let existingPin = this.allPushpins.find(pin => pin.latitude === doc.latitude && pin.longitude === doc.longitude) ?? this._selectedPinOrRoute; if (doc.latitude !== undefined && doc.longitude !== undefined && !existingPin) { existingPin = this.createPushpin(NumCast(doc.latitude), NumCast(doc.longitude), StrCast(doc.map)); } @@ -370,10 +344,10 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem const sourceAnchorCreator = action(() => { const note = this.getAnchor(true); - if (note && this.selectedPinOrRoute) { - note.latitude = this.selectedPinOrRoute.latitude; - note.longitude = this.selectedPinOrRoute.longitude; - note.map = this.selectedPinOrRoute.map; + if (note && this._selectedPinOrRoute) { + note.latitude = this._selectedPinOrRoute.latitude; + note.longitude = this._selectedPinOrRoute.longitude; + note.map = this._selectedPinOrRoute.map; } return note as Doc; }); @@ -399,10 +373,10 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem const createFunc = undoable( action(() => { const note = this._sidebarRef.current?.anchorMenuClick(this.getAnchor(true), ['latitude', 'longitude', LinkedTo]); - if (note && this.selectedPinOrRoute) { - note.latitude = this.selectedPinOrRoute.latitude; - note.longitude = this.selectedPinOrRoute.longitude; - note.map = this.selectedPinOrRoute.map; + if (note && this._selectedPinOrRoute) { + note.latitude = this._selectedPinOrRoute.latitude; + note.longitude = this._selectedPinOrRoute.longitude; + note.map = this._selectedPinOrRoute.map; } }), 'create note annotation' @@ -423,12 +397,7 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem return false; }; - setPreviewCursor = (func?: (x: number, y: number, drag: boolean, hide: boolean, doc: Opt) => void) => (this._setPreviewCursor = func); - - addDocumentWrapper = (doc: Doc | Doc[], annotationKey?: string) => this.addDocument(doc, annotationKey); - pointerEvents = () => (this._props.isContentActive() && !MarqueeOptionsMenu.Instance.isShown() ? 'all' : 'none'); - panelWidth = () => this._props.PanelWidth() / (this._props.NativeDimScaling?.() || 1) - this.sidebarWidth(); panelHeight = () => this._props.PanelHeight() / (this._props.NativeDimScaling?.() || 1); scrollXf = () => this.ScreenToLocalBoxXf().translate(0, NumCast(this.layoutDoc._layout_scrollTop)); @@ -439,52 +408,9 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick; savedAnnotations = () => this._savedAnnotations; - _bingSearchManager: any; - _bingMap: any; - get MicrosoftMaps() { - return (window as any).Microsoft.Maps; - } - // uses Bing Search to retrieve lat/lng for a location. eg., - // const results = this.geocodeQuery(map.map, 'Philadelphia, PA'); - // to move the map to that location: - // const location = await this.geocodeQuery(this._bingMap, 'Philadelphia, PA'); - // this._bingMap.current.setView({ - // mapTypeId: this.MicrosoftMaps.MapTypeId.aerial, - // center: new this.MicrosoftMaps.Location(loc.latitude, loc.longitude), - // }); - // - bingGeocode = (map: any, query: string) => { - return new Promise<{ latitude: number; longitude: number }>((res, reject) => { - //If search manager is not defined, load the search module. - if (!this._bingSearchManager) { - //Create an instance of the search manager and call the geocodeQuery function again. - this.MicrosoftMaps.loadModule('Microsoft.Maps.Search', () => { - this._bingSearchManager = new this.MicrosoftMaps.Search.SearchManager(map.current); - res(this.bingGeocode(map, query)); - }); - } else { - this._bingSearchManager.geocode({ - where: query, - callback: action((r: any) => res(r.results[0].location)), - errorCallback: (e: any) => reject(), - }); - } - }); - }; - - @observable - bingSearchBarContents: any = this.Document.map; // For Bing Maps: The contents of the Bing search bar (string) - - geoDataRequestOptions = { - entityType: 'PopulatedPlace', - }; - - // The pin that is selected - @observable selectedPinOrRoute: Doc | undefined = undefined; - @action deselectPinOrRoute = () => { - if (this.selectedPinOrRoute) { + if (this._selectedPinOrRoute) { // // Removes filter // Doc.setDocFilter(this.Document, 'latitude', this.selectedPin.latitude, 'remove'); // Doc.setDocFilter(this.Document, 'longitude', this.selectedPin.longitude, 'remove'); @@ -511,79 +437,6 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem } return new Promise>(res => DocumentManager.Instance.AddViewRenderedCb(doc, dv => res(dv))); }; - /* - * Pushpin onclick - */ - @action - pushpinClicked = (pinDoc: Doc) => { - this.deselectPinOrRoute(); - this.selectedPinOrRoute = pinDoc; - this.bingSearchBarContents = pinDoc.map; - - // Doc.setDocFilter(this.Document, 'latitude', this.selectedPin.latitude, 'match'); - // Doc.setDocFilter(this.Document, 'longitude', this.selectedPin.longitude, 'match'); - Doc.setDocFilter(this.Document, LinkedTo, `mapPin=${Field.toScriptString(this.selectedPinOrRoute)}`, 'check'); - - this.recolorPin(this.selectedPinOrRoute, 'green'); - - MapAnchorMenu.Instance.Delete = this.deleteSelectedPinOrRoute; - MapAnchorMenu.Instance.Center = this.centerOnSelectedPin; - MapAnchorMenu.Instance.OnClick = this.createNoteAnnotation; - MapAnchorMenu.Instance.StartDrag = this.startAnchorDrag; - - const point = this._bingMap.current.tryLocationToPixel(new this.MicrosoftMaps.Location(this.selectedPinOrRoute.latitude, this.selectedPinOrRoute.longitude)); - const x = point.x + (this._props.PanelWidth() - this.sidebarWidth()) / 2; - const y = point.y + this._props.PanelHeight() / 2 + 32; - const cpt = this.ScreenToLocalBoxXf().inverse().transformPoint(x, y); - MapAnchorMenu.Instance.jumpTo(cpt[0], cpt[1], true); - - document.addEventListener('pointerdown', this.tryHideMapAnchorMenu, true); - }; - - /** - * Map OnClick - */ - @action - mapOnClick = (e: { location: { latitude: any; longitude: any } }) => { - this._props.select(false); - this.deselectPinOrRoute(); - }; - /* - * Updates values of layout doc to match the current map - */ - @action - mapRecentered = () => { - if ( - Math.abs(NumCast(this.dataDoc.latitude) - this._bingMap.current.getCenter().latitude) > 1e-7 || // - Math.abs(NumCast(this.dataDoc.longitude) - this._bingMap.current.getCenter().longitude) > 1e-7 - ) { - this.dataDoc.latitude = this._bingMap.current.getCenter().latitude; - this.dataDoc.longitude = this._bingMap.current.getCenter().longitude; - this.dataDoc.map = ''; - this.bingSearchBarContents = ''; - } - this.dataDoc.map_zoom = this._bingMap.current.getZoom(); - }; - /* - * Updates maptype - */ - @action - updateMapType = () => (this.dataDoc.map_type = this._bingMap.current.getMapTypeId()); - - /* - * For Bing Maps - * Called by search button's onClick - * Finds the geocode of the searched contents and sets location to that location - **/ - @action - bingSearch = () => { - return this.bingGeocode(this._bingMap, this.bingSearchBarContents).then(location => { - this.dataDoc.latitude = location.latitude; - this.dataDoc.longitude = location.longitude; - this.dataDoc.map_zoom = this._bingMap.current.getZoom(); - this.dataDoc.map = this.bingSearchBarContents; - }); - }; /* * Returns doc w/ relevant info @@ -592,14 +445,14 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem /// this should use SELECTED pushpin for lat/long if there is a selection, otherwise CENTER const anchor = Docs.Create.ConfigDocument({ title: 'MapAnchor:' + this.Document.title, - text: (StrCast(this.selectedPinOrRoute?.map) || StrCast(this.Document.map) || 'map location') as any, - config_latitude: NumCast((existingPin ?? this.selectedPinOrRoute)?.latitude ?? this.dataDoc.latitude), - config_longitude: NumCast((existingPin ?? this.selectedPinOrRoute)?.longitude ?? this.dataDoc.longitude), + text: (StrCast(this._selectedPinOrRoute?.map) || StrCast(this.Document.map) || 'map location') as any, + config_latitude: NumCast((existingPin ?? this._selectedPinOrRoute)?.latitude ?? this.dataDoc.latitude), + config_longitude: NumCast((existingPin ?? this._selectedPinOrRoute)?.longitude ?? this.dataDoc.longitude), config_map_zoom: NumCast(this.dataDoc.map_zoom), // config_map_type: StrCast(this.dataDoc.map_type), - config_map: StrCast((existingPin ?? this.selectedPinOrRoute)?.map) || StrCast(this.dataDoc.map), + config_map: StrCast((existingPin ?? this._selectedPinOrRoute)?.map) || StrCast(this.dataDoc.map), layout_unrendered: true, - mapPin: existingPin ?? this.selectedPinOrRoute, + mapPin: existingPin ?? this._selectedPinOrRoute, annotationOn: this.Document, }); if (anchor) { @@ -613,25 +466,6 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem map_docToPinMap = new Map(); map_pinHighlighted = new Map(); - /* - * Input: pin doc - * Adds MicrosoftMaps Pushpin to the map (render) - */ - @action - addPushpin = (pin: Doc) => { - const pushPin = pin.infoWindowOpen - ? new this.MicrosoftMaps.Pushpin(new this.MicrosoftMaps.Location(pin.latitude, pin.longitude), {}) - : new this.MicrosoftMaps.Pushpin( - new this.MicrosoftMaps.Location(pin.latitude, pin.longitude) - // {icon: 'http://icons.iconarchive.com/icons/icons-land/vista-map-markers/24/Map-Marker-Marker-Outside-Chartreuse-icon.png'} - ); - - this._bingMap.current.entities.push(pushPin); - - this.MicrosoftMaps.Events.addHandler(pushPin, 'click', (e: any) => this.pushpinClicked(pin)); - // this.MicrosoftMaps.Events.addHandler(pushPin, 'dblclick', (e: any) => this.pushpinDblClicked(pushPin, pin)); - this.map_docToPinMap.set(pin, pushPin); - }; /* * Input: pin doc @@ -640,27 +474,16 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem @action removePushpinOrRoute = (pinOrRouteDoc: Doc) => this.removeMapDocument(pinOrRouteDoc, this.annotationKey); - /* - * Removes pushpin from map render - */ - deletePushpin = (pinDoc: Doc) => { - if (!this._unmounting) { - this._bingMap.current.entities.remove(this.map_docToPinMap.get(pinDoc)); - } - this.map_docToPinMap.delete(pinDoc); - this.selectedPinOrRoute = undefined; - }; - @action deleteSelectedPinOrRoute = undoable(() => { console.log('deleting'); - if (this.selectedPinOrRoute) { + if (this._selectedPinOrRoute) { // Removes filter - Doc.setDocFilter(this.Document, 'latitude', this.selectedPinOrRoute.latitude, 'remove'); - Doc.setDocFilter(this.Document, 'longitude', this.selectedPinOrRoute.longitude, 'remove'); - Doc.setDocFilter(this.Document, LinkedTo, `mapPin=${Field.toScriptString(DocCast(this.selectedPinOrRoute))}`, 'remove'); + Doc.setDocFilter(this.Document, 'latitude', this._selectedPinOrRoute.latitude, 'remove'); + Doc.setDocFilter(this.Document, 'longitude', this._selectedPinOrRoute.longitude, 'remove'); + Doc.setDocFilter(this.Document, LinkedTo, `mapPin=${Field.toScriptString(DocCast(this._selectedPinOrRoute))}`, 'remove'); - this.removePushpinOrRoute(this.selectedPinOrRoute); + this.removePushpinOrRoute(this._selectedPinOrRoute); } MapAnchorMenu.Instance.fadeOut(true); document.removeEventListener('pointerdown', this.tryHideMapAnchorMenu, true); @@ -677,7 +500,7 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem e.preventDefault(); MapAnchorMenu.Instance.fadeOut(true); runInAction(() => { - this.temporaryRouteSource = { + this._temporaryRouteSource = { type: 'FeatureCollection', features: [], }; @@ -688,9 +511,9 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem @action centerOnSelectedPin = () => { - if (this.selectedPinOrRoute) { + if (this._selectedPinOrRoute) { this._mapRef.current?.flyTo({ - center: [NumCast(this.selectedPinOrRoute.longitude), NumCast(this.selectedPinOrRoute.latitude)], + center: [NumCast(this._selectedPinOrRoute.longitude), NumCast(this._selectedPinOrRoute.latitude)], }); } // if (this.selectedPin) { @@ -703,33 +526,6 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem document.removeEventListener('pointerdown', this.tryHideMapAnchorMenu); }; - /** - * View options for bing maps - */ - bingViewOptions = { - // center: { latitude: this.dataDoc.latitude ?? defaultCenter.lat, longitude: this.dataDoc.longitude ?? defaultCenter.lng }, - zoom: this.dataDoc.latitude ?? 10, - mapTypeId: 'grayscale', - }; - - /** - * Map options - */ - bingMapOptions = { - navigationBarMode: 'square', - backgroundColor: '#f1f3f4', - enableInertia: true, - supportedMapTypes: ['grayscale', 'canvasLight'], - disableMapTypeSelectorMouseOver: true, - // showScalebar:true - // disableRoadView:true, - // disableBirdseye:true - streetsideOptions: { - showProblemReporting: false, - showCurrentAddress: false, - }, - }; - recolorPin = (pin: Doc, color?: string) => { // this._bingMap.current.entities.remove(this.map_docToPinMap.get(pin)); // this.map_docToPinMap.delete(pin); @@ -739,109 +535,6 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem // this.map_docToPinMap.set(pin, newpin); }; - /* - * Called when BingMap is first rendered - * Initializes starting values - */ - @observable _mapReady = false; - @action - bingMapReady = (map: any) => { - this._mapReady = true; - this._bingMap = map.map; - if (!this._bingMap.current) { - alert('NO Map!?'); - } - this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'click', this.mapOnClick); - this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'viewchangeend', undoable(this.mapRecentered, 'Map Layout Change')); - this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'maptypechanged', undoable(this.updateMapType, 'Map ViewType Change')); - - this._disposers.mapLocation = reaction( - () => this.Document.map, - mapLoc => (this.bingSearchBarContents = mapLoc), - { fireImmediately: true } - ); - this._disposers.highlight = reaction( - () => this.allAnnotations.map(doc => doc[Highlight]), - () => { - const allConfigPins = this.allAnnotations.map(doc => ({ doc, pushpin: DocCast(doc.mapPin) })).filter(pair => pair.pushpin); - allConfigPins.forEach(({ doc, pushpin }) => { - if (!pushpin[Highlight] && this.map_pinHighlighted.get(pushpin)) { - this.recolorPin(pushpin); - this.map_pinHighlighted.delete(pushpin); - } - }); - allConfigPins.forEach(({ doc, pushpin }) => { - if (doc[Highlight] && !this.map_pinHighlighted.get(pushpin)) { - this.recolorPin(pushpin, 'orange'); - this.map_pinHighlighted.set(pushpin, true); - } - }); - }, - { fireImmediately: true } - ); - - this._disposers.location = reaction( - () => ({ lat: this.Document.latitude, lng: this.Document.longitude, zoom: this.Document.map_zoom, mapType: this.Document.map_type }), - locationObject => { - // if (this._bingMap.current) - try { - locationObject?.zoom && - this._bingMap.current?.setView({ - mapTypeId: locationObject.mapType, - zoom: locationObject.zoom, - center: new this.MicrosoftMaps.Location(locationObject.lat, locationObject.lng), - }); - } catch (e) { - console.log(e); - } - }, - { fireImmediately: true } - ); - }; - - dragToggle = (e: React.PointerEvent) => { - let dragClone: HTMLDivElement | undefined; - - setupMoveUpEvents( - e, - e, - e => { - // move event - if (!dragClone) { - dragClone = this._dragRef.current?.cloneNode(true) as HTMLDivElement; // copy draggable pin - dragClone.style.position = 'absolute'; - dragClone.style.zIndex = '10000'; - DragManager.Root().appendChild(dragClone); // add clone to root - } - dragClone.style.transform = `translate(${e.clientX - 15}px, ${e.clientY - 15}px)`; - return false; - }, - e => { - // up event - if (!dragClone) return; - DragManager.Root().removeChild(dragClone); - let target = document.elementFromPoint(e.x, e.y); // element for specified x and y coordinates - while (target) { - if (target === this._ref.current) { - const cpt = this.ScreenToLocalBoxXf().transformPoint(e.clientX, e.clientY); - const x = cpt[0] - (this._props.PanelWidth() - this.sidebarWidth()) / 2; - const y = cpt[1] - 20 /* height of search bar */ - this._props.PanelHeight() / 2; - const location = this._bingMap.current.tryPixelToLocation(new this.MicrosoftMaps.Point(x, y)); - this.createPushpin(location.latitude, location.longitude); - break; - } - target = target.parentElement; - } - }, - e => { - const createPin = () => this.createPushpin(this.Document.latitude, this.Document.longitude, this.Document.map); - if (this.bingSearchBarContents) { - this.bingSearch().then(createPin); - } else createPin(); - } - ); - }; - // incrementer: number = 0; /* * Creates Pushpin doc and adds it to the list of annotations @@ -880,7 +573,7 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem if (createPinForDestination) { this.createPushpin(destination.center[1], destination.center[0], destination.place_name); } - this.temporaryRouteSource = { + this._temporaryRouteSource = { type: 'FeatureCollection', features: [], }; @@ -890,10 +583,14 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem // TODO: Display error that can't create route to same location }, 'createmaproute'); - searchbarKeyDown = (e: any) => e.key === 'Enter' && this.bingSearch(); - - @observable - featuresFromGeocodeResults: any[] = []; + @action + searchbarKeyDown = (e: any) => { + if (e.key === 'Enter' && this._featuresFromGeocodeResults) { + const center = this._featuresFromGeocodeResults[0]?.center; + this._featuresFromGeocodeResults = []; + setTimeout(() => center && this._mapRef.current?.flyTo({ center })); + } + }; @action addMarkerForFeature = (feature: any) => { @@ -910,7 +607,7 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem center: feature.center, }); } - this.featuresFromGeocodeResults = []; + this._featuresFromGeocodeResults = []; } else { // TODO: handle error } @@ -922,11 +619,11 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem */ handleSearchChange = async (searchText: string) => { const features = await MapboxApiUtility.forwardGeocodeForFeatures(searchText); - if (features && !this.isAnimating) { + if (features && !this._isAnimating) { runInAction(() => { - this.settingsOpen = false; - this.featuresFromGeocodeResults = features; - this.routeToAnimate = undefined; + this._settingsOpen = false; + this._featuresFromGeocodeResults = features; + this._routeToAnimate = undefined; }); } // try { @@ -946,8 +643,8 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem @action handleMapClick = (e: MapLayerMouseEvent) => { - this.featuresFromGeocodeResults = []; - this.settingsOpen = false; + this._featuresFromGeocodeResults = []; + this._settingsOpen = false; if (this._mapRef.current) { const features = this._mapRef.current.queryRenderedFeatures(e.point, { layers: ['map-routes-layer'], @@ -960,8 +657,8 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem const routeDoc: Doc | undefined = this.allRoutes.find(routeDoc => routeDoc.title === routeTitle); this.deselectPinOrRoute(); // TODO: Also deselect route if selected if (routeDoc) { - this.selectedPinOrRoute = routeDoc; - Doc.setDocFilter(this.Document, LinkedTo, `mapRoute=${Field.toScriptString(this.selectedPinOrRoute)}`, 'check'); + this._selectedPinOrRoute = routeDoc; + Doc.setDocFilter(this.Document, LinkedTo, `mapRoute=${Field.toScriptString(this._selectedPinOrRoute)}`, 'check'); // TODO: Recolor route @@ -1008,7 +705,7 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem const features = await MapboxApiUtility.reverseGeocodeForFeatures(longitude, latitude); if (features) { runInAction(() => { - this.featuresFromGeocodeResults = features; + this._featuresFromGeocodeResults = features; }); } @@ -1028,21 +725,18 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem // } }; - @observable - currentPopup: PopupInfo | undefined = undefined; - @action handleMarkerClick = (e: MarkerEvent, pinDoc: Doc) => { - this.featuresFromGeocodeResults = []; + this._featuresFromGeocodeResults = []; this.deselectPinOrRoute(); // TODO: check this method - this.selectedPinOrRoute = pinDoc; + this._selectedPinOrRoute = pinDoc; // this.bingSearchBarContents = pinDoc.map; // Doc.setDocFilter(this.Document, 'latitude', this.selectedPin.latitude, 'match'); // Doc.setDocFilter(this.Document, 'longitude', this.selectedPin.longitude, 'match'); - Doc.setDocFilter(this.Document, LinkedTo, `mapPin=${Field.toScriptString(this.selectedPinOrRoute)}`, 'check'); + Doc.setDocFilter(this.Document, LinkedTo, `mapPin=${Field.toScriptString(this._selectedPinOrRoute)}`, 'check'); - this.recolorPin(this.selectedPinOrRoute, 'green'); // TODO: check this method + this.recolorPin(this._selectedPinOrRoute, 'green'); // TODO: check this method MapAnchorMenu.Instance.Delete = this.deleteSelectedPinOrRoute; MapAnchorMenu.Instance.Center = this.centerOnSelectedPin; @@ -1072,12 +766,6 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem // }) }; - @observable - temporaryRouteSource: FeatureCollection = { - type: 'FeatureCollection', - features: [], - }; - @action displayRoute = (routeInfoMap: Record | undefined, type: TransportationType) => { if (routeInfoMap) { @@ -1096,41 +784,23 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem }; // TODO: Create pin for destination // TODO: Fly to point where full route will be shown - this.temporaryRouteSource = newTempRouteSource; + this._temporaryRouteSource = newTempRouteSource; } }; - @observable - isAnimating: boolean = false; - - @observable - routeToAnimate: Doc | undefined = undefined; - - @observable - animationPhase: number = 0; - - @observable - finishedFlyTo: boolean = false; - @action setAnimationPhase = (newValue: number) => { - this.animationPhase = newValue; + this._animationPhase = newValue; }; - @observable - frameId: number | null = null; - @action setFrameId = (frameId: number) => { - this.frameId = frameId; + this._frameId = frameId; }; - @observable - animationUtility: AnimationUtility | null = null; - @action setAnimationUtility = (util: AnimationUtility) => { - this.animationUtility = util; + this._animationUtility = util; }; @action @@ -1138,8 +808,8 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem if (routeDoc) { MapAnchorMenu.Instance.fadeOut(true); document.removeEventListener('pointerdown', this.tryHideMapAnchorMenu, true); - this.featuresFromGeocodeResults = []; - this.routeToAnimate = routeDoc; + this._featuresFromGeocodeResults = []; + this._routeToAnimate = routeDoc; } }; @@ -1161,29 +831,20 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem @computed get preAnimationViewState() { - if (!this.isAnimating) { + if (!this._isAnimating) { return this.mapboxMapViewState; } } - @observable - isStreetViewAnimation: boolean = false; - - @observable - animationSpeed: AnimationSpeed = AnimationSpeed.MEDIUM; - - @observable - animationLineColor: string = '#ffff00'; - @action setAnimationLineColor = (color: ColorResult) => { - this.animationLineColor = color.hex; + this._animationLineColor = color.hex; }; @action updateAnimationSpeed = () => { let newAnimationSpeed: AnimationSpeed; - switch (this.animationSpeed) { + switch (this._animationSpeed) { case AnimationSpeed.SLOW: newAnimationSpeed = AnimationSpeed.MEDIUM; break; @@ -1197,63 +858,33 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem newAnimationSpeed = AnimationSpeed.MEDIUM; break; } - this.animationSpeed = newAnimationSpeed; - if (this.animationUtility) { - this.animationUtility.updateAnimationSpeed(newAnimationSpeed); + this._animationSpeed = newAnimationSpeed; + if (this._animationUtility) { + this._animationUtility.updateAnimationSpeed(newAnimationSpeed); } }; @computed get animationSpeedTooltipText(): string { - switch (this.animationSpeed) { - case AnimationSpeed.SLOW: - return '1x speed'; - case AnimationSpeed.MEDIUM: - return '2x speed'; - case AnimationSpeed.FAST: - return '3x speed'; - default: - return '2x speed'; - } + switch (this._animationSpeed) { + case AnimationSpeed.SLOW: return '1x speed'; + case AnimationSpeed.MEDIUM: return '2x speed'; + case AnimationSpeed.FAST: return '3x speed'; + default: return '2x speed'; + } // prettier-ignore } @computed get animationSpeedIcon(): JSX.Element { - switch (this.animationSpeed) { - case AnimationSpeed.SLOW: - return slowSpeedIcon; - case AnimationSpeed.MEDIUM: - return mediumSpeedIcon; - case AnimationSpeed.FAST: - return fastSpeedIcon; - default: - return mediumSpeedIcon; - } + switch (this._animationSpeed) { + case AnimationSpeed.SLOW: return slowSpeedIcon; + case AnimationSpeed.MEDIUM: return mediumSpeedIcon; + case AnimationSpeed.FAST: return fastSpeedIcon; + default: return mediumSpeedIcon; + } // prettier-ignore } @action toggleIsStreetViewAnimation = () => { - const newVal = !this.isStreetViewAnimation; - this.isStreetViewAnimation = newVal; - if (this.animationUtility) { - this.animationUtility.updateIsStreetViewAnimation(newVal); - } - }; - - @observable - dynamicRouteFeature: Feature = { - type: 'Feature', - properties: {}, - geometry: { - type: 'LineString', - coordinates: [], - }, - }; - - @observable - path: turf.helpers.Feature = { - type: 'Feature', - geometry: { - type: 'LineString', - coordinates: [], - }, - properties: {}, + const newVal = !this._isStreetViewAnimation; + this._isStreetViewAnimation = newVal; + this._animationUtility?.updateIsStreetViewAnimation(newVal); }; getFeatureFromRouteDoc = (routeDoc: Doc): Feature => { @@ -1272,19 +903,19 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem @action playAnimation = (status: AnimationStatus) => { - if (!this._mapRef.current || !this.routeToAnimate) { + if (!this._mapRef.current || !this._routeToAnimate) { return; } - this.animationPhase = status === AnimationStatus.RESUME ? this.animationPhase : 0; - this.frameId = AnimationStatus.RESUME ? this.frameId : null; - this.finishedFlyTo = AnimationStatus.RESUME ? this.finishedFlyTo : false; + this._animationPhase = status === AnimationStatus.RESUME ? this._animationPhase : 0; + this._frameId = AnimationStatus.RESUME ? this._frameId : null; + this._finishedFlyTo = AnimationStatus.RESUME ? this._finishedFlyTo : false; const path = turf.lineString(this.selectedRouteCoordinates); - this.settingsOpen = false; + this._settingsOpen = false; this.path = path; - this.isAnimating = true; + this._isAnimating = true; runInAction(() => { return new Promise(async resolve => { @@ -1293,18 +924,11 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem lat: this.selectedRouteCoordinates[0][1], }; - const animationUtil = new AnimationUtility(targetLngLat, this.selectedRouteCoordinates, this.isStreetViewAnimation, this.animationSpeed, this.showTerrain, this._mapRef.current); - runInAction(() => { - this.setAnimationUtility(animationUtil); - }); - - const updateFrameId = (newFrameId: number) => { - this.setFrameId(newFrameId); - }; + const animationUtil = new AnimationUtility(targetLngLat, this.selectedRouteCoordinates, this._isStreetViewAnimation, this._animationSpeed, this._showTerrain, this._mapRef.current); + runInAction(() => this.setAnimationUtility(animationUtil)); - const updateAnimationPhase = (newAnimationPhase: number) => { - this.setAnimationPhase(newAnimationPhase); - }; + const updateFrameId = (newFrameId: number) => this.setFrameId(newFrameId); + const updateAnimationPhase = (newAnimationPhase: number) => this.setAnimationPhase(newAnimationPhase); if (status !== AnimationStatus.RESUME) { const result = await animationUtil.flyInAndRotate({ @@ -1324,9 +948,7 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem console.log('Altitude: ', result.altitude); } - runInAction(() => { - this.finishedFlyTo = true; - }); + runInAction(() => (this._finishedFlyTo = true)); // follow the path while slowly rotating the camera, passing in the camera bearing and altitude from the previous animation await animationUtil.animatePath({ @@ -1335,7 +957,7 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem // startBearing: -20, // startAltitude: this.isStreetViewAnimation ? 80 : 12000, // pitch: this.isStreetViewAnimation ? 80: 50, - currentAnimationPhase: this.animationPhase, + currentAnimationPhase: this._animationPhase, updateAnimationPhase, updateFrameId, }); @@ -1353,7 +975,7 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem }); setTimeout(() => { - this.isStreetViewAnimation = false; + this._isStreetViewAnimation = false; resolve(); }, 10000); }); @@ -1362,27 +984,27 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem @action pauseAnimation = () => { - if (this.frameId && this.animationPhase > 0) { - window.cancelAnimationFrame(this.frameId); - this.frameId = null; - this.isAnimating = false; + if (this._frameId && this._animationPhase > 0) { + window.cancelAnimationFrame(this._frameId); + this._frameId = null; + this._isAnimating = false; } }; @action stopAnimation = (close: boolean) => { - if (this.frameId) { - window.cancelAnimationFrame(this.frameId); + if (this._frameId) { + window.cancelAnimationFrame(this._frameId); } - this.animationPhase = 0; - this.frameId = null; - this.finishedFlyTo = false; - this.isAnimating = false; + this._animationPhase = 0; + this._frameId = null; + this._finishedFlyTo = false; + this._isAnimating = false; if (close) { - this.animationSpeed = AnimationSpeed.MEDIUM; - this.isStreetViewAnimation = false; - this.routeToAnimate = undefined; - this.animationUtility = null; + this._animationSpeed = AnimationSpeed.MEDIUM; + this._isStreetViewAnimation = false; + this._routeToAnimate = undefined; + this._animationUtility = null; } }; @@ -1390,21 +1012,21 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem return ( <> { - if (this.isAnimating && this.finishedFlyTo) { + if (this._isAnimating && this._finishedFlyTo) { this.pauseAnimation(); - } else if (this.animationPhase > 0) { + } else if (this._animationPhase > 0) { this.playAnimation(AnimationStatus.RESUME); // Resume from the current phase } else { this.playAnimation(AnimationStatus.START); // Play from the beginning } }} - icon={this.isAnimating && this.finishedFlyTo ? : } + icon={this._isAnimating && this._finishedFlyTo ? : } color="black" size={Size.MEDIUM} /> - {this.isAnimating && this.finishedFlyTo && ( + {this._isAnimating && this._finishedFlyTo && ( { @@ -1420,7 +1042,7 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem <>
|
- } /> + } />
|
|
@@ -1436,26 +1058,17 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem @action hideRoute = () => { - this.temporaryRouteSource = { + this._temporaryRouteSource = { type: 'FeatureCollection', features: [], }; }; - @observable - settingsOpen: boolean = false; - - @observable - mapStyle: string = 'mapbox://styles/mapbox/standard'; - - @observable - showTerrain: boolean = true; - @action toggleSettings = () => { - if (!this.isAnimating && this.animationPhase == 0) { - this.featuresFromGeocodeResults = []; - this.settingsOpen = !this.settingsOpen; + if (!this._isAnimating && this._animationPhase == 0) { + this._featuresFromGeocodeResults = []; + this._settingsOpen = !this._settingsOpen; } }; @@ -1500,14 +1113,10 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem @action onStepZoomChange = (increment: boolean) => { if (this._mapRef.current) { - let newZoom: number; - if (increment) { - console.log('inc'); - newZoom = Math.min(16, this.mapboxMapViewState.zoom + 1); - } else { - console.log('dec'); - newZoom = Math.max(0, this.mapboxMapViewState.zoom - 1); - } + const newZoom = increment // + ? Math.min(16, this.mapboxMapViewState.zoom + 1) + : Math.max(0, this.mapboxMapViewState.zoom - 1); + this._mapRef.current.setZoom(newZoom); this.dataDoc.map_zoom = newZoom; } @@ -1523,7 +1132,7 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem }; @action - toggleShowTerrain = () => (this.showTerrain = !this.showTerrain); + toggleShowTerrain = () => (this._showTerrain = !this._showTerrain); getMarkerIcon = (pinDoc: Doc): JSX.Element | null => { const markerType = StrCast(pinDoc.markerType); @@ -1532,25 +1141,8 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem return MarkerIcons.getFontAwesomeIcon(markerType, '2x', markerColor) ?? null; }; - static _firstRender = true; - static _rerenderDelay = 500; - _rerenderTimeout: any; + _textRef = React.createRef(); render() { - // bcz: no idea what's going on here, but bings maps have some kind of bug - // such that we need to delay rendering a second map on startup until the first map is rendered. - this.Document[DocCss]; - if (MapBox._rerenderDelay) { - // prettier-ignore - this._rerenderTimeout = this._rerenderTimeout ?? - setTimeout(action(() => { - if ((window as any).Microsoft?.Maps?.Internal._WorkDispatcher) { - MapBox._rerenderDelay = 0; - } - this._rerenderTimeout = undefined; - this.Document[DocCss] = this.Document[DocCss] + 1; - }), MapBox._rerenderDelay); - return null; - } const scale = this._props.NativeDimScaling?.() || 1; const parscale = scale === 1 ? 1 : this.ScreenToLocalBoxXf().Scale ?? 1; @@ -1560,20 +1152,18 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem
e.stopPropagation()} - onPointerDown={async e => { - e.button === 0 && !e.ctrlKey && e.stopPropagation(); - }} + onPointerDown={e => e.button === 0 && !e.ctrlKey && e.stopPropagation()} style={{ transformOrigin: 'top left', transform: `scale(${scale})`, width: `calc(100% - ${this.sidebarWidthPercent})`, pointerEvents: this.pointerEvents() }}>
{renderAnnotations(this.transparentFilter)}
{renderAnnotations(this.opaqueFilter)} {SnappingManager.IsDragging ? null : renderAnnotations()} - {!this.routeToAnimate && ( + {!this._routeToAnimate && (
- this.handleSearchChange(e.target.value)} /> + this.handleSearchChange(e.target.value)} /> } type={Type.TERT} onClick={e => this.toggleSettings()} />
)} - {this.settingsOpen && !this.routeToAnimate && ( + {this._settingsOpen && !this._routeToAnimate && (
Map Style:
@@ -1605,21 +1195,21 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem
Show terrain:
- +
)} - {this.routeToAnimate && ( + {this._routeToAnimate && (
-
{StrCast(this.routeToAnimate.title)}
+
{StrCast(this._routeToAnimate.title)}
{this.getRouteAnimationOptions()}
)} - {this.featuresFromGeocodeResults.length > 0 && ( + {this._featuresFromGeocodeResults.length > 0 && (
- + <>

Choose a location for your pin:

- {this.featuresFromGeocodeResults + {this._featuresFromGeocodeResults .filter(feature => feature.place_name) .map((feature, idx) => (
() implem
{feature.place_name}
))} -
+
)} () implem width: NumCast(this.layoutDoc._width) * parscale, height: NumCast(this.layoutDoc._height) * parscale, }} - initialViewState={this.isAnimating ? undefined : this.mapboxMapViewState} + initialViewState={this._isAnimating ? undefined : this.mapboxMapViewState} onZoom={this.onMapZoom} onMove={this.onMapMove} onClick={this.handleMapClick} onDblClick={this.handleMapDblClick} - terrain={this.showTerrain ? { source: 'mapbox-dem', exaggeration: 2.0 } : undefined}> + terrain={this._showTerrain ? { source: 'mapbox-dem', exaggeration: 2.0 } : undefined}> - + - {!this.isAnimating && this.animationPhase == 0 && } - {this.routeToAnimate && (this.isAnimating || this.animationPhase > 0) && ( + {!this._isAnimating && this._animationPhase == 0 && ( + + )} + {this._routeToAnimate && (this._isAnimating || this._animationPhase > 0) && ( <> - {!this.isStreetViewAnimation && ( + {!this._isStreetViewAnimation && ( <> () implem type="line" source="animated-route" paint={{ - 'line-color': this.animationLineColor, + 'line-color': this._animationLineColor, 'line-width': 5, }} /> @@ -1722,10 +1314,9 @@ export class MapBox extends ViewBoxAnnotatableComponent() implem )} <> - {!this.isAnimating && - this.animationPhase == 0 && - this.allPushpins - // .filter(anno => !anno.layout_unrendered) + {!this._isAnimating && + this._animationPhase == 0 && + this.allPushpins // .filter(anno => !anno.layout_unrendered) .map((pushpin, idx) => ( ) => this.handleMarkerClick(e, pushpin)}> {this.getMarkerIcon(pushpin)} diff --git a/src/client/views/nodes/MapBox/MapPushpinBox.tsx b/src/client/views/nodes/MapBox/MapPushpinBox.tsx index fc5b4dd18..8ebc90157 100644 --- a/src/client/views/nodes/MapBox/MapPushpinBox.tsx +++ b/src/client/views/nodes/MapBox/MapPushpinBox.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { ViewBoxBaseComponent } from '../../DocComponent'; import { FieldView, FieldViewProps } from '../FieldView'; -import { MapBox } from './MapBox'; +import { MapBoxContainer } from '../MapboxMapBox/MapboxContainer'; /** * Map Pushpin doc class @@ -18,7 +18,7 @@ export class MapPushpinBox extends ViewBoxBaseComponent() { } get mapBoxView() { - return this.DocumentView?.()?.containerViewPath?.().lastElement()?.ComponentView as MapBox; + return this.DocumentView?.()?.containerViewPath?.().lastElement()?.ComponentView as MapBoxContainer; } get mapBox() { return this.DocumentView?.().containerViewPath?.().lastElement()?.Document; diff --git a/src/client/views/nodes/RecordingBox/RecordingView.scss b/src/client/views/nodes/RecordingBox/RecordingView.scss index 287cccd8f..f2d5a980d 100644 --- a/src/client/views/nodes/RecordingBox/RecordingView.scss +++ b/src/client/views/nodes/RecordingBox/RecordingView.scss @@ -1,208 +1,200 @@ video { - // flex: 100%; - width: 100%; - // min-height: 400px; - //height: auto; - height: 100%; - //display: block; - object-fit: cover; - background-color: black; -} - -button { - margin: 0 .5rem + // flex: 100%; + width: 100%; + // min-height: 400px; + //height: auto; + height: 100%; + //display: block; + object-fit: cover; + background-color: black; } .recording-container { - height: 100%; - width: 100%; - // display: flex; - pointer-events: all; - background-color: black; + height: 100%; + width: 100%; + // display: flex; + pointer-events: all; + background-color: black; + button { + margin: 0 0.5rem; + } } .video-wrapper { - // max-width: 600px; - // max-width: 700px; - // position: relative; - display: flex; - justify-content: center; - // overflow: hidden; - border-radius: 10px; - margin: 0; + // max-width: 600px; + // max-width: 700px; + // position: relative; + display: flex; + justify-content: center; + // overflow: hidden; + border-radius: 10px; + margin: 0; } .video-wrapper:hover .controls { - bottom: 34.5px; - transform: translateY(0%); - opacity: 100%; + bottom: 34.5px; + transform: translateY(0%); + opacity: 100%; } .controls { - display: flex; - align-items: center; - justify-content: center; - position: absolute; - width: 100%; - flex-wrap: wrap; - background: rgba(255, 255, 255, 0.25); - box-shadow: 0 8px 32px 0 rgba(255, 255, 255, 0.1); - // backdrop-filter: blur(4px); - border-radius: 10px; - border: 1px solid rgba(255, 255, 255, 0.18); - transition: all 0.3s ease-in-out; - bottom: 34.5px; - height: 60px; + display: flex; + align-items: center; + justify-content: center; + position: absolute; + width: 100%; + flex-wrap: wrap; + background: rgba(255, 255, 255, 0.25); + box-shadow: 0 8px 32px 0 rgba(255, 255, 255, 0.1); + // backdrop-filter: blur(4px); + border-radius: 10px; + border: 1px solid rgba(255, 255, 255, 0.18); + transition: all 0.3s ease-in-out; + bottom: 34.5px; + height: 60px; } .controls:active { - bottom: 40px; + bottom: 40px; } .actions button { - background: none; - border: none; - outline: none; - cursor: pointer; + background: none; + border: none; + outline: none; + cursor: pointer; } .actions button i { - background-color: none; - color: white; - font-size: 30px; + background-color: none; + color: white; + font-size: 30px; } - .velocity { - appearance: none; - background: none; - color: white; - outline: none; - border: none; - text-align: center; - font-size: 16px; + appearance: none; + background: none; + color: white; + outline: none; + border: none; + text-align: center; + font-size: 16px; } .mute-btn { - background: none; - border: none; - outline: none; - cursor: pointer; + background: none; + border: none; + outline: none; + cursor: pointer; } .mute-btn i { - background-color: none; - color: white; - font-size: 20px; + background-color: none; + color: white; + font-size: 20px; } .recording-sign { - height: 20px; - width: auto; - display: flex; - flex-direction: row; - position: absolute; - top: 10px; - right: 15px; - align-items: center; - justify-content: center; - - .timer { - font-size: 15px; - color: white; - margin: 0; - } - - .dot { - height: 15px; - width: 15px; - margin: 5px; - background-color: red; - border-radius: 50%; - display: inline-block; - } + height: 20px; + width: auto; + display: flex; + flex-direction: row; + position: absolute; + top: 10px; + right: 15px; + align-items: center; + justify-content: center; + + .timer { + font-size: 15px; + color: white; + margin: 0; + } + + .dot { + height: 15px; + width: 15px; + margin: 5px; + background-color: red; + border-radius: 50%; + display: inline-block; + } } .controls-inner-container { - display: flex; - flex-direction: row; - position: relative; - width: 100%; - align-items: center; - justify-content: center; + display: flex; + flex-direction: row; + position: relative; + width: 100%; + align-items: center; + justify-content: center; } .record-button-wrapper { - width: 35px; - height: 35px; - font-size: 0; - background-color: grey; - border: 0px; - border-radius: 35px; - margin: 10px; - display: flex; - justify-content: center; - - .record-button { - background-color: red; - border: 0px; - border-radius: 50%; - height: 80%; - width: 80%; - align-self: center; - margin: 0; - - &:hover { - height: 85%; - width: 85%; - } - } - - .stop-button { - background-color: red; - border: 0px; - border-radius: 10%; - height: 70%; - width: 70%; - align-self: center; - margin: 0; - - - // &:hover { - // width: 40px; - // height: 40px - // } - } - + width: 35px; + height: 35px; + font-size: 0; + background-color: grey; + border: 0px; + border-radius: 35px; + margin: 10px; + display: flex; + justify-content: center; + + .record-button { + background-color: red; + border: 0px; + border-radius: 50%; + height: 80%; + width: 80%; + align-self: center; + margin: 0; + + &:hover { + height: 85%; + width: 85%; + } + } + + .stop-button { + background-color: red; + border: 0px; + border-radius: 10%; + height: 70%; + width: 70%; + align-self: center; + margin: 0; + + // &:hover { + // width: 40px; + // height: 40px + // } + } } .options-wrapper { - height: 100%; - display: flex; - flex-direction: row; - align-content: center; - position: relative; - top: 0; - bottom: 0; - - &.video-edit-wrapper { - - // right: 50% - 15; - - .track-screen { - font-weight: 200; - } - - } - - &.track-screen-wrapper { - - // right: 50% - 30; - - .track-screen { - font-weight: 200; - color: aqua; - } - - } -} \ No newline at end of file + height: 100%; + display: flex; + flex-direction: row; + align-content: center; + position: relative; + top: 0; + bottom: 0; + + &.video-edit-wrapper { + // right: 50% - 15; + + .track-screen { + font-weight: 200; + } + } + + &.track-screen-wrapper { + // right: 50% - 30; + + .track-screen { + font-weight: 200; + color: aqua; + } + } +} diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx index 8802a032f..cdfeebe66 100644 --- a/src/client/views/nodes/formattedText/DashFieldView.tsx +++ b/src/client/views/nodes/formattedText/DashFieldView.tsx @@ -22,7 +22,7 @@ import { OpenWhere } from '../DocumentView'; import './DashFieldView.scss'; import { FormattedTextBox } from './FormattedTextBox'; import { DocData } from '../../../../fields/DocSymbols'; -import { NodeSelection, TextSelection } from 'prosemirror-state'; +import { NodeSelection } from 'prosemirror-state'; export class DashFieldView { dom: HTMLDivElement; // container for label and value @@ -60,7 +60,7 @@ export class DashFieldView { return; } } - tBox.setFocus(state.selection.to + 1); + tBox.setFocus(state.selection.to); } } }; @@ -84,6 +84,7 @@ export class DashFieldView { width={node.attrs.width} height={node.attrs.height} hideKey={node.attrs.hideKey} + hideValue={node.attrs.hideValue} editable={node.attrs.editable} expanded={this.Expanded} dataDoc={node.attrs.dataDoc} @@ -112,6 +113,7 @@ interface IDashFieldViewInternal { fieldKey: string; docId: string; hideKey: boolean; + hideValue: boolean; tbox: FormattedTextBox; width: number; height: number; @@ -217,12 +219,28 @@ export class DashFieldViewInternal extends ObservableReactComponent this._dashDoc && (this._dashDoc[this._fieldKey + '_hideKey'] = !this._dashDoc[this._fieldKey + '_hideKey'])), + action(() => { + const editor = this._props.tbox.EditorView!; + editor.dispatch(editor.state.tr.setNodeMarkup(this._props.getPos(), this._props.node.type, { ...this._props.node.attrs, hideKey: !this._props.node.attrs.hideKey ? true : false })); + }), 'hideKey' ); + toggleValueHide = undoable( + action(() => { + const editor = this._props.tbox.EditorView!; + editor.dispatch(editor.state.tr.setNodeMarkup(this._props.getPos(), this._props.node.type, { ...this._props.node.attrs, hideValue: !this._props.node.attrs.hideValue ? true : false })); + }), + 'hideValue' + ); + + @observable _showValue = false; @computed get _hideKey() { - return this._dashDoc?.[this._fieldKey + '_hideKey'] && !this._expanded; + return this._props.hideKey && !this._expanded; + } + + @computed get _hideValue() { + return !this._showValue && this._props.hideValue && !this._expanded; } // clicking on the label creates a pivot view collection of all documents @@ -231,7 +249,11 @@ export class DashFieldViewInternal extends ObservableReactComponent { DashFieldViewMenu.createFieldView = this.createPivotForField; DashFieldViewMenu.toggleFieldHide = this.toggleFieldHide; + DashFieldViewMenu.toggleValueHide = this.toggleValueHide; DashFieldViewMenu.Instance.show(e.clientX, e.clientY + 16, this._fieldKey); + this._dashDoc?.[this._fieldKey + '_hideValue'] && runInAction(() => (this._showValue = !this._showValue)); + const editor = this._props.tbox.EditorView!; + setTimeout(() => editor.dispatch(editor.state.tr.setSelection(new NodeSelection(editor.state.doc.resolve(this._props.getPos())))), 100); }); }; @@ -257,12 +279,12 @@ export class DashFieldViewInternal extends ObservableReactComponent - {this._props.hideKey || this._hideKey ? null : ( + {this._hideKey ? null : ( {(Doc.AreProtosEqual(DocCast(this._textBoxDoc.rootDocument) ?? this._textBoxDoc, DocCast(this._dashDoc?.rootDocument) ?? this._dashDoc) ? '' : this._dashDoc?.title + ':') + this._fieldKey} )} - {this._props.fieldKey.startsWith('#') ? null : this.fieldValueContent} + {this._props.fieldKey.startsWith('#') || this._hideValue ? null : this.fieldValueContent} {/* {!this.values.length ? null : ( + {!this.values.length ? null : ( + - )} */} + )}
); } diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 66df1eaf2..3700b08d6 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -2064,8 +2064,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent (this._isHovering = true))} - onPointerLeave={action(() => (this._isHovering = false))} + onPointerEnter={action(() => { + this._isHovering = true; + this.layoutDoc[`_${this._props.fieldKey}_usePath`] && (this.Document.isHovering = true); + })} + onPointerLeave={action(() => (this.Document.isHovering = this._isHovering = false))} ref={r => { this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel); this._oldWheel = r; -- cgit v1.2.3-70-g09d2