From b9483279f4a778e0cc997e304b4f0b87e6ec1e5d Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 15 Apr 2020 00:29:00 -0400 Subject: changed collection chrome filter to just open filter sidebar. fixed scrollbar to make sure that all datapoints are included. simplified filter documents to have only a datadocument. --- src/client/documents/Documents.ts | 1 - .../views/collections/CollectionTreeView.tsx | 11 +- src/client/views/collections/CollectionView.tsx | 20 +- .../views/collections/CollectionViewChromes.scss | 3 +- .../views/collections/CollectionViewChromes.tsx | 316 ++++++--------------- 5 files changed, 100 insertions(+), 251 deletions(-) (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index e6f3b21ca..129ab0403 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -142,7 +142,6 @@ export interface DocumentOptions { treeViewHideHeaderFields?: boolean; // whether to hide the drop down options for tree view items. treeViewOpen?: boolean; // whether this document is expanded in a tree view treeViewChecked?: ScriptField; // script to call when a tree view checkbox is checked - isFacetFilter?: boolean; // whether document functions as a facet filter in a tree view limitHeight?: number; // maximum height for newly created (eg, from pasting) text documents // [key: string]: Opt; pointerHack?: boolean; // for buttons, allows onClick handler to fire onPointerDown diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index b96ee4bc4..9ec8c4c5b 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -840,12 +840,11 @@ Scripting.addGlobal(function readFacetData(layoutDoc: Doc, dataDoc: Doc, dataKey } }); const facetValueDocSet = (nonNumbers / facetValues.length > .1 ? facetValues.sort() : facetValues.sort((n1: string, n2: string) => Number(n1) - Number(n2))).map(facetValue => - Docs.Create.TextDocument("", { - title: facetValue.toString(), - treeViewChecked: ComputedField.MakeFunction("determineCheckedState(layoutDoc, facetHeader, facetValue)", - {}, - { layoutDoc, facetHeader, facetValue }) - })); + { const doc = new Doc(); + doc.title = facetValue.toString(); + doc.treeViewChecked = ComputedField.MakeFunction("determineCheckedState(layoutDoc, facetHeader, facetValue)",{},{ layoutDoc, facetHeader, facetValue }); + return doc; + }); return new List(facetValueDocSet); }); diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 13a657800..831691f8c 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -45,8 +45,6 @@ import { ScriptField, ComputedField } from '../../../new_fields/ScriptField'; import { InteractionUtils } from '../../util/InteractionUtils'; import { ObjectField } from '../../../new_fields/ObjectField'; import CollectionMapView from './CollectionMapView'; -import { ClientUtils } from '../../util/ClientUtils'; -import { GoogleApiWrapper } from 'google-maps-react'; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -279,7 +277,8 @@ export class CollectionView extends Touchable { onMovePrevRequest={action(() => this._curLightboxImg = (this._curLightboxImg + images.length - 1) % images.length)} onMoveNextRequest={action(() => this._curLightboxImg = (this._curLightboxImg + 1) % images.length)} />); } - @observable _facetWidth = 0; + get _facetWidth() { return NumCast(this.props.Document._facetWidth) } + set _facetWidth(value) { this.props.Document._facetWidth = value; } bodyPanelWidth = () => this.props.PanelWidth() - this.facetWidth(); getTransform = () => this.props.ScreenToLocalTransform().translate(-this.facetWidth(), 0); @@ -365,17 +364,22 @@ export class CollectionView extends Touchable { Doc.GetProto(newFacet).type = DocumentType.COL; // forces item to show an open/close button instead ofa checkbox newFacet.treeViewExpandedView = "layout"; newFacet.treeViewOpen = true; - newFacet[newFacetField + "-min"] = ranged === undefined ? minVal : ranged[0]; - newFacet[newFacetField + "-max"] = ranged === undefined ? maxVal : ranged[1]; - Doc.GetProto(newFacet)[newFacetField + "-minThumb"] = minVal; - Doc.GetProto(newFacet)[newFacetField + "-maxThumb"] = maxVal; + const extendedMinVal = minVal - Math.min(1, Math.abs(maxVal - minVal) * .05); + const extendedMaxVal = maxVal + Math.min(1, Math.abs(maxVal - minVal) * .05); + newFacet[newFacetField + "-min"] = ranged === undefined ? extendedMinVal : ranged[0]; + newFacet[newFacetField + "-max"] = ranged === undefined ? extendedMaxVal : ranged[1]; + Doc.GetProto(newFacet)[newFacetField + "-minThumb"] = extendedMinVal; + Doc.GetProto(newFacet)[newFacetField + "-maxThumb"] = extendedMaxVal; newFacet.target = this.props.Document; const scriptText = `setDocFilterRange(this.target, "${facetHeader}", range)`; newFacet.onThumbChanged = ScriptField.MakeScript(scriptText, { this: Doc.name, range: "number" }); Doc.AddDocToList(facetCollection, this.props.fieldKey + "-filter", newFacet); } else { - newFacet = Docs.Create.TreeDocument([], { title: facetHeader, treeViewOpen: true, isFacetFilter: true }); + newFacet = new Doc(); + newFacet.title = facetHeader; + newFacet.treeViewOpen = true; + newFacet.type = DocumentType.COL; const capturedVariables = { layoutDoc: this.props.Document, dataDoc: this.dataDoc }; newFacet.data = ComputedField.MakeFunction(`readFacetData(layoutDoc, dataDoc, "${this.props.fieldKey}", "${facetHeader}")`, {}, capturedVariables); } diff --git a/src/client/views/collections/CollectionViewChromes.scss b/src/client/views/collections/CollectionViewChromes.scss index a691b4805..9529ef525 100644 --- a/src/client/views/collections/CollectionViewChromes.scss +++ b/src/client/views/collections/CollectionViewChromes.scss @@ -67,10 +67,11 @@ color:grey; margin-top:auto; margin-bottom:auto; + margin-left: 5px; } .collectionViewBaseChrome-viewSpecs { - margin-left: 10px; + margin-left: 25px; display: grid; .collectionViewBaseChrome-filterIcon { diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index 66f627083..cef85e148 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -6,7 +6,6 @@ import { Doc, DocListCast } from "../../../new_fields/Doc"; import { Id } from "../../../new_fields/FieldSymbols"; import { List } from "../../../new_fields/List"; import { listSpec } from "../../../new_fields/Schema"; -import { ScriptField } from "../../../new_fields/ScriptField"; import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types"; import { Utils, emptyFunction, setupMoveUpEvents } from "../../../Utils"; import { DragManager } from "../../util/DragManager"; @@ -16,8 +15,6 @@ import { COLLECTION_BORDER_WIDTH } from "../globalCssVariables.scss"; import { CollectionViewType } from "./CollectionView"; import { CollectionView } from "./CollectionView"; import "./CollectionViewChromes.scss"; -import * as Autosuggest from 'react-autosuggest'; -import KeyRestrictionRow from "./KeyRestrictionRow"; const datepicker = require('js-datepicker'); interface CollectionViewChromeProps { @@ -84,62 +81,10 @@ export class CollectionViewBaseChrome extends React.Component(); private _viewRef = React.createRef(); - private _autosuggestRef = React.createRef(); @observable private _currentKey: string = ""; - @observable private _viewSpecsOpen: boolean = false; - @observable private _dateWithinValue: string = ""; - @observable private _dateValue: Date | string = ""; - @observable private _keyRestrictions: [JSX.Element, string][] = []; - @observable private suggestions: string[] = []; - @computed private get filterValue() { return Cast(this.props.CollectionView.props.Document.viewSpecScript, ScriptField); } - - getFilters = (script: string) => { - const re: any = /(!)?\(\(\(doc\.(\w+)\s+&&\s+\(doc\.\w+\s+as\s+\w+\)\.includes\(\"(\w+)\"\)/g; - const arr: any[] = re.exec(script); - const toReturn: Filter[] = []; - if (arr !== null) { - const filter: Filter = { - key: arr[2], - value: arr[3], - contains: (arr[1] === "!") ? false : true, - }; - toReturn.push(filter); - script = script.replace(arr[0], ""); - if (re.exec(script) !== null) { - toReturn.push(...this.getFilters(script)); - } - else { return toReturn; } - } - return toReturn; - } - - addKeyRestrictions = (fields: Filter[]) => { - - if (fields.length !== 0) { - for (let i = 0; i < fields.length; i++) { - this._keyRestrictions.push([ runInAction(() => this._keyRestrictions[i][1] = value)} />, ""]); - - } - if (this._keyRestrictions.length === 1) { - this._keyRestrictions.push([ runInAction(() => this._keyRestrictions[1][1] = value)} />, ""]); - } - } - else { - this._keyRestrictions.push([ runInAction(() => this._keyRestrictions[0][1] = value)} />, ""]); - this._keyRestrictions.push([ runInAction(() => this._keyRestrictions[1][1] = value)} />, ""]); - } - } componentDidMount = () => { - - let fields: Filter[] = []; - if (this.filterValue) { - const string = this.filterValue.script.originalScript; - fields = this.getFilters(string); - } - runInAction(() => { - this.addKeyRestrictions(fields); // chrome status is one of disabled, collapsed, or visible. this determines initial state from document const chromeStatus = this.props.CollectionView.props.Document._chromeStatus; if (chromeStatus) { @@ -158,7 +103,7 @@ export class CollectionViewBaseChrome extends React.Component { //@ts-ignore - this.props.CollectionView.props.Document._viewType = e.target.selectedOptions[0].value; + this.document._viewType = e.target.selectedOptions[0].value; } commandChanged = (e: React.ChangeEvent) => { @@ -167,104 +112,93 @@ export class CollectionViewBaseChrome extends React.Component { - if (this._viewSpecsOpen) this.closeViewSpecs(); - else { - this._viewSpecsOpen = true; - - //@ts-ignore - if (!e.target?.classList[0]?.startsWith("qs")) { - this.closeDatePicker(); - } - - e.stopPropagation(); - document.removeEventListener("pointerdown", this.closeViewSpecs); - document.addEventListener("pointerdown", this.closeViewSpecs); - } + toggleViewSpecs = (e: React.SyntheticEvent) => { + this.document._facetWidth = this.document._facetWidth ? 0 : 200; + e.stopPropagation(); } @action closeViewSpecs = () => { - this._viewSpecsOpen = false; - document.removeEventListener("pointerdown", this.closeViewSpecs); - } - - @action - openDatePicker = (e: React.PointerEvent) => { - this.openViewSpecs(e); - if (this._picker) { - this._picker.alwaysShow = true; - this._picker.show(); - // TODO: calendar is offset when zoomed in/out - // this._picker.calendar.style.position = "absolute"; - // let transform = this.props.CollectionView.props.ScreenToLocalTransform(); - // let x = parseInt(this._picker.calendar.style.left) / transform.Scale; - // let y = parseInt(this._picker.calendar.style.top) / transform.Scale; - // this._picker.calendar.style.left = x; - // this._picker.calendar.style.top = y; - - e.stopPropagation(); - } - } - - @action - addKeyRestriction = (e: React.MouseEvent) => { - const index = this._keyRestrictions.length; - this._keyRestrictions.push([ runInAction(() => this._keyRestrictions[index][1] = value)} />, ""]); - - this.openViewSpecs(e); - } - - @action.bound - applyFilter = (e: React.MouseEvent) => { - - this.openViewSpecs(e); - - const keyRestrictionScript = "(" + this._keyRestrictions.map(i => i[1]).filter(i => i.length > 0).join(" && ") + ")"; - const yearOffset = this._dateWithinValue[1] === 'y' ? 1 : 0; - const monthOffset = this._dateWithinValue[1] === 'm' ? parseInt(this._dateWithinValue[0]) : 0; - const weekOffset = this._dateWithinValue[1] === 'w' ? parseInt(this._dateWithinValue[0]) : 0; - const dayOffset = (this._dateWithinValue[1] === 'd' ? parseInt(this._dateWithinValue[0]) : 0) + weekOffset * 7; - let dateRestrictionScript = ""; - if (this._dateValue instanceof Date) { - const lowerBound = new Date(this._dateValue.getFullYear() - yearOffset, this._dateValue.getMonth() - monthOffset, this._dateValue.getDate() - dayOffset); - const upperBound = new Date(this._dateValue.getFullYear() + yearOffset, this._dateValue.getMonth() + monthOffset, this._dateValue.getDate() + dayOffset + 1); - dateRestrictionScript = `((doc.creationDate as any).date >= ${lowerBound.valueOf()} && (doc.creationDate as any).date <= ${upperBound.valueOf()})`; - } - else { - const createdDate = new Date(this._dateValue); - if (!isNaN(createdDate.getTime())) { - const lowerBound = new Date(createdDate.getFullYear() - yearOffset, createdDate.getMonth() - monthOffset, createdDate.getDate() - dayOffset); - const upperBound = new Date(createdDate.getFullYear() + yearOffset, createdDate.getMonth() + monthOffset, createdDate.getDate() + dayOffset + 1); - dateRestrictionScript = `((doc.creationDate as any).date >= ${lowerBound.valueOf()} && (doc.creationDate as any).date <= ${upperBound.valueOf()})`; - } - } - const fullScript = dateRestrictionScript.length || keyRestrictionScript.length ? dateRestrictionScript.length ? - `${dateRestrictionScript} ${keyRestrictionScript.length ? "&&" : ""} (${keyRestrictionScript})` : - `(${keyRestrictionScript}) ${dateRestrictionScript.length ? "&&" : ""} ${dateRestrictionScript}` : - "true"; + this.document._facetWidth = 0; + } + + // @action + // openDatePicker = (e: React.PointerEvent) => { + // if (this._picker) { + // this._picker.alwaysShow = true; + // this._picker.show(); + // // TODO: calendar is offset when zoomed in/out + // // this._picker.calendar.style.position = "absolute"; + // // let transform = this.props.CollectionView.props.ScreenToLocalTransform(); + // // let x = parseInt(this._picker.calendar.style.left) / transform.Scale; + // // let y = parseInt(this._picker.calendar.style.top) / transform.Scale; + // // this._picker.calendar.style.left = x; + // // this._picker.calendar.style.top = y; + + // e.stopPropagation(); + // } + // } + + // runInAction(() => this._dateValue = e.target.value)} + // onPointerDown={this.openDatePicker} + // placeholder="Value" /> + // @action.bound + // applyFilter = (e: React.MouseEvent) => { + // const keyRestrictionScript = "(" + this._keyRestrictions.map(i => i[1]).filter(i => i.length > 0).join(" && ") + ")"; + // const yearOffset = this._dateWithinValue[1] === 'y' ? 1 : 0; + // const monthOffset = this._dateWithinValue[1] === 'm' ? parseInt(this._dateWithinValue[0]) : 0; + // const weekOffset = this._dateWithinValue[1] === 'w' ? parseInt(this._dateWithinValue[0]) : 0; + // const dayOffset = (this._dateWithinValue[1] === 'd' ? parseInt(this._dateWithinValue[0]) : 0) + weekOffset * 7; + // let dateRestrictionScript = ""; + // if (this._dateValue instanceof Date) { + // const lowerBound = new Date(this._dateValue.getFullYear() - yearOffset, this._dateValue.getMonth() - monthOffset, this._dateValue.getDate() - dayOffset); + // const upperBound = new Date(this._dateValue.getFullYear() + yearOffset, this._dateValue.getMonth() + monthOffset, this._dateValue.getDate() + dayOffset + 1); + // dateRestrictionScript = `((doc.creationDate as any).date >= ${lowerBound.valueOf()} && (doc.creationDate as any).date <= ${upperBound.valueOf()})`; + // } + // else { + // const createdDate = new Date(this._dateValue); + // if (!isNaN(createdDate.getTime())) { + // const lowerBound = new Date(createdDate.getFullYear() - yearOffset, createdDate.getMonth() - monthOffset, createdDate.getDate() - dayOffset); + // const upperBound = new Date(createdDate.getFullYear() + yearOffset, createdDate.getMonth() + monthOffset, createdDate.getDate() + dayOffset + 1); + // dateRestrictionScript = `((doc.creationDate as any).date >= ${lowerBound.valueOf()} && (doc.creationDate as any).date <= ${upperBound.valueOf()})`; + // } + // } + // const fullScript = dateRestrictionScript.length || keyRestrictionScript.length ? dateRestrictionScript.length ? + // `${dateRestrictionScript} ${keyRestrictionScript.length ? "&&" : ""} (${keyRestrictionScript})` : + // `(${keyRestrictionScript}) ${dateRestrictionScript.length ? "&&" : ""} ${dateRestrictionScript}` : + // "true"; + + // this.props.CollectionView.props.Document.viewSpecScript = ScriptField.MakeFunction(fullScript, { doc: Doc.name }); + // } + + // datePickerRef = (node: HTMLInputElement) => { + // if (node) { + // try { + // this._picker = datepicker("#" + node.id, { + // disabler: (date: Date) => date > new Date(), + // onSelect: (instance: any, date: Date) => runInAction(() => {}), // this._dateValue = date), + // dateSelected: new Date() + // }); + // } catch (e) { + // console.log("date picker exception:" + e); + // } + // } + // } - this.props.CollectionView.props.Document.viewSpecScript = ScriptField.MakeFunction(fullScript, { doc: Doc.name }); - } - - @action - closeDatePicker = () => { - if (this._picker) { - this._picker.alwaysShow = false; - this._picker.hide(); - } - document.removeEventListener("pointerdown", this.closeDatePicker); - } @action toggleCollapse = () => { - this.props.CollectionView.props.Document._chromeStatus = this.props.CollectionView.props.Document._chromeStatus === "enabled" ? "collapsed" : "enabled"; + this.document._chromeStatus = this.document._chromeStatus === "enabled" ? "collapsed" : "enabled"; if (this.props.collapse) { this.props.collapse(this.props.CollectionView.props.Document._chromeStatus !== "enabled"); } } subChrome = () => { - const collapsed = this.props.CollectionView.props.Document._chromeStatus !== "enabled"; + const collapsed = this.document._chromeStatus !== "enabled"; if (collapsed) return null; switch (this.props.type) { case CollectionViewType.Stacking: return (); @@ -279,13 +213,6 @@ export class CollectionViewBaseChrome extends React.Component { - this.props.CollectionView.props.Document.viewSpecScript = ScriptField.MakeFunction("true", { doc: Doc.name }); - this._keyRestrictions = []; - this.addKeyRestrictions([]); - } - private dropDisposer?: DragManager.DragDropDisposer; protected createDropTarget = (ele: HTMLDivElement) => { this.dropDisposer && this.dropDisposer(); @@ -304,48 +231,6 @@ export class CollectionViewBaseChrome extends React.Component { - if (node) { - try { - this._picker = datepicker("#" + node.id, { - disabler: (date: Date) => date > new Date(), - onSelect: (instance: any, date: Date) => runInAction(() => this._dateValue = date), - dateSelected: new Date() - }); - } catch (e) { - console.log("date picker exception:" + e); - } - } - } - - renderSuggestion = (suggestion: string) => { - return

{suggestion}

; - } - getSuggestionValue = (suggestion: string) => suggestion; - - @action - onKeyChange = (e: React.ChangeEvent, { newValue }: { newValue: string }) => { - this._currentKey = newValue; - } - onSuggestionFetch = async ({ value }: { value: string }) => { - const sugg = await this.getKeySuggestions(value); - runInAction(() => this.suggestions = sugg); - } - @action - onSuggestionClear = () => { - this.suggestions = []; - } - getKeySuggestions = async (value: string): Promise => { - return this._buttonizableCommands.filter(c => c.title.indexOf(value) !== -1).map(c => c.title); - } - - autoSuggestDown = (e: React.PointerEvent) => { - e.stopPropagation(); - } - - private _startDragPosition: { x: number, y: number } = { x: 0, y: 0 }; - private _sensitivity: number = 16; - dragViewDown = (e: React.PointerEvent) => { setupMoveUpEvents(this, e, (e, down, delta) => { const vtype = this.props.CollectionView.collectionViewType; @@ -367,7 +252,6 @@ export class CollectionViewBaseChrome extends React.Component -
+
+
+ +
+
+
@@ -414,49 +303,6 @@ export class CollectionViewBaseChrome extends React.Component
-
-
- -
-
- {this._keyRestrictions.map(i => i[0])} -
-
- CREATED WITHIN: -
- - runInAction(() => this._dateValue = e.target.value)} - onPointerDown={this.openDatePicker} - placeholder="Value" /> -
-
- - - -
-
-
-- cgit v1.2.3-70-g09d2 From d5c0ed9a29593583a4180973f854106dc10d4b30 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 15 Apr 2020 02:32:47 -0400 Subject: moved filter to right side of collection. got rid of back button in pivot view - click background. --- src/Utils.ts | 10 +++-- .../views/collections/CollectionTimeView.tsx | 30 +++++++-------- src/client/views/collections/CollectionView.scss | 4 +- src/client/views/collections/CollectionView.tsx | 43 +++++++++++++++------- .../views/collections/CollectionViewChromes.scss | 8 +++- .../views/collections/CollectionViewChromes.tsx | 12 +++--- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 + .../views/nodes/CollectionFreeFormDocumentView.tsx | 3 +- 8 files changed, 69 insertions(+), 43 deletions(-) (limited to 'src') diff --git a/src/Utils.ts b/src/Utils.ts index a8cde0624..58f272ba5 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -475,7 +475,9 @@ export function setupMoveUpEvents( e: React.PointerEvent, moveEvent: (e: PointerEvent, down: number[], delta: number[]) => boolean, upEvent: (e: PointerEvent) => void, - clickEvent: (e: PointerEvent) => void) { + clickEvent: (e: PointerEvent) => void, + stopPropagation: boolean = true +) { (target as any)._downX = (target as any)._lastX = e.clientX; (target as any)._downY = (target as any)._lastY = e.clientY; @@ -499,8 +501,10 @@ export function setupMoveUpEvents( document.removeEventListener("pointermove", _moveEvent); document.removeEventListener("pointerup", _upEvent); }; - e.stopPropagation(); - e.preventDefault(); + if (stopPropagation) { + e.stopPropagation(); + e.preventDefault(); + } document.removeEventListener("pointermove", _moveEvent); document.removeEventListener("pointerup", _upEvent); document.addEventListener("pointermove", _moveEvent); diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 31b720b81..1760e2419 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -72,8 +72,22 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { }), returnFalse, emptyFunction); } + contentsDown = (e: React.PointerEvent) => { + setupMoveUpEvents(this, e, returnFalse, returnFalse, action(() => { + let prevFilterIndex = NumCast(this.props.Document._prevFilterIndex); + if (prevFilterIndex > 0) { + prevFilterIndex--; + this.props.Document._docFilters = ObjectField.MakeCopy(this.props.Document["_prevDocFilter" + prevFilterIndex] as ObjectField); + this.props.Document._docRangeFilters = ObjectField.MakeCopy(this.props.Document["_prevDocRangeFilters" + prevFilterIndex] as ObjectField); + this.props.Document._prevFilterIndex = prevFilterIndex; + } else { + this.props.Document._docFilters = new List([]); + } + }), false); + } + @computed get contents() { - return
+ return
; } @@ -132,20 +146,6 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { color: "#f1efeb" // this.props.headingObject ? this.props.headingObject.color : "#f1efeb"; }; return
-
; } diff --git a/src/client/views/collections/CollectionView.scss b/src/client/views/collections/CollectionView.scss index a0b73b90f..d43dd387a 100644 --- a/src/client/views/collections/CollectionView.scss +++ b/src/client/views/collections/CollectionView.scss @@ -20,7 +20,7 @@ top: 55%; border: 1px black solid; z-index: 2; - left: -10px; + right: -10px; } .collectionTimeView-treeView { display: flex; @@ -28,7 +28,7 @@ width: 200px; height: 100%; position: absolute; - left: 0; + right: 0; top: 0; .collectionTimeView-addfacet { diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 831691f8c..0a3577bc7 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -13,7 +13,7 @@ import { List } from '../../../new_fields/List'; import { BoolCast, Cast, NumCast, StrCast, ScriptCast } from '../../../new_fields/Types'; import { ImageField } from '../../../new_fields/URLField'; import { TraceMobx } from '../../../new_fields/util'; -import { Utils, setupMoveUpEvents, returnFalse, returnZero } from '../../../Utils'; +import { Utils, setupMoveUpEvents, returnFalse, returnZero, emptyPath, emptyFunction, returnOne } from '../../../Utils'; import { DocumentType } from '../../documents/DocumentTypes'; import { DocumentManager } from '../../util/DocumentManager'; import { ImageUtils } from '../../util/Import & Export/ImageUtils'; @@ -45,6 +45,7 @@ import { ScriptField, ComputedField } from '../../../new_fields/ScriptField'; import { InteractionUtils } from '../../util/InteractionUtils'; import { ObjectField } from '../../../new_fields/ObjectField'; import CollectionMapView from './CollectionMapView'; +import { Transform } from 'prosemirror-transform'; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -281,7 +282,6 @@ export class CollectionView extends Touchable { set _facetWidth(value) { this.props.Document._facetWidth = value; } bodyPanelWidth = () => this.props.PanelWidth() - this.facetWidth(); - getTransform = () => this.props.ScreenToLocalTransform().translate(-this.facetWidth(), 0); facetWidth = () => Math.max(0, Math.min(this.props.PanelWidth() - 25, this._facetWidth)); @computed get dataDoc() { @@ -389,7 +389,7 @@ export class CollectionView extends Touchable { onPointerDown = (e: React.PointerEvent) => { setupMoveUpEvents(this, e, action((e: PointerEvent, down: number[], delta: number[]) => { - this._facetWidth = Math.max(this.props.ScreenToLocalTransform().transformPoint(e.clientX, 0)[0], 0); + this._facetWidth = this.props.PanelWidth() - Math.max(this.props.ScreenToLocalTransform().transformPoint(e.clientX, 0)[0], 0); return false; }), returnFalse, action(() => this._facetWidth = this.facetWidth() < 15 ? Math.min(this.props.PanelWidth() - 25, 200) : 0)); } @@ -415,27 +415,44 @@ export class CollectionView extends Touchable {
e.stopPropagation()}>
- Facet Filters + Facet Filters
- @@ -461,7 +478,7 @@ export class CollectionView extends Touchable { }} onContextMenu={this.onContextMenu}> {this.showIsTagged()} -
+
{this.collectionViewType !== undefined ? this.SubView(this.collectionViewType, props) : (null)}
{this.lightbox(DocListCast(this.props.Document[this.props.fieldKey]).filter(d => d.type === DocumentType.IMG).map(d => @@ -471,9 +488,7 @@ export class CollectionView extends Touchable { : ""))} {!this.props.isSelected() || this.props.PanelHeight() < 100 || this.props.Document.hideFilterView ? (null) : -
- -
+
} {this.filterView}
); diff --git a/src/client/views/collections/CollectionViewChromes.scss b/src/client/views/collections/CollectionViewChromes.scss index 9529ef525..5203eb55f 100644 --- a/src/client/views/collections/CollectionViewChromes.scss +++ b/src/client/views/collections/CollectionViewChromes.scss @@ -61,7 +61,8 @@ pointer-events: all; // margin-top: 10px; } - .collectionViewBaseChrome-template { + .collectionViewBaseChrome-template, + .collectionViewBaseChrome-viewModes { display: grid; background: rgb(238, 238, 238); color:grey; @@ -69,9 +70,12 @@ margin-bottom:auto; margin-left: 5px; } + .collectionViewBaseChrome-viewModes { + margin-left: 25px; + } .collectionViewBaseChrome-viewSpecs { - margin-left: 25px; + margin-left: 5px; display: grid; .collectionViewBaseChrome-filterIcon { diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index cef85e148..7315d2c4e 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -276,12 +276,7 @@ export class CollectionViewBaseChrome extends React.Component -
-
- -
-
-
+
@@ -303,6 +298,11 @@ export class CollectionViewBaseChrome extends React.Component
+
+
+ +
+
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index a77f09163..d98fe190c 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -907,6 +907,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u onViewDefDivClick = (e: React.MouseEvent, payload: any) => { (this.props.Document.onViewDefDivClick as ScriptField)?.script.run({ this: this.props.Document, payload }); + e.stopPropagation(); } private viewDefToJSX(viewDef: ViewDefBounds): Opt { const { x, y, z } = viewDef; @@ -991,6 +992,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u {...this.getChildDocumentViewProps(pair.layout, pair.data)} dataProvider={this.childDataProvider} LayoutDoc={this.childLayoutDocFunc} + pointerEvents={this.props.layoutEngine?.() !== undefined ? "none" : undefined} jitterRotation={NumCast(this.props.Document.jitterRotation)} fitToBox={this.props.fitToBox || BoolCast(this.props.freezeChildDimensions)} FreezeDimensions={BoolCast(this.props.freezeChildDimensions)} diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index e7cb2c015..05ad98c43 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -22,6 +22,7 @@ export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { width?: number; height?: number; jitterRotation: number; + pointerEvents?: "none"; transition?: string; fitToBox?: boolean; } @@ -92,7 +93,7 @@ export class CollectionFreeFormDocumentView extends DocComponent {!this.props.fitToBox ? -- cgit v1.2.3-70-g09d2 From a6d17ef79fb94334735998d3d11f7ea068dea93a Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 15 Apr 2020 03:15:25 -0400 Subject: cleaned up some more of the pivot view event handling api --- .../views/collections/CollectionTimeView.tsx | 23 ++++++++++------------ src/client/views/collections/CollectionView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 7 +++++-- 3 files changed, 16 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 1760e2419..e05223ca0 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -1,6 +1,6 @@ import { action, computed, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; -import { Doc } from "../../../new_fields/Doc"; +import { Doc, Opt, DocCastAsync } from "../../../new_fields/Doc"; import { List } from "../../../new_fields/List"; import { ObjectField } from "../../../new_fields/ObjectField"; import { RichTextField } from "../../../new_fields/RichTextField"; @@ -26,18 +26,15 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { _changing = false; @observable _layoutEngine = "pivot"; @observable _collapsed: boolean = false; - componentWillUnmount() { - this.props.Document.onChildClick = undefined; - } + @observable _childClickedScript: Opt; + @observable _viewDefDivClick: Opt; async componentDidMount() { - const childText = "const alias = getAlias(this); switchView(alias, thisContainer.childDetailView); alias.dropAction='alias'; alias.removeDropProperties=new List(['dropAction']); useRightSplit(alias, shiftKey); "; - this.props.Document.onChildClick = ScriptField.MakeScript(childText, { this: Doc.name, heading: "string", thisContainer: Doc.name, shiftKey: "boolean" }); - this.props.Document._fitToBox = true; - if (!this.props.Document.onViewDefClick) { - this.props.Document.onViewDefDivClick = ScriptField.MakeScript("pivotColumnClick(this,payload)", { payload: "any" }); - } - this.props.Document.childDetailView = Cast(this.props.Document.childDetailView, Doc, null) ||// bcz: needs to be here to make sure the childDetailView layout template has been loaded when the first item is clicked; - DocumentView.findTemplate("detailView", StrCast(this.props.Document.type), ""); + const detailView = (await DocCastAsync(this.props.Document.childDetailView)) || DocumentView.findTemplate("detailView", StrCast(this.props.Document.type), ""); + const childText = "const alias = getAlias(this); switchView(alias, detailView); alias.dropAction='alias'; alias.removeDropProperties=new List(['dropAction']); useRightSplit(alias, shiftKey); "; + runInAction(() => { + this._childClickedScript = ScriptField.MakeScript(childText, { this: Doc.name, shiftKey: "boolean" }, { detailView: detailView! }); + this._viewDefDivClick = ScriptField.MakeScript("pivotColumnClick(this,payload)", { payload: "any" }); + }); } layoutEngine = () => this._layoutEngine; @@ -88,7 +85,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { @computed get contents() { return
- +
; } diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 0a3577bc7..19e235ff2 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -278,7 +278,7 @@ export class CollectionView extends Touchable { onMovePrevRequest={action(() => this._curLightboxImg = (this._curLightboxImg + images.length - 1) % images.length)} onMoveNextRequest={action(() => this._curLightboxImg = (this._curLightboxImg + 1) % images.length)} />); } - get _facetWidth() { return NumCast(this.props.Document._facetWidth) } + get _facetWidth() { return NumCast(this.props.Document._facetWidth); } set _facetWidth(value) { this.props.Document._facetWidth = value; } bodyPanelWidth = () => this.props.PanelWidth() - this.facetWidth(); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index d98fe190c..f19181a20 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -44,6 +44,7 @@ import MarqueeOptionsMenu from "./MarqueeOptionsMenu"; import { MarqueeView } from "./MarqueeView"; import React = require("react"); import { CollectionViewType } from "../CollectionView"; +import { Script } from "vm"; library.add(faEye as any, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt, faCompass, faUpload, faBraille, faChalkboard, faFileUpload); @@ -69,6 +70,8 @@ type PanZoomDocument = makeInterface<[typeof panZoomSchema, typeof documentSchem const PanZoomDocument = makeInterface(panZoomSchema, documentSchema, positionSchema, pageSchema); export type collectionFreeformViewProps = { forceScaling?: boolean; // whether to force scaling of content (needed by ImageBox) + childClickScript?: ScriptField; + viewDefDivClick?: ScriptField; }; @observer @@ -847,7 +850,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u } @computed get libraryPath() { return this.props.LibraryPath ? [...this.props.LibraryPath, this.props.Document] : []; } - @computed get onChildClickHandler() { return ScriptCast(this.Document.onChildClick); } + @computed get onChildClickHandler() { return this.props.childClickScript || ScriptCast(this.Document.onChildClick); } backgroundHalo = () => BoolCast(this.Document.useClusters); getChildDocumentViewProps(childLayout: Doc, childData?: Doc): DocumentViewProps { @@ -906,7 +909,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u } onViewDefDivClick = (e: React.MouseEvent, payload: any) => { - (this.props.Document.onViewDefDivClick as ScriptField)?.script.run({ this: this.props.Document, payload }); + (this.props.viewDefDivClick || ScriptCast(this.props.Document.onViewDefDivClick))?.script.run({ this: this.props.Document, payload }); e.stopPropagation(); } private viewDefToJSX(viewDef: ViewDefBounds): Opt { -- cgit v1.2.3-70-g09d2 From 142cb372c6dec9fa641786784cbdd6dca6896d33 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Wed, 15 Apr 2020 00:42:07 -0700 Subject: added robust error checking for lat, lng and address values, reverts to previous on invalid entry or zero results --- src/client/views/collections/CollectionMapView.tsx | 63 +++++++++++++++------- 1 file changed, 44 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionMapView.tsx b/src/client/views/collections/CollectionMapView.tsx index 64946e59e..5b8b6e75a 100644 --- a/src/client/views/collections/CollectionMapView.tsx +++ b/src/client/views/collections/CollectionMapView.tsx @@ -12,6 +12,7 @@ import { DocumentManager } from "../../util/DocumentManager"; import { UndoManager, undoBatch } from "../../util/UndoManager"; import { IReactionDisposer, reaction, computed, runInAction } from "mobx"; import requestPromise = require("request-promise"); +import { emptyFunction } from "../../../Utils"; type MapSchema = makeInterface<[typeof documentSchema]>; const MapSchema = makeInterface(documentSchema); @@ -119,11 +120,11 @@ class CollectionMapView extends CollectionSubView & } private respondToAddressChange = async (newAddress: string, doc: Doc) => { - const { results } = await query(newAddress); - if (!results?.length) { - return; + const response = await query(newAddress); + if (!response || response.status === "ZERO_RESULTS") { + return false; } - const { geometry, formatted_address } = results[0]; + const { geometry, formatted_address } = response.results[0]; const { lat, lng } = geometry.location; runInAction(() => { if (doc["mapLocation-lat"] !== lat || doc["mapLocation-lng"] !== lng) { @@ -136,18 +137,20 @@ class CollectionMapView extends CollectionSubView & Doc.SetInPlace(doc, "mapLocation-address", formatted_address, true); } }); + return true; } private respondToLocationChange = async (newLat: FieldResult, newLng: FieldResult, doc: Doc) => { - const { results } = await query({ lat: NumCast(newLat), lng: NumCast(newLng) }); - if (!results?.length) { - return; + const response = await query({ lat: NumCast(newLat), lng: NumCast(newLng) }); + if (!response || response.status === "ZERO_RESULTS") { + return false; } - const { formatted_address } = results[0]; + const { formatted_address } = response.results[0]; if (formatted_address !== doc["mapLocation-address"]) { this._cancelAddrReq.set(doc[Id], true); Doc.SetInPlace(doc, "mapLocation-address", formatted_address, true); } + return true; } @computed get contents() { @@ -156,23 +159,45 @@ class CollectionMapView extends CollectionSubView & this.latlngUpdaters.forEach(disposer => disposer()); this.latlngUpdaters = []; return this.childLayoutPairs.map(({ layout }) => { + const id = layout[Id]; this.addressUpdaters.push(reaction( () => ({ lat: layout["mapLocation-lat"], lng: layout["mapLocation-lng"] }), - ({ lat, lng }) => { - if (this._cancelLocReq.get(layout[Id])) { - this._cancelLocReq.set(layout[Id], false); - } else if (lat !== undefined && lng !== undefined) { - this.respondToLocationChange(lat, lng, layout); + emptyFunction, + { + equals: (previous, { lat, lng }) => { + if (this._cancelLocReq.get(id)) { + this._cancelLocReq.set(id, false); + } else if (lat !== undefined && lng !== undefined) { + this.respondToLocationChange(lat, lng, layout).then(success => { + if (!success) { + this._cancelLocReq.set(id, true); + runInAction(() => { + layout["mapLocation-lat"] = previous.lat; + layout["mapLocation-lng"] = previous.lng; + }); + } + }); + } + return previous === { lat, lng }; } } )); this.latlngUpdaters.push(reaction( - () => ({ address: Cast(layout["mapLocation-address"], "string", null) }), - ({ address }) => { - if (this._cancelAddrReq.get(layout[Id])) { - this._cancelAddrReq.set(layout[Id], false); - } else if (address?.length) { - this.respondToAddressChange(address, layout); + () => Cast(layout["mapLocation-address"], "string", null), + emptyFunction, + { + equals: (previous, address) => { + if (this._cancelAddrReq.get(id)) { + this._cancelAddrReq.set(id, false); + } else if (address?.length) { + this.respondToAddressChange(address, layout).then(success => { + if (!success) { + this._cancelAddrReq.set(id, true); + layout["mapLocation-address"] = previous; + } + }); + } + return previous === address; } } )); -- cgit v1.2.3-70-g09d2 From 15f3a7898268b8fc6eded456515726a2c40b6b46 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Wed, 15 Apr 2020 01:22:18 -0700 Subject: using interesting mobx paradigm to manage value interception --- src/client/views/collections/CollectionMapView.tsx | 49 ++++++++++------------ 1 file changed, 21 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionMapView.tsx b/src/client/views/collections/CollectionMapView.tsx index 5b8b6e75a..4fbccac33 100644 --- a/src/client/views/collections/CollectionMapView.tsx +++ b/src/client/views/collections/CollectionMapView.tsx @@ -10,7 +10,7 @@ import { CollectionSubView } from "./CollectionSubView"; import React = require("react"); import { DocumentManager } from "../../util/DocumentManager"; import { UndoManager, undoBatch } from "../../util/UndoManager"; -import { IReactionDisposer, reaction, computed, runInAction } from "mobx"; +import { IReactionDisposer, reaction, computed, runInAction, Lambda } from "mobx"; import requestPromise = require("request-promise"); import { emptyFunction } from "../../../Utils"; @@ -42,8 +42,8 @@ class CollectionMapView extends CollectionSubView & private _cancelAddrReq = new Map(); private _cancelLocReq = new Map(); private _initialLookupPending = new Map(); - private addressUpdaters: IReactionDisposer[] = []; - private latlngUpdaters: IReactionDisposer[] = []; + private addressUpdaters: Lambda[] = []; + private latlngUpdaters: Lambda[] = []; /** * Note that all the uses of runInAction below are not included @@ -153,18 +153,17 @@ class CollectionMapView extends CollectionSubView & return true; } - @computed get contents() { + @computed get reactiveContents() { this.addressUpdaters.forEach(disposer => disposer()); this.addressUpdaters = []; this.latlngUpdaters.forEach(disposer => disposer()); this.latlngUpdaters = []; return this.childLayoutPairs.map(({ layout }) => { const id = layout[Id]; - this.addressUpdaters.push(reaction( - () => ({ lat: layout["mapLocation-lat"], lng: layout["mapLocation-lng"] }), - emptyFunction, - { - equals: (previous, { lat, lng }) => { + this.addressUpdaters.push( + computed(() => ({ lat: layout["mapLocation-lat"], lng: layout["mapLocation-lng"] })) + .observe(({ oldValue, newValue }) => { + const { lat, lng } = newValue; if (this._cancelLocReq.get(id)) { this._cancelLocReq.set(id, false); } else if (lat !== undefined && lng !== undefined) { @@ -172,35 +171,29 @@ class CollectionMapView extends CollectionSubView & if (!success) { this._cancelLocReq.set(id, true); runInAction(() => { - layout["mapLocation-lat"] = previous.lat; - layout["mapLocation-lng"] = previous.lng; + layout["mapLocation-lat"] = oldValue ? oldValue.lat : undefined; + layout["mapLocation-lng"] = oldValue ? oldValue.lng : undefined; }); } }); } - return previous === { lat, lng }; - } - } - )); - this.latlngUpdaters.push(reaction( - () => Cast(layout["mapLocation-address"], "string", null), - emptyFunction, - { - equals: (previous, address) => { + }) + ); + this.latlngUpdaters.push( + computed(() => Cast(layout["mapLocation-address"], "string", null)) + .observe(({ oldValue, newValue }) => { if (this._cancelAddrReq.get(id)) { this._cancelAddrReq.set(id, false); - } else if (address?.length) { - this.respondToAddressChange(address, layout).then(success => { + } else if (newValue?.length) { + this.respondToAddressChange(newValue, layout).then(success => { if (!success) { this._cancelAddrReq.set(id, true); - layout["mapLocation-address"] = previous; + layout["mapLocation-address"] = oldValue; } }); } - return previous === address; - } - } - )); + }) + ); return this.renderMarker(layout); }); } @@ -233,7 +226,7 @@ class CollectionMapView extends CollectionSubView & }); })} > - {this.contents} + {this.reactiveContents}
; -- cgit v1.2.3-70-g09d2 From a3e2d21f848bae54b0de8d3a81a996f2f551c84f Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 15 Apr 2020 11:50:36 -0400 Subject: fixed onCheckedClick to use scriptingBox --- src/client/documents/Documents.ts | 2 ++ .../views/collections/CollectionTreeView.tsx | 27 +++++++++++----------- src/client/views/nodes/DocumentView.tsx | 2 +- src/client/views/nodes/ScriptingBox.tsx | 4 ++-- .../authentication/models/current_user_utils.ts | 6 +++-- 5 files changed, 23 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 129ab0403..608bd28ae 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -116,6 +116,8 @@ export interface DocumentOptions { boxShadow?: string; dontRegisterChildren?: boolean; "onClick-rawScript"?: string; // onClick script in raw text form + "onCheckedClick-rawScript"?: string; // onChecked script in raw text form + "onCheckedClick-params"?: List; // parameter list for onChecked treeview functions _pivotField?: string; // field key used to determine headings for sections in stacking, masonry, pivot views schemaColumns?: List; dockingConfig?: string; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 9ec8c4c5b..d2c8cc3ad 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -19,7 +19,7 @@ import { makeTemplate } from '../../util/DropConverter'; import { Scripting } from '../../util/Scripting'; import { SelectionManager } from '../../util/SelectionManager'; import { Transform } from '../../util/Transform'; -import { undoBatch } from '../../util/UndoManager'; +import { undoBatch, UndoManager } from '../../util/UndoManager'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; import { EditableView } from "../EditableView"; @@ -397,11 +397,13 @@ class TreeView extends React.Component { } } + get onCheckedClick() { return this.props.onCheckedClick || ScriptCast(this.props.document.onCheckedClick); } + @action bulletClick = (e: React.MouseEvent) => { - if (this.props.onCheckedClick && this.props.document.type !== DocumentType.COL) { + if (this.onCheckedClick && this.props.document.type !== DocumentType.COL) { // this.props.document.treeViewChecked = this.props.document.treeViewChecked === "check" ? "x" : this.props.document.treeViewChecked === "x" ? undefined : "check"; - ScriptCast(this.props.onCheckedClick).script.run({ + this.onCheckedClick.script.run({ this: this.props.document.isTemplateForField && this.props.dataDoc ? this.props.dataDoc : this.props.document, heading: this.props.containingCollection.title, checked: this.props.document.treeViewChecked === "check" ? "x" : this.props.document.treeViewChecked === "x" ? undefined : "check", @@ -415,7 +417,7 @@ class TreeView extends React.Component { @computed get renderBullet() { - const checked = this.props.document.type === DocumentType.COL ? undefined : this.props.onCheckedClick ? (this.props.document.treeViewChecked ? this.props.document.treeViewChecked : "unchecked") : undefined; + const checked = this.props.document.type === DocumentType.COL ? undefined : this.onCheckedClick ? (this.props.document.treeViewChecked ? this.props.document.treeViewChecked : "unchecked") : undefined; return
{}
; @@ -764,8 +766,7 @@ export class CollectionTreeView extends CollectionSubView(Document, undefined as const existingOnClick = ContextMenu.Instance.findByDescription("OnClick..."); const onClicks: ContextMenuProps[] = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : []; onClicks.push({ - description: "Edit onChecked Script", icon: "edit", event: (obj: any) => ScriptBox.EditButtonScript("On Checked Changed ...", this.props.Document, - "onCheckedClick", obj.x, obj.y, { heading: "boolean", checked: "boolean", treeViewContainer: Doc.name }) + description: "Edit onChecked Script", event: () => UndoManager.RunInBatch(() => DocumentView.makeCustomViewClicked(this.props.Document, undefined, "onCheckedClick"), "edit onCheckedClick"), icon: "edit" }); !existingOnClick && ContextMenu.Instance.addItem({ description: "OnClick...", subitems: onClicks, icon: "hand-point-right" }); } @@ -818,7 +819,7 @@ export class CollectionTreeView extends CollectionSubView(Document, undefined as TreeView.GetChildElements(childDocs, this.props.Document, this.props.Document, this.props.DataDoc, this.props.fieldKey, this.props.ContainingCollectionDoc, undefined, addDoc, this.remove, moveDoc, dropAction, this.props.addDocTab, this.props.pinToPres, this.props.backgroundColor, this.props.ScreenToLocalTransform, this.outerXf, this.props.active, this.props.PanelWidth, this.props.ChromeHeight, this.props.renderDepth, () => this.props.treeViewHideHeaderFields || BoolCast(this.props.Document.treeViewHideHeaderFields), - BoolCast(this.props.Document.treeViewPreventOpen), [], this.props.LibraryPath, this.props.onCheckedClick || ScriptCast(this.props.Document.onCheckedClick), + BoolCast(this.props.Document.treeViewPreventOpen), [], this.props.LibraryPath, this.props.onCheckedClick, this.props.onChildClick || ScriptCast(this.props.Document.onChildClick), this.props.ignoreFields) } @@ -839,12 +840,12 @@ Scripting.addGlobal(function readFacetData(layoutDoc: Doc, dataDoc: Doc, dataKey nonNumbers++; } }); - const facetValueDocSet = (nonNumbers / facetValues.length > .1 ? facetValues.sort() : facetValues.sort((n1: string, n2: string) => Number(n1) - Number(n2))).map(facetValue => - { const doc = new Doc(); - doc.title = facetValue.toString(); - doc.treeViewChecked = ComputedField.MakeFunction("determineCheckedState(layoutDoc, facetHeader, facetValue)",{},{ layoutDoc, facetHeader, facetValue }); - return doc; - }); + const facetValueDocSet = (nonNumbers / facetValues.length > .1 ? facetValues.sort() : facetValues.sort((n1: string, n2: string) => Number(n1) - Number(n2))).map(facetValue => { + const doc = new Doc(); + doc.title = facetValue.toString(); + doc.treeViewChecked = ComputedField.MakeFunction("determineCheckedState(layoutDoc, facetHeader, facetValue)", {}, { layoutDoc, facetHeader, facetValue }); + return doc; + }); return new List(facetValueDocSet); }); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index cb7811fbb..54e4d549e 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -746,7 +746,7 @@ export class DocumentView extends DocComponent(Docu onClicks.push({ description: this.Document.ignoreClick ? "Select" : "Do Nothing", event: () => this.Document.ignoreClick = !this.Document.ignoreClick, icon: this.Document.ignoreClick ? "unlock" : "lock" }); onClicks.push({ description: this.Document.isLinkButton ? "Remove Follow Behavior" : "Follow Link in Place", event: this.toggleFollowInPlace, icon: "concierge-bell" }); onClicks.push({ description: this.Document.isLinkButton || this.Document.onClick ? "Remove Click Behavior" : "Follow Link", event: this.toggleLinkButtonBehavior, icon: "concierge-bell" }); - onClicks.push({ description: "Edit onClick Script", icon: "edit", event: (obj: any) => ScriptBox.EditButtonScript("On Button Clicked ...", this.props.Document, "onClick", obj.x, obj.y) }); + onClicks.push({ description: "Edit onClick Script", event: () => UndoManager.RunInBatch(() => DocumentView.makeCustomViewClicked(this.props.Document, undefined, "onClick"), "edit onClick"), icon: "edit" }); !existingOnClick && cm.addItem({ description: "OnClick...", subitems: onClicks, icon: "hand-point-right" }); const funcs: ContextMenuProps[] = []; diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx index a257898ab..c607d6614 100644 --- a/src/client/views/nodes/ScriptingBox.tsx +++ b/src/client/views/nodes/ScriptingBox.tsx @@ -28,8 +28,8 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent { target && docCast(this.source).then((source) => { target.proto.data = new List([source || this]); } ); } )", { target: Doc.name }), { title: "On Child Clicked (open in target)", _width: 300, _height: 200 }); - const onClick = Docs.Create.ScriptingDocument(ScriptField.MakeScript("console.log('click')"), { title: "onClick", isTemplateDoc: true, isTemplateForField: "onClick", _width: 300, _height: 200 }, "onClick"); + const onClick = Docs.Create.ScriptingDocument(undefined, { title: "onClick", "onClick-rawScript": "console.log('click')", isTemplateDoc: true, isTemplateForField: "onClick", _width: 300, _height: 200 }, "onClick"); + const onCheckedClick = Docs.Create.ScriptingDocument(undefined, + { title: "onCheckedClick", "onCheckedClick-rawScript": "console.log(heading + checked + containingTreeView)", "onCheckedClick-params": new List(["heading", "checked", "containingTreeView"]), isTemplateDoc: true, isTemplateForField: "onCheckedClick", _width: 300, _height: 200 }, "onCheckedClick"); doc.childClickFuncs = Docs.Create.TreeDocument([openInTarget], { title: "on Child Click function templates" }); - doc.clickFuncs = Docs.Create.TreeDocument([onClick], { title: "onClick funcs" }); + doc.clickFuncs = Docs.Create.TreeDocument([onClick, onCheckedClick], { title: "onClick funcs" }); } static updateUserDocument(doc: Doc) { -- cgit v1.2.3-70-g09d2 From 86885c0e97322ae99f331e594a5c67cf04cb4ec2 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 15 Apr 2020 12:33:21 -0400 Subject: extended getLocation to work with the map itself in addition to makers so that document titles can be used to indicate locations. --- src/client/views/collections/CollectionMapView.tsx | 35 +++++++++++----------- 1 file changed, 17 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionMapView.tsx b/src/client/views/collections/CollectionMapView.tsx index 4fbccac33..583594057 100644 --- a/src/client/views/collections/CollectionMapView.tsx +++ b/src/client/views/collections/CollectionMapView.tsx @@ -1,18 +1,17 @@ import { GoogleApiWrapper, Map as GeoMap, MapProps, Marker } from "google-maps-react"; +import { computed, Lambda, runInAction } from "mobx"; import { observer } from "mobx-react"; -import { Doc, Opt, DocListCast, FieldResult } from "../../../new_fields/Doc"; +import { Doc, DocListCast, FieldResult, Opt } from "../../../new_fields/Doc"; import { documentSchema } from "../../../new_fields/documentSchemas"; import { Id } from "../../../new_fields/FieldSymbols"; import { makeInterface } from "../../../new_fields/Schema"; import { Cast, NumCast, ScriptCast, StrCast } from "../../../new_fields/Types"; +import { DocumentManager } from "../../util/DocumentManager"; +import { undoBatch, UndoManager } from "../../util/UndoManager"; import "./CollectionMapView.scss"; import { CollectionSubView } from "./CollectionSubView"; import React = require("react"); -import { DocumentManager } from "../../util/DocumentManager"; -import { UndoManager, undoBatch } from "../../util/UndoManager"; -import { IReactionDisposer, reaction, computed, runInAction, Lambda } from "mobx"; import requestPromise = require("request-promise"); -import { emptyFunction } from "../../../Utils"; type MapSchema = makeInterface<[typeof documentSchema]>; const MapSchema = makeInterface(documentSchema); @@ -58,15 +57,15 @@ class CollectionMapView extends CollectionSubView & const lat: Opt = Cast(doc[fieldKey + "-lat"], "number", null) || (Cast(doc[fieldKey + "-lat"], "string", null) && Number(Cast(doc[fieldKey + "-lat"], "string", null))) || undefined; const lng: Opt = Cast(doc[fieldKey + "-lng"], "number", null) || (Cast(doc[fieldKey + "-lng"], "string", null) && Number(Cast(doc[fieldKey + "-lng"], "string", null))) || undefined; const zoom: Opt = Cast(doc[fieldKey + "-zoom"], "number", null) || (Cast(doc[fieldKey + "-zoom"], "string", null) && Number(Cast(doc[fieldKey + "-zoom"], "string", null))) || undefined; - const address: Opt = Cast(doc[fieldKey + "-address"], "string", null); + const address: Opt = Cast(doc[fieldKey + "-address"], "string", (lat === undefined || lng === undefined ? Cast(doc.title, "string", null) : null)); if (lat !== undefined && lng !== undefined) { return ({ lat, lng, zoom }); } else if (address) { const id = doc[Id]; if (!this._initialLookupPending.get(id)) { - this._initialLookupPending.set(id, true); + this._initialLookupPending.set(id, true); `` setTimeout(() => { - this.respondToAddressChange(address, doc).then(() => this._initialLookupPending.delete(id)); + this.respondToAddressChange(address, fieldKey, doc).then(() => this._initialLookupPending.delete(id)); }); } return defaultLocation; @@ -119,7 +118,7 @@ class CollectionMapView extends CollectionSubView & />; } - private respondToAddressChange = async (newAddress: string, doc: Doc) => { + private respondToAddressChange = async (newAddress: string, fieldKey: string, doc: Doc) => { const response = await query(newAddress); if (!response || response.status === "ZERO_RESULTS") { return false; @@ -127,28 +126,28 @@ class CollectionMapView extends CollectionSubView & const { geometry, formatted_address } = response.results[0]; const { lat, lng } = geometry.location; runInAction(() => { - if (doc["mapLocation-lat"] !== lat || doc["mapLocation-lng"] !== lng) { + if (doc[fieldKey + "-lat"] !== lat || doc[fieldKey + "-lng"] !== lng) { this._cancelLocReq.set(doc[Id], true); - Doc.SetInPlace(doc, "mapLocation-lat", lat, true); - Doc.SetInPlace(doc, "mapLocation-lng", lng, true); + Doc.SetInPlace(doc, fieldKey + "-lat", lat, true); + Doc.SetInPlace(doc, fieldKey + "-lng", lng, true); } if (formatted_address !== newAddress) { this._cancelAddrReq.set(doc[Id], true); - Doc.SetInPlace(doc, "mapLocation-address", formatted_address, true); + Doc.SetInPlace(doc, fieldKey + "-address", formatted_address, true); } }); return true; } - private respondToLocationChange = async (newLat: FieldResult, newLng: FieldResult, doc: Doc) => { + private respondToLocationChange = async (newLat: FieldResult, newLng: FieldResult, fieldKey: string, doc: Doc) => { const response = await query({ lat: NumCast(newLat), lng: NumCast(newLng) }); if (!response || response.status === "ZERO_RESULTS") { return false; } const { formatted_address } = response.results[0]; - if (formatted_address !== doc["mapLocation-address"]) { + if (formatted_address !== doc[fieldKey + "-address"]) { this._cancelAddrReq.set(doc[Id], true); - Doc.SetInPlace(doc, "mapLocation-address", formatted_address, true); + Doc.SetInPlace(doc, fieldKey + "-address", formatted_address, true); } return true; } @@ -167,7 +166,7 @@ class CollectionMapView extends CollectionSubView & if (this._cancelLocReq.get(id)) { this._cancelLocReq.set(id, false); } else if (lat !== undefined && lng !== undefined) { - this.respondToLocationChange(lat, lng, layout).then(success => { + this.respondToLocationChange(lat, lng, "mapLocation", layout).then(success => { if (!success) { this._cancelLocReq.set(id, true); runInAction(() => { @@ -185,7 +184,7 @@ class CollectionMapView extends CollectionSubView & if (this._cancelAddrReq.get(id)) { this._cancelAddrReq.set(id, false); } else if (newValue?.length) { - this.respondToAddressChange(newValue, layout).then(success => { + this.respondToAddressChange(newValue, "mapLocation", layout).then(success => { if (!success) { this._cancelAddrReq.set(id, true); layout["mapLocation-address"] = oldValue; -- cgit v1.2.3-70-g09d2 From 531aab6465459557055c0c02e35b1029192263b4 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Wed, 15 Apr 2020 10:19:58 -0700 Subject: final cleanup --- src/client/views/collections/CollectionMapView.tsx | 83 +++++++++++----------- 1 file changed, 42 insertions(+), 41 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionMapView.tsx b/src/client/views/collections/CollectionMapView.tsx index 4fbccac33..062419b74 100644 --- a/src/client/views/collections/CollectionMapView.tsx +++ b/src/client/views/collections/CollectionMapView.tsx @@ -1,6 +1,6 @@ import { GoogleApiWrapper, Map as GeoMap, MapProps, Marker } from "google-maps-react"; import { observer } from "mobx-react"; -import { Doc, Opt, DocListCast, FieldResult } from "../../../new_fields/Doc"; +import { Doc, Opt, DocListCast, FieldResult, Field } from "../../../new_fields/Doc"; import { documentSchema } from "../../../new_fields/documentSchemas"; import { Id } from "../../../new_fields/FieldSymbols"; import { makeInterface } from "../../../new_fields/Schema"; @@ -10,9 +10,8 @@ import { CollectionSubView } from "./CollectionSubView"; import React = require("react"); import { DocumentManager } from "../../util/DocumentManager"; import { UndoManager, undoBatch } from "../../util/UndoManager"; -import { IReactionDisposer, reaction, computed, runInAction, Lambda } from "mobx"; +import { computed, runInAction, Lambda } from "mobx"; import requestPromise = require("request-promise"); -import { emptyFunction } from "../../../Utils"; type MapSchema = makeInterface<[typeof documentSchema]>; const MapSchema = makeInterface(documentSchema); @@ -23,8 +22,14 @@ export type LocationData = google.maps.LatLngLiteral & { zoom?: number; }; +interface DocLatLng { + lat: FieldResult; + lng: FieldResult; +} + // Nowhere, Oklahoma const defaultLocation = { lat: 35.1592238, lng: -98.444512, zoom: 15 }; +const noResults = "ZERO_RESULTS"; const query = async (data: string | google.maps.LatLngLiteral) => { const contents = typeof data === "string" ? `address=${data.replace(/\s+/g, "+")}` : `latlng=${data.lat},${data.lng}`; @@ -42,8 +47,7 @@ class CollectionMapView extends CollectionSubView & private _cancelAddrReq = new Map(); private _cancelLocReq = new Map(); private _initialLookupPending = new Map(); - private addressUpdaters: Lambda[] = []; - private latlngUpdaters: Lambda[] = []; + private responders: { location: Lambda, address: Lambda }[] = []; /** * Note that all the uses of runInAction below are not included @@ -66,7 +70,7 @@ class CollectionMapView extends CollectionSubView & if (!this._initialLookupPending.get(id)) { this._initialLookupPending.set(id, true); setTimeout(() => { - this.respondToAddressChange(address, doc).then(() => this._initialLookupPending.delete(id)); + this.respondToAddressChange(doc, address).then(() => this._initialLookupPending.delete(id)); }); } return defaultLocation; @@ -119,30 +123,45 @@ class CollectionMapView extends CollectionSubView & />; } - private respondToAddressChange = async (newAddress: string, doc: Doc) => { + private respondToAddressChange = async (doc: Doc, newAddress: string, oldAddress?: string) => { + if (newAddress === oldAddress) { + return false; + } const response = await query(newAddress); - if (!response || response.status === "ZERO_RESULTS") { + const id = doc[Id]; + if (!response || response.status === noResults) { + this._cancelAddrReq.set(id, true); + doc["mapLocation-address"] = oldAddress; return false; } const { geometry, formatted_address } = response.results[0]; const { lat, lng } = geometry.location; runInAction(() => { if (doc["mapLocation-lat"] !== lat || doc["mapLocation-lng"] !== lng) { - this._cancelLocReq.set(doc[Id], true); + this._cancelLocReq.set(id, true); Doc.SetInPlace(doc, "mapLocation-lat", lat, true); Doc.SetInPlace(doc, "mapLocation-lng", lng, true); } if (formatted_address !== newAddress) { - this._cancelAddrReq.set(doc[Id], true); + this._cancelAddrReq.set(id, true); Doc.SetInPlace(doc, "mapLocation-address", formatted_address, true); } }); return true; } - private respondToLocationChange = async (newLat: FieldResult, newLng: FieldResult, doc: Doc) => { - const response = await query({ lat: NumCast(newLat), lng: NumCast(newLng) }); - if (!response || response.status === "ZERO_RESULTS") { + private respondToLocationChange = async (doc: Doc, newLatLng: DocLatLng, oldLatLng: Opt) => { + if (newLatLng === oldLatLng) { + return false; + } + const response = await query({ lat: NumCast(newLatLng.lat), lng: NumCast(newLatLng.lng) }); + const id = doc[Id]; + if (!response || response.status === noResults) { + this._cancelLocReq.set(id, true); + runInAction(() => { + doc["mapLocation-lat"] = oldLatLng?.lat; + doc["mapLocation-lng"] = oldLatLng?.lng; + }); return false; } const { formatted_address } = response.results[0]; @@ -154,46 +173,28 @@ class CollectionMapView extends CollectionSubView & } @computed get reactiveContents() { - this.addressUpdaters.forEach(disposer => disposer()); - this.addressUpdaters = []; - this.latlngUpdaters.forEach(disposer => disposer()); - this.latlngUpdaters = []; + this.responders.forEach(({ location, address }) => { location(); address(); }); + this.responders = []; return this.childLayoutPairs.map(({ layout }) => { const id = layout[Id]; - this.addressUpdaters.push( - computed(() => ({ lat: layout["mapLocation-lat"], lng: layout["mapLocation-lng"] })) + this.responders.push({ + location: computed(() => ({ lat: layout["mapLocation-lat"], lng: layout["mapLocation-lng"] })) .observe(({ oldValue, newValue }) => { - const { lat, lng } = newValue; if (this._cancelLocReq.get(id)) { this._cancelLocReq.set(id, false); - } else if (lat !== undefined && lng !== undefined) { - this.respondToLocationChange(lat, lng, layout).then(success => { - if (!success) { - this._cancelLocReq.set(id, true); - runInAction(() => { - layout["mapLocation-lat"] = oldValue ? oldValue.lat : undefined; - layout["mapLocation-lng"] = oldValue ? oldValue.lng : undefined; - }); - } - }); + } else if (newValue.lat !== undefined && newValue.lng !== undefined) { + this.respondToLocationChange(layout, newValue, oldValue); } - }) - ); - this.latlngUpdaters.push( - computed(() => Cast(layout["mapLocation-address"], "string", null)) + }), + address: computed(() => Cast(layout["mapLocation-address"], "string", null)) .observe(({ oldValue, newValue }) => { if (this._cancelAddrReq.get(id)) { this._cancelAddrReq.set(id, false); } else if (newValue?.length) { - this.respondToAddressChange(newValue, layout).then(success => { - if (!success) { - this._cancelAddrReq.set(id, true); - layout["mapLocation-address"] = oldValue; - } - }); + this.respondToAddressChange(layout, newValue, oldValue); } }) - ); + }); return this.renderMarker(layout); }); } -- cgit v1.2.3-70-g09d2 From 9a2d00da67b0436d28dd64f8a25aa8a2b1a5140d Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Wed, 15 Apr 2020 10:40:07 -0700 Subject: syntax --- src/client/views/collections/CollectionMapView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionMapView.tsx b/src/client/views/collections/CollectionMapView.tsx index 1d8ad2458..b5043d1c5 100644 --- a/src/client/views/collections/CollectionMapView.tsx +++ b/src/client/views/collections/CollectionMapView.tsx @@ -207,7 +207,7 @@ class CollectionMapView extends CollectionSubView & const { Document, fieldKey, active, google } = this.props; let center = this.getLocation(Document, `${fieldKey}-mapCenter`); if (center === undefined) { - center = childLayoutPairs.map(pair => this.getLocation(pair.layout, fieldKey)).find(layout => layout); + center = childLayoutPairs.map(({ layout }) => this.getLocation(layout, fieldKey)).find(layout => layout); if (center === undefined) { center = defaultLocation; } -- cgit v1.2.3-70-g09d2 From da6d058cd842209bdfd0f618e1cc19c99139135b Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 15 Apr 2020 14:14:57 -0400 Subject: improved title support for map entries using @ to reset address. added lockedPosition support for maps... kinda. --- src/client/views/collections/CollectionMapView.tsx | 43 ++++++++++++++-------- 1 file changed, 28 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionMapView.tsx b/src/client/views/collections/CollectionMapView.tsx index 583594057..f533a3874 100644 --- a/src/client/views/collections/CollectionMapView.tsx +++ b/src/client/views/collections/CollectionMapView.tsx @@ -1,5 +1,5 @@ import { GoogleApiWrapper, Map as GeoMap, MapProps, Marker } from "google-maps-react"; -import { computed, Lambda, runInAction } from "mobx"; +import { computed, Lambda, runInAction, action } from "mobx"; import { observer } from "mobx-react"; import { Doc, DocListCast, FieldResult, Opt } from "../../../new_fields/Doc"; import { documentSchema } from "../../../new_fields/documentSchemas"; @@ -54,22 +54,22 @@ class CollectionMapView extends CollectionSubView & private getLocation = (doc: Opt, fieldKey: string): Opt => { if (doc) { - const lat: Opt = Cast(doc[fieldKey + "-lat"], "number", null) || (Cast(doc[fieldKey + "-lat"], "string", null) && Number(Cast(doc[fieldKey + "-lat"], "string", null))) || undefined; - const lng: Opt = Cast(doc[fieldKey + "-lng"], "number", null) || (Cast(doc[fieldKey + "-lng"], "string", null) && Number(Cast(doc[fieldKey + "-lng"], "string", null))) || undefined; - const zoom: Opt = Cast(doc[fieldKey + "-zoom"], "number", null) || (Cast(doc[fieldKey + "-zoom"], "string", null) && Number(Cast(doc[fieldKey + "-zoom"], "string", null))) || undefined; - const address: Opt = Cast(doc[fieldKey + "-address"], "string", (lat === undefined || lng === undefined ? Cast(doc.title, "string", null) : null)); - if (lat !== undefined && lng !== undefined) { - return ({ lat, lng, zoom }); - } else if (address) { + const titleLoc = StrCast(doc.title).startsWith("@") ? StrCast(doc.title).substring(1) : undefined; + const lat = Cast(doc[fieldKey + "-lat"], "number", null) || (Cast(doc[fieldKey + "-lat"], "string", null) && Number(Cast(doc[fieldKey + "-lat"], "string", null))) || undefined; + const lng = Cast(doc[fieldKey + "-lng"], "number", null) || (Cast(doc[fieldKey + "-lng"], "string", null) && Number(Cast(doc[fieldKey + "-lng"], "string", null))) || undefined; + const zoom = Cast(doc[fieldKey + "-zoom"], "number", null) || (Cast(doc[fieldKey + "-zoom"], "string", null) && Number(Cast(doc[fieldKey + "-zoom"], "string", null))) || undefined; + const address = titleLoc || StrCast(doc[fieldKey + "-address"], StrCast(doc.title)); + if (titleLoc || (address && (lat === undefined || lng === undefined))) { const id = doc[Id]; if (!this._initialLookupPending.get(id)) { - this._initialLookupPending.set(id, true); `` + this._initialLookupPending.set(id, true); setTimeout(() => { + titleLoc && Doc.SetInPlace(doc, "title", titleLoc, true); this.respondToAddressChange(address, fieldKey, doc).then(() => this._initialLookupPending.delete(id)); }); } - return defaultLocation; } + return (lat === undefined || lng === undefined) ? defaultLocation : { lat, lng, zoom }; } return undefined; } @@ -217,12 +217,25 @@ class CollectionMapView extends CollectionSubView & zoom={center.zoom || 10} initialCenter={center} center={center} + onIdle={(_props: any, map: any) => { + if (this.layoutDoc.lockedTransform) { + map.setZoom(center?.zoom || 10); + } else { + center?.zoom !== map.getZoom() && undoBatch(action(() => { + Document[fieldKey + "-mapCenter-zoom"] = map.getZoom(); + }))(); + } + }} onDragend={undoBatch((_props: MapProps, map: google.maps.Map) => { - const { lat, lng } = map.getCenter(); - runInAction(() => { - Document[fieldKey + "-mapCenter-lat"] = lat(); - Document[fieldKey + "-mapCenter-lng"] = lng(); - }); + if (this.layoutDoc.lockedTransform) { + center?.lat && center.lng && map.setCenter(center); + } else { + const { lat, lng } = map.getCenter(); + runInAction(() => { + Document[fieldKey + "-mapCenter-lat"] = lat(); + Document[fieldKey + "-mapCenter-lng"] = lng(); + }); + } })} > {this.reactiveContents} -- cgit v1.2.3-70-g09d2 From 4d1782cbb359de2b672786df24985fbcf4be238a Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 15 Apr 2020 14:49:57 -0400 Subject: fixed bug just added with initial location of map --- src/client/views/collections/CollectionMapView.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionMapView.tsx b/src/client/views/collections/CollectionMapView.tsx index 3051b1ae7..2cb25fd9a 100644 --- a/src/client/views/collections/CollectionMapView.tsx +++ b/src/client/views/collections/CollectionMapView.tsx @@ -57,13 +57,13 @@ class CollectionMapView extends CollectionSubView & * and address–updating reactions. */ - private getLocation = (doc: Opt, fieldKey: string): Opt => { + private getLocation = (doc: Opt, fieldKey: string, returnDefault: boolean = true): Opt => { if (doc) { const titleLoc = StrCast(doc.title).startsWith("@") ? StrCast(doc.title).substring(1) : undefined; const lat = Cast(doc[`${fieldKey}-lat`], "number", null) || (Cast(doc[`${fieldKey}-lat`], "string", null) && Number(Cast(doc[`${fieldKey}-lat`], "string", null))) || undefined; const lng = Cast(doc[`${fieldKey}-lng`], "number", null) || (Cast(doc[`${fieldKey}-lng`], "string", null) && Number(Cast(doc[`${fieldKey}-lng`], "string", null))) || undefined; const zoom = Cast(doc[`${fieldKey}-zoom`], "number", null) || (Cast(doc[`${fieldKey}-zoom`], "string", null) && Number(Cast(doc[`${fieldKey}-zoom`], "string", null))) || undefined; - const address = titleLoc || StrCast(doc[`${fieldKey}-address`], StrCast(doc.title)); + const address = titleLoc || StrCast(doc[`${fieldKey}-address`], StrCast(doc.title).replace(/^-/, "")); if (titleLoc || (address && (lat === undefined || lng === undefined))) { const id = doc[Id]; if (!this._initialLookupPending.get(id)) { @@ -74,7 +74,7 @@ class CollectionMapView extends CollectionSubView & }); } } - return (lat === undefined || lng === undefined) ? defaultLocation : { lat, lng, zoom }; + return (lat === undefined || lng === undefined) ? (returnDefault ? defaultLocation : undefined) : { lat, lng, zoom }; } return undefined; } @@ -205,9 +205,9 @@ class CollectionMapView extends CollectionSubView & render() { const { childLayoutPairs } = this; const { Document, fieldKey, active, google } = this.props; - let center = this.getLocation(Document, `${fieldKey}-mapCenter`); + let center = this.getLocation(Document, `${fieldKey}-mapCenter`, false); if (center === undefined) { - center = childLayoutPairs.map(({ layout }) => this.getLocation(layout, fieldKey)).find(layout => layout); + center = childLayoutPairs.map(({ layout }) => this.getLocation(layout, fieldKey, false)).find(layout => layout); if (center === undefined) { center = defaultLocation; } -- cgit v1.2.3-70-g09d2 From eea49c30c0fa8035de63c60e1f4c3d9a29d896f1 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 15 Apr 2020 16:55:05 -0400 Subject: fixed changing cursor location in title text in tree views nested in freeform collecftions --- src/client/views/nodes/DocumentView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 54e4d549e..e6ae2d801 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -299,7 +299,7 @@ export class DocumentView extends DocComponent(Docu Doc.UnBrushDoc(this.props.Document); } } else if (this.onClickHandler?.script && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes("ScriptingBox")) { // bcz: hack? don't execute script if you're clicking on a scripting box itself - SelectionManager.DeselectAll(); + //SelectionManager.DeselectAll(); const func = () => this.onClickHandler.script.run({ this: this.layoutDoc, self: this.rootDoc, -- cgit v1.2.3-70-g09d2 From 7d3b2880bebf034607b946360c3e08338cf1d115 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Wed, 15 Apr 2020 14:04:13 -0700 Subject: fixed fieldKey errors: --- src/client/views/collections/CollectionMapView.tsx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionMapView.tsx b/src/client/views/collections/CollectionMapView.tsx index 2cb25fd9a..c80555a2e 100644 --- a/src/client/views/collections/CollectionMapView.tsx +++ b/src/client/views/collections/CollectionMapView.tsx @@ -99,8 +99,9 @@ class CollectionMapView extends CollectionSubView & } private renderMarkerIcon = (layout: Doc) => { - const { Document, fieldKey } = this.props; - const iconUrl = StrCast(Document.mapIconUrl, null); + const { Document } = this.props; + const fieldKey = Doc.LayoutFieldKey(layout); + const iconUrl = StrCast(layout.mapIconUrl, StrCast(Document.mapIconUrl)); if (iconUrl) { const iconWidth = NumCast(layout[`${fieldKey}-iconWidth`], 45); const iconHeight = NumCast(layout[`${fieldKey}-iconHeight`], 45); @@ -114,7 +115,7 @@ class CollectionMapView extends CollectionSubView & } private renderMarker = (layout: Doc) => { - const location = this.getLocation(layout, this.props.fieldKey); + const location = this.getLocation(layout, Doc.LayoutFieldKey(layout)); return !location ? (null) : & } @computed get reactiveContents() { - const { fieldKey } = this.props; this.responders.forEach(({ location, address }) => { location(); address(); }); this.responders = []; return this.childLayoutPairs.map(({ layout }) => { + const fieldKey = Doc.LayoutFieldKey(layout); const id = layout[Id]; this.responders.push({ location: computed(() => ({ lat: layout[`${fieldKey}-lat`], lng: layout[`${fieldKey}-lng`] })) @@ -207,7 +208,7 @@ class CollectionMapView extends CollectionSubView & const { Document, fieldKey, active, google } = this.props; let center = this.getLocation(Document, `${fieldKey}-mapCenter`, false); if (center === undefined) { - center = childLayoutPairs.map(({ layout }) => this.getLocation(layout, fieldKey, false)).find(layout => layout); + center = childLayoutPairs.map(({ layout }) => this.getLocation(layout, Doc.LayoutFieldKey(layout), false)).find(layout => layout); if (center === undefined) { center = defaultLocation; } -- cgit v1.2.3-70-g09d2 From e0f16b89cba102a4fcd156bb3d4148432eca2ab7 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 15 Apr 2020 19:10:09 -0400 Subject: removed lock icon from top-level documents. made schema functions compile without typechecking. metadata #'s starting with a # are now numbers. --- src/client/util/RichTextRules.ts | 3 ++- src/client/views/collections/CollectionSchemaView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/client/util/RichTextRules.ts b/src/client/util/RichTextRules.ts index 6bbe81115..3746199ba 100644 --- a/src/client/util/RichTextRules.ts +++ b/src/client/util/RichTextRules.ts @@ -110,7 +110,8 @@ export class RichTextRules { return state.tr; } if (value !== "" && value !== undefined) { - this.Document[DataSym][fieldKey] = value === "true" ? true : value === "false" ? false : value; + const num = value.match(/^[0-9.]/); + this.Document[DataSym][fieldKey] = value === "true" ? true : value === "false" ? false : (num ? Number(value) : value); } const fieldView = state.schema.nodes.dashField.create({ fieldKey, docid }); return state.tr.deleteRange(start, end).insert(start, fieldView); diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 57be77fdd..380d91d2f 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -736,7 +736,7 @@ export class SchemaTable extends React.Component { return (doc as any)[key][row + ${row}][(doc as any).schemaColumns[col + ${col}].heading]; } return ${script}`; - const compiled = CompileScript(script, { params: { this: Doc.name }, capturedVariables: { doc: this.props.Document, key: this.props.fieldKey }, typecheck: true, transformer: this.createTransformer(row, col) }); + const compiled = CompileScript(script, { params: { this: Doc.name }, capturedVariables: { doc: this.props.Document, key: this.props.fieldKey }, typecheck: false, transformer: this.createTransformer(row, col) }); if (compiled.compiled) { doc[field] = new ComputedField(compiled); return true; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index e6ae2d801..c0d530160 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1163,7 +1163,7 @@ export class DocumentView extends DocComponent(Docu
: this.innards} - {this.Document.isBackground !== undefined || this.isSelected(false) ?
this.toggleBackground(true)}>
: (null)} + {(this.Document.isBackground !== undefined || this.isSelected(false)) && this.props.renderDepth > 0 ?
this.toggleBackground(true)}>
: (null)}
; { this._showKPQuery ? : undefined; } } -- cgit v1.2.3-70-g09d2 From 35a31253ed3c7f4d31cebc2d1f2d6b1b4084108c Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Wed, 15 Apr 2020 22:27:38 -0700 Subject: cleanup --- src/client/views/collections/CollectionMapView.tsx | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionMapView.tsx b/src/client/views/collections/CollectionMapView.tsx index c80555a2e..7b7828d7d 100644 --- a/src/client/views/collections/CollectionMapView.tsx +++ b/src/client/views/collections/CollectionMapView.tsx @@ -208,10 +208,8 @@ class CollectionMapView extends CollectionSubView & const { Document, fieldKey, active, google } = this.props; let center = this.getLocation(Document, `${fieldKey}-mapCenter`, false); if (center === undefined) { - center = childLayoutPairs.map(({ layout }) => this.getLocation(layout, Doc.LayoutFieldKey(layout), false)).find(layout => layout); - if (center === undefined) { - center = defaultLocation; - } + const childLocations = childLayoutPairs.map(({ layout }) => this.getLocation(layout, Doc.LayoutFieldKey(layout), false)); + center = childLocations.find(location => location) || defaultLocation; } return
& center={center} onIdle={(_props?: MapProps, map?: google.maps.Map) => { if (this.layoutDoc.lockedTransform) { - map?.setZoom(center?.zoom || 10); // reset zoom (probably can tell the map to disallow zooming somehow) + // reset zoom (ideally, we could probably can tell the map to disallow zooming somehow instead) + map?.setZoom(center?.zoom || 10); + map?.setCenter({ lat: center?.lat!, lng: center?.lng! }); } else { const zoom = map?.getZoom(); - center?.zoom !== zoom && undoBatch(action(() => { + (center?.zoom !== zoom) && undoBatch(action(() => { Document[`${fieldKey}-mapCenter-zoom`] = zoom; }))(); } }} onDragend={(_props?: MapProps, map?: google.maps.Map) => { if (this.layoutDoc.lockedTransform) { - map?.setCenter({ lat: center?.lat!, lng: center?.lng! }); // reset the drag (probably can tell the map to disallow dragging somehow) + // reset the drag (ideally, we could probably can tell the map to disallow dragging somehow instead) + map?.setCenter({ lat: center?.lat!, lng: center?.lng! }); } else { undoBatch(action(({ lat, lng }) => { Document[`${fieldKey}-mapCenter-lat`] = lat(); -- cgit v1.2.3-70-g09d2 From aed0e3c7a85d4b67b119c9016366a1dbca04eb81 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 16 Apr 2020 09:48:35 -0400 Subject: getting rid of mongoose server connection warning --- src/server/database.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/server/database.ts b/src/server/database.ts index a46531641..2d95e7e70 100644 --- a/src/server/database.ts +++ b/src/server/database.ts @@ -35,7 +35,7 @@ export namespace Database { console.log(`mongoose established default connection at ${url}`); resolve(); }); - mongoose.connect(url, { useNewUrlParser: true }); + mongoose.connect(url, { useNewUrlParser: true, useUnifiedTopology: true }); }); } } catch (e) { -- cgit v1.2.3-70-g09d2 From cda5add3327f2ed6739e727ef1cf77937be23f17 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 16 Apr 2020 21:36:26 +0000 Subject: making debug server work --- package-lock.json | 5 +++-- src/server/database.ts | 18 ++++++++++++------ src/server/index.ts | 1 + 3 files changed, 16 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/package-lock.json b/package-lock.json index 72f6122d6..0f0384625 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6900,13 +6900,14 @@ "resolved": "https://registry.npmjs.org/image-size-stream/-/image-size-stream-1.1.0.tgz", "integrity": "sha1-Ivou2mbG31AQh0bacUkmSy0l+Gs=", "requires": { + "image-size": "github:netroy/image-size#da2c863807a3e9602617bdd357b0de3ab4a064c1", "readable-stream": "^1.0.33", "tryit": "^1.0.1" }, "dependencies": { "image-size": { - "version": "git+https://github.com/netroy/image-size.git#da2c863807a3e9602617bdd357b0de3ab4a064c1", - "from": "git+https://github.com/netroy/image-size.git#da2c863807a3e9602617bdd357b0de3ab4a064c1" + "version": "github:netroy/image-size#da2c863807a3e9602617bdd357b0de3ab4a064c1", + "from": "github:netroy/image-size#da2c863807a3e9602617bdd357b0de3ab4a064c1" }, "isarray": { "version": "0.0.1", diff --git a/src/server/database.ts b/src/server/database.ts index 2d95e7e70..1da31c5ff 100644 --- a/src/server/database.ts +++ b/src/server/database.ts @@ -14,7 +14,7 @@ export namespace Database { export let disconnect: Function; const schema = 'Dash'; const port = 27017; - export const url = `mongodb://localhost:${port}/${schema}`; + export const url = `mongodb://localhost:${port}/`; enum ConnectionStates { disconnected = 0, @@ -35,7 +35,7 @@ export namespace Database { console.log(`mongoose established default connection at ${url}`); resolve(); }); - mongoose.connect(url, { useNewUrlParser: true, useUnifiedTopology: true }); + mongoose.connect(url, { useNewUrlParser: true, useUnifiedTopology: true, dbName: schema }); }); } } catch (e) { @@ -46,17 +46,22 @@ export namespace Database { } } - class Database implements IDatabase { + export class Database implements IDatabase { public static DocumentsCollection = 'documents'; private MongoClient = mongodb.MongoClient; private currentWrites: { [id: string]: Promise } = {}; private db?: mongodb.Db; private onConnect: (() => void)[] = []; - constructor() { - this.MongoClient.connect(url, { connectTimeoutMS: 30000, socketTimeoutMS: 30000 }, (_err, client) => { + } + + doConnect() { + console.error(`\nConnecting to Mongo with URL : ${url}\n`); + this.MongoClient.connect(url, { connectTimeoutMS: 30000, socketTimeoutMS: 30000, useUnifiedTopology: true }, (_err, client) => { + console.error("mongo connect response\n"); if (!client) { - console.error("\nPlease start MongoDB by running 'mongod' in a terminal before continuing...\n"); + console.error("\nMongo connect failed with the error:\n"); + console.log(_err); process.exit(0); } this.db = client.db(); @@ -65,6 +70,7 @@ export namespace Database { } public async update(id: string, value: any, callback: (err: mongodb.MongoError, res: mongodb.UpdateWriteOpResult) => void, upsert = true, collectionName = Database.DocumentsCollection) { + if (this.db) { const collection = this.db.collection(collectionName); const prom = this.currentWrites[id]; diff --git a/src/server/index.ts b/src/server/index.ts index 8b040c926..1d7520b1c 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -148,5 +148,6 @@ export async function launchServer() { if (process.env.RELEASE) { (sessionAgent = new DashSessionAgent()).launch(); } else { + (Database.Instance as Database.Database).doConnect(); launchServer(); } -- cgit v1.2.3-70-g09d2 From ab007b636b99de38f7dee8ff08d1259dfc47e02a Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 16 Apr 2020 21:47:56 -0400 Subject: fixed detail view for pivot views for templates --- src/client/views/collections/CollectionTimeView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index e05223ca0..1d1949c99 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -30,7 +30,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { @observable _viewDefDivClick: Opt; async componentDidMount() { const detailView = (await DocCastAsync(this.props.Document.childDetailView)) || DocumentView.findTemplate("detailView", StrCast(this.props.Document.type), ""); - const childText = "const alias = getAlias(this); switchView(alias, detailView); alias.dropAction='alias'; alias.removeDropProperties=new List(['dropAction']); useRightSplit(alias, shiftKey); "; + const childText = "const alias = getAlias(self); switchView(alias, detailView); alias.dropAction='alias'; alias.removeDropProperties=new List(['dropAction']); useRightSplit(alias, shiftKey); "; runInAction(() => { this._childClickedScript = ScriptField.MakeScript(childText, { this: Doc.name, shiftKey: "boolean" }, { detailView: detailView! }); this._viewDefDivClick = ScriptField.MakeScript("pivotColumnClick(this,payload)", { payload: "any" }); -- cgit v1.2.3-70-g09d2 From f555ce5eda3fd0a49777e76b007171071c302f23 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 17 Apr 2020 00:13:48 -0400 Subject: offset images to appear in middle of panel vertically --- src/client/views/nodes/ImageBox.tsx | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 815a3f7b2..4be9eef29 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -422,17 +422,29 @@ export class ImageBox extends ViewBoxAnnotatableComponent; } + // adjust y position to center image in panel aspect is bigger than image aspect. + // bcz :note, this is broken for rotated images + get ycenter() { + const { nativeWidth, nativeHeight } = this.nativeSize; + const rotation = NumCast(this.dataDoc[this.fieldKey + "-rotation"]); + const aspect = (rotation % 180) ? nativeWidth / nativeHeight : nativeHeight / nativeWidth; + return this.props.PanelHeight() / this.props.PanelWidth() > aspect ? + (this.props.PanelHeight() - this.props.PanelWidth() * aspect) / 2 : 0; + } + + screenToLocalTransform = () => this.props.ScreenToLocalTransform().translate(0, -this.ycenter / this.props.ContentScaling()); + contentFunc = () => [this.content]; render() { TraceMobx(); const dragging = !SelectionManager.GetIsDragging() ? "" : "-dragging"; return (
{this.contentFunc} -- cgit v1.2.3-70-g09d2 From ac40232e5bbbb98680912eb3c505bab994079074 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 17 Apr 2020 09:39:25 -0400 Subject: fixed auto focus to work on clicked pt --- .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 4 ++-- src/client/views/nodes/DocumentView.tsx | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index f19181a20..02f9bd487 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -31,7 +31,7 @@ import { ContextMenu } from "../../ContextMenu"; import { ContextMenuProps } from "../../ContextMenuItem"; import { InkingControl } from "../../InkingControl"; import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView"; -import { DocumentViewProps } from "../../nodes/DocumentView"; +import { DocumentViewProps, DocumentView } from "../../nodes/DocumentView"; import { FormattedTextBox } from "../../nodes/FormattedTextBox"; import { pageSchema } from "../../nodes/ImageBox"; import PDFMenu from "../../pdf/PDFMenu"; @@ -822,7 +822,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u if (!willZoom) { Doc.BrushDoc(this.props.Document); - !doc.z && this.scaleAtPt([NumCast(doc.x), NumCast(doc.y)], 1); + !doc.z && this.scaleAtPt(DocumentView._focusHack, 1); // [NumCast(doc.x), NumCast(doc.y)], 1); } else { if (DocListCast(this.dataDoc[this.props.fieldKey]).includes(doc)) { if (!doc.z) this.setPan(newPanX, newPanY, "Ease", true); // docs that are floating in their collection can't be panned to from their collection -- need to propagate the pan to a parent freeform somehow diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index c0d530160..fb0b1d4f4 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -317,6 +317,9 @@ export class DocumentView extends DocComponent(Docu if ((this.props.Document.onDragStart || (this.props.Document.rootDocument && this.props.Document.isTemplateForField)) && !(e.ctrlKey || e.button > 0)) { // onDragStart implies a button doc that we don't want to select when clicking. RootDocument & isTEmplaetForField implies we're clicking on part of a template instance and we want to select the whole template, not the part stopPropagate = false; // don't stop propagation for field templates -- want the selection to propagate up to the root document of the template } else { + DocumentView._focusHack = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY) || [0, 0]; + DocumentView._focusHack = [DocumentView._focusHack[0] + NumCast(this.props.Document.x), DocumentView._focusHack[1] + NumCast(this.props.Document.y)]; + this.props.focus(this.props.Document, false); SelectionManager.SelectDoc(this, e.ctrlKey); } @@ -326,6 +329,7 @@ export class DocumentView extends DocComponent(Docu preventDefault && e.preventDefault(); } } + static _focusHack: number[] = []; // bcz :this will get fixed... // follows a link - if the target is on screen, it highlights/pans to it. // if the target isn't onscreen, then it will open up the target in a tab, on the right, or in place -- cgit v1.2.3-70-g09d2 From 0736662068dbeb02a8a9dda84bc0ac523650d8c6 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 17 Apr 2020 10:51:17 -0400 Subject: fixed native size of images with template on reloading --- src/client/util/Import & Export/ImageUtils.ts | 1 + src/client/views/nodes/ImageBox.tsx | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/client/util/Import & Export/ImageUtils.ts b/src/client/util/Import & Export/ImageUtils.ts index 9fae5ff93..c8d1530b3 100644 --- a/src/client/util/Import & Export/ImageUtils.ts +++ b/src/client/util/Import & Export/ImageUtils.ts @@ -24,6 +24,7 @@ export namespace ImageUtils { const proto = Doc.GetProto(document); proto["data-nativeWidth"] = nativeWidth; proto["data-nativeHeight"] = nativeHeight; + proto["data-path"] = source; proto.contentSize = contentSize ? contentSize : undefined; return data !== undefined; }; diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 4be9eef29..6bc7c8440 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -250,8 +250,8 @@ export class ImageBox extends ViewBoxAnnotatableComponent { const cachedNativeSize = { - width: NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"]), - height: NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"]) + width: imgPath === this.dataDoc[this.fieldKey + "-path"] ? NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"]) : 0, + height: imgPath === this.dataDoc[this.fieldKey + "-path"] ? NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"]) : 0, }; const docAspect = this.layoutDoc[HeightSym]() / this.layoutDoc[WidthSym](); const cachedAspect = cachedNativeSize.height / cachedNativeSize.width; @@ -265,6 +265,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent 0.1) { -- cgit v1.2.3-70-g09d2 From eaffd29f3837a9f5834488511b5b6c6283c13dee Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Fri, 17 Apr 2020 08:30:16 -0700 Subject: fixed home / doc access serving logic --- src/server/index.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/server/index.ts b/src/server/index.ts index 1d7520b1c..f26c8a6ab 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -106,12 +106,17 @@ function routeSetter({ isRelease, addSupervisedRoute, logRegistrationOutcome }: method: Method.GET, subscription: ["/home", new RouteSubscriber("doc").add("docId")], secureHandler: serve, - publicHandler: ({ req, ...remaining }) => { + publicHandler: ({ req, res, ...remaining }) => { const { originalUrl: target } = req; const sharing = qs.parse(qs.extract(req.originalUrl), { sort: false }).sharing === "true"; const docAccess = target.startsWith("/doc/"); + // since this is the public handler, there's no meaning of '/home' to speak of + // since there's no user logged in, so the only viable operation + // for a guest is to look at a shared document if (sharing && docAccess) { - serve({ req, ...remaining }); + serve({ req, res, ...remaining }); + } else { + res.redirect("/login"); } } }); -- cgit v1.2.3-70-g09d2 From 5fdd55e5e293835f6902b0f3c2cbcb054dc27747 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 17 Apr 2020 18:02:23 -0400 Subject: added more annotation ability to web pages. need a mode switch to follow links/select text now. --- src/client/views/nodes/WebBox.scss | 15 +++++ src/client/views/nodes/WebBox.tsx | 109 +++++++++++++++++++++++-------------- src/client/views/pdf/PDFViewer.tsx | 2 +- src/new_fields/documentSchemas.ts | 2 + 4 files changed, 87 insertions(+), 41 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/WebBox.scss b/src/client/views/nodes/WebBox.scss index b41687c11..3c82e5240 100644 --- a/src/client/views/nodes/WebBox.scss +++ b/src/client/views/nodes/WebBox.scss @@ -3,6 +3,21 @@ .webBox-container, .webBox-container-dragging { transform-origin: top left; + .webBox-outerContent { + width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; + overflow: auto; + pointer-events: all; + .webBox-innerContent { + width:100%; + } + } + div.webBox-outerContent::-webkit-scrollbar-thumb { + display:none; + } } .webBox-cont, .webBox-cont-dragging { diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 55ad7eb0f..b61d38d62 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -1,6 +1,6 @@ import { library } from "@fortawesome/fontawesome-svg-core"; import { faStickyNote } from '@fortawesome/free-solid-svg-icons'; -import { action, computed, observable } from "mobx"; +import { action, computed, observable, trace } from "mobx"; import { observer } from "mobx-react"; import { Doc, FieldResult } from "../../../new_fields/Doc"; import { documentSchema } from "../../../new_fields/documentSchemas"; @@ -18,7 +18,6 @@ import { ViewBoxAnnotatableComponent } from "../DocComponent"; import { DocumentDecorations } from "../DocumentDecorations"; import { InkingControl } from "../InkingControl"; import { FieldView, FieldViewProps } from './FieldView'; -import { KeyValueBox } from "./KeyValueBox"; import "./WebBox.scss"; import React = require("react"); import * as WebRequest from 'web-request'; @@ -26,7 +25,6 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; const htmlToText = require("html-to-text"); - library.add(faStickyNote); type WebDocument = makeInterface<[typeof documentSchema]>; @@ -40,19 +38,38 @@ export class WebBox extends ViewBoxAnnotatableComponent(); private _iframeRef = React.createRef(); private _iframeIndicatorRef = React.createRef(); private _iframeDragRef = React.createRef(); @observable private _pressX: number = 0; @observable private _pressY: number = 0; - + private _scrollTop = 0; + private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean) => void); + + iframeLoaded = action((e: any) => { + this._iframeRef.current!.contentDocument?.addEventListener('pointerdown', this.iframedown, false); + this._iframeRef.current!.contentDocument?.addEventListener('scroll', this.iframeScrolled, false); + this.layoutDoc.scrollHeight = this._iframeRef.current!.contentDocument?.children?.[0].scrollHeight || 1000; + this._iframeRef.current!.contentDocument!.children[0].scrollTop = NumCast(this.layoutDoc.scrollTop); + }); + setPreviewCursor = (func?: (x: number, y: number, drag: boolean) => void) => this._setPreviewCursor = func; + iframedown = (e: PointerEvent) => { + this._setPreviewCursor?.(e.screenX, e.screenY, false); + } + iframeScrolled = (e: any) => { + const scroll = (e.target as any)?.children?.[0].scrollTop; + this.layoutDoc.scrollTop = this._outerRef.current!.scrollTop = this._scrollTop = scroll; + } async componentDidMount() { this.setURL(); + this._iframeRef.current!.setAttribute("enable-annotation", "true"); + document.addEventListener("pointerup", this.onLongPressUp); document.addEventListener("pointermove", this.onLongPressMove); - const field = Cast(this.props.Document[this.props.fieldKey], WebField); + const field = Cast(this.rootDoc[this.props.fieldKey], WebField); if (field?.url.href.indexOf("youtube") !== -1) { const youtubeaspect = 400 / 315; const nativeWidth = NumCast(this.layoutDoc._nativeWidth); @@ -66,12 +83,13 @@ export class WebBox extends ViewBoxAnnotatableComponent { let url: string = ""; - const field = Cast(this.props.Document[this.props.fieldKey], WebField); + const field = Cast(this.rootDoc[this.props.fieldKey], WebField); if (field) url = field.url.href; const newBox = Docs.Create.TextDocument(url, { - x: NumCast(this.props.Document.x), - y: NumCast(this.props.Document.y), + x: NumCast(this.rootDoc.x), + y: NumCast(this.rootDoc.y), title: url, _width: 200, _height: 70, }); SelectionManager.SelectedDocuments().map(dv => { - dv.props.addDocument && dv.props.addDocument(newBox); - dv.props.removeDocument && dv.props.removeDocument(dv.props.Document); + dv.props.addDocument?.(newBox); + dv.props.removeDocument?.(dv.rootDoc); }); Doc.BrushDoc(newBox); @@ -293,7 +311,7 @@ export class WebBox extends ViewBoxAnnotatableComponent; } else if (field instanceof WebField) { - view =