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 +++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 24 deletions(-) (limited to 'src/client/documents') 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; } -- 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/documents') 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.map(val => ( diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 2deecb6ad..80e56efe0 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -478,7 +478,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent FieldValue(this.dataDoc.title)); if (!(cfield instanceof ComputedField)) { this.dataDoc.title = (prefix + str.substring(0, Math.min(40, str.length)) + (str.length > 40 ? '...' : '')).trim(); - if (str.startsWith('@') && str.length > 1) { - Doc.AddToMyPublished(this.Document); - } } } }; @@ -510,7 +507,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent) => { const editorView = this._editorView; if (editorView && (editorView as any).docView && !Doc.AreProtosEqual(target, this.Document)) { - const autoLinkTerm = StrCast(target.title).replace(/^@/, ''); + const autoLinkTerm = Field.toString(target.title as Field).replace(/^@/, ''); var alink: Doc | undefined; this.findInNode(editorView, editorView.state.doc, autoLinkTerm).forEach(sel => { if ( @@ -1312,15 +1309,15 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent NumCast(this.layoutDoc._layout_scrollTop), pos => { - if (!this._ignoreScroll && this._scrollRef.current && !this._props.dontSelectOnLoad) { + if (!this._ignoreScroll && this.ProseRef && !this._props.dontSelectOnLoad) { const viewTrans = quickScroll ?? StrCast(this.Document._viewTransition); const durationMiliStr = viewTrans.match(/([0-9]*)ms/); const durationSecStr = viewTrans.match(/([0-9.]*)s/); const duration = durationMiliStr ? Number(durationMiliStr[1]) : durationSecStr ? Number(durationSecStr[1]) * 1000 : 0; if (duration) { - this._scrollStopper = smoothScroll(duration, this._scrollRef.current, Math.abs(pos || 0), 'ease', this._scrollStopper); + this._scrollStopper = smoothScroll(duration, this.ProseRef, Math.abs(pos || 0), 'ease', this._scrollStopper); } else { - this._scrollRef.current.scrollTo({ top: pos }); + this.ProseRef.scrollTo({ top: pos }); } } }, @@ -1418,7 +1415,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { const docPos = editorView.coordsAtPos(editorView.state.selection.to); const viewRect = self._ref.current!.getBoundingClientRect(); - const scrollRef = self._scrollRef.current; + const scrollRef = self.ProseRef; const topOff = docPos.top < viewRect.top ? docPos.top - viewRect.top : undefined; const botOff = docPos.bottom > viewRect.bottom ? docPos.bottom - viewRect.bottom : undefined; if (((topOff && Math.abs(Math.trunc(topOff)) > 0) || (botOff && Math.abs(Math.trunc(botOff)) > 0)) && scrollRef) { @@ -1750,20 +1747,21 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent document publishing to Doc.myPublishedDocs + const match = RTFCast(this.Document[this.fieldKey]).Text.match(/^(@[a-zA-Z][a-zA-Z_0-9 -]*[a-zA-Z_0-9-]+)/); + if (match) { + this.dataDoc.title_custom = true; + this.dataDoc.title = match[1]; // this triggers the collectionDockingView to publish this Doc + this.EditorView?.dispatch(this.EditorView?.state.tr.deleteRange(0, match[1].length + 1)); + } + this.endUndoTypingBatch(); FormattedTextBox.LiveTextUndo?.end(); FormattedTextBox.LiveTextUndo = undefined; const state = this._editorView!.state; - if (StrCast(this.Document.title).startsWith('@') && !this.dataDoc.title_custom) { - UndoManager.RunInBatch(() => { - this.dataDoc.title_custom = true; - this.dataDoc.layout_showTitle = 'title'; - const tr = this._editorView!.state.tr; - this._editorView?.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(0), tr.doc.resolve(StrCast(this.Document.title).length + 2))).deleteSelection()); - }, 'titler'); - } // if the text box blurs and none of its contents are focused(), then pass the blur along setTimeout(() => !this.ProseRef?.contains(document.activeElement) && this._props.onBlur?.()); }; diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts index 5e53a019e..e8cf9e992 100644 --- a/src/client/views/nodes/formattedText/RichTextRules.ts +++ b/src/client/views/nodes/formattedText/RichTextRules.ts @@ -295,8 +295,8 @@ export class RichTextRules { // create a hyperlink to a titled document // @() - new InputRule(new RegExp(/(^|\s)@\(([a-zA-Z_@\.\? \-0-9]+)\)/), (state, match, start, end) => { - const docTitle = match[2]; + new InputRule(new RegExp(/@\(([a-zA-Z_@\.\? \-0-9]+)\)/), (state, match, start, end) => { + const docTitle = match[1]; const prefixLength = '@('.length; if (docTitle) { const linkToDoc = (target: Doc) => { @@ -342,12 +342,7 @@ export class RichTextRules { const assign = match[4] === ':' ? (match[4] = '') : match[4]; const value = match[5]; const dataDoc = value === undefined ? !fieldKey.startsWith('_') : !assign?.startsWith('='); - const getTitledDoc = (docTitle: string) => { - if (!DocServer.FindDocByTitle(docTitle)) { - Doc.AddToMyPublished(Docs.Create.TextDocument('', { title: docTitle, _width: 400, _layout_autoHeight: true })); - } - return DocServer.FindDocByTitle(docTitle); - }; + const getTitledDoc = (docTitle: string) => DocServer.FindDocByTitle(docTitle); // if the value has commas assume its an array (unless it's part of a chat gpt call indicated by '((' ) if (value?.includes(',') && !value.startsWith('((')) { const values = value.split(','); @@ -359,7 +354,7 @@ export class RichTextRules { if (fieldKey === this.TextBox.fieldKey) return this.TextBox.EditorView!.state.tr; } const target = docTitle ? getTitledDoc(docTitle) : undefined; - const fieldView = state.schema.nodes.dashField.create({ fieldKey, docId: target?.[Id], hideKey: false, hideValue: false, dataDoc }); + const fieldView = state.schema.nodes.dashField.create({ fieldKey, docId: target?.[Id], hideKey: false, hideValue: false }); return state.tr.setSelection(new TextSelection(state.doc.resolve(start), state.doc.resolve(end))).replaceSelectionWith(fieldView, true); }, { inCode: true } diff --git a/src/client/views/nodes/formattedText/nodes_rts.ts b/src/client/views/nodes/formattedText/nodes_rts.ts index e335044ea..cab3a6ef5 100644 --- a/src/client/views/nodes/formattedText/nodes_rts.ts +++ b/src/client/views/nodes/formattedText/nodes_rts.ts @@ -266,7 +266,6 @@ export const nodes: { [index: string]: NodeSpec } = { hideKey: { default: false }, hideValue: { default: false }, editable: { default: true }, - dataDoc: { default: false }, }, leafText: node => Field.toString((DocServer.GetCachedRefField(node.attrs.docId as string) as Doc)?.[node.attrs.fieldKey as string] as Field), group: 'inline', diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 200896e25..9973232bf 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -86,7 +86,8 @@ export namespace Field { // this is a bit hacky, but we treat '^@' references to a published document // as a kind of macro to include the content of those documents Doc.MyPublishedDocs.forEach(doc => { - const regex = new RegExp(`^\\^${doc.title}\\s`, 'm'); + const regexMultilineFlag = 'm'; + const regex = new RegExp(`^\\^${StrCast(doc.title).replace(/[\(\)]*/g, '')}\\s`, regexMultilineFlag); // need to remove characters that can cause the regular expression to be invalid const sections = (Cast(doc.text, RichTextField, null)?.Text ?? '').split('--DOCDATA--'); if (script.match(regex)) { script = script.replace(regex, sections[0]) + (sections.length > 1 ? sections[1] : ''); @@ -218,8 +219,14 @@ export class Doc extends RefField { public static IsInMyOverlay(doc: Doc) { return Doc.MyOverlayDocs.includes(doc); } // prettier-ignore public static AddToMyOverlay(doc: Doc) { Doc.ActiveDashboard?.myOverlayDocs ? Doc.AddDocToList(Doc.ActiveDashboard, 'myOverlayDocs', doc) : Doc.AddDocToList(DocCast(Doc.UserDoc().myOverlayDocs), undefined, doc); } // prettier-ignore public static RemFromMyOverlay(doc: Doc) { Doc.ActiveDashboard?.myOverlayDocs ? Doc.RemoveDocFromList(Doc.ActiveDashboard,'myOverlayDocs', doc) : Doc.RemoveDocFromList(DocCast(Doc.UserDoc().myOverlayDocs), undefined, doc); } // prettier-ignore - public static AddToMyPublished(doc: Doc) { Doc.ActiveDashboard?.myPublishedDocs ? Doc.AddDocToList(Doc.ActiveDashboard, 'myPublishedDocs', doc) : Doc.AddDocToList(DocCast(Doc.UserDoc().myPublishedDocs), undefined, doc); } // prettier-ignore - public static RemFromMyPublished(doc: Doc){ Doc.ActiveDashboard?.myPublishedDocs ? Doc.RemoveDocFromList(Doc.ActiveDashboard,'myPublishedDocs', doc) : Doc.RemoveDocFromList(DocCast(Doc.UserDoc().myPublishedDocs), undefined, doc); } // prettier-ignore + public static AddToMyPublished(doc: Doc) { + doc[DocData].title_custom = true; + doc[DocData].layout_showTitle = 'title'; + Doc.ActiveDashboard?.myPublishedDocs ? Doc.AddDocToList(Doc.ActiveDashboard, 'myPublishedDocs', doc) : Doc.AddDocToList(DocCast(Doc.UserDoc().myPublishedDocs), undefined, doc); } // prettier-ignore + public static RemFromMyPublished(doc: Doc){ + doc[DocData].title_custom = false; + doc[DocData].layout_showTitle = undefined; + Doc.ActiveDashboard?.myPublishedDocs ? Doc.RemoveDocFromList(Doc.ActiveDashboard,'myPublishedDocs', doc) : Doc.RemoveDocFromList(DocCast(Doc.UserDoc().myPublishedDocs), undefined, doc); } // prettier-ignore public static IsComicStyle(doc?: Doc) { return doc && Doc.ActiveDashboard && !Doc.IsSystem(doc) && Doc.UserDoc().renderStyle === 'comic' ; } // prettier-ignore constructor(id?: FieldId, forceSave?: boolean) { diff --git a/src/fields/util.ts b/src/fields/util.ts index c2ec3f13a..ad592391e 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -1,4 +1,4 @@ -import { $mobx, action, observable, runInAction, trace } from 'mobx'; +import { $mobx, action, observable, runInAction, trace, values } from 'mobx'; import { computedFn } from 'mobx-utils'; import { returnZero } from '../Utils'; import { DocServer } from '../client/DocServer'; @@ -16,6 +16,7 @@ import { RichTextField } from './RichTextField'; import { SchemaHeaderField } from './SchemaHeaderField'; import { ComputedField } from './ScriptField'; import { DocCast, ScriptCast, StrCast } from './Types'; +import { BaseException } from 'pdfjs-dist/types/src/shared/util'; function _readOnlySetter(): never { throw new Error("Documents can't be modified in read-only mode"); @@ -56,6 +57,8 @@ const _setterImpl = action(function (target: any, prop: string | symbol | number delete curValue[FieldChanged]; } + if (typeof prop === 'string' && _propSetterCB.has(prop)) _propSetterCB.get(prop)!(target[SelfProxy], value); + const effectiveAcl = GetEffectiveAcl(target); const writeMode = DocServer.getFieldWriteMode(prop as string); @@ -282,6 +285,17 @@ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc dataDocChanged && updateCachedAcls(dataDoc); } +export var _propSetterCB = new Map void) | undefined>(); +/** + * sets a callback function to be called whenever a value is assigned to the specified field key. + * For example, this is used to "publish" documents with titles that start with '@' + * @param prop + * @param setter + */ +export function SetPropSetterCb(prop: string, setter: ((target: any, value: any) => void) | undefined) { + _propSetterCB.set(prop, setter); +} + // // target should be either a Doc or ListImpl. receiver should be a Proxy Or List. // -- cgit v1.2.3-70-g09d2 From 83deb55fa4e99e25cebd4a9d4eb882c2fddee28b Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 1 Apr 2024 13:44:16 -0400 Subject: fixed header template to be marginally functional. --- src/Utils.ts | 3 +- src/client/documents/Documents.ts | 7 ++-- src/client/util/CurrentUserUtils.ts | 25 +++++++------ .../views/nodes/formattedText/FormattedTextBox.tsx | 42 +++++++++------------- src/fields/Doc.ts | 3 +- 5 files changed, 35 insertions(+), 45 deletions(-) (limited to 'src/client/documents') diff --git a/src/Utils.ts b/src/Utils.ts index 21c91278f..a64c7c8a7 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -654,10 +654,9 @@ export function smoothScroll(duration: number, element: HTMLElement | HTMLElemen const currentDate = new Date().getTime(); const currentTime = currentDate - startDate; const setScrollTop = (element: HTMLElement, value: number) => (element.scrollTop = value); - elements.forEach((element, i) => currentTime && setScrollTop(element, easeFunc(transition, Math.min(currentTime, duration), starts[i], to - starts[i], duration))); - if (!_stop) { if (currentTime < duration) { + elements.forEach((element, i) => currentTime && setScrollTop(element, easeFunc(transition, Math.min(currentTime, duration), starts[i], to - starts[i], duration))); requestAnimationFrame(animateScroll); } else { elements.forEach(element => setScrollTop(element, to)); diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index eb15c332f..20e74a3e1 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -254,9 +254,9 @@ export class DocumentOptions { dontRegisterView?: BOOLt = new BoolInfo('are views of this document registered so that they can be found when following links, etc', false); _undoIgnoreFields?: List; //'fields that should not be added to the undo stack (opacity for Undo/Redo/and sidebar) AND whether modifications to document are undoable (true for linearview menu buttons to prevent open/close from entering undo stack)' undoIgnoreFields?: List; //'fields that should not be added to the undo stack (opacity for Undo/Redo/and sidebar) AND whether modifications to document are undoable (true for linearview menu buttons to prevent open/close from entering undo stack)' - _headerHeight?: NUMt = new NumInfo('height of document header used for displaying title', false); - _headerFontSize?: NUMt = new NumInfo('font size of header of custom notes', false); - _headerPointerEvents?: PEVt = new PEInfo('types of events the header of a custom text document can consume'); + _header_height?: NUMt = new NumInfo('height of document header used for displaying title', false); + _header_fontSize?: NUMt = new NumInfo('font size of header of custom notes', false); + _header_pointerEvents?: PEVt = new PEInfo('types of events the header of a custom text document can consume'); _lockedPosition?: BOOLt = new BoolInfo("lock the x,y coordinates of the document so that it can't be dragged"); _lockedTransform?: BOOLt = new BoolInfo('lock the freeform_panx,freeform_pany and scale parameters of the document so that it be panned/zoomed'); @@ -284,6 +284,7 @@ export class DocumentOptions { layout_boxShadow?: string; // box-shadow css string OR "standard" to use dash standard box shadow layout_maxShown?: NUMt = new NumInfo('maximum number of children to display at one time (see multicolumnview)'); _layout_autoHeight?: BOOLt = new BoolInfo('whether document automatically resizes vertically to display contents'); + _layout_autoHeightMargins?: NUMt = new NumInfo('Margin heights to be added to the computed auto height of a Doc'); _layout_curPage?: NUMt = new NumInfo('current page of a PDF or other? paginated document', false); _layout_currentTimecode?: NUMt = new NumInfo('the current timecode of a time-based document (e.g., current time of a video) value is in seconds', false); _layout_centered?: BOOLt = new BoolInfo('whether text should be vertically centered in Doc'); diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index b06801066..16e0cb14a 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -222,20 +222,19 @@ export class CurrentUserUtils { }; const headerBtnHgt = 10; const headerTemplate = (opts:DocumentOptions) => { - const header = Docs.Create.RTFDocument(new RichTextField(JSON.stringify(json), ""), { ...opts, title: "Untitled Header", + const header = Docs.Create.RTFDocument(new RichTextField(JSON.stringify(json), ""), { ...opts, title: "Header Template", layout: - "" + - ` ` + - " " + - ` Metadata` + - "" + ` + + + Metadata + ` }, "header"); - // "
" + - // " " + - // " " + + // " " + + // " " + // "
"; - MakeTemplate(Doc.GetProto(header)); + MakeTemplate(header); return header; } const slideView = (opts:DocumentOptions) => { @@ -243,9 +242,9 @@ export class CurrentUserUtils { [ Docs.Create.MulticolumnDocument([], { title: "hero", _height: 200, isSystem: true }), Docs.Create.TextDocument("", { title: "text", _layout_fitWidth:true, _height: 100, isSystem: true, _text_fontFamily: StrCast(Doc.UserDoc().fontFamily), _text_fontSize: StrCast(Doc.UserDoc().fontSize) }) - ], {...opts, title: "Untitled Slide View"}); + ], {...opts, title: "Slide View Template"}); - MakeTemplate(Doc.GetProto(slide)); + MakeTemplate(slide); return slide; } const plotlyApi = () => { @@ -364,7 +363,7 @@ pie title Minerals in my tap water {key: "Button", creator: Docs.Create.ButtonDocument, opts: { _width: 150, _height: 50, _xPadding: 10, _yPadding: 10, title_custom: true, waitForDoubleClickToClick: 'never'}, scripts: {onClick: FollowLinkScript()?.script.originalScript ?? ""}}, {key: "Script", creator: opts => Docs.Create.ScriptingDocument(null, opts), opts: { _width: 200, _height: 250, }}, {key: "DataViz", creator: opts => Docs.Create.DataVizDocument("/users/rz/Downloads/addresses.csv", opts), opts: { _width: 300, _height: 300 }}, - {key: "Header", creator: headerTemplate, opts: { _width: 300, _height: 70, _headerPointerEvents: "all", _headerHeight: 12, _headerFontSize: 9, _layout_autoHeight: true, treeView_HideUnrendered: true}}, + {key: "Header", creator: headerTemplate, opts: { _width: 300, _height: 120, _header_pointerEvents: "all", _header_height: 50, _header_fontSize: 9,_layout_autoHeightMargins: 50, _layout_autoHeight: true, treeView_HideUnrendered: true}}, {key: "ViewSlide", creator: slideView, opts: { _width: 400, _height: 300, _xMargin: 3, _yMargin: 3,}}, {key: "Trail", creator: Docs.Create.PresDocument, opts: { _width: 400, _height: 30, _type_collection: CollectionViewType.Stacking, dropAction: dropActionType.embed, treeView_HideTitle: true, _layout_fitWidth:true, layout_boxShadow: "0 0" }}, {key: "Tab", creator: opts => Docs.Create.FreeformDocument([], opts), opts: { _width: 500, _height: 800, _layout_fitWidth: true, _freeform_backgroundGrid: true, }}, diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 269a114bb..2e8444379 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -884,7 +884,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { this.dataDoc.layout_meta = Cast(Doc.UserDoc().emptyHeader, Doc, null)?.layout; this.Document.layout_fieldKey = 'layout_meta'; - setTimeout(() => (this.layoutDoc._headerHeight = this.layoutDoc._layout_autoHeightMargins = 50), 50); + setTimeout(() => (this.layoutDoc._header_height = this.layoutDoc._layout_autoHeightMargins = 50), 50); }), icon: 'eye', }); @@ -1305,25 +1305,17 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent NumCast(this.layoutDoc._layout_scrollTop), pos => { - if (!this._ignoreScroll && this._scrollRef && !this._props.dontSelectOnLoad) { - const viewTrans = quickScroll ?? StrCast(this.Document._viewTransition); - const durationMiliStr = viewTrans.match(/([0-9]*)ms/); - const durationSecStr = viewTrans.match(/([0-9.]*)s/); - const duration = durationMiliStr ? Number(durationMiliStr[1]) : durationSecStr ? Number(durationSecStr[1]) * 1000 : 0; - if (duration) { - this._scrollStopper = smoothScroll(duration, this._scrollRef, Math.abs(pos || 0), 'ease', this._scrollStopper); - } else { - this._scrollRef.scrollTo({ top: pos }); - } + if (!this._ignoreScroll && this._scrollRef) { + const durationStr = StrCast(this.Document._viewTransition).match(/([0-9]+)(m?)s/); + const duration = Number(durationStr?.[1]) * (durationStr?.[2] ? 1 : 1000); + this._scrollStopper = smoothScroll(duration || 0, this._scrollRef, Math.abs(pos || 0), 'ease', this._scrollStopper); } }, { fireImmediately: true } ); - quickScroll = undefined; this.tryUpdateScrollHeight(); setTimeout(this.tryUpdateScrollHeight, 250); } @@ -1749,7 +1741,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent document publishing to Doc.myPublishedDocs - const match = RTFCast(this.Document[this.fieldKey]).Text.match(/^(@[a-zA-Z][a-zA-Z_0-9 -]*[a-zA-Z_0-9-]+)/); + const match = RTFCast(this.Document[this.fieldKey])?.Text.match(/^(@[a-zA-Z][a-zA-Z_0-9 -]*[a-zA-Z_0-9-]+)/); if (match) { this.dataDoc.title_custom = true; this.dataDoc.title = match[1]; // this triggers the collectionDockingView to publish this Doc @@ -1824,13 +1816,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { if (!LinkInfo.Instance?.LinkInfo && this._scrollRef) { - if (!this._props.dontSelectOnLoad) { - this._ignoreScroll = true; - this.layoutDoc._layout_scrollTop = this._scrollRef.scrollTop; - this._ignoreScroll = false; - e.stopPropagation(); - e.preventDefault(); - } + this._ignoreScroll = true; + this.layoutDoc._layout_scrollTop = this._scrollRef.scrollTop; + this._ignoreScroll = false; + e.stopPropagation(); + e.preventDefault(); } }; tryUpdateScrollHeight = () => { @@ -2026,7 +2016,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent + const styleFromLayoutString = Doc.styleFromLayoutString(this.Document, this._props, scale); // this converts any expressions in the format string to style props. e.g., const height = Number(styleFromLayoutString.height?.replace('px', '')); // prevent default if selected || child is active but this doc isn't scrollable if ( @@ -2059,7 +2049,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent !this._props.isContentActive() && FormattedTextBoxComment.textBox === this && FormattedTextBoxComment.Hide); const paddingX = NumCast(this.layoutDoc._xMargin, this._props.xPadding || 0); const paddingY = NumCast(this.layoutDoc._yMargin, this._props.yPadding || 0); - const styleFromLayoutString = Doc.styleFromLayoutString(this.Document, this._props, scale); // this converts any expressions in the format string to style props. e.g., + const styleFromLayoutString = Doc.styleFromLayoutString(this.Document, this._props, scale); // this converts any expressions in the format string to style props. e.g., return styleFromLayoutString?.height === '0px' ? null : (
(this._scrollRef = r)} style={{ - width: this._props.dontSelectOnLoad || this.noSidebar ? '100%' : `calc(100% - ${this.layout_sidebarWidthPercent})`, + width: this.noSidebar ? '100%' : `calc(100% - ${this.layout_sidebarWidthPercent})`, overflow: this.layoutDoc._createDocOnCR ? 'hidden' : this.layoutDoc._layout_autoHeight ? 'visible' : undefined, }} onScroll={this.onScroll} @@ -2128,8 +2118,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent
- {this.noSidebar || this._props.dontSelectOnLoad || !this.SidebarShown || this.layout_sidebarWidthPercent === '0%' ? null : this.sidebarCollection} - {this.noSidebar || this.Document._layout_noSidebar || this._props.dontSelectOnLoad || this.Document._createDocOnCR || this.layoutDoc._chromeHidden ? null : this.sidebarHandle} + {this.noSidebar || !this.SidebarShown || this.layout_sidebarWidthPercent === '0%' ? null : this.sidebarCollection} + {this.noSidebar || this.Document._layout_noSidebar || this.Document._createDocOnCR || this.layoutDoc._chromeHidden ? null : this.sidebarHandle} {this.audioHandle} {this.layoutDoc._layout_enableAltContentUI && !this.layoutDoc._chromeHidden ? this.overlayAlternateIcon : null}
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 9973232bf..48214cf25 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -1162,7 +1162,8 @@ export namespace Doc { return doc[StrCast(doc.layout_fieldKey, 'layout')]; } export function LayoutFieldKey(doc: Doc, templateLayoutString?: string): string { - return StrCast(templateLayoutString || Doc.Layout(doc).layout).split("'")[1]; // bcz: TODO check on this . used to always reference 'layout', now it uses the layout speicfied by the current layout_fieldKey + const match = StrCast(templateLayoutString || Doc.Layout(doc).layout).match(/fieldKey={'([^']+)'}/); + return match?.[1] || ''; // bcz: TODO check on this . used to always reference 'layout', now it uses the layout speicfied by the current layout_fieldKey } export function NativeAspect(doc: Doc, dataDoc?: Doc, useDim?: boolean) { return Doc.NativeWidth(doc, dataDoc, useDim) / (Doc.NativeHeight(doc, dataDoc, useDim) || 1); -- cgit v1.2.3-70-g09d2 From 0a02dfa252f4eee451ba4ea74f82b90be489687e Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 1 Apr 2024 14:07:05 -0400 Subject: fixed exceptions on link to link positions --- src/client/documents/Documents.ts | 8 ++++---- src/client/views/linking/LinkMenuItem.tsx | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/client/documents') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 20e74a3e1..29ec1d19e 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -1517,8 +1517,8 @@ export namespace DocUtils { return linkDoc; }); - const a = source.layout_unrendered ? 'link_anchor_1.annotationOn' : 'link_anchor_1'; - const b = target.layout_unrendered ? 'link_anchor_2.annotationOn' : 'link_anchor_2'; + const a = source.layout_unrendered ? 'link_anchor_1?.annotationOn' : 'link_anchor_1'; + const b = target.layout_unrendered ? 'link_anchor_2?.annotationOn' : 'link_anchor_2'; return makeLink( Docs.Create.LinkDocument( @@ -1533,8 +1533,8 @@ export namespace DocUtils { link_displayLine: linkSettings.link_displayLine, link_relationship: linkSettings.link_relationship, link_description: linkSettings.link_description, - x: ComputedField.MakeFunction(`(this.${a}.x+this.${b}.x)/2`) as any, - y: ComputedField.MakeFunction(`(this.${a}.y+this.${b}.y)/2`) as any, + x: ComputedField.MakeFunction(`((this.${a}?.x||0)+(this.${b}?.x||0))/2`) as any, + y: ComputedField.MakeFunction(`((this.${a}?.y||0)+(this.${b}?.y||0))/2`) as any, link_autoMoveAnchors: true, _lockedPosition: true, _layout_showCaption: '', // removed since they conflict with showing a link with a LinkBox (ie, line, not comparison box) diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx index 81dd0eb98..a2c9d10b6 100644 --- a/src/client/views/linking/LinkMenuItem.tsx +++ b/src/client/views/linking/LinkMenuItem.tsx @@ -183,7 +183,7 @@ export class LinkMenuItem extends ObservableReactComponent {
Show/Hide Link}> -
+
-- cgit v1.2.3-70-g09d2 From 583420f7b97b5d540fa269f9ce5625953bacdbe6 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 5 Apr 2024 00:33:12 -0400 Subject: updates for new css-loader --- src/client/documents/Documents.ts | 2 +- src/client/util/DragManager.ts | 2 +- src/client/views/InkingStroke.tsx | 2 +- src/client/views/MainView.tsx | 2 +- .../views/collections/CollectionCarousel3DView.tsx | 3 +- src/client/views/collections/TreeView.tsx | 4 +-- .../collectionSchema/CollectionSchemaView.tsx | 2 +- .../views/nodes/DataVizBox/components/TableBox.tsx | 41 +++++++++++++--------- src/client/views/nodes/LinkAnchorBox.tsx | 2 +- src/mobile/ImageUpload.tsx | 2 +- 10 files changed, 36 insertions(+), 26 deletions(-) (limited to 'src/client/documents') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 29ec1d19e..b160379df 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -60,7 +60,7 @@ 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'; -const { default: { DFLT_IMAGE_NATIVE_DIM } } = require('../views/global/globalCssVariables.module.scss'); // prettier-ignore +const { DFLT_IMAGE_NATIVE_DIM } = require('../views/global/globalCssVariables.module.scss'); // prettier-ignore const defaultNativeImageDim = Number(DFLT_IMAGE_NATIVE_DIM.replace('px', '')); class EmptyBox { diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index aa0f77c72..9627c5df2 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -28,7 +28,7 @@ import { SelectionManager } from './SelectionManager'; import { SnappingManager } from './SnappingManager'; import { UndoManager } from './UndoManager'; import { DocData } from '../../fields/DocSymbols'; -const { default : { contextMenuZindex } } = require('../views/global/globalCssVariables.module.scss'); // prettier-ignore +const { contextMenuZindex } = require('../views/global/globalCssVariables.module.scss'); // prettier-ignore export enum dropActionType { embed = 'embed', // create a new embedding of the dragged document for the new location diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 5a9f10ba4..51baaa23e 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -44,7 +44,7 @@ import { FieldView, FieldViewProps } from './nodes/FieldView'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; import { PinProps, PresBox } from './nodes/trails'; import { StyleProp } from './StyleProvider'; -const { default: { INK_MASK_SIZE } } = require('./global/globalCssVariables.module.scss'); // prettier-ignore +const { INK_MASK_SIZE } = require('./global/globalCssVariables.module.scss'); // prettier-ignore @observer export class InkingStroke extends ViewBoxAnnotatableComponent() implements ViewBoxInterface { static readonly MaskDim = INK_MASK_SIZE; // choose a really big number to make sure mask fits over container (which in theory can be arbitrarily big) diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index e8a3a37cb..4b1e59385 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -71,7 +71,7 @@ import { PresBox } from './nodes/trails'; import { AnchorMenu } from './pdf/AnchorMenu'; import { GPTPopup } from './pdf/GPTPopup/GPTPopup'; import { TopBar } from './topbar/TopBar'; -const { default: { LEFT_MENU_WIDTH, TOPBAR_HEIGHT } } = require('./global/globalCssVariables.module.scss'); // prettier-ignore +const { LEFT_MENU_WIDTH, TOPBAR_HEIGHT } = require('./global/globalCssVariables.module.scss'); // prettier-ignore const _global = (window /* browser */ || global) /* node */ as any; @observer diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx index 5454c6f9f..4e4bd43bf 100644 --- a/src/client/views/collections/CollectionCarousel3DView.tsx +++ b/src/client/views/collections/CollectionCarousel3DView.tsx @@ -14,7 +14,8 @@ import { DocumentView } from '../nodes/DocumentView'; import { FocusViewOptions } from '../nodes/FieldView'; import './CollectionCarousel3DView.scss'; import { CollectionSubView } from './CollectionSubView'; -const { default: { CAROUSEL3D_CENTER_SCALE, CAROUSEL3D_SIDE_SCALE, CAROUSEL3D_TOP } } = require('../global/globalCssVariables.module.scss'); // prettier-ignore +const { CAROUSEL3D_CENTER_SCALE, CAROUSEL3D_SIDE_SCALE, CAROUSEL3D_TOP } = require('../global/globalCssVariables.module.scss'); + @observer export class CollectionCarousel3DView extends CollectionSubView() { @computed get scrollSpeed() { diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 5eac6cb09..8c29c3ada 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -35,7 +35,7 @@ import { CollectionTreeView, TreeViewType } from './CollectionTreeView'; import { CollectionView } from './CollectionView'; import { TreeSort } from './TreeSort'; import './TreeView.scss'; -const { default: { TREE_BULLET_WIDTH } } = require('../global/globalCssVariables.module.scss'); // prettier-ignore +const { TREE_BULLET_WIDTH } = require('../global/globalCssVariables.module.scss'); // prettier-ignore export interface TreeViewProps { treeView: CollectionTreeView; @@ -928,7 +928,7 @@ export class TreeView extends ObservableReactComponent { case 'Tab': e.stopPropagation?.(); e.preventDefault?.(); - setTimeout(() => RichTextMenu.Instance.TextView?.EditorView?.focus(), 150); + setTimeout(() => RichTextMenu.Instance?.TextView?.EditorView?.focus(), 150); UndoManager.RunInBatch(() => (e.shiftKey ? this._props.outdentDocument?.(true) : this._props.indentDocument?.(true)), 'tab'); return true; case 'Backspace': diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index df023b00f..6a956f2ac 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -28,7 +28,7 @@ import { CollectionSubView } from '../CollectionSubView'; import './CollectionSchemaView.scss'; import { SchemaColumnHeader } from './SchemaColumnHeader'; import { SchemaRowBox } from './SchemaRowBox'; -const { default: { SCHEMA_NEW_NODE_HEIGHT } } = require('../../global/globalCssVariables.module.scss'); // prettier-ignore +const { SCHEMA_NEW_NODE_HEIGHT } = require('../../global/globalCssVariables.module.scss'); // prettier-ignore export enum ColumnType { Number, diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index 1b239b5e5..53d1869d9 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -12,7 +12,7 @@ import { ObservableReactComponent } from '../../../ObservableReactComponent'; import { DocumentView } from '../../DocumentView'; import { DataVizView } from '../DataVizBox'; import './Chart.scss'; -const { default: { DATA_VIZ_TABLE_ROW_HEIGHT } } = require('../../../global/globalCssVariables.module.scss'); // prettier-ignore +const { DATA_VIZ_TABLE_ROW_HEIGHT } = require('../../../global/globalCssVariables.module.scss'); // prettier-ignore interface TableBoxProps { Document: Doc; layoutDoc: Doc; @@ -155,15 +155,14 @@ export class TableBox extends ObservableReactComponent { }, emptyFunction, action(e => { - if (e.shiftKey){ - if (this._props.titleCol == col) this._props.titleCol = ""; + if (e.shiftKey) { + if (this._props.titleCol == col) this._props.titleCol = ''; else this._props.titleCol = col; this._props.selectTitleCol(this._props.titleCol); - } - else{ + } else { const newAxes = this._props.axes; if (newAxes.includes(col)) newAxes.splice(newAxes.indexOf(col), 1); - else if (newAxes.length > 2) newAxes[newAxes.length-1] = col; + else if (newAxes.length > 2) newAxes[newAxes.length - 1] = col; else newAxes.push(col); this._props.selectAxes(newAxes); } @@ -220,12 +219,22 @@ export class TableBox extends ObservableReactComponent { 2 && this._props.axes.lastElement() === col) ? 'darkred' - : (this._props.axes.lastElement()===col || (this._props.axes.length>2 && this._props.axes[1]==col))? 'darkblue' : undefined, - background: this._props.axes.slice().reverse().lastElement() === col ? '#E3fbdb' - : (this._props.axes.length>2 && this._props.axes.lastElement() === col) ? '#Fbdbdb' - : (this._props.axes.lastElement()===col || (this._props.axes.length>2 && this._props.axes[1]==col))? '#c6ebf7' : undefined, + color: + this._props.axes.slice().reverse().lastElement() === col + ? 'darkgreen' + : this._props.axes.length > 2 && this._props.axes.lastElement() === col + ? 'darkred' + : this._props.axes.lastElement() === col || (this._props.axes.length > 2 && this._props.axes[1] == col) + ? 'darkblue' + : undefined, + background: + this._props.axes.slice().reverse().lastElement() === col + ? '#E3fbdb' + : this._props.axes.length > 2 && this._props.axes.lastElement() === col + ? '#Fbdbdb' + : this._props.axes.lastElement() === col || (this._props.axes.length > 2 && this._props.axes[1] == col) + ? '#c6ebf7' + : undefined, // blue: #ADD8E6 // green: #E3fbdb // red: #Fbdbdb @@ -251,10 +260,10 @@ export class TableBox extends ObservableReactComponent { }}> {this.columns.map(col => { var colSelected = false; - if (this._props.axes.length>2) colSelected = this._props.axes[0]==col || this._props.axes[1]==col || this._props.axes[2]==col; - else if (this._props.axes.length>1) colSelected = this._props.axes[0]==col || this._props.axes[1]==col; - else if (this._props.axes.length>0) colSelected = this._props.axes[0]==col; - if (this._props.titleCol==col) colSelected = true; + if (this._props.axes.length > 2) colSelected = this._props.axes[0] == col || this._props.axes[1] == col || this._props.axes[2] == col; + else if (this._props.axes.length > 1) colSelected = this._props.axes[0] == col || this._props.axes[1] == col; + else if (this._props.axes.length > 0) colSelected = this._props.axes[0] == col; + if (this._props.titleCol == col) colSelected = true; return (
{this._props.records[rowId][col]}
diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx index 0a4325d8c..ff1e62885 100644 --- a/src/client/views/nodes/LinkAnchorBox.tsx +++ b/src/client/views/nodes/LinkAnchorBox.tsx @@ -13,7 +13,7 @@ import { StyleProp } from '../StyleProvider'; import { FieldView, FieldViewProps } from './FieldView'; import './LinkAnchorBox.scss'; import { LinkInfo } from './LinkDocPreview'; -const { default: { MEDIUM_GRAY }, } = require('../global/globalCssVariables.module.scss'); // prettier-ignore +const { MEDIUM_GRAY } = require('../global/globalCssVariables.module.scss'); // prettier-ignore @observer export class LinkAnchorBox extends ViewBoxBaseComponent() { public static LayoutString(fieldKey: string) { diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx index e333e6a2e..da01e099c 100644 --- a/src/mobile/ImageUpload.tsx +++ b/src/mobile/ImageUpload.tsx @@ -14,7 +14,7 @@ import { listSpec } from '../fields/Schema'; import { Cast } from '../fields/Types'; import './ImageUpload.scss'; import { MobileInterface } from './MobileInterface'; -const { default: { DFLT_IMAGE_NATIVE_DIM } } = require('../client/views/global/globalCssVariables.module.scss'); // prettier-ignore +const { DFLT_IMAGE_NATIVE_DIM } = require('../client/views/global/globalCssVariables.module.scss'); // prettier-ignore export interface ImageUploadProps { Document: Doc; // Target document for upload (upload location) } -- cgit v1.2.3-70-g09d2