From 587a97e9f5fc49952d7520829d719614477e2717 Mon Sep 17 00:00:00 2001 From: Stanley Yip Date: Sun, 19 Apr 2020 01:50:59 -0700 Subject: generate snap lines --- src/client/util/DragManager.ts | 6 ++ .../collectionFreeForm/CollectionFreeFormView.tsx | 70 +++++++++++++++++++++- 2 files changed, 75 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 3e9a5b63a..21306c339 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -18,6 +18,7 @@ import { AudioBox } from "../views/nodes/AudioBox"; import { DateField } from "../../new_fields/DateField"; import { DocumentView } from "../views/nodes/DocumentView"; import { UndoManager } from "./UndoManager"; +import { PointData } from "../../new_fields/InkField"; export type dropActionType = "place" | "alias" | "copy" | undefined; export function SetupDrag( @@ -73,6 +74,7 @@ export function SetupDrag( export namespace DragManager { let dragDiv: HTMLDivElement; + let snapLines: [PointData, PointData][]; export function Root() { const root = document.getElementById("root"); @@ -281,6 +283,10 @@ export namespace DragManager { StartDrag([ele], {}, downX, downY); } + export function SetSnapLines() { + snapLines = []; + } + function StartDrag(eles: HTMLElement[], dragData: { [id: string]: any }, downX: number, downY: number, options?: DragOptions, finishDrag?: (dropData: DragCompleteEvent) => void) { eles = eles.filter(e => e); if (!dragDiv) { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 87cf716e5..36ec4c72e 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -7,7 +7,7 @@ import { computedFn } from "mobx-utils"; import { Doc, HeightSym, Opt, WidthSym, DocListCast } from "../../../../new_fields/Doc"; import { documentSchema, positionSchema } from "../../../../new_fields/documentSchemas"; import { Id } from "../../../../new_fields/FieldSymbols"; -import { InkData, InkField, InkTool } from "../../../../new_fields/InkField"; +import { InkData, InkField, InkTool, PointData } from "../../../../new_fields/InkField"; import { List } from "../../../../new_fields/List"; import { RichTextField } from "../../../../new_fields/RichTextField"; import { createSchema, listSpec, makeInterface } from "../../../../new_fields/Schema"; @@ -1089,6 +1089,73 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u ContextMenu.Instance.addItem({ description: "Freeform Options ...", subitems: layoutItems, icon: "eye" }); } + intersectRect(r1: { left: number, top: number, width: number, height: number }, + r2: { left: number, top: number, width: number, height: number }) { + return !(r2.left > r1.left + r1.width || r2.left + r2.width < r1.left || r2.top > r1.top + r1.height || r2.top + r2.height < r1.top); + } + + onPointerOver = (e: React.PointerEvent) => { + if (SelectionManager.GetIsDragging()) { + const size = this.props.ScreenToLocalTransform().transformDirection(this.props.PanelWidth(), this.props.PanelHeight()); + const selRect = { left: this.panX() - size[0] / 2, top: this.panY() - size[1] / 2, width: size[0], height: size[1] }; + console.log(selRect); + const selection: Doc[] = []; + this.getActiveDocuments().filter(doc => !doc.isBackground && doc.z === undefined).map(doc => { + const layoutDoc = Doc.Layout(doc); + const x = NumCast(doc.x); + const y = NumCast(doc.y); + const w = NumCast(layoutDoc._width); + const h = NumCast(layoutDoc._height); + if (this.intersectRect({ left: x, top: y, width: w, height: h }, selRect)) { + selection.push(doc); + } + }); + if (!selection.length) { + this.getActiveDocuments().filter(doc => doc.z === undefined).map(doc => { + const layoutDoc = Doc.Layout(doc); + const x = NumCast(doc.x); + const y = NumCast(doc.y); + const w = NumCast(layoutDoc._width); + const h = NumCast(layoutDoc._height); + if (this.intersectRect({ left: x, top: y, width: w, height: h }, selRect)) { + selection.push(doc); + } + }); + } + if (!selection.length) { + const left = this._downX < this._lastX ? this._downX : this._lastX; + const top = this._downY < this._lastY ? this._downY : this._lastY; + const topLeft = this.getContainerTransform().transformPoint(left, top); + const size = this.getContainerTransform().transformDirection(this._lastX - this._downX, this._lastY - this._downY); + const otherBounds = { left: topLeft[0], top: topLeft[1], width: Math.abs(size[0]), height: Math.abs(size[1]) }; + this.getActiveDocuments().filter(doc => doc.z !== undefined).map(doc => { + const layoutDoc = Doc.Layout(doc); + const x = NumCast(doc.x); + const y = NumCast(doc.y); + const w = NumCast(layoutDoc._width); + const h = NumCast(layoutDoc._height); + if (this.intersectRect({ left: x, top: y, width: w, height: h }, otherBounds)) { + selection.push(doc); + } + }); + } + const lines: [PointData, PointData][] = []; + selection.forEach(doc => { + const x = NumCast(doc.x); + const y = NumCast(doc.y); + const w = doc[WidthSym](); + const h = doc[HeightSym](); + lines.push([{ X: x, Y: y }, { X: x + w, Y: y }]); // top line + lines.push([{ X: x, Y: y }, { X: x, Y: y + h }]); // left line + lines.push([{ X: x + w, Y: y }, { X: x + w, Y: y + h }]); // right line + lines.push([{ X: x, Y: y + h }, { X: x + w, Y: y + h }]); // bottom line + lines.push([{ X: x + w / 2, Y: y }, { X: x + w / 2, Y: y + h }]); // horizontal center line + lines.push([{ X: x, Y: y + h / 2 }, { X: x + w, Y: y + h / 2 }]); // vertical center line + }) + DragManager.SetSnapLines(lines); + } + } + private childViews = () => { const children = typeof this.props.children === "function" ? (this.props.children as any)() as JSX.Element[] : []; return [ @@ -1150,6 +1217,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u // otherwise, they are stored in fieldKey. All annotations to this document are stored in the extension document return
Date: Mon, 20 Apr 2020 20:06:53 -0700 Subject: better snapping, scaling is off still --- src/client/util/DragManager.ts | 67 +++++++++++++++++++--- .../collectionFreeForm/CollectionFreeFormView.tsx | 55 ++++++++++++------ 2 files changed, 96 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 21306c339..b0cabfaad 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -74,7 +74,8 @@ export function SetupDrag( export namespace DragManager { let dragDiv: HTMLDivElement; - let snapLines: [PointData, PointData][]; + let horizSnapLines: number[]; + let vertSnapLines: number[]; export function Root() { const root = document.getElementById("root"); @@ -283,8 +284,9 @@ export namespace DragManager { StartDrag([ele], {}, downX, downY); } - export function SetSnapLines() { - snapLines = []; + export function SetSnapLines(horizLines: number[], vertLines: number[]) { + horizSnapLines = horizLines; + vertSnapLines = vertLines; } function StartDrag(eles: HTMLElement[], dragData: { [id: string]: any }, downX: number, downY: number, options?: DragOptions, finishDrag?: (dropData: DragCompleteEvent) => void) { @@ -302,12 +304,22 @@ export namespace DragManager { const ys: number[] = []; const docs = dragData instanceof DocumentDragData ? dragData.draggedDocuments : dragData instanceof PdfAnnoDragData ? [dragData.dragDocument] : []; + const elesCont = { + left: Number.MAX_SAFE_INTEGER, + top: Number.MAX_SAFE_INTEGER, + right: Number.MIN_SAFE_INTEGER, + bottom: Number.MIN_SAFE_INTEGER + }; const dragElements = eles.map(ele => { if (!ele.parentNode) dragDiv.appendChild(ele); const dragElement = ele.parentNode === dragDiv ? ele : ele.cloneNode(true) as HTMLElement; const rect = ele.getBoundingClientRect(); const scaleX = rect.width / ele.offsetWidth, scaleY = rect.height / ele.offsetHeight; + elesCont.left = Math.min(rect.left, elesCont.left); + elesCont.top = Math.min(rect.top, elesCont.top); + elesCont.right = Math.max(rect.right, elesCont.right); + elesCont.bottom = Math.max(rect.bottom, elesCont.bottom); xs.push(rect.left); ys.push(rect.top); scaleXs.push(scaleX); @@ -357,6 +369,12 @@ export namespace DragManager { let lastX = downX; let lastY = downY; + const xFromLeft = downX - elesCont.left; + const yFromTop = downY - elesCont.top; + const xFromRight = elesCont.right - downX; + const yFromBottom = elesCont.bottom - downY; + console.log(elesCont); + console.log(xFromLeft, yFromTop); const moveHandler = (e: PointerEvent) => { e.preventDefault(); // required or dragging text menu link item ends up dragging the link button as native drag/drop if (dragData instanceof DocumentDragData) { @@ -373,10 +391,45 @@ export namespace DragManager { }, dragData.droppedDocuments); } //TODO: Why can't we use e.movementX and e.movementY? - const moveX = e.pageX - lastX; - const moveY = e.pageY - lastY; - lastX = e.pageX; - lastY = e.pageY; + let thisX = e.pageX; + let thisY = e.pageY; + const currLeft = e.pageX - xFromLeft; + const currTop = e.pageY - yFromTop; + const currRight = e.pageX + xFromRight; + const currBottom = e.pageY + yFromBottom; + const closestLeft = vertSnapLines.reduce((prev, curr) => Math.abs(prev - currLeft) > Math.abs(curr - currLeft) ? curr : prev); + const closestTop = horizSnapLines.reduce((prev, curr) => Math.abs(prev - currTop) > Math.abs(curr - currTop) ? curr : prev); + const closestRight = vertSnapLines.reduce((prev, curr) => Math.abs(prev - currRight) > Math.abs(curr - currRight) ? curr : prev); + const closestBottom = horizSnapLines.reduce((prev, curr) => Math.abs(prev - currBottom) > Math.abs(curr - currBottom) ? curr : prev); + const distFromClosestLeft = Math.abs(e.pageX - xFromLeft - closestLeft); + const distFromClosestTop = Math.abs(e.pageY - yFromTop - closestTop); + const distFromClosestRight = Math.abs(e.pageX + xFromRight - closestRight); + const distFromClosestBottom = Math.abs(e.pageY + yFromBottom - closestBottom); + if (distFromClosestLeft < 10 && distFromClosestLeft < distFromClosestRight) { + thisX = closestLeft + xFromLeft; + } + else if (distFromClosestRight < 10) { + thisX = closestRight - xFromRight; + } + if (distFromClosestTop < 10 && distFromClosestTop < distFromClosestRight) { + thisY = closestTop + yFromTop; + } + else if (distFromClosestBottom < 10) { + thisY = closestBottom - yFromBottom; + } + + // const closestHoriz = horizSnapLines.reduce((prev, curr) => Math.abs(prev - thisY) > Math.abs(curr - thisY) ? curr : prev); + // const closestVert = vertSnapLines.reduce((prev, curr) => Math.abs(prev - thisX) > Math.abs(curr - thisX) ? curr : prev); + // if (Math.abs(thisY - closestHoriz) < 10) { + // thisY = closestHoriz; + // } + // if (Math.abs(thisX - closestVert) < 10) { + // thisX = closestVert; + // } + const moveX = thisX - lastX; + const moveY = thisY - lastY; + lastX = thisX; + lastY = thisY; dragElements.map((dragElement, i) => (dragElement.style.transform = `translate(${(xs[i] += moveX) + (options?.offsetX || 0)}px, ${(ys[i] += moveY) + (options?.offsetY || 0)}px) scale(${scaleXs[i]}, ${scaleYs[i]})`) ); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 36ec4c72e..c4c37141b 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1094,6 +1094,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u return !(r2.left > r1.left + r1.width || r2.left + r2.width < r1.left || r2.top > r1.top + r1.height || r2.top + r2.height < r1.top); } + @action onPointerOver = (e: React.PointerEvent) => { if (SelectionManager.GetIsDragging()) { const size = this.props.ScreenToLocalTransform().transformDirection(this.props.PanelWidth(), this.props.PanelHeight()); @@ -1123,11 +1124,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u }); } if (!selection.length) { - const left = this._downX < this._lastX ? this._downX : this._lastX; - const top = this._downY < this._lastY ? this._downY : this._lastY; - const topLeft = this.getContainerTransform().transformPoint(left, top); - const size = this.getContainerTransform().transformDirection(this._lastX - this._downX, this._lastY - this._downY); - const otherBounds = { left: topLeft[0], top: topLeft[1], width: Math.abs(size[0]), height: Math.abs(size[1]) }; + const otherBounds = { left: this.panX(), top: this.panY(), width: Math.abs(size[0]), height: Math.abs(size[1]) }; this.getActiveDocuments().filter(doc => doc.z !== undefined).map(doc => { const layoutDoc = Doc.Layout(doc); const x = NumCast(doc.x); @@ -1139,23 +1136,38 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u } }); } - const lines: [PointData, PointData][] = []; + const horizLines: number[] = []; + const vertLines: number[] = []; selection.forEach(doc => { - const x = NumCast(doc.x); - const y = NumCast(doc.y); - const w = doc[WidthSym](); - const h = doc[HeightSym](); - lines.push([{ X: x, Y: y }, { X: x + w, Y: y }]); // top line - lines.push([{ X: x, Y: y }, { X: x, Y: y + h }]); // left line - lines.push([{ X: x + w, Y: y }, { X: x + w, Y: y + h }]); // right line - lines.push([{ X: x, Y: y + h }, { X: x + w, Y: y + h }]); // bottom line - lines.push([{ X: x + w / 2, Y: y }, { X: x + w / 2, Y: y + h }]); // horizontal center line - lines.push([{ X: x, Y: y + h / 2 }, { X: x + w, Y: y + h / 2 }]); // vertical center line - }) - DragManager.SetSnapLines(lines); + const layoutDoc = Doc.Layout(doc); + const x = NumCast(doc.x) - selRect.left; + const y = NumCast(doc.y) - selRect.top; + const w = NumCast(layoutDoc._width); + const h = NumCast(layoutDoc._height); + // const s = this._mainCont!.getBoundingClientRect().width / selRect.width; + // const tLFromCorner = [s * x, s * y]; + const topLeft = this.getLocalTransform().inverse().transformDirection(x, y); + console.log(topLeft); + const topLeftInScreen = [this._mainCont!.getBoundingClientRect().left + topLeft[0], this._mainCont!.getBoundingClientRect().top + topLeft[1]]; + const docSize = this.getLocalTransform().inverse().transformDirection(w, h); + console.log(topLeftInScreen); + horizLines.push(topLeftInScreen[1]); // top line + horizLines.push(topLeftInScreen[1] + docSize[1]); // bottom line + horizLines.push(topLeftInScreen[1] + docSize[1] / 2); // horiz center line + vertLines.push(topLeftInScreen[0]);//left line + vertLines.push(topLeftInScreen[0] + docSize[0]);// right line + vertLines.push(topLeftInScreen[0] + docSize[0] / 2);// vert center line + }); + // console.log(horizLines, vertLines); + // this._hLines = horizLines; + // this._vLines = vertLines; + DragManager.SetSnapLines(horizLines, vertLines); } } + @observable private _hLines: number[] | undefined; + @observable private _vLines: number[] | undefined; + private childViews = () => { const children = typeof this.props.children === "function" ? (this.props.children as any)() as JSX.Element[] : []; return [ @@ -1242,7 +1254,12 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u }}>
- +
+ + {this._hLines?.map(l => )} + {this._vLines?.map(l => )} + +
; } } -- cgit v1.2.3-70-g09d2 From 58ba643f2642432ca6041f5d348aadf005323b73 Mon Sep 17 00:00:00 2001 From: Stanley Yip Date: Wed, 22 Apr 2020 20:36:06 -0700 Subject: snapping! --- src/client/util/DragManager.ts | 10 ++++++---- src/client/views/MainView.tsx | 10 ++++++++++ .../collectionFreeForm/CollectionFreeFormView.tsx | 22 +++++++--------------- 3 files changed, 23 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index b0cabfaad..02d9f7200 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -19,6 +19,7 @@ import { DateField } from "../../new_fields/DateField"; import { DocumentView } from "../views/nodes/DocumentView"; import { UndoManager } from "./UndoManager"; import { PointData } from "../../new_fields/InkField"; +import { MainView } from "../views/MainView"; export type dropActionType = "place" | "alias" | "copy" | undefined; export function SetupDrag( @@ -74,8 +75,8 @@ export function SetupDrag( export namespace DragManager { let dragDiv: HTMLDivElement; - let horizSnapLines: number[]; - let vertSnapLines: number[]; + export let horizSnapLines: number[]; + export let vertSnapLines: number[]; export function Root() { const root = document.getElementById("root"); @@ -284,9 +285,12 @@ export namespace DragManager { StartDrag([ele], {}, downX, downY); } + @action export function SetSnapLines(horizLines: number[], vertLines: number[]) { horizSnapLines = horizLines; vertSnapLines = vertLines; + MainView.Instance._hLines = horizLines; + MainView.Instance._vLines = vertLines; } function StartDrag(eles: HTMLElement[], dragData: { [id: string]: any }, downX: number, downY: number, options?: DragOptions, finishDrag?: (dropData: DragCompleteEvent) => void) { @@ -373,8 +377,6 @@ export namespace DragManager { const yFromTop = downY - elesCont.top; const xFromRight = elesCont.right - downX; const yFromBottom = elesCont.bottom - downY; - console.log(elesCont); - console.log(xFromLeft, yFromTop); const moveHandler = (e: PointerEvent) => { e.preventDefault(); // required or dragging text menu link item ends up dragging the link button as native drag/drop if (dragData instanceof DocumentDragData) { diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 40cabcf83..1f88410b8 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -42,6 +42,7 @@ import { OverlayView } from './OverlayView'; import PDFMenu from './pdf/PDFMenu'; import { PreviewCursor } from './PreviewCursor'; import { ScriptField } from '../../new_fields/ScriptField'; +import { DragManager } from '../util/DragManager'; @observer export class MainView extends React.Component { @@ -563,6 +564,9 @@ export class MainView extends React.Component { return this._mainViewRef; } + @observable public _hLines: any; + @observable public _vLines: any; + render() { return (
@@ -580,6 +584,12 @@ export class MainView extends React.Component { +
+ + {this._hLines?.map(l => )} + {this._vLines?.map(l => )} + +
); } } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index c4c37141b..ef49970e2 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1099,7 +1099,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u if (SelectionManager.GetIsDragging()) { const size = this.props.ScreenToLocalTransform().transformDirection(this.props.PanelWidth(), this.props.PanelHeight()); const selRect = { left: this.panX() - size[0] / 2, top: this.panY() - size[1] / 2, width: size[0], height: size[1] }; - console.log(selRect); const selection: Doc[] = []; this.getActiveDocuments().filter(doc => !doc.isBackground && doc.z === undefined).map(doc => { const layoutDoc = Doc.Layout(doc); @@ -1140,17 +1139,12 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u const vertLines: number[] = []; selection.forEach(doc => { const layoutDoc = Doc.Layout(doc); - const x = NumCast(doc.x) - selRect.left; - const y = NumCast(doc.y) - selRect.top; + const x = NumCast(doc.x); + const y = NumCast(doc.y); const w = NumCast(layoutDoc._width); const h = NumCast(layoutDoc._height); - // const s = this._mainCont!.getBoundingClientRect().width / selRect.width; - // const tLFromCorner = [s * x, s * y]; - const topLeft = this.getLocalTransform().inverse().transformDirection(x, y); - console.log(topLeft); - const topLeftInScreen = [this._mainCont!.getBoundingClientRect().left + topLeft[0], this._mainCont!.getBoundingClientRect().top + topLeft[1]]; - const docSize = this.getLocalTransform().inverse().transformDirection(w, h); - console.log(topLeftInScreen); + const topLeftInScreen = this.getTransform().inverse().transformPoint(x, y); + const docSize = this.getTransform().inverse().transformDirection(w, h); horizLines.push(topLeftInScreen[1]); // top line horizLines.push(topLeftInScreen[1] + docSize[1]); // bottom line horizLines.push(topLeftInScreen[1] + docSize[1] / 2); // horiz center line @@ -1158,11 +1152,9 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u vertLines.push(topLeftInScreen[0] + docSize[0]);// right line vertLines.push(topLeftInScreen[0] + docSize[0] / 2);// vert center line }); - // console.log(horizLines, vertLines); - // this._hLines = horizLines; - // this._vLines = vertLines; DragManager.SetSnapLines(horizLines, vertLines); } + e.stopPropagation(); } @observable private _hLines: number[] | undefined; @@ -1254,12 +1246,12 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument, u }}> -
+ {/*
{this._hLines?.map(l => )} {this._vLines?.map(l => )} -
+
*/} ; } } -- cgit v1.2.3-70-g09d2 From 55d1ea38c1355ef97efedd6c1fbdbc29d7b5d821 Mon Sep 17 00:00:00 2001 From: Stanley Yip Date: Tue, 28 Apr 2020 18:06:07 -0700 Subject: snap lines hidden --- src/client/views/MainView.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 1f88410b8..12f0adf70 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -584,12 +584,13 @@ export class MainView extends React.Component { + {/* TO VIEW SNAP LINES
- {this._hLines?.map(l => )} - {this._vLines?.map(l => )} + {this._hLines?.map(l => )} + {this._vLines?.map(l => )} -
+ */} ); } } -- cgit v1.2.3-70-g09d2 From 43e573ea0cf4634b65b513c633f90be84846f8df Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 29 Apr 2020 21:08:37 -0400 Subject: changed detailedView template to be a layoutstring. fixed text boxes to allow new templates from templated text boxes. fixed __LAYOUT__ to work with comound layout strings --- src/client/documents/Documents.ts | 19 +++++++++++++++++-- src/client/views/animationtimeline/Timeline.tsx | 4 +--- .../views/nodes/formattedText/FormattedTextBox.tsx | 20 +++++++++++++++++--- src/new_fields/Doc.ts | 2 +- .../authentication/models/current_user_utils.ts | 2 +- 5 files changed, 37 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 811bb5fb2..0d1d73ca3 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -541,8 +541,23 @@ export namespace Docs { return InstanceFromProto(Prototypes.get(DocumentType.COLOR), "", options); } - export function TextDocument(text: string, options: DocumentOptions = {}) { - return InstanceFromProto(Prototypes.get(DocumentType.RTF), text, options, undefined, "text"); + export function TextDocument(text: string, options: DocumentOptions = {}, fieldKey: string = "text") { + const rtf = { + doc: { + type: "doc", content: [{ + type: "paragraph", + content: [{ + type: "text", + text + }] + }] + }, + selection: { type: "text", anchor: 1, head: 1 }, + storedMarks: [] + }; + + const field = text ? new RichTextField(JSON.stringify(rtf), text) : undefined; + return InstanceFromProto(Prototypes.get(DocumentType.RTF), field, options, undefined, fieldKey); } export function LinkDocument(source: { doc: Doc, ctx?: Doc }, target: { doc: Doc, ctx?: Doc }, options: DocumentOptions = {}, id?: string) { diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 677267ca0..fe1e40778 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -119,9 +119,7 @@ export class Timeline extends React.Component { } componentWillUnmount() { - runInAction(() => { - this.props.Document.AnimationLength = this._time; //save animation length - }); + this.props.Document.AnimationLength = this._time; //save animation length } ///////////////////////////////////////////////// diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 782a91547..2038efbc6 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -419,14 +419,28 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp const funcs: ContextMenuProps[] = []; this.rootDoc.isTemplateDoc && funcs.push({ description: "Make Default Layout", event: async () => Doc.UserDoc().defaultTextLayout = new PrefetchProxy(this.props.Document), icon: "eye" }); - !this.rootDoc.isTemplateDoc && funcs.push({ description: "Show Template", event: async () => this.props.addDocTab(Doc.GetProto(this.layoutDoc), "onRight"), icon: "eye" }); funcs.push({ description: "Reset Default Layout", event: () => Doc.UserDoc().defaultTextLayout = undefined, icon: "eye" }); - !this.rootDoc.isTemplateDoc && funcs.push({ + !this.layoutDoc.isTemplateDoc && funcs.push({ description: "Make Template", event: () => { - this.props.Document.isTemplateDoc = makeTemplate(this.props.Document); + this.rootDoc.isTemplateDoc = makeTemplate(this.rootDoc); Doc.AddDocToList(Cast(Doc.UserDoc()["template-notes"], Doc, null), "data", this.props.Document); }, icon: "eye" }); + this.layoutDoc.isTemplateDoc && funcs.push({ + description: "Make New Template", event: () => { + const title = this.rootDoc.title as string; + this.rootDoc.layout = (this.layoutDoc as Doc).layout as string; + this.rootDoc.title = this.layoutDoc.isTemplateForField as string; + this.rootDoc.isTemplateDoc = false; + this.rootDoc.isTemplateForField = ""; + this.rootDoc.layoutKey = "layout"; + this.rootDoc.isTemplateDoc = makeTemplate(this.rootDoc, true, title); + this.rootDoc._width = this.layoutDoc._width || 300; // the width and height are stored on the template, since we're getting rid of the old template + this.rootDoc._height = this.layoutDoc._height || 200; // we need to copy them over to the root. This should probably apply to all '_' fields + this.rootDoc._backgroundColor = Cast(this.layoutDoc._backgroundColor, "string", null); + Doc.AddDocToList(Cast(Doc.UserDoc()["template-notes"], Doc, null), "data", this.rootDoc); + }, icon: "eye" + }); funcs.push({ description: "Toggle Single Line", event: () => this.props.Document._singleLine = !this.props.Document._singleLine, icon: "expand-arrows-alt" }); funcs.push({ description: "Toggle Sidebar", event: () => this.props.Document._showSidebar = !this.props.Document._showSidebar, icon: "expand-arrows-alt" }); funcs.push({ description: "Toggle Dictation Icon", event: () => this.props.Document._showAudio = !this.props.Document._showAudio, icon: "expand-arrows-alt" }); diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 153af933a..77eee03ce 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -183,7 +183,7 @@ export class Doc extends RefField { let renderFieldKey: any; const layoutField = templateLayoutDoc[StrCast(templateLayoutDoc.layoutKey, "layout")]; if (typeof layoutField === "string") { - renderFieldKey = layoutField.split("'")[1]; + renderFieldKey = layoutField.split("fieldKey={'")[1].split("'")[0];//layoutField.split("'")[1]; } else { return Cast(layoutField, Doc, null); } diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 4b2aafac1..eedd3ee67 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -72,7 +72,7 @@ export class CurrentUserUtils { } if (doc["template-button-description"] === undefined) { - const descriptionTemplate = Docs.Create.TextDocument("", { title: "header", _height: 100 }); + const descriptionTemplate = Docs.Create.TextDocument(" ", { title: "header", _height: 100 }, "header"); // text needs to be a space to allow templateText to be created Doc.GetProto(descriptionTemplate).layout = "
"; descriptionTemplate.isTemplateDoc = makeTemplate(descriptionTemplate, true, "descriptionView"); -- cgit v1.2.3-70-g09d2 From 37b5878ac3a8f0bd5168431b71e58eee27a3ec99 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 29 Apr 2020 22:27:59 -0400 Subject: fixed problems with snapping so that it snaps on finishDrag. cleaned up code a bit. --- src/client/util/DragManager.ts | 81 ++++++++++++---------- src/client/views/MainView.tsx | 14 ++-- .../collectionFreeForm/CollectionFreeFormView.tsx | 60 +++++----------- 3 files changed, 68 insertions(+), 87 deletions(-) (limited to 'src') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index a905dff0a..36c26fe2c 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -75,8 +75,8 @@ export function SetupDrag( export namespace DragManager { let dragDiv: HTMLDivElement; - export let horizSnapLines: number[]; - export let vertSnapLines: number[]; + export let horizSnapLines: number[] = []; + export let vertSnapLines: number[] = []; export function Root() { const root = document.getElementById("root"); @@ -296,7 +296,6 @@ export namespace DragManager { StartDrag([ele], {}, downX, downY); } - @action export function SetSnapLines(horizLines: number[], vertLines: number[]) { horizSnapLines = horizLines; vertSnapLines = vertLines; @@ -304,6 +303,36 @@ export namespace DragManager { MainView.Instance._vLines = vertLines; } + function snapDrag(e: PointerEvent, xFromLeft: number, yFromTop: number, xFromRight: number, yFromBottom: number) { + let thisX = e.pageX; + let thisY = e.pageY; + const currLeft = e.pageX - xFromLeft; + const currTop = e.pageY - yFromTop; + const currRight = e.pageX + xFromRight; + const currBottom = e.pageY + yFromBottom; + const closestLeft = vertSnapLines.reduce((prev, curr) => Math.abs(prev - currLeft) > Math.abs(curr - currLeft) ? curr : prev); + const closestTop = horizSnapLines.reduce((prev, curr) => Math.abs(prev - currTop) > Math.abs(curr - currTop) ? curr : prev); + const closestRight = vertSnapLines.reduce((prev, curr) => Math.abs(prev - currRight) > Math.abs(curr - currRight) ? curr : prev); + const closestBottom = horizSnapLines.reduce((prev, curr) => Math.abs(prev - currBottom) > Math.abs(curr - currBottom) ? curr : prev); + const distFromClosestLeft = Math.abs(e.pageX - xFromLeft - closestLeft); + const distFromClosestTop = Math.abs(e.pageY - yFromTop - closestTop); + const distFromClosestRight = Math.abs(e.pageX + xFromRight - closestRight); + const distFromClosestBottom = Math.abs(e.pageY + yFromBottom - closestBottom); + if (distFromClosestLeft < 10 && distFromClosestLeft < distFromClosestRight) { + thisX = closestLeft + xFromLeft; + } + else if (distFromClosestRight < 10) { + thisX = closestRight - xFromRight; + } + if (distFromClosestTop < 10 && distFromClosestTop < distFromClosestRight) { + thisY = closestTop + yFromTop; + } + else if (distFromClosestBottom < 10) { + thisY = closestBottom - yFromBottom; + } + return { thisX, thisY }; + } + export let docsBeingDragged: Doc[] = []; function StartDrag(eles: HTMLElement[], dragData: { [id: string]: any }, downX: number, downY: number, options?: DragOptions, finishDrag?: (dropData: DragCompleteEvent) => void) { eles = eles.filter(e => e); if (!dragDiv) { @@ -318,7 +347,7 @@ export namespace DragManager { const xs: number[] = []; const ys: number[] = []; - const docs = dragData instanceof DocumentDragData ? dragData.draggedDocuments : dragData instanceof PdfAnnoDragData ? [dragData.dragDocument] : []; + docsBeingDragged = dragData instanceof DocumentDragData ? dragData.draggedDocuments : dragData instanceof PdfAnnoDragData ? [dragData.dragDocument] : []; const elesCont = { left: Number.MAX_SAFE_INTEGER, top: Number.MAX_SAFE_INTEGER, @@ -354,7 +383,7 @@ export namespace DragManager { dragElement.style.width = `${rect.width / scaleX}px`; dragElement.style.height = `${rect.height / scaleY}px`; - if (docs.length) { + if (docsBeingDragged.length) { const pdfBox = dragElement.getElementsByTagName("canvas"); const pdfBoxSrc = ele.getElementsByTagName("canvas"); Array.from(pdfBox).map((pb, i) => pb.getContext('2d')!.drawImage(pdfBoxSrc[i], 0, 0)); @@ -408,32 +437,8 @@ export namespace DragManager { button: 0 }, dragData.droppedDocuments); } - let thisX = e.pageX; - let thisY = e.pageY; - const currLeft = e.pageX - xFromLeft; - const currTop = e.pageY - yFromTop; - const currRight = e.pageX + xFromRight; - const currBottom = e.pageY + yFromBottom; - const closestLeft = vertSnapLines.reduce((prev, curr) => Math.abs(prev - currLeft) > Math.abs(curr - currLeft) ? curr : prev); - const closestTop = horizSnapLines.reduce((prev, curr) => Math.abs(prev - currTop) > Math.abs(curr - currTop) ? curr : prev); - const closestRight = vertSnapLines.reduce((prev, curr) => Math.abs(prev - currRight) > Math.abs(curr - currRight) ? curr : prev); - const closestBottom = horizSnapLines.reduce((prev, curr) => Math.abs(prev - currBottom) > Math.abs(curr - currBottom) ? curr : prev); - const distFromClosestLeft = Math.abs(e.pageX - xFromLeft - closestLeft); - const distFromClosestTop = Math.abs(e.pageY - yFromTop - closestTop); - const distFromClosestRight = Math.abs(e.pageX + xFromRight - closestRight); - const distFromClosestBottom = Math.abs(e.pageY + yFromBottom - closestBottom); - if (distFromClosestLeft < 10 && distFromClosestLeft < distFromClosestRight) { - thisX = closestLeft + xFromLeft; - } - else if (distFromClosestRight < 10) { - thisX = closestRight - xFromRight; - } - if (distFromClosestTop < 10 && distFromClosestTop < distFromClosestRight) { - thisY = closestTop + yFromTop; - } - else if (distFromClosestBottom < 10) { - thisY = closestBottom - yFromBottom; - } + + const { thisX, thisY } = snapDrag(e, xFromLeft, yFromTop, xFromRight, yFromBottom); alias = "move"; const moveX = thisX - lastX; @@ -462,7 +467,7 @@ export namespace DragManager { }; const upHandler = (e: PointerEvent) => { hideDragShowOriginalElements(); - dispatchDrag(eles, e, dragData, options, finishDrag); + dispatchDrag(eles, e, dragData, xFromLeft, yFromTop, xFromRight, yFromBottom, options, finishDrag); SelectionManager.SetIsDragging(false); endDrag(); options?.dragComplete?.(new DragCompleteEvent(false, dragData)); @@ -471,7 +476,8 @@ export namespace DragManager { document.addEventListener("pointerup", upHandler); } - function dispatchDrag(dragEles: HTMLElement[], e: PointerEvent, dragData: { [index: string]: any }, options?: DragOptions, finishDrag?: (e: DragCompleteEvent) => void) { + function dispatchDrag(dragEles: HTMLElement[], e: PointerEvent, dragData: { [index: string]: any }, + xFromLeft: number, yFromTop: number, xFromRight: number, yFromBottom: number, options?: DragOptions, finishDrag?: (e: DragCompleteEvent) => void) { const removed = dragData.dontHideOnDrop ? [] : dragEles.map(dragEle => { const ret = { ele: dragEle, w: dragEle.style.width, h: dragEle.style.height, o: dragEle.style.overflow }; dragEle.style.width = "0"; @@ -485,14 +491,15 @@ export namespace DragManager { r.ele.style.height = r.h; r.ele.style.overflow = r.o; }); + const { thisX, thisY } = snapDrag(e, xFromLeft, yFromTop, xFromRight, yFromBottom); if (target) { const complete = new DragCompleteEvent(false, dragData); target.dispatchEvent( new CustomEvent("dashPreDrop", { bubbles: true, detail: { - x: e.x, - y: e.y, + x: thisX, + y: thisY, complete: complete, shiftKey: e.shiftKey, altKey: e.altKey, @@ -506,8 +513,8 @@ export namespace DragManager { new CustomEvent("dashOnDrop", { bubbles: true, detail: { - x: e.x, - y: e.y, + x: thisX, + y: thisY, complete: complete, shiftKey: e.shiftKey, altKey: e.altKey, diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 0102d1327..62b2d1d18 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -588,13 +588,13 @@ export class MainView extends React.Component { - {/* TO VIEW SNAP LINES -
- - {this._hLines?.map(l => )} - {this._vLines?.map(l => )} - -
*/} + {// TO VIEW SNAP LINES + /*
+ + {this._hLines?.map(l => )} + {this._vLines?.map(l => )} + +
*/} ); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index d291cad21..0c9403429 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1129,7 +1129,7 @@ export class CollectionFreeFormView extends CollectionSubView !doc.isBackground && doc.z === undefined).map(doc => { - const layoutDoc = Doc.Layout(doc); - const x = NumCast(doc.x); - const y = NumCast(doc.y); - const w = NumCast(layoutDoc._width); - const h = NumCast(layoutDoc._height); - if (this.intersectRect({ left: x, top: y, width: w, height: h }, selRect)) { + const docDims = (doc: Doc, layoutDoc: Doc) => ({ left: NumCast(doc.x), top: NumCast(doc.y), width: NumCast(layoutDoc._width), height: NumCast(layoutDoc._height) }); + const compareDoc = (doc: Doc, rect: { left: number, top: number, width: number, height: number }) => { + if (this.intersectRect(docDims(doc, Doc.Layout(doc)), rect)) { selection.push(doc); } - }); - if (!selection.length) { - this.getActiveDocuments().filter(doc => doc.z === undefined).map(doc => { - const layoutDoc = Doc.Layout(doc); - const x = NumCast(doc.x); - const y = NumCast(doc.y); - const w = NumCast(layoutDoc._width); - const h = NumCast(layoutDoc._height); - if (this.intersectRect({ left: x, top: y, width: w, height: h }, selRect)) { - selection.push(doc); - } - }); - } - if (!selection.length) { - const otherBounds = { left: this.panX(), top: this.panY(), width: Math.abs(size[0]), height: Math.abs(size[1]) }; - this.getActiveDocuments().filter(doc => doc.z !== undefined).map(doc => { - const layoutDoc = Doc.Layout(doc); - const x = NumCast(doc.x); - const y = NumCast(doc.y); - const w = NumCast(layoutDoc._width); - const h = NumCast(layoutDoc._height); - if (this.intersectRect({ left: x, top: y, width: w, height: h }, otherBounds)) { - selection.push(doc); - } - }); } + const otherBounds = { left: this.panX(), top: this.panY(), width: Math.abs(size[0]), height: Math.abs(size[1]) }; + this.getActiveDocuments().filter(doc => !doc.isBackground && doc.z === undefined).map(doc => compareDoc(doc, selRect)); // first try foreground docs + !selection.length && this.getActiveDocuments().filter(doc => doc.z === undefined).map(doc => compareDoc(doc, selRect)); // then background docs + !selection.length && this.getActiveDocuments().filter(doc => doc.z !== undefined).map(doc => compareDoc(doc, otherBounds)); // then floating docs + const horizLines: number[] = []; const vertLines: number[] = []; - selection.forEach(doc => { - const layoutDoc = Doc.Layout(doc); - const x = NumCast(doc.x); - const y = NumCast(doc.y); - const w = NumCast(layoutDoc._width); - const h = NumCast(layoutDoc._height); - const topLeftInScreen = this.getTransform().inverse().transformPoint(x, y); - const docSize = this.getTransform().inverse().transformDirection(w, h); + selection.filter(doc => !DragManager.docsBeingDragged.includes(doc)).forEach(doc => { + const { left, top, width, height } = docDims(doc, Doc.Layout(doc)); + const topLeftInScreen = this.getTransform().inverse().transformPoint(left, top); + const docSize = this.getTransform().inverse().transformDirection(width, height); + horizLines.push(topLeftInScreen[1]); // top line horizLines.push(topLeftInScreen[1] + docSize[1]); // bottom line horizLines.push(topLeftInScreen[1] + docSize[1] / 2); // horiz center line @@ -1292,12 +1265,13 @@ export class CollectionFreeFormView extends CollectionSubView - {/*
+ {// uncomment to show snap lines + /*
{this._hLines?.map(l => )} {this._vLines?.map(l => )} -
*/} +
*/} ; } } -- cgit v1.2.3-70-g09d2 From 90c45914694a971c1b3cb356921c04f337625db5 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 30 Apr 2020 00:06:08 -0400 Subject: fixes for snapping & timeline. changed looi of document decorations --- src/client/util/DragManager.ts | 8 ++--- src/client/views/DocumentDecorations.scss | 34 +++++++++++++++++++++- src/client/views/DocumentDecorations.tsx | 9 +++--- src/client/views/MainView.tsx | 1 - src/client/views/MetadataEntryMenu.scss | 9 +++--- src/client/views/animationtimeline/Timeline.tsx | 33 ++++++++------------- .../collectionFreeForm/CollectionFreeFormView.tsx | 14 ++++++--- .../views/nodes/formattedText/FormattedTextBox.tsx | 8 +++-- 8 files changed, 74 insertions(+), 42 deletions(-) (limited to 'src') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 36c26fe2c..bccdf38ce 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -310,10 +310,10 @@ export namespace DragManager { const currTop = e.pageY - yFromTop; const currRight = e.pageX + xFromRight; const currBottom = e.pageY + yFromBottom; - const closestLeft = vertSnapLines.reduce((prev, curr) => Math.abs(prev - currLeft) > Math.abs(curr - currLeft) ? curr : prev); - const closestTop = horizSnapLines.reduce((prev, curr) => Math.abs(prev - currTop) > Math.abs(curr - currTop) ? curr : prev); - const closestRight = vertSnapLines.reduce((prev, curr) => Math.abs(prev - currRight) > Math.abs(curr - currRight) ? curr : prev); - const closestBottom = horizSnapLines.reduce((prev, curr) => Math.abs(prev - currBottom) > Math.abs(curr - currBottom) ? curr : prev); + const closestLeft = vertSnapLines.reduce((prev, curr) => Math.abs(prev - currLeft) > Math.abs(curr - currLeft) ? curr : prev, currLeft); + const closestTop = horizSnapLines.reduce((prev, curr) => Math.abs(prev - currTop) > Math.abs(curr - currTop) ? curr : prev, currTop); + const closestRight = vertSnapLines.reduce((prev, curr) => Math.abs(prev - currRight) > Math.abs(curr - currRight) ? curr : prev, currRight); + const closestBottom = horizSnapLines.reduce((prev, curr) => Math.abs(prev - currBottom) > Math.abs(curr - currBottom) ? curr : prev, currBottom); const distFromClosestLeft = Math.abs(e.pageX - xFromLeft - closestLeft); const distFromClosestTop = Math.abs(e.pageY - yFromTop - closestTop); const distFromClosestRight = Math.abs(e.pageX + xFromRight - closestRight); diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss index 28cf9fd47..61d517d43 100644 --- a/src/client/views/DocumentDecorations.scss +++ b/src/client/views/DocumentDecorations.scss @@ -21,9 +21,13 @@ $linkGap : 3px; background: none; } + .documentDecorations-resizer { pointer-events: auto; background: $alt-accent; + opacity: 0.1; + } + .documentDecorations-resizer:hover { opacity: 1; } @@ -80,7 +84,20 @@ $linkGap : 3px; #documentDecorations-topLeftResizer, #documentDecorations-bottomRightResizer { cursor: nwse-resize; - background: dimGray; + background: unset; + opacity: 1; + } + #documentDecorations-topLeftResizer { + border-left: black 2px solid; + border-top: black solid 2px; + } + #documentDecorations-bottomRightResizer { + border-right: black 2px solid; + border-bottom: black solid 2px; + } + #documentDecorations-topLeftResizer:hover, + #documentDecorations-bottomRightResizer:hover { + opacity: 1; } #documentDecorations-bottomRightResizer { @@ -89,8 +106,23 @@ $linkGap : 3px; #documentDecorations-topRightResizer, #documentDecorations-bottomLeftResizer { + cursor: nesw-resize; + background: unset; + opacity: 1; + } + #documentDecorations-topRightResizer { + border-right: black 2px solid; + border-top: black 2px solid; + } + #documentDecorations-bottomLeftResizer { + border-left: black 2px solid; + border-bottom: black 2px solid; + } + #documentDecorations-topRightResizer:hover, + #documentDecorations-bottomLeftResizer:hover { cursor: nesw-resize; background: dimGray; + opacity: 1; } #documentDecorations-topResizer, diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 312acd5b2..973ec2e89 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -473,10 +473,11 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}>
e.preventDefault()}>
- {seldoc.props.renderDepth <= 1 || !seldoc.props.ContainingCollectionView ? (null) :
e.preventDefault()}> - -
} + {seldoc.props.renderDepth <= 1 || !seldoc.props.ContainingCollectionView ? (null) : +
e.preventDefault()}> + +
}
e.preventDefault()}>
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 62b2d1d18..e5a8ebcb5 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -42,7 +42,6 @@ import { OverlayView } from './OverlayView'; import PDFMenu from './pdf/PDFMenu'; import { PreviewCursor } from './PreviewCursor'; import { ScriptField } from '../../new_fields/ScriptField'; -import { DragManager } from '../util/DragManager'; import { TimelineMenu } from './animationtimeline/TimelineMenu'; @observer diff --git a/src/client/views/MetadataEntryMenu.scss b/src/client/views/MetadataEntryMenu.scss index 5776cf070..28de0b7a5 100644 --- a/src/client/views/MetadataEntryMenu.scss +++ b/src/client/views/MetadataEntryMenu.scss @@ -9,9 +9,10 @@ } .metadataEntry-autoSuggester { - width: 100%; + width: 80%; height: 100%; - padding-right: 10px; + margin: 0; + display: inline-block; } #metadataEntry-outer { @@ -25,7 +26,7 @@ flex-direction: column; } .metadataEntry-inputArea { - display:flex; + display:inline-block; flex-direction: row; } @@ -44,7 +45,7 @@ .react-autosuggest__input { border: 1px solid #aaa; border-radius: 4px; - width: 100%; + width: 75%; } .react-autosuggest__input--focused { diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index fe1e40778..77656b85f 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -71,7 +71,6 @@ export class Timeline extends React.Component { @observable private _tickIncrement = this.DEFAULT_TICK_INCREMENT; @observable private _time = 100000; //DEFAULT @observable private _playButton = faPlayCircle; - @observable private _timelineVisible = false; @observable private _mouseToggled = false; @observable private _doubleClickEnabled = false; @observable private _titleHeight = 0; @@ -336,20 +335,6 @@ export class Timeline extends React.Component { } - /** - * context menu function. - * opens the timeline or closes the timeline. - * Used in: Freeform - */ - timelineContextMenu = (e: React.MouseEvent): void => { - ContextMenu.Instance.addItem({ - description: (this._timelineVisible ? "Close" : "Open") + " Animation Timeline", event: action(() => { - this._timelineVisible = !this._timelineVisible; - }), icon: this._timelineVisible ? faEyeSlash : faEye - }); - } - - /** * timeline zoom function * use mouse middle button to zoom in/out the timeline @@ -463,7 +448,7 @@ export class Timeline extends React.Component {
-
+
{this.timeIndicator(lengthString, totalTime)}
this.resetView(this.props.Document)}>
this.setView(this.props.Document)}>
@@ -481,10 +466,16 @@ export class Timeline extends React.Component { ); } else { + const ctime = `Current: ${this.getCurrentTime()}`; + const ttime = `Total: ${this.toReadTime(this._time)}`; return (
-
{`Current: ${this.getCurrentTime()}`}
-
{`Total: ${this.toReadTime(this._time)}`}
+
+ {ctime} +
+
+ {ttime} +
); } @@ -601,8 +592,8 @@ export class Timeline extends React.Component { trace(); // change visible and total width return ( -
-
+
+
{this.drawTicks()} @@ -611,7 +602,7 @@ export class Timeline extends React.Component {
{DocListCast(this.children).map(doc => - this.mapOfTracks.push(ref)} node={doc} currentBarX={this._currentBarX} changeCurrentBarX={this.changeCurrentBarX} transform={this.props.ScreenToLocalTransform()} time={this._time} tickSpacing={this._tickSpacing} tickIncrement={this._tickIncrement} collection={this.props.Document} timelineVisible={this._timelineVisible} /> + this.mapOfTracks.push(ref)} node={doc} currentBarX={this._currentBarX} changeCurrentBarX={this.changeCurrentBarX} transform={this.props.ScreenToLocalTransform()} time={this._time} tickSpacing={this._tickSpacing} tickIncrement={this._tickIncrement} collection={this.props.Document} timelineVisible={true} /> )}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 0c9403429..77de486d9 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,5 +1,5 @@ import { library } from "@fortawesome/fontawesome-svg-core"; -import { faEye } from "@fortawesome/free-regular-svg-icons"; +import { faEye, faEyeSlash } from "@fortawesome/free-regular-svg-icons"; import { faBraille, faChalkboard, faCompass, faCompressArrowsAlt, faExpandArrowsAlt, faFileUpload, faPaintBrush, faTable, faUpload } from "@fortawesome/free-solid-svg-icons"; import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; @@ -1093,7 +1093,6 @@ export class CollectionFreeFormView extends CollectionSubView { this.props.Document._panX = this.props.Document._panY = 0; this.props.Document.scale = 1; }, icon: "compress-arrows-alt" }); optionItems.push({ description: `${this.Document._LODdisable ? "Enable LOD" : "Disable LOD"}`, event: () => this.Document._LODdisable = !this.Document._LODdisable, icon: "table" }); optionItems.push({ description: `${this.fitToContent ? "Unset" : "Set"} Fit To Container`, event: () => this.Document._fitToBox = !this.fitToContent, icon: !this.fitToContent ? "expand-arrows-alt" : "compress-arrows-alt" }); @@ -1130,8 +1129,15 @@ export class CollectionFreeFormView extends CollectionSubView { + this._timelineVisible = !this._timelineVisible; + }), icon: this._timelineVisible ? faEyeSlash : faEye + }); } + @observable _timelineVisible = false; intersectRect(r1: { left: number, top: number, width: number, height: number }, r2: { left: number, top: number, width: number, height: number }) { @@ -1215,7 +1221,7 @@ export class CollectionFreeFormView extends CollectionSubView {this.children} - + {this._timelineVisible ? : (null)} ; } diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 2038efbc6..4df693c9a 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -435,9 +435,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp this.rootDoc.isTemplateForField = ""; this.rootDoc.layoutKey = "layout"; this.rootDoc.isTemplateDoc = makeTemplate(this.rootDoc, true, title); - this.rootDoc._width = this.layoutDoc._width || 300; // the width and height are stored on the template, since we're getting rid of the old template - this.rootDoc._height = this.layoutDoc._height || 200; // we need to copy them over to the root. This should probably apply to all '_' fields - this.rootDoc._backgroundColor = Cast(this.layoutDoc._backgroundColor, "string", null); + setTimeout(() => { + this.rootDoc._width = this.layoutDoc._width || 300; // the width and height are stored on the template, since we're getting rid of the old template + this.rootDoc._height = this.layoutDoc._height || 200; // we need to copy them over to the root. This should probably apply to all '_' fields + this.rootDoc._backgroundColor = Cast(this.layoutDoc._backgroundColor, "string", null); + }, 10); Doc.AddDocToList(Cast(Doc.UserDoc()["template-notes"], Doc, null), "data", this.rootDoc); }, icon: "eye" }); -- cgit v1.2.3-70-g09d2 From 9adbc15b97c05bd506e3b70f57b2e6b9eb0fcfa7 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 30 Apr 2020 01:05:31 -0400 Subject: fixed doc dec resizing to use rootDoc instead of layoutDoc. fixed formattedText to not resize when template has not yet been expanded (ie, after switching from one template to another using the TemplateMenu) --- src/client/views/DocumentDecorations.tsx | 37 +++++++++++----------- .../views/nodes/formattedText/FormattedTextBox.tsx | 15 +++++++-- 2 files changed, 30 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 973ec2e89..99e071d6a 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -286,12 +286,11 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> SelectionManager.SelectedDocuments().forEach(action((element: DocumentView) => { if (dX !== 0 || dY !== 0 || dW !== 0 || dH !== 0) { - const doc = PositionDocument(element.props.Document); - const layoutDoc = PositionDocument(Doc.Layout(element.props.Document)); - let nwidth = layoutDoc._nativeWidth || 0; - let nheight = layoutDoc._nativeHeight || 0; - const width = (layoutDoc._width || 0); - const height = (layoutDoc._height || (nheight / nwidth * width)); + const doc = PositionDocument(element.rootDoc); + let nwidth = doc._nativeWidth || 0; + let nheight = doc._nativeHeight || 0; + const width = (doc._width || 0); + const height = (doc._height || (nheight / nwidth * width)); const scale = element.props.ScreenToLocalTransform().Scale * element.props.ContentScaling(); if (nwidth && nheight) { if (Math.abs(dW) > Math.abs(dH)) dH = dW * nheight / nwidth; @@ -303,8 +302,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> doc.y = (doc.y || 0) + dY * (actualdH - height); const fixedAspect = (nwidth && nheight); if (fixedAspect && (!nwidth || !nheight)) { - layoutDoc._nativeWidth = nwidth = layoutDoc._width || 0; - layoutDoc._nativeHeight = nheight = layoutDoc._height || 0; + doc._nativeWidth = nwidth = doc._width || 0; + doc._nativeHeight = nheight = doc._height || 0; } const anno = Cast(doc.annotationOn, Doc, null); if (e.ctrlKey && anno) { @@ -320,24 +319,24 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> else if (nwidth > 0 && nheight > 0) { if (Math.abs(dW) > Math.abs(dH)) { if (!fixedAspect) { - layoutDoc._nativeWidth = actualdW / (layoutDoc._width || 1) * (layoutDoc._nativeWidth || 0); + doc._nativeWidth = actualdW / (doc._width || 1) * (doc._nativeWidth || 0); } - layoutDoc._width = actualdW; - if (fixedAspect && !layoutDoc._fitWidth) layoutDoc._height = nheight / nwidth * layoutDoc._width; - else layoutDoc._height = actualdH; + doc._width = actualdW; + if (fixedAspect && !doc._fitWidth) doc._height = nheight / nwidth * doc._width; + else doc._height = actualdH; } else { if (!fixedAspect) { - layoutDoc._nativeHeight = actualdH / (layoutDoc._height || 1) * (doc._nativeHeight || 0); + doc._nativeHeight = actualdH / (doc._height || 1) * (doc._nativeHeight || 0); } - layoutDoc._height = actualdH; - if (fixedAspect && !layoutDoc._fitWidth) layoutDoc._width = nwidth / nheight * layoutDoc._height; - else layoutDoc._width = actualdW; + doc._height = actualdH; + if (fixedAspect && !doc._fitWidth) doc._width = nwidth / nheight * doc._height; + else doc._width = actualdW; } } else { - dW && (layoutDoc._width = actualdW); - dH && (layoutDoc._height = actualdH); - dH && layoutDoc._autoHeight && (layoutDoc._autoHeight = false); + dW && (doc._width = actualdW); + dH && (doc._height = actualdH); + dH && doc._autoHeight && (doc._autoHeight = false); } } })); diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 4df693c9a..3fb3f5644 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1215,11 +1215,20 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp this.layoutDoc._autoHeight = false; } const nh = this.layoutDoc.isTemplateForField ? 0 : NumCast(this.dataDoc._nativeHeight, 0); - const dh = NumCast(this.layoutDoc._height, 0); + const dh = NumCast(this.rootDoc._height, 0); const newHeight = Math.max(10, (nh ? dh / nh * scrollHeight : scrollHeight) + (this.props.ChromeHeight ? this.props.ChromeHeight() : 0)); if (Math.abs(newHeight - dh) > 1) { // bcz: Argh! without this, we get into a React crash if the same document is opened in a freeform view and in the treeview. no idea why, but after dragging the freeform document, selecting it, and selecting text, it will compute to 1 pixel higher than the treeview which causes a cycle - this.layoutDoc._height = newHeight; - this.dataDoc._nativeHeight = nh ? scrollHeight : undefined; + if (this.rootDoc !== this.layoutDoc && !this.layoutDoc.resolvedDataDoc) { + // if we have a template that hasn't been resolved yet, we can't set the height or we'd be setting it on the unresolved template. So set a timeout and hope its arrived... + console.log("Delayed height adjustment..."); + setTimeout(() => { + this.rootDoc._height = newHeight; + this.dataDoc._nativeHeight = nh ? scrollHeight : undefined; + }, 10); + } else { + this.rootDoc._height = newHeight; + this.dataDoc._nativeHeight = nh ? scrollHeight : undefined; + } } } } -- cgit v1.2.3-70-g09d2 From 0f4b9e541e4e1332bbed95f4a99113162ffef806 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 30 Apr 2020 11:10:27 -0400 Subject: added double click script support --- src/client/documents/Documents.ts | 2 ++ src/client/views/ScriptBox.tsx | 4 ++-- .../views/collections/CollectionStackingView.tsx | 7 ++++--- src/client/views/collections/CollectionSubView.tsx | 2 ++ src/client/views/collections/CollectionView.tsx | 7 ++++--- .../collectionFreeForm/CollectionFreeFormView.tsx | 3 ++- .../CollectionMulticolumnView.tsx | 2 ++ .../CollectionMultirowView.tsx | 3 ++- .../views/nodes/ContentFittingDocumentView.tsx | 1 + src/client/views/nodes/DocumentView.tsx | 23 ++++++++++++++++------ src/new_fields/Types.ts | 4 ++-- src/new_fields/documentSchemas.ts | 1 + .../authentication/models/current_user_utils.ts | 8 ++++++-- 13 files changed, 47 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 0d1d73ca3..436e59daf 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -95,6 +95,7 @@ export interface DocumentOptions { hideHeadings?: boolean; // whether stacking view column headings should be hidden isTemplateForField?: string; // the field key for which the containing document is a rendering template isTemplateDoc?: boolean; + scriptKey?: string; // the script key that a child click func script template document will write into templates?: List; backgroundColor?: string | ScriptField; // background color for data doc _backgroundColor?: string | ScriptField; // background color for each template layout doc ( overrides backgroundColor ) @@ -132,6 +133,7 @@ export interface DocumentOptions { activePen?: Doc; // which pen document is currently active (used as the radio button state for the 'unhecked' pen tool scripts) onClick?: ScriptField; onChildClick?: ScriptField; // script given to children of a collection to execute when they are clicked + onChildDoubleClick?: ScriptField; // script given to children of a collection to execute when they are double clicked onPointerDown?: ScriptField; onPointerUp?: ScriptField; dropConverter?: ScriptField; // script to run when documents are dropped on this Document. diff --git a/src/client/views/ScriptBox.tsx b/src/client/views/ScriptBox.tsx index 153b81876..66d3b937e 100644 --- a/src/client/views/ScriptBox.tsx +++ b/src/client/views/ScriptBox.tsx @@ -81,9 +81,9 @@ export class ScriptBox extends React.Component { ); } //let l = docList(this.source[0].data).length; if (l) { let ind = this.target[0].index !== undefined ? (this.target[0].index+1) % l : 0; this.target[0].index = ind; this.target[0].proto = getProto(docList(this.source[0].data)[ind]);} - public static EditButtonScript(title: string, doc: Doc, fieldKey: string, clientX: number, clientY: number, contextParams?: { [name: string]: string }) { + public static EditButtonScript(title: string, doc: Doc, fieldKey: string, clientX: number, clientY: number, contextParams?: { [name: string]: string }, defaultScript?: ScriptField) { let overlayDisposer: () => void = emptyFunction; - const script = ScriptCast(doc[fieldKey]); + const script = ScriptCast(doc[fieldKey]) || defaultScript; let originalText: string | undefined = undefined; if (script) { originalText = script.script.originalScript; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index e3720bf01..556d7df5c 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -150,8 +150,8 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { this.createDashEventsTarget(ele!); //so the whole grid is the drop target? } - @computed get onChildClickHandler() { return ScriptCast(this.Document.onChildClick); } - @computed get onClickHandler() { return ScriptCast(this.Document.onChildClick); } + @computed get onChildClickHandler() { return this.props.childClickScript || ScriptCast(this.Document.onChildClick); } + @computed get onChildDoubleClickHandler() { return this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick); } addDocTab = (doc: Doc, where: string) => { if (where === "inPlace" && this.layoutDoc.isInPlaceContainer) { @@ -178,7 +178,8 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { fitToBox={BoolCast(this.props.Document._freezeChildDimensions)} rootSelected={this.rootSelected} dropAction={StrCast(this.props.Document.childDropAction) as dropActionType} - onClick={layoutDoc.isTemplateDoc ? this.onClickHandler : this.onChildClickHandler} + onClick={this.onChildClickHandler} + onDoubleClick={this.onChildDoubleClickHandler} getTransform={dxf} focus={this.props.focus} CollectionDoc={this.props.CollectionView?.props.Document} diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 1bfd408f8..8cc1af55b 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -43,6 +43,8 @@ export interface CollectionViewProps extends FieldViewProps { export interface SubCollectionViewProps extends CollectionViewProps { CollectionView: Opt; children?: never | (() => JSX.Element[]) | React.ReactNode; + childClickScript?: ScriptField; + childDoubleClickScript?: ScriptField; freezeChildDimensions?: boolean; // used by TimeView to coerce documents to treat their width height as their native width/height overrideDocuments?: Doc[]; // used to override the documents shown by the sub collection to an explicit list (see LinkBox) ignoreFields?: string[]; // used in TreeView to ignore specified fields (see LinkBox) diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 801704673..2c52097aa 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -247,13 +247,14 @@ export class CollectionView extends Touchable { const existingOnClick = ContextMenu.Instance.findByDescription("OnClick..."); const onClicks = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : []; - const funcs = [{ key: "onChildClick", name: "On Child Clicked", script: undefined as any as ScriptField }]; + const funcs = [{ key: "onChildClick", name: "On Child Clicked", script: undefined as any as ScriptField }, + { key: "onChildDoubleClick", name: "On Child Double Clicked", script: undefined as any as ScriptField }]; DocListCast(Cast(Doc.UserDoc().childClickFuncs, Doc, null).data).forEach(childClick => - funcs.push({ key: "onChildClick", name: StrCast(childClick.title), script: ScriptCast(childClick.script) })); + funcs.push({ key: StrCast(childClick.scriptKey), name: StrCast(childClick.title), script: ScriptCast(childClick.data) })); funcs.map(func => onClicks.push({ description: `Edit ${func.name} script`, icon: "edit", event: (obj: any) => { func.script && (this.props.Document[func.key] = ObjectField.MakeCopy(func.script)); - ScriptBox.EditButtonScript(func.name + "...", this.props.Document, func.key, obj.x, obj.y, { thisContainer: Doc.name }); + ScriptBox.EditButtonScript(func.name + "...", this.props.Document, func.key, obj.x, obj.y, { thisContainer: Doc.name }, func.script); } })); !existingOnClick && ContextMenu.Instance.addItem({ description: "OnClick...", subitems: onClicks, icon: "hand-point-right" }); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 77de486d9..11d0f298d 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -70,7 +70,6 @@ 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; }; @@ -855,6 +854,7 @@ export class CollectionFreeFormView extends CollectionSubView BoolCast(this.Document.useClusters); @computed get backgroundActive() { return this.layoutDoc.isBackground && (this.props.ContainingCollectionView?.active() || this.props.active()); } parentActive = () => this.props.active() || this.backgroundActive ? true : false; @@ -873,6 +873,7 @@ export class CollectionFreeFormView extends CollectionSubView { @@ -229,6 +230,7 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu rootSelected={this.rootSelected} dropAction={StrCast(this.props.Document.childDropAction) as dropActionType} onClick={this.onChildClickHandler} + onDoubleClick={this.onChildDoubleClickHandler} getTransform={dxf} focus={this.props.focus} CollectionDoc={this.props.CollectionView?.props.Document} diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx index af0cc3b5c..615efdb39 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx @@ -203,7 +203,7 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument) @computed get onChildClickHandler() { return ScriptCast(this.Document.onChildClick); } - + @computed get onChildDoubleClickHandler() { return ScriptCast(this.Document.onChildDoubleClick); } addDocTab = (doc: Doc, where: string) => { if (where === "inPlace" && this.layoutDoc.isInPlaceContainer) { @@ -229,6 +229,7 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument) rootSelected={this.rootSelected} dropAction={StrCast(this.props.Document.childDropAction) as dropActionType} onClick={this.onChildClickHandler} + onDoubleClick={this.onChildDoubleClickHandler} getTransform={dxf} focus={this.props.focus} CollectionDoc={this.props.CollectionView?.props.Document} diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx index 641797cac..d0b0c8ee6 100644 --- a/src/client/views/nodes/ContentFittingDocumentView.tsx +++ b/src/client/views/nodes/ContentFittingDocumentView.tsx @@ -32,6 +32,7 @@ interface ContentFittingDocumentViewProps { CollectionView?: CollectionView; CollectionDoc?: Doc; onClick?: ScriptField; + onDoubleClick?: ScriptField; backgroundColor?: (doc: Doc) => string | undefined; getTransform: () => Transform; addDocument?: (document: Doc) => boolean; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index fdcaa2df3..7b28a45f8 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -64,6 +64,7 @@ export interface DocumentViewProps { contextMenuItems?: () => { script: ScriptField, label: string }[]; rootSelected: (outsideReaction?: boolean) => boolean; // whether the root of a template has been selected onClick?: ScriptField; + onDoubleClick?: ScriptField; onPointerDown?: ScriptField; onPointerUp?: ScriptField; dropAction?: dropActionType; @@ -116,6 +117,7 @@ export class DocumentView extends DocComponent(Docu @computed get nativeWidth() { return NumCast(this.layoutDoc._nativeWidth, this.props.NativeWidth() || (this.freezeDimensions ? this.layoutDoc[WidthSym]() : 0)); } @computed get nativeHeight() { return NumCast(this.layoutDoc._nativeHeight, this.props.NativeHeight() || (this.freezeDimensions ? this.layoutDoc[HeightSym]() : 0)); } @computed get onClickHandler() { return this.props.onClick || Cast(this.layoutDoc.onClick, ScriptField, null) || this.Document.onClick; } + @computed get onDoubleClickHandler() { return this.props.onDoubleClick || Cast(this.layoutDoc.onDoubleClick, ScriptField, null) || this.Document.onDoubleClick; } @computed get onPointerDownHandler() { return this.props.onPointerDown ? this.props.onPointerDown : this.Document.onPointerDown; } @computed get onPointerUpHandler() { return this.props.onPointerUp ? this.props.onPointerUp : this.Document.onPointerUp; } NativeWidth = () => this.nativeWidth; @@ -289,13 +291,22 @@ export class DocumentView extends DocComponent(Docu !this.props.Document.isBackground && this.props.bringToFront(this.props.Document); if (this._doubleTap && this.props.renderDepth && !this.onClickHandler?.script) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click if (!(e.nativeEvent as any).formattedHandled) { - const fullScreenAlias = Doc.MakeAlias(this.props.Document); - if (StrCast(fullScreenAlias.layoutKey) !== "layout_fullScreen" && fullScreenAlias.layout_fullScreen) { - fullScreenAlias.layoutKey = "layout_fullScreen"; + if (this.onDoubleClickHandler?.script && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes("ScriptingBox")) { // bcz: hack? don't execute script if you're clicking on a scripting box itself + const func = () => this.onDoubleClickHandler.script.run({ + this: this.layoutDoc, + self: this.rootDoc, + thisContainer: this.props.ContainingCollectionDoc, shiftKey: e.shiftKey + }, console.log); + func(); + } else { + const fullScreenAlias = Doc.MakeAlias(this.props.Document); + if (StrCast(fullScreenAlias.layoutKey) !== "layout_fullScreen" && fullScreenAlias.layout_fullScreen) { + fullScreenAlias.layoutKey = "layout_fullScreen"; + } + UndoManager.RunInBatch(() => this.props.addDocTab(fullScreenAlias, "inTab"), "double tap"); + SelectionManager.DeselectAll(); + Doc.UnBrushDoc(this.props.Document); } - UndoManager.RunInBatch(() => this.props.addDocTab(fullScreenAlias, "inTab"), "double tap"); - SelectionManager.DeselectAll(); - 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(); diff --git a/src/new_fields/Types.ts b/src/new_fields/Types.ts index aa44cefa0..3d784448d 100644 --- a/src/new_fields/Types.ts +++ b/src/new_fields/Types.ts @@ -88,8 +88,8 @@ export function DateCast(field: FieldResult) { return Cast(field, DateField, null); } -export function ScriptCast(field: FieldResult) { - return Cast(field, ScriptField, null); +export function ScriptCast(field: FieldResult, defaultVal: ScriptField | null = null) { + return Cast(field, ScriptField, defaultVal); } type WithoutList = T extends List ? (R extends RefField ? (R | Promise)[] : R[]) : T; diff --git a/src/new_fields/documentSchemas.ts b/src/new_fields/documentSchemas.ts index 7a0be8863..5ca0d681e 100644 --- a/src/new_fields/documentSchemas.ts +++ b/src/new_fields/documentSchemas.ts @@ -81,6 +81,7 @@ export const collectionSchema = createSchema({ childLayout: Doc, // layout template for children of a collecion childDetailView: Doc, // layout template to apply to a child when its clicked on in a collection and opened (requires onChildClick or other script to use this field) onChildClick: ScriptField, // script to run for each child when its clicked + onChildDoubleClick: ScriptField, // script to run for each child when its clicked onCheckedClick: ScriptField, // script to run when a checkbox is clicked next to a child in a tree view }); diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index eedd3ee67..1be977e4f 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -594,9 +594,13 @@ export class CurrentUserUtils { if (doc.childClickFuncs === undefined) { const openInTarget = Docs.Create.ScriptingDocument(ScriptField.MakeScript( "docCast(thisContainer.target).then((target) => { target && docCast(this.source).then((source) => { target.proto.data = new List([source || this]); } ); } )", - { target: Doc.name }), { title: "On Child Clicked (open in target)", _width: 300, _height: 200 }); + { target: Doc.name }), { title: "On Child Clicked (open in target)", _width: 300, _height: 200, scriptKey: "onChildClick" }); - doc.childClickFuncs = Docs.Create.TreeDocument([openInTarget], { title: "on Child Click function templates" }); + const openDetail = Docs.Create.ScriptingDocument(ScriptField.MakeScript( + "openOnRight(self.doubleClickView)", + { target: Doc.name }), { title: "On Child Dbl Clicked (open double click view)", _width: 300, _height: 200, scriptKey: "onChildDoubleClick" }); + + doc.childClickFuncs = Docs.Create.TreeDocument([openInTarget, openDetail], { title: "on Child Click function templates" }); } // this is equivalent to using PrefetchProxies to make sure all the childClickFuncs have been retrieved. PromiseValue(Cast(doc.childClickFuncs, Doc)).then(func => func && PromiseValue(func.data).then(DocListCast)); -- cgit v1.2.3-70-g09d2 From d4dd4ccd299ba2e06b35a6f14f698a26d026aeee Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 30 Apr 2020 11:34:08 -0400 Subject: clean up of childclick template func menus --- src/client/documents/Documents.ts | 2 +- src/client/views/collections/CollectionView.tsx | 16 ++++++++++------ src/server/authentication/models/current_user_utils.ts | 10 +++++++--- 3 files changed, 18 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 436e59daf..0809ae24f 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -95,7 +95,7 @@ export interface DocumentOptions { hideHeadings?: boolean; // whether stacking view column headings should be hidden isTemplateForField?: string; // the field key for which the containing document is a rendering template isTemplateDoc?: boolean; - scriptKey?: string; // the script key that a child click func script template document will write into + targetScriptKey?: string; // where to write a template script (used by collections with click templates which need to target onClick, onDoubleClick, etc) templates?: List; backgroundColor?: string | ScriptField; // background color for data doc _backgroundColor?: string | ScriptField; // background color for each template layout doc ( overrides backgroundColor ) diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 2c52097aa..79bb6c41b 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -247,16 +247,20 @@ export class CollectionView extends Touchable { const existingOnClick = ContextMenu.Instance.findByDescription("OnClick..."); const onClicks = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : []; - const funcs = [{ key: "onChildClick", name: "On Child Clicked", script: undefined as any as ScriptField }, - { key: "onChildDoubleClick", name: "On Child Double Clicked", script: undefined as any as ScriptField }]; - DocListCast(Cast(Doc.UserDoc().childClickFuncs, Doc, null).data).forEach(childClick => - funcs.push({ key: StrCast(childClick.scriptKey), name: StrCast(childClick.title), script: ScriptCast(childClick.data) })); + const funcs = [ + { key: "onChildClick", name: "On Child Clicked" }, + { key: "onChildDoubleClick", name: "On Child Double Clicked" }]; funcs.map(func => onClicks.push({ description: `Edit ${func.name} script`, icon: "edit", event: (obj: any) => { - func.script && (this.props.Document[func.key] = ObjectField.MakeCopy(func.script)); - ScriptBox.EditButtonScript(func.name + "...", this.props.Document, func.key, obj.x, obj.y, { thisContainer: Doc.name }, func.script); + ScriptBox.EditButtonScript(func.name + "...", this.props.Document, func.key, obj.x, obj.y, { thisContainer: Doc.name }); } })); + DocListCast(Cast(Doc.UserDoc().childClickFuncs, Doc, null).data).forEach(childClick => + onClicks.push({ + description: `Set child ${childClick.title}`, + icon: "edit", + event: () => this.props.Document[StrCast(childClick.targetScriptKey)] = ObjectField.MakeCopy(ScriptCast(childClick.data)), + })); !existingOnClick && ContextMenu.Instance.addItem({ description: "OnClick...", subitems: onClicks, icon: "hand-point-right" }); const more = ContextMenu.Instance.findByDescription("More..."); diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 1be977e4f..2c861d4fa 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -593,12 +593,16 @@ export class CurrentUserUtils { static setupClickEditorTemplates(doc: Doc) { if (doc.childClickFuncs === undefined) { const openInTarget = Docs.Create.ScriptingDocument(ScriptField.MakeScript( - "docCast(thisContainer.target).then((target) => { target && docCast(this.source).then((source) => { target.proto.data = new List([source || this]); } ); } )", - { target: Doc.name }), { title: "On Child Clicked (open in target)", _width: 300, _height: 200, scriptKey: "onChildClick" }); + "docCast(thisContainer.target).then((target) => {" + + " target && docCast(this.source).then((source) => { " + + " target.proto.data = new List([source || this]); " + + " }); " + + "})", + { target: Doc.name }), { title: "Click to open in target", _width: 300, _height: 200, targetScriptKey: "onChildClick" }); const openDetail = Docs.Create.ScriptingDocument(ScriptField.MakeScript( "openOnRight(self.doubleClickView)", - { target: Doc.name }), { title: "On Child Dbl Clicked (open double click view)", _width: 300, _height: 200, scriptKey: "onChildDoubleClick" }); + { target: Doc.name }), { title: "Double click to open doubleClickView", _width: 300, _height: 200, targetScriptKey: "onChildDoubleClick" }); doc.childClickFuncs = Docs.Create.TreeDocument([openInTarget, openDetail], { title: "on Child Click function templates" }); } -- cgit v1.2.3-70-g09d2 From baae91e7829676f03878696e9b13e1bdb4fb3c33 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 30 Apr 2020 11:40:57 -0400 Subject: from last --- src/client/views/collections/CollectionView.tsx | 2 +- src/server/authentication/models/current_user_utils.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 79bb6c41b..8d8c321e8 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -255,7 +255,7 @@ export class CollectionView extends Touchable { ScriptBox.EditButtonScript(func.name + "...", this.props.Document, func.key, obj.x, obj.y, { thisContainer: Doc.name }); } })); - DocListCast(Cast(Doc.UserDoc().childClickFuncs, Doc, null).data).forEach(childClick => + DocListCast(Cast(Doc.UserDoc()["clickFuncs-child"], Doc, null).data).forEach(childClick => onClicks.push({ description: `Set child ${childClick.title}`, icon: "edit", diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 2c861d4fa..e49cc4804 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -591,7 +591,7 @@ export class CurrentUserUtils { } static setupClickEditorTemplates(doc: Doc) { - if (doc.childClickFuncs === undefined) { + if (doc["clickFuncs-child"] === undefined) { const openInTarget = Docs.Create.ScriptingDocument(ScriptField.MakeScript( "docCast(thisContainer.target).then((target) => {" + " target && docCast(this.source).then((source) => { " + @@ -604,10 +604,10 @@ export class CurrentUserUtils { "openOnRight(self.doubleClickView)", { target: Doc.name }), { title: "Double click to open doubleClickView", _width: 300, _height: 200, targetScriptKey: "onChildDoubleClick" }); - doc.childClickFuncs = Docs.Create.TreeDocument([openInTarget, openDetail], { title: "on Child Click function templates" }); + doc["clickFuncs-child"] = Docs.Create.TreeDocument([openInTarget, openDetail], { title: "on Child Click function templates" }); } // this is equivalent to using PrefetchProxies to make sure all the childClickFuncs have been retrieved. - PromiseValue(Cast(doc.childClickFuncs, Doc)).then(func => func && PromiseValue(func.data).then(DocListCast)); + PromiseValue(Cast(doc["clickFuncs-child"], Doc)).then(func => func && PromiseValue(func.data).then(DocListCast)); if (doc.clickFuncs === undefined) { const onClick = Docs.Create.ScriptingDocument(undefined, { -- cgit v1.2.3-70-g09d2 From 3130198655c6f090e90ed30378595d57aefd168c Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 30 Apr 2020 12:08:16 -0400 Subject: ugh -- fixed my bug with snapping. --- src/client/util/DragManager.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index bccdf38ce..646a27649 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -310,10 +310,10 @@ export namespace DragManager { const currTop = e.pageY - yFromTop; const currRight = e.pageX + xFromRight; const currBottom = e.pageY + yFromBottom; - const closestLeft = vertSnapLines.reduce((prev, curr) => Math.abs(prev - currLeft) > Math.abs(curr - currLeft) ? curr : prev, currLeft); - const closestTop = horizSnapLines.reduce((prev, curr) => Math.abs(prev - currTop) > Math.abs(curr - currTop) ? curr : prev, currTop); - const closestRight = vertSnapLines.reduce((prev, curr) => Math.abs(prev - currRight) > Math.abs(curr - currRight) ? curr : prev, currRight); - const closestBottom = horizSnapLines.reduce((prev, curr) => Math.abs(prev - currBottom) > Math.abs(curr - currBottom) ? curr : prev, currBottom); + const closestLeft = vertSnapLines.length ? vertSnapLines.reduce((prev, curr) => Math.abs(prev - currLeft) > Math.abs(curr - currLeft) ? curr : prev) : currLeft; + const closestTop = horizSnapLines.length ? horizSnapLines.reduce((prev, curr) => Math.abs(prev - currTop) > Math.abs(curr - currTop) ? curr : prev) : currTop; + const closestRight = vertSnapLines.length ? vertSnapLines.reduce((prev, curr) => Math.abs(prev - currRight) > Math.abs(curr - currRight) ? curr : prev) : currRight; + const closestBottom = horizSnapLines.length ? horizSnapLines.reduce((prev, curr) => Math.abs(prev - currBottom) > Math.abs(curr - currBottom) ? curr : prev) : currBottom; const distFromClosestLeft = Math.abs(e.pageX - xFromLeft - closestLeft); const distFromClosestTop = Math.abs(e.pageY - yFromTop - closestTop); const distFromClosestRight = Math.abs(e.pageX + xFromRight - closestRight); -- cgit v1.2.3-70-g09d2 From fc7ce2009ea1959be7de0f284f7c999a49af4e6e Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 30 Apr 2020 12:38:46 -0400 Subject: fixed drag snap bug --- src/client/util/DragManager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 646a27649..225d25d2c 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -324,7 +324,7 @@ export namespace DragManager { else if (distFromClosestRight < 10) { thisX = closestRight - xFromRight; } - if (distFromClosestTop < 10 && distFromClosestTop < distFromClosestRight) { + if (distFromClosestTop < 10 && distFromClosestTop < distFromClosestBottom) { thisY = closestTop + yFromTop; } else if (distFromClosestBottom < 10) { -- cgit v1.2.3-70-g09d2 From 113735b9dcde9923a804e1489c530625e2bf8d2f Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 30 Apr 2020 13:59:58 -0400 Subject: fixed up snapping with resize --- src/client/util/DragManager.ts | 11 ++++++++--- src/client/views/DocumentDecorations.tsx | 17 +++++++++++++++++ src/client/views/nodes/DocumentView.tsx | 1 + 3 files changed, 26 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 225d25d2c..c03d9ea1b 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -20,6 +20,7 @@ import { DocumentView } from "../views/nodes/DocumentView"; import { UndoManager } from "./UndoManager"; import { PointData } from "../../new_fields/InkField"; import { MainView } from "../views/MainView"; +import { action } from "mobx"; export type dropActionType = "alias" | "copy" | "move" | undefined; // undefined = move export function SetupDrag( @@ -303,7 +304,7 @@ export namespace DragManager { MainView.Instance._vLines = vertLines; } - function snapDrag(e: PointerEvent, xFromLeft: number, yFromTop: number, xFromRight: number, yFromBottom: number) { + export function snapDrag(e: PointerEvent, xFromLeft: number, yFromTop: number, xFromRight: number, yFromBottom: number) { let thisX = e.pageX; let thisY = e.pageY; const currLeft = e.pageX - xFromLeft; @@ -454,10 +455,14 @@ export namespace DragManager { dragElements.map(dragElement => dragElement.parentNode === dragDiv && dragDiv.removeChild(dragElement)); eles.map(ele => ele.parentElement && ele.parentElement?.className === dragData.dragDivName ? (ele.parentElement.hidden = false) : (ele.hidden = false)); }; - const endDrag = () => { + const endDrag = action(() => { document.removeEventListener("pointermove", moveHandler, true); document.removeEventListener("pointerup", upHandler); - }; + MainView.Instance._hLines = []; + MainView.Instance._vLines = []; + vertSnapLines.length = 0; + horizSnapLines.length = 0; + }); AbortDrag = () => { hideDragShowOriginalElements(); diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 99e071d6a..e2759291a 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -20,6 +20,7 @@ import React = require("react"); import { Id } from '../../new_fields/FieldSymbols'; import e = require('express'); import { CollectionDockingView } from './collections/CollectionDockingView'; +import { MainView } from './MainView'; library.add(faCaretUp); library.add(faObjectGroup); @@ -46,6 +47,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> private _linkBoxHeight = 20 + 3; // link button height + margin private _titleHeight = 20; private _resizeUndo?: UndoManager.Batch; + private _offX = 0; _offY = 0; // offset from click pt to inner edge of resize border + private _snapX = 0; _snapY = 0; // last snapped location of resize border @observable private _accumulatedTitle = ""; @observable private _titleControlString: string = "#title"; @observable private _edtingTitle = false; @@ -238,12 +241,24 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> setupMoveUpEvents(this, e, this.onPointerMove, this.onPointerUp, (e) => { }); if (e.button === 0) { this._resizeHdlId = e.currentTarget.id; + const bounds = e.currentTarget.getBoundingClientRect(); + this._offX = this._resizeHdlId.toLowerCase().includes("left") ? bounds.right - e.clientX : bounds.left - e.clientX; + this._offY = this._resizeHdlId.toLowerCase().includes("top") ? bounds.bottom - e.clientY : bounds.top - e.clientY; this.Interacting = true; this._resizeUndo = UndoManager.StartBatch("DocDecs resize"); + SelectionManager.SelectedDocuments()[0].props.setupDragLines?.(); } + this._snapX = e.pageX; + this._snapY = e.pageY; } onPointerMove = (e: PointerEvent, down: number[], move: number[]): boolean => { + const { thisX, thisY } = DragManager.snapDrag(e, -this._offX, -this._offY, this._offX, this._offY); + move[0] = thisX - this._snapX; + move[1] = thisY - this._snapY; + this._snapX = thisX; + this._snapY = thisY; + let dX = 0, dY = 0, dW = 0, dH = 0; switch (this._resizeHdlId) { @@ -349,6 +364,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> this.Interacting = false; (e.button === 0) && this._resizeUndo?.end(); this._resizeUndo = undefined; + MainView.Instance._hLines = []; + MainView.Instance._vLines = []; } @computed diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 7b28a45f8..085637440 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -74,6 +74,7 @@ export interface DocumentViewProps { removeDocument?: (doc: Doc) => boolean; moveDocument?: (doc: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean) => boolean; ScreenToLocalTransform: () => Transform; + setupDragLines?: () => void; renderDepth: number; ContentScaling: () => number; PanelWidth: () => number; -- cgit v1.2.3-70-g09d2 From 22748f8d35235941fc6622b19a2d4d3f809ccee7 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 30 Apr 2020 17:16:14 -0400 Subject: working version of snapping with resize / templates / centers --- .VSCodeCounter/details.md | 661 +++++++++++++++++ .VSCodeCounter/results.csv | 648 ++++++++++++++++ .VSCodeCounter/results.md | 164 +++++ .VSCodeCounter/results.txt | 813 +++++++++++++++++++++ package-lock.json | 81 +- src/Utils.ts | 4 +- src/client/util/DragManager.ts | 41 +- src/client/views/MainView.tsx | 8 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 70 +- .../views/nodes/formattedText/DashFieldView.tsx | 4 - .../authentication/models/current_user_utils.ts | 6 +- 11 files changed, 2395 insertions(+), 105 deletions(-) create mode 100644 .VSCodeCounter/details.md create mode 100644 .VSCodeCounter/results.csv create mode 100644 .VSCodeCounter/results.md create mode 100644 .VSCodeCounter/results.txt (limited to 'src') diff --git a/.VSCodeCounter/details.md b/.VSCodeCounter/details.md new file mode 100644 index 000000000..2f988953b --- /dev/null +++ b/.VSCodeCounter/details.md @@ -0,0 +1,661 @@ +# Details + +Date : 2020-04-30 14:40:16 + +Directory /Users/bcz/Documents/GitHub/Dash-Web + +Total : 646 files, 224911 codes, 32987 comments, 15880 blanks, all 273778 lines + +[summary](results.md) + +## Files +| filename | language | code | comment | blank | total | +| :--- | :--- | ---: | ---: | ---: | ---: | +| [README.md](file:///Users/bcz/Documents/GitHub/Dash-Web/README.md) | Markdown | 6 | 0 | 3 | 9 | +| [build/index.html](file:///Users/bcz/Documents/GitHub/Dash-Web/build/index.html) | HTML | 9 | 0 | 3 | 12 | +| [dash.bat](file:///Users/bcz/Documents/GitHub/Dash-Web/dash.bat) | Batch | 2 | 0 | 1 | 3 | +| [deploy/assets/env.json](file:///Users/bcz/Documents/GitHub/Dash-Web/deploy/assets/env.json) | JSON | 15 | 0 | 0 | 15 | +| [deploy/assets/pdf.worker.js](file:///Users/bcz/Documents/GitHub/Dash-Web/deploy/assets/pdf.worker.js) | JavaScript | 55,662 | 174 | 686 | 56,522 | +| [deploy/debug/repl.html](file:///Users/bcz/Documents/GitHub/Dash-Web/deploy/debug/repl.html) | HTML | 11 | 0 | 3 | 14 | +| [deploy/debug/test.html](file:///Users/bcz/Documents/GitHub/Dash-Web/deploy/debug/test.html) | HTML | 10 | 0 | 3 | 13 | +| [deploy/debug/viewer.html](file:///Users/bcz/Documents/GitHub/Dash-Web/deploy/debug/viewer.html) | HTML | 11 | 0 | 3 | 14 | +| [deploy/index.html](file:///Users/bcz/Documents/GitHub/Dash-Web/deploy/index.html) | HTML | 13 | 0 | 3 | 16 | +| [deploy/mobile/image.html](file:///Users/bcz/Documents/GitHub/Dash-Web/deploy/mobile/image.html) | HTML | 12 | 0 | 3 | 15 | +| [deploy/mobile/ink.html](file:///Users/bcz/Documents/GitHub/Dash-Web/deploy/mobile/ink.html) | HTML | 10 | 0 | 3 | 13 | +| [package-lock.json](file:///Users/bcz/Documents/GitHub/Dash-Web/package-lock.json) | JSON | 18,689 | 0 | 1 | 18,690 | +| [package.json](file:///Users/bcz/Documents/GitHub/Dash-Web/package.json) | JSON | 266 | 0 | 1 | 267 | +| [sentence_parser.py](file:///Users/bcz/Documents/GitHub/Dash-Web/sentence_parser.py) | Python | 6 | 0 | 1 | 7 | +| [session.config.json](file:///Users/bcz/Documents/GitHub/Dash-Web/session.config.json) | JSON | 12 | 0 | 1 | 13 | +| [solr-8.3.1/bin/install_solr_service.sh](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/bin/install_solr_service.sh) | Shell Script | 307 | 29 | 35 | 371 | +| [solr-8.3.1/bin/oom_solr.sh](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/bin/oom_solr.sh) | Shell Script | 13 | 15 | 3 | 31 | +| [solr-8.3.1/bin/solr.cmd](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/bin/solr.cmd) | Batch | 1,782 | 43 | 210 | 2,035 | +| [solr-8.3.1/bin/solr.in.cmd](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/bin/solr.in.cmd) | Batch | 16 | 133 | 29 | 178 | +| [solr-8.3.1/bin/solr.in.sh](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/bin/solr.in.sh) | Shell Script | 0 | 172 | 34 | 206 | +| [solr-8.3.1/contrib/prometheus-exporter/bin/solr-exporter.cmd](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/contrib/prometheus-exporter/bin/solr-exporter.cmd) | Batch | 82 | 0 | 26 | 108 | +| [solr-8.3.1/contrib/prometheus-exporter/conf/grafana-solr-dashboard.json](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/contrib/prometheus-exporter/conf/grafana-solr-dashboard.json) | JSON | 4,465 | 0 | 1 | 4,466 | +| [solr-8.3.1/contrib/prometheus-exporter/conf/solr-exporter-config.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/contrib/prometheus-exporter/conf/solr-exporter-config.xml) | XML | 1,734 | 63 | 10 | 1,807 | +| [solr-8.3.1/docs/images/solr.svg](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/docs/images/solr.svg) | XML | 39 | 0 | 1 | 40 | +| [solr-8.3.1/docs/index.html](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/docs/index.html) | HTML | 20 | 0 | 1 | 21 | +| [solr-8.3.1/example/example-DIH/solr/atom/conf/atom-data-config.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/atom/conf/atom-data-config.xml) | XML | 21 | 6 | 9 | 36 | +| [solr-8.3.1/example/example-DIH/solr/atom/conf/solrconfig.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/atom/conf/solrconfig.xml) | XML | 20 | 37 | 8 | 65 | +| [solr-8.3.1/example/example-DIH/solr/atom/core.properties](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/atom/core.properties) | Properties | 0 | 0 | 2 | 2 | +| [solr-8.3.1/example/example-DIH/solr/db/conf/clustering/carrot2/kmeans-attributes.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/db/conf/clustering/carrot2/kmeans-attributes.xml) | XML | 13 | 6 | 1 | 20 | +| [solr-8.3.1/example/example-DIH/solr/db/conf/clustering/carrot2/lingo-attributes.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/db/conf/clustering/carrot2/lingo-attributes.xml) | XML | 13 | 11 | 1 | 25 | +| [solr-8.3.1/example/example-DIH/solr/db/conf/clustering/carrot2/stc-attributes.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/db/conf/clustering/carrot2/stc-attributes.xml) | XML | 13 | 6 | 1 | 20 | +| [solr-8.3.1/example/example-DIH/solr/db/conf/currency.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/db/conf/currency.xml) | XML | 45 | 19 | 4 | 68 | +| [solr-8.3.1/example/example-DIH/solr/db/conf/db-data-config.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/db/conf/db-data-config.xml) | XML | 26 | 0 | 4 | 30 | +| [solr-8.3.1/example/example-DIH/solr/db/conf/elevate.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/db/conf/elevate.xml) | XML | 3 | 37 | 3 | 43 | +| [solr-8.3.1/example/example-DIH/solr/db/conf/solrconfig.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/db/conf/solrconfig.xml) | XML | 292 | 958 | 104 | 1,354 | +| [solr-8.3.1/example/example-DIH/solr/db/conf/update-script.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/db/conf/update-script.js) | JavaScript | 15 | 26 | 13 | 54 | +| [solr-8.3.1/example/example-DIH/solr/db/conf/xslt/example.xsl](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/db/conf/xslt/example.xsl) | XSL | 98 | 20 | 15 | 133 | +| [solr-8.3.1/example/example-DIH/solr/db/conf/xslt/example_atom.xsl](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/db/conf/xslt/example_atom.xsl) | XSL | 40 | 20 | 8 | 68 | +| [solr-8.3.1/example/example-DIH/solr/db/conf/xslt/example_rss.xsl](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/db/conf/xslt/example_rss.xsl) | XSL | 41 | 20 | 6 | 67 | +| [solr-8.3.1/example/example-DIH/solr/db/conf/xslt/luke.xsl](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/db/conf/xslt/luke.xsl) | XSL | 301 | 19 | 18 | 338 | +| [solr-8.3.1/example/example-DIH/solr/db/conf/xslt/updateXml.xsl](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/db/conf/xslt/updateXml.xsl) | XSL | 35 | 25 | 11 | 71 | +| [solr-8.3.1/example/example-DIH/solr/db/core.properties](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/db/core.properties) | Properties | 0 | 0 | 2 | 2 | +| [solr-8.3.1/example/example-DIH/solr/mail/conf/clustering/carrot2/kmeans-attributes.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/mail/conf/clustering/carrot2/kmeans-attributes.xml) | XML | 13 | 6 | 1 | 20 | +| [solr-8.3.1/example/example-DIH/solr/mail/conf/clustering/carrot2/lingo-attributes.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/mail/conf/clustering/carrot2/lingo-attributes.xml) | XML | 13 | 11 | 1 | 25 | +| [solr-8.3.1/example/example-DIH/solr/mail/conf/clustering/carrot2/stc-attributes.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/mail/conf/clustering/carrot2/stc-attributes.xml) | XML | 13 | 6 | 1 | 20 | +| [solr-8.3.1/example/example-DIH/solr/mail/conf/currency.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/mail/conf/currency.xml) | XML | 45 | 19 | 4 | 68 | +| [solr-8.3.1/example/example-DIH/solr/mail/conf/elevate.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/mail/conf/elevate.xml) | XML | 3 | 37 | 3 | 43 | +| [solr-8.3.1/example/example-DIH/solr/mail/conf/mail-data-config.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/mail/conf/mail-data-config.xml) | XML | 8 | 4 | 1 | 13 | +| [solr-8.3.1/example/example-DIH/solr/mail/conf/solrconfig.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/mail/conf/solrconfig.xml) | XML | 294 | 958 | 105 | 1,357 | +| [solr-8.3.1/example/example-DIH/solr/mail/conf/update-script.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/mail/conf/update-script.js) | JavaScript | 15 | 26 | 13 | 54 | +| [solr-8.3.1/example/example-DIH/solr/mail/conf/xslt/example.xsl](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/mail/conf/xslt/example.xsl) | XSL | 98 | 20 | 15 | 133 | +| [solr-8.3.1/example/example-DIH/solr/mail/conf/xslt/example_atom.xsl](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/mail/conf/xslt/example_atom.xsl) | XSL | 40 | 20 | 8 | 68 | +| [solr-8.3.1/example/example-DIH/solr/mail/conf/xslt/example_rss.xsl](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/mail/conf/xslt/example_rss.xsl) | XSL | 41 | 20 | 6 | 67 | +| [solr-8.3.1/example/example-DIH/solr/mail/conf/xslt/luke.xsl](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/mail/conf/xslt/luke.xsl) | XSL | 301 | 19 | 18 | 338 | +| [solr-8.3.1/example/example-DIH/solr/mail/conf/xslt/updateXml.xsl](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/mail/conf/xslt/updateXml.xsl) | XSL | 35 | 25 | 11 | 71 | +| [solr-8.3.1/example/example-DIH/solr/mail/core.properties](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/mail/core.properties) | Properties | 0 | 0 | 2 | 2 | +| [solr-8.3.1/example/example-DIH/solr/solr.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/solr.xml) | XML | 2 | 0 | 1 | 3 | +| [solr-8.3.1/example/example-DIH/solr/solr/conf/clustering/carrot2/kmeans-attributes.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/solr/conf/clustering/carrot2/kmeans-attributes.xml) | XML | 13 | 6 | 1 | 20 | +| [solr-8.3.1/example/example-DIH/solr/solr/conf/clustering/carrot2/lingo-attributes.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/solr/conf/clustering/carrot2/lingo-attributes.xml) | XML | 13 | 11 | 1 | 25 | +| [solr-8.3.1/example/example-DIH/solr/solr/conf/clustering/carrot2/stc-attributes.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/solr/conf/clustering/carrot2/stc-attributes.xml) | XML | 13 | 6 | 1 | 20 | +| [solr-8.3.1/example/example-DIH/solr/solr/conf/currency.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/solr/conf/currency.xml) | XML | 45 | 19 | 4 | 68 | +| [solr-8.3.1/example/example-DIH/solr/solr/conf/elevate.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/solr/conf/elevate.xml) | XML | 3 | 37 | 3 | 43 | +| [solr-8.3.1/example/example-DIH/solr/solr/conf/solr-data-config.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/solr/conf/solr-data-config.xml) | XML | 8 | 16 | 2 | 26 | +| [solr-8.3.1/example/example-DIH/solr/solr/conf/solrconfig.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/solr/conf/solrconfig.xml) | XML | 292 | 958 | 102 | 1,352 | +| [solr-8.3.1/example/example-DIH/solr/solr/conf/update-script.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/solr/conf/update-script.js) | JavaScript | 15 | 26 | 13 | 54 | +| [solr-8.3.1/example/example-DIH/solr/solr/conf/xslt/example.xsl](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/solr/conf/xslt/example.xsl) | XSL | 98 | 20 | 15 | 133 | +| [solr-8.3.1/example/example-DIH/solr/solr/conf/xslt/example_atom.xsl](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/solr/conf/xslt/example_atom.xsl) | XSL | 40 | 20 | 8 | 68 | +| [solr-8.3.1/example/example-DIH/solr/solr/conf/xslt/example_rss.xsl](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/solr/conf/xslt/example_rss.xsl) | XSL | 41 | 20 | 6 | 67 | +| [solr-8.3.1/example/example-DIH/solr/solr/conf/xslt/luke.xsl](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/solr/conf/xslt/luke.xsl) | XSL | 301 | 19 | 18 | 338 | +| [solr-8.3.1/example/example-DIH/solr/solr/conf/xslt/updateXml.xsl](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/solr/conf/xslt/updateXml.xsl) | XSL | 35 | 25 | 11 | 71 | +| [solr-8.3.1/example/example-DIH/solr/solr/core.properties](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/solr/core.properties) | Properties | 0 | 0 | 2 | 2 | +| [solr-8.3.1/example/example-DIH/solr/tika/conf/solrconfig.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/tika/conf/solrconfig.xml) | XML | 17 | 38 | 7 | 62 | +| [solr-8.3.1/example/example-DIH/solr/tika/conf/tika-data-config.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/tika/conf/tika-data-config.xml) | XML | 17 | 3 | 7 | 27 | +| [solr-8.3.1/example/example-DIH/solr/tika/core.properties](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/example-DIH/solr/tika/core.properties) | Properties | 0 | 0 | 2 | 2 | +| [solr-8.3.1/example/exampledocs/books.json](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/exampledocs/books.json) | JSON | 51 | 0 | 1 | 52 | +| [solr-8.3.1/example/exampledocs/gb18030-example.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/exampledocs/gb18030-example.xml) | XML | 14 | 16 | 3 | 33 | +| [solr-8.3.1/example/exampledocs/hd.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/exampledocs/hd.xml) | XML | 33 | 20 | 4 | 57 | +| [solr-8.3.1/example/exampledocs/ipod_other.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/exampledocs/ipod_other.xml) | XML | 32 | 20 | 9 | 61 | +| [solr-8.3.1/example/exampledocs/ipod_video.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/exampledocs/ipod_video.xml) | XML | 21 | 18 | 2 | 41 | +| [solr-8.3.1/example/exampledocs/manufacturers.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/exampledocs/manufacturers.xml) | XML | 57 | 16 | 3 | 76 | +| [solr-8.3.1/example/exampledocs/mem.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/exampledocs/mem.xml) | XML | 45 | 24 | 9 | 78 | +| [solr-8.3.1/example/exampledocs/money.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/exampledocs/money.xml) | XML | 42 | 17 | 7 | 66 | +| [solr-8.3.1/example/exampledocs/monitor.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/exampledocs/monitor.xml) | XML | 14 | 18 | 3 | 35 | +| [solr-8.3.1/example/exampledocs/monitor2.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/exampledocs/monitor2.xml) | XML | 13 | 18 | 3 | 34 | +| [solr-8.3.1/example/exampledocs/mp500.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/exampledocs/mp500.xml) | XML | 23 | 18 | 3 | 44 | +| [solr-8.3.1/example/exampledocs/sample.html](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/exampledocs/sample.html) | HTML | 13 | 0 | 1 | 14 | +| [solr-8.3.1/example/exampledocs/sd500.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/exampledocs/sd500.xml) | XML | 19 | 18 | 2 | 39 | +| [solr-8.3.1/example/exampledocs/solr.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/exampledocs/solr.xml) | XML | 20 | 16 | 3 | 39 | +| [solr-8.3.1/example/exampledocs/test_utf8.sh](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/exampledocs/test_utf8.sh) | Shell Script | 57 | 21 | 16 | 94 | +| [solr-8.3.1/example/exampledocs/utf8-example.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/exampledocs/utf8-example.xml) | XML | 19 | 20 | 4 | 43 | +| [solr-8.3.1/example/exampledocs/vidcard.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/exampledocs/vidcard.xml) | XML | 40 | 21 | 2 | 63 | +| [solr-8.3.1/example/files/browse-resources/velocity/resources.properties](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/files/browse-resources/velocity/resources.properties) | Properties | 72 | 6 | 5 | 83 | +| [solr-8.3.1/example/files/browse-resources/velocity/resources_de_DE.properties](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/files/browse-resources/velocity/resources_de_DE.properties) | Properties | 18 | 0 | 1 | 19 | +| [solr-8.3.1/example/files/browse-resources/velocity/resources_fr_FR.properties](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/files/browse-resources/velocity/resources_fr_FR.properties) | Properties | 18 | 0 | 3 | 21 | +| [solr-8.3.1/example/files/conf/currency.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/files/conf/currency.xml) | XML | 45 | 19 | 4 | 68 | +| [solr-8.3.1/example/files/conf/elevate.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/files/conf/elevate.xml) | XML | 3 | 37 | 3 | 43 | +| [solr-8.3.1/example/files/conf/params.json](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/files/conf/params.json) | JSON | 34 | 0 | 1 | 35 | +| [solr-8.3.1/example/files/conf/solrconfig.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/files/conf/solrconfig.xml) | XML | 298 | 979 | 102 | 1,379 | +| [solr-8.3.1/example/files/conf/update-script.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/files/conf/update-script.js) | JavaScript | 80 | 13 | 23 | 116 | +| [solr-8.3.1/example/files/conf/velocity/dropit.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/files/conf/velocity/dropit.js) | JavaScript | 0 | 0 | 2 | 2 | +| [solr-8.3.1/example/files/conf/velocity/jquery.tx3-tag-cloud.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/files/conf/velocity/jquery.tx3-tag-cloud.js) | JavaScript | 0 | 0 | 2 | 2 | +| [solr-8.3.1/example/files/conf/velocity/js/dropit.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/files/conf/velocity/js/dropit.js) | JavaScript | 64 | 15 | 19 | 98 | +| [solr-8.3.1/example/files/conf/velocity/js/jquery.autocomplete.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/files/conf/velocity/js/jquery.autocomplete.js) | JavaScript | 620 | 68 | 76 | 764 | +| [solr-8.3.1/example/files/conf/velocity/js/jquery.tx3-tag-cloud.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/files/conf/velocity/js/jquery.tx3-tag-cloud.js) | JavaScript | 46 | 16 | 9 | 71 | +| [solr-8.3.1/example/films/film_data_generator.py](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/films/film_data_generator.py) | Python | 82 | 24 | 12 | 118 | +| [solr-8.3.1/example/films/films.json](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/films/films.json) | JSON | 15,830 | 0 | 1 | 15,831 | +| [solr-8.3.1/example/films/films.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/example/films/films.xml) | XML | 11,438 | 0 | 1 | 11,439 | +| [solr-8.3.1/server/contexts/solr-jetty-context.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/contexts/solr-jetty-context.xml) | XML | 8 | 0 | 1 | 9 | +| [solr-8.3.1/server/etc/jetty-http.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/etc/jetty-http.xml) | XML | 33 | 15 | 4 | 52 | +| [solr-8.3.1/server/etc/jetty-https.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/etc/jetty-https.xml) | XML | 56 | 16 | 5 | 77 | +| [solr-8.3.1/server/etc/jetty-https8.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/etc/jetty-https8.xml) | XML | 34 | 32 | 4 | 70 | +| [solr-8.3.1/server/etc/jetty-ssl.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/etc/jetty-ssl.xml) | XML | 23 | 11 | 4 | 38 | +| [solr-8.3.1/server/etc/jetty.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/etc/jetty.xml) | XML | 110 | 94 | 18 | 222 | +| [solr-8.3.1/server/etc/webdefault.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/etc/webdefault.xml) | XML | 272 | 232 | 24 | 528 | +| [solr-8.3.1/server/resources/jetty-logging.properties](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/resources/jetty-logging.properties) | Properties | 1 | 0 | 1 | 2 | +| [solr-8.3.1/server/resources/log4j2-console.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/resources/log4j2-console.xml) | XML | 19 | 43 | 6 | 68 | +| [solr-8.3.1/server/resources/log4j2.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/resources/log4j2.xml) | XML | 54 | 80 | 9 | 143 | +| [solr-8.3.1/server/scripts/cloud-scripts/snapshotscli.sh](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/scripts/cloud-scripts/snapshotscli.sh) | Shell Script | 152 | 2 | 23 | 177 | +| [solr-8.3.1/server/scripts/cloud-scripts/zkcli.bat](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/scripts/cloud-scripts/zkcli.bat) | Batch | 11 | 8 | 7 | 26 | +| [solr-8.3.1/server/scripts/cloud-scripts/zkcli.sh](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/scripts/cloud-scripts/zkcli.sh) | Shell Script | 9 | 9 | 9 | 27 | +| [solr-8.3.1/server/solr-webapp/webapp/WEB-INF/web.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/WEB-INF/web.xml) | XML | 62 | 42 | 11 | 115 | +| [solr-8.3.1/server/solr-webapp/webapp/css/angular/analysis.css](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/css/angular/analysis.css) | CSS | 237 | 19 | 48 | 304 | +| [solr-8.3.1/server/solr-webapp/webapp/css/angular/chosen.css](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/css/angular/chosen.css) | CSS | 402 | 55 | 9 | 466 | +| [solr-8.3.1/server/solr-webapp/webapp/css/angular/cloud.css](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/css/angular/cloud.css) | CSS | 594 | 23 | 106 | 723 | +| [solr-8.3.1/server/solr-webapp/webapp/css/angular/collections.css](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/css/angular/collections.css) | CSS | 296 | 18 | 65 | 379 | +| [solr-8.3.1/server/solr-webapp/webapp/css/angular/common.css](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/css/angular/common.css) | CSS | 647 | 19 | 106 | 772 | +| [solr-8.3.1/server/solr-webapp/webapp/css/angular/cores.css](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/css/angular/cores.css) | CSS | 171 | 18 | 37 | 226 | +| [solr-8.3.1/server/solr-webapp/webapp/css/angular/dashboard.css](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/css/angular/dashboard.css) | CSS | 134 | 18 | 28 | 180 | +| [solr-8.3.1/server/solr-webapp/webapp/css/angular/dataimport.css](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/css/angular/dataimport.css) | CSS | 292 | 18 | 61 | 371 | +| [solr-8.3.1/server/solr-webapp/webapp/css/angular/documents.css](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/css/angular/documents.css) | CSS | 131 | 23 | 26 | 180 | +| [solr-8.3.1/server/solr-webapp/webapp/css/angular/files.css](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/css/angular/files.css) | CSS | 29 | 18 | 7 | 54 | +| [solr-8.3.1/server/solr-webapp/webapp/css/angular/index.css](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/css/angular/index.css) | CSS | 164 | 18 | 35 | 217 | +| [solr-8.3.1/server/solr-webapp/webapp/css/angular/java-properties.css](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/css/angular/java-properties.css) | CSS | 24 | 18 | 6 | 48 | +| [solr-8.3.1/server/solr-webapp/webapp/css/angular/jquery-ui.min.css](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/css/angular/jquery-ui.min.css) | CSS | 1 | 26 | 2 | 29 | +| [solr-8.3.1/server/solr-webapp/webapp/css/angular/jquery-ui.structure.min.css](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/css/angular/jquery-ui.structure.min.css) | CSS | 1 | 22 | 2 | 25 | +| [solr-8.3.1/server/solr-webapp/webapp/css/angular/logging.css](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/css/angular/logging.css) | CSS | 303 | 19 | 63 | 385 | +| [solr-8.3.1/server/solr-webapp/webapp/css/angular/login.css](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/css/angular/login.css) | CSS | 80 | 18 | 12 | 110 | +| [solr-8.3.1/server/solr-webapp/webapp/css/angular/menu.css](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/css/angular/menu.css) | CSS | 257 | 18 | 56 | 331 | +| [solr-8.3.1/server/solr-webapp/webapp/css/angular/overview.css](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/css/angular/overview.css) | CSS | 20 | 18 | 5 | 43 | +| [solr-8.3.1/server/solr-webapp/webapp/css/angular/plugins.css](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/css/angular/plugins.css) | CSS | 172 | 18 | 31 | 221 | +| [solr-8.3.1/server/solr-webapp/webapp/css/angular/query.css](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/css/angular/query.css) | CSS | 120 | 18 | 25 | 163 | +| [solr-8.3.1/server/solr-webapp/webapp/css/angular/replication.css](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/css/angular/replication.css) | CSS | 404 | 18 | 79 | 501 | +| [solr-8.3.1/server/solr-webapp/webapp/css/angular/schema.css](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/css/angular/schema.css) | CSS | 596 | 20 | 112 | 728 | +| [solr-8.3.1/server/solr-webapp/webapp/css/angular/segments.css](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/css/angular/segments.css) | CSS | 133 | 18 | 22 | 173 | +| [solr-8.3.1/server/solr-webapp/webapp/css/angular/stream.css](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/css/angular/stream.css) | CSS | 178 | 22 | 34 | 234 | +| [solr-8.3.1/server/solr-webapp/webapp/css/angular/suggestions.css](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/css/angular/suggestions.css) | CSS | 43 | 18 | 4 | 65 | +| [solr-8.3.1/server/solr-webapp/webapp/css/angular/threads.css](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/css/angular/threads.css) | CSS | 119 | 18 | 24 | 161 | +| [solr-8.3.1/server/solr-webapp/webapp/img/solr.svg](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/img/solr.svg) | XML | 39 | 0 | 1 | 40 | +| [solr-8.3.1/server/solr-webapp/webapp/index.html](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/index.html) | HTML | 203 | 16 | 38 | 257 | +| [solr-8.3.1/server/solr-webapp/webapp/js/angular/app.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/js/angular/app.js) | JavaScript | 512 | 19 | 31 | 562 | +| [solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/alias-overview.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/alias-overview.js) | JavaScript | 8 | 16 | 4 | 28 | +| [solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/analysis.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/analysis.js) | JavaScript | 161 | 18 | 23 | 202 | +| [solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/cloud.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/cloud.js) | JavaScript | 847 | 51 | 124 | 1,022 | +| [solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/cluster-suggestions.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/cluster-suggestions.js) | JavaScript | 43 | 18 | 2 | 63 | +| [solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/collection-overview.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/collection-overview.js) | JavaScript | 18 | 16 | 6 | 40 | +| [solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/collections.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/collections.js) | JavaScript | 244 | 19 | 27 | 290 | +| [solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/core-overview.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/core-overview.js) | JavaScript | 69 | 16 | 9 | 94 | +| [solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/cores.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/cores.js) | JavaScript | 151 | 16 | 14 | 181 | +| [solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/dataimport.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/dataimport.js) | JavaScript | 234 | 25 | 44 | 303 | +| [solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/documents.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/documents.js) | JavaScript | 107 | 18 | 13 | 138 | +| [solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/files.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/files.js) | JavaScript | 72 | 16 | 13 | 101 | +| [solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/index.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/index.js) | JavaScript | 61 | 23 | 14 | 98 | +| [solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/java-properties.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/java-properties.js) | JavaScript | 27 | 16 | 3 | 46 | +| [solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/logging.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/logging.js) | JavaScript | 112 | 35 | 12 | 159 | +| [solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/login.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/login.js) | JavaScript | 269 | 30 | 19 | 318 | +| [solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/plugins.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/plugins.js) | JavaScript | 130 | 19 | 19 | 168 | +| [solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/query.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/query.js) | JavaScript | 88 | 19 | 14 | 121 | +| [solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/replication.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/replication.js) | JavaScript | 178 | 18 | 40 | 236 | +| [solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/schema.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/schema.js) | JavaScript | 524 | 19 | 69 | 612 | +| [solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/segments.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/segments.js) | JavaScript | 64 | 16 | 20 | 100 | +| [solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/stream.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/stream.js) | JavaScript | 173 | 16 | 51 | 240 | +| [solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/threads.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/threads.js) | JavaScript | 33 | 16 | 2 | 51 | +| [solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/unknown.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/unknown.js) | JavaScript | 14 | 22 | 2 | 38 | +| [solr-8.3.1/server/solr-webapp/webapp/js/angular/services.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/js/angular/services.js) | JavaScript | 311 | 18 | 11 | 340 | +| [solr-8.3.1/server/solr-webapp/webapp/libs/angular-chosen.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/libs/angular-chosen.js) | JavaScript | 112 | 24 | 4 | 140 | +| [solr-8.3.1/server/solr-webapp/webapp/libs/angular-cookies.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/libs/angular-cookies.js) | JavaScript | 73 | 135 | 22 | 230 | +| [solr-8.3.1/server/solr-webapp/webapp/libs/angular-cookies.min.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/libs/angular-cookies.min.js) | JavaScript | 2 | 29 | 1 | 32 | +| [solr-8.3.1/server/solr-webapp/webapp/libs/angular-resource.min.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/libs/angular-resource.min.js) | JavaScript | 7 | 29 | 1 | 37 | +| [solr-8.3.1/server/solr-webapp/webapp/libs/angular-route.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/libs/angular-route.js) | JavaScript | 316 | 636 | 67 | 1,019 | +| [solr-8.3.1/server/solr-webapp/webapp/libs/angular-route.min.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/libs/angular-route.min.js) | JavaScript | 9 | 29 | 1 | 39 | +| [solr-8.3.1/server/solr-webapp/webapp/libs/angular-sanitize.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/libs/angular-sanitize.js) | JavaScript | 311 | 328 | 65 | 704 | +| [solr-8.3.1/server/solr-webapp/webapp/libs/angular-sanitize.min.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/libs/angular-sanitize.min.js) | JavaScript | 10 | 29 | 1 | 40 | +| [solr-8.3.1/server/solr-webapp/webapp/libs/angular-utf8-base64.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/libs/angular-utf8-base64.js) | JavaScript | 157 | 48 | 13 | 218 | +| [solr-8.3.1/server/solr-webapp/webapp/libs/angular-utf8-base64.min.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/libs/angular-utf8-base64.min.js) | JavaScript | 1 | 42 | 3 | 46 | +| [solr-8.3.1/server/solr-webapp/webapp/libs/angular.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/libs/angular.js) | JavaScript | 10,845 | 13,211 | 2,038 | 26,094 | +| [solr-8.3.1/server/solr-webapp/webapp/libs/angular.min.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/libs/angular.min.js) | JavaScript | 73 | 201 | 0 | 274 | +| [solr-8.3.1/server/solr-webapp/webapp/libs/chosen.jquery.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/libs/chosen.jquery.js) | JavaScript | 1,151 | 36 | 8 | 1,195 | +| [solr-8.3.1/server/solr-webapp/webapp/libs/chosen.jquery.min.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/libs/chosen.jquery.min.js) | JavaScript | 2 | 29 | 0 | 31 | +| [solr-8.3.1/server/solr-webapp/webapp/libs/d3.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/libs/d3.js) | JavaScript | 7,720 | 519 | 1,135 | 9,374 | +| [solr-8.3.1/server/solr-webapp/webapp/libs/highlight.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/libs/highlight.js) | JavaScript | 2 | 29 | 1 | 32 | +| [solr-8.3.1/server/solr-webapp/webapp/libs/jquery-1.7.2.min.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/libs/jquery-1.7.2.min.js) | JavaScript | 3 | 26 | 2 | 31 | +| [solr-8.3.1/server/solr-webapp/webapp/libs/jquery-2.1.3.min.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/libs/jquery-2.1.3.min.js) | JavaScript | 3 | 26 | 1 | 30 | +| [solr-8.3.1/server/solr-webapp/webapp/libs/jquery-ui.min.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/libs/jquery-ui.min.js) | JavaScript | 2 | 26 | 3 | 31 | +| [solr-8.3.1/server/solr-webapp/webapp/libs/jquery.jstree.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/libs/jquery.jstree.js) | JavaScript | 3,222 | 228 | 85 | 3,535 | +| [solr-8.3.1/server/solr-webapp/webapp/libs/ngtimeago.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/libs/ngtimeago.js) | JavaScript | 66 | 23 | 13 | 102 | +| [solr-8.3.1/server/solr-webapp/webapp/partials/alias_overview.html](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/partials/alias_overview.html) | HTML | 21 | 16 | 10 | 47 | +| [solr-8.3.1/server/solr-webapp/webapp/partials/analysis.html](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/partials/analysis.html) | HTML | 87 | 16 | 26 | 129 | +| [solr-8.3.1/server/solr-webapp/webapp/partials/cloud.html](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/partials/cloud.html) | HTML | 263 | 16 | 24 | 303 | +| [solr-8.3.1/server/solr-webapp/webapp/partials/cluster_suggestions.html](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/partials/cluster_suggestions.html) | HTML | 30 | 16 | 4 | 50 | +| [solr-8.3.1/server/solr-webapp/webapp/partials/collection_overview.html](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/partials/collection_overview.html) | HTML | 48 | 16 | 22 | 86 | +| [solr-8.3.1/server/solr-webapp/webapp/partials/collections.html](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/partials/collections.html) | HTML | 301 | 16 | 79 | 396 | +| [solr-8.3.1/server/solr-webapp/webapp/partials/core_overview.html](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/partials/core_overview.html) | HTML | 125 | 16 | 66 | 207 | +| [solr-8.3.1/server/solr-webapp/webapp/partials/cores.html](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/partials/cores.html) | HTML | 142 | 16 | 67 | 225 | +| [solr-8.3.1/server/solr-webapp/webapp/partials/dataimport.html](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/partials/dataimport.html) | HTML | 142 | 16 | 52 | 210 | +| [solr-8.3.1/server/solr-webapp/webapp/partials/documents.html](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/partials/documents.html) | HTML | 83 | 20 | 9 | 112 | +| [solr-8.3.1/server/solr-webapp/webapp/partials/files.html](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/partials/files.html) | HTML | 17 | 16 | 15 | 48 | +| [solr-8.3.1/server/solr-webapp/webapp/partials/index.html](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/partials/index.html) | HTML | 135 | 42 | 85 | 262 | +| [solr-8.3.1/server/solr-webapp/webapp/partials/java-properties.html](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/partials/java-properties.html) | HTML | 10 | 16 | 2 | 28 | +| [solr-8.3.1/server/solr-webapp/webapp/partials/logging-levels.html](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/partials/logging-levels.html) | HTML | 35 | 16 | 6 | 57 | +| [solr-8.3.1/server/solr-webapp/webapp/partials/logging.html](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/partials/logging.html) | HTML | 40 | 16 | 2 | 58 | +| [solr-8.3.1/server/solr-webapp/webapp/partials/login.html](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/partials/login.html) | HTML | 134 | 16 | 11 | 161 | +| [solr-8.3.1/server/solr-webapp/webapp/partials/plugins.html](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/partials/plugins.html) | HTML | 48 | 17 | 8 | 73 | +| [solr-8.3.1/server/solr-webapp/webapp/partials/query.html](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/partials/query.html) | HTML | 270 | 16 | 84 | 370 | +| [solr-8.3.1/server/solr-webapp/webapp/partials/replication.html](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/partials/replication.html) | HTML | 153 | 16 | 71 | 240 | +| [solr-8.3.1/server/solr-webapp/webapp/partials/schema.html](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/partials/schema.html) | HTML | 336 | 16 | 104 | 456 | +| [solr-8.3.1/server/solr-webapp/webapp/partials/segments.html](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/partials/segments.html) | HTML | 70 | 16 | 14 | 100 | +| [solr-8.3.1/server/solr-webapp/webapp/partials/stream.html](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/partials/stream.html) | HTML | 40 | 16 | 9 | 65 | +| [solr-8.3.1/server/solr-webapp/webapp/partials/threads.html](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/partials/threads.html) | HTML | 36 | 16 | 14 | 66 | +| [solr-8.3.1/server/solr-webapp/webapp/partials/unknown.html](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr-webapp/webapp/partials/unknown.html) | HTML | 5 | 16 | 3 | 24 | +| [solr-8.3.1/server/solr/configsets/_default/conf/params.json](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr/configsets/_default/conf/params.json) | JSON | 20 | 0 | 1 | 21 | +| [solr-8.3.1/server/solr/configsets/_default/conf/solrconfig.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr/configsets/_default/conf/solrconfig.xml) | XML | 296 | 976 | 98 | 1,370 | +| [solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/_rest_managed.json](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/_rest_managed.json) | JSON | 1 | 0 | 1 | 2 | +| [solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/_schema_analysis_stopwords_english.json](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/_schema_analysis_stopwords_english.json) | JSON | 38 | 0 | 1 | 39 | +| [solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/_schema_analysis_synonyms_english.json](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/_schema_analysis_synonyms_english.json) | JSON | 11 | 0 | 1 | 12 | +| [solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/clustering/carrot2/kmeans-attributes.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/clustering/carrot2/kmeans-attributes.xml) | XML | 13 | 6 | 1 | 20 | +| [solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/clustering/carrot2/lingo-attributes.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/clustering/carrot2/lingo-attributes.xml) | XML | 13 | 11 | 1 | 25 | +| [solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/clustering/carrot2/stc-attributes.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/clustering/carrot2/stc-attributes.xml) | XML | 13 | 6 | 1 | 20 | +| [solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/currency.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/currency.xml) | XML | 45 | 19 | 4 | 68 | +| [solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/elevate.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/elevate.xml) | XML | 3 | 37 | 3 | 43 | +| [solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/params.json](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/params.json) | JSON | 11 | 0 | 1 | 12 | +| [solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/solrconfig.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/solrconfig.xml) | XML | 410 | 1,097 | 124 | 1,631 | +| [solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/update-script.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/update-script.js) | JavaScript | 15 | 26 | 13 | 54 | +| [solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/velocity/jquery.autocomplete.css](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/velocity/jquery.autocomplete.css) | CSS | 34 | 9 | 6 | 49 | +| [solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/velocity/jquery.autocomplete.js](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/velocity/jquery.autocomplete.js) | JavaScript | 620 | 68 | 76 | 764 | +| [solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/velocity/main.css](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/velocity/main.css) | CSS | 185 | 0 | 47 | 232 | +| [solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/xslt/example.xsl](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/xslt/example.xsl) | XSL | 98 | 20 | 15 | 133 | +| [solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/xslt/example_atom.xsl](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/xslt/example_atom.xsl) | XSL | 40 | 20 | 8 | 68 | +| [solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/xslt/example_rss.xsl](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/xslt/example_rss.xsl) | XSL | 41 | 20 | 6 | 67 | +| [solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/xslt/luke.xsl](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/xslt/luke.xsl) | XSL | 301 | 19 | 18 | 338 | +| [solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/xslt/updateXml.xsl](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/xslt/updateXml.xsl) | XSL | 35 | 25 | 11 | 71 | +| [solr-8.3.1/server/solr/dash/conf/params.json](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr/dash/conf/params.json) | JSON | 20 | 0 | 0 | 20 | +| [solr-8.3.1/server/solr/dash/conf/schema.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr/dash/conf/schema.xml) | XML | 51 | 4 | 7 | 62 | +| [solr-8.3.1/server/solr/dash/conf/solrconfig.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr/dash/conf/solrconfig.xml) | XML | 270 | 962 | 97 | 1,329 | +| [solr-8.3.1/server/solr/dash/core.properties](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr/dash/core.properties) | Properties | 4 | 2 | 1 | 7 | +| [solr-8.3.1/server/solr/solr.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr/solr.xml) | XML | 21 | 25 | 11 | 57 | +| [solr-8.3.1/server/solr/zoo.cfg](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/solr/zoo.cfg) | Properties | 3 | 25 | 4 | 32 | +| [solr-8.3.1/server/tmp/start_3204295554151338130.properties](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/tmp/start_3204295554151338130.properties) | Properties | 9 | 2 | 1 | 12 | +| [solr-8.3.1/server/tmp/start_5812170489311981381.properties](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/tmp/start_5812170489311981381.properties) | Properties | 9 | 2 | 1 | 12 | +| [solr-8.3.1/server/tmp/start_6476327636763392575.properties](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/tmp/start_6476327636763392575.properties) | Properties | 9 | 2 | 1 | 12 | +| [solr-8.3.1/server/tmp/start_7329004517204835686.properties](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/tmp/start_7329004517204835686.properties) | Properties | 9 | 2 | 1 | 12 | +| [solr-8.3.1/server/tmp/start_9067375725008958788.properties](file:///Users/bcz/Documents/GitHub/Dash-Web/solr-8.3.1/server/tmp/start_9067375725008958788.properties) | Properties | 9 | 2 | 1 | 12 | +| [src/Utils.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/Utils.ts) | TypeScript | 441 | 23 | 81 | 545 | +| [src/client/ClientRecommender.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/ClientRecommender.scss) | SCSS | 9 | 1 | 2 | 12 | +| [src/client/ClientRecommender.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/ClientRecommender.tsx) | TypeScript React | 320 | 61 | 44 | 425 | +| [src/client/DocServer.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/DocServer.ts) | TypeScript | 279 | 136 | 65 | 480 | +| [src/client/Network.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/Network.ts) | TypeScript | 34 | 0 | 5 | 39 | +| [src/client/apis/GoogleAuthenticationManager.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/apis/GoogleAuthenticationManager.scss) | SCSS | 16 | 0 | 3 | 19 | +| [src/client/apis/GoogleAuthenticationManager.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/apis/GoogleAuthenticationManager.tsx) | TypeScript React | 115 | 2 | 11 | 128 | +| [src/client/apis/IBM_Recommender.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/apis/IBM_Recommender.ts) | TypeScript | 0 | 33 | 7 | 40 | +| [src/client/apis/google_docs/GoogleApiClientUtils.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/apis/google_docs/GoogleApiClientUtils.ts) | TypeScript | 225 | 9 | 27 | 261 | +| [src/client/apis/google_docs/GooglePhotosClientUtils.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/apis/google_docs/GooglePhotosClientUtils.ts) | TypeScript | 318 | 0 | 46 | 364 | +| [src/client/apis/youtube/YoutubeBox.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/apis/youtube/YoutubeBox.scss) | SCSS | 105 | 5 | 16 | 126 | +| [src/client/apis/youtube/YoutubeBox.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/apis/youtube/YoutubeBox.tsx) | TypeScript React | 274 | 48 | 40 | 362 | +| [src/client/cognitive_services/CognitiveServices.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/cognitive_services/CognitiveServices.ts) | TypeScript | 342 | 10 | 57 | 409 | +| [src/client/documents/DocumentTypes.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/documents/DocumentTypes.ts) | TypeScript | 32 | 2 | 3 | 37 | +| [src/client/documents/Documents.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/documents/Documents.ts) | TypeScript | 807 | 141 | 87 | 1,035 | +| [src/client/goldenLayout.d.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/goldenLayout.d.ts) | TypeScript | 2 | 0 | 1 | 3 | +| [src/client/goldenLayout.js](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/goldenLayout.js) | JavaScript | 3,084 | 1,571 | 720 | 5,375 | +| [src/client/util/DictationManager.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/util/DictationManager.ts) | TypeScript | 312 | 25 | 51 | 388 | +| [src/client/util/DocumentManager.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/util/DocumentManager.ts) | TypeScript | 207 | 16 | 21 | 244 | +| [src/client/util/DragManager.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/util/DragManager.ts) | TypeScript | 504 | 11 | 35 | 550 | +| [src/client/util/DropConverter.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/util/DropConverter.ts) | TypeScript | 70 | 6 | 2 | 78 | +| [src/client/util/History.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/util/History.ts) | TypeScript | 166 | 13 | 27 | 206 | +| [src/client/util/Import & Export/DirectoryImportBox.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/util/Import%20%26%20Export/DirectoryImportBox.scss) | SCSS | 6 | 0 | 0 | 6 | +| [src/client/util/Import & Export/DirectoryImportBox.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/util/Import%20%26%20Export/DirectoryImportBox.tsx) | TypeScript React | 393 | 0 | 31 | 424 | +| [src/client/util/Import & Export/ImageUtils.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/util/Import%20%26%20Export/ImageUtils.ts) | TypeScript | 35 | 0 | 4 | 39 | +| [src/client/util/Import & Export/ImportMetadataEntry.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/util/Import%20%26%20Export/ImportMetadataEntry.tsx) | TypeScript React | 132 | 0 | 17 | 149 | +| [src/client/util/InteractionUtils.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/util/InteractionUtils.tsx) | TypeScript React | 122 | 112 | 21 | 255 | +| [src/client/util/KeyCodes.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/util/KeyCodes.ts) | TypeScript | 100 | 36 | 0 | 136 | +| [src/client/util/LinkManager.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/util/LinkManager.ts) | TypeScript | 161 | 30 | 23 | 214 | +| [src/client/util/ProsemirrorCopy/prompt.js](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/util/ProsemirrorCopy/prompt.js) | JavaScript | 128 | 30 | 22 | 180 | +| [src/client/util/Scripting.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/util/Scripting.ts) | TypeScript | 247 | 15 | 30 | 292 | +| [src/client/util/ScrollBox.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/util/ScrollBox.tsx) | TypeScript React | 19 | 0 | 2 | 21 | +| [src/client/util/SearchUtil.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/util/SearchUtil.ts) | TypeScript | 123 | 4 | 18 | 145 | +| [src/client/util/SelectionManager.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/util/SelectionManager.ts) | TypeScript | 69 | 5 | 15 | 89 | +| [src/client/util/SerializationHelper.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/util/SerializationHelper.ts) | TypeScript | 113 | 15 | 15 | 143 | +| [src/client/util/SettingsManager.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/util/SettingsManager.scss) | SCSS | 111 | 0 | 25 | 136 | +| [src/client/util/SettingsManager.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/util/SettingsManager.tsx) | TypeScript React | 114 | 0 | 17 | 131 | +| [src/client/util/SharingManager.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/util/SharingManager.scss) | SCSS | 122 | 0 | 18 | 140 | +| [src/client/util/SharingManager.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/util/SharingManager.tsx) | TypeScript React | 273 | 0 | 25 | 298 | +| [src/client/util/Transform.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/util/Transform.ts) | TypeScript | 76 | 0 | 23 | 99 | +| [src/client/util/TypedEvent.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/util/TypedEvent.ts) | TypeScript | 29 | 3 | 8 | 40 | +| [src/client/util/UndoManager.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/util/UndoManager.ts) | TypeScript | 167 | 1 | 27 | 195 | +| [src/client/util/clamp.js](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/util/clamp.js) | JavaScript | 14 | 0 | 1 | 15 | +| [src/client/util/convertToCSSPTValue.js](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/util/convertToCSSPTValue.js) | JavaScript | 31 | 4 | 8 | 43 | +| [src/client/util/jsx-decl.d.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/util/jsx-decl.d.ts) | TypeScript | 1 | 0 | 1 | 2 | +| [src/client/util/request-image-size.js](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/util/request-image-size.js) | JavaScript | 51 | 10 | 14 | 75 | +| [src/client/util/toCSSLineSpacing.js](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/util/toCSSLineSpacing.js) | JavaScript | 35 | 15 | 14 | 64 | +| [src/client/views/AntimodeMenu.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/AntimodeMenu.scss) | SCSS | 35 | 1 | 6 | 42 | +| [src/client/views/AntimodeMenu.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/AntimodeMenu.tsx) | TypeScript React | 121 | 14 | 22 | 157 | +| [src/client/views/ContextMenu.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/ContextMenu.scss) | SCSS | 130 | 17 | 14 | 161 | +| [src/client/views/ContextMenu.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/ContextMenu.tsx) | TypeScript React | 258 | 3 | 33 | 294 | +| [src/client/views/ContextMenuItem.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/ContextMenuItem.tsx) | TypeScript React | 107 | 0 | 10 | 117 | +| [src/client/views/DictationOverlay.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/DictationOverlay.tsx) | TypeScript React | 64 | 0 | 7 | 71 | +| [src/client/views/DocComponent.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/DocComponent.tsx) | TypeScript React | 87 | 20 | 15 | 122 | +| [src/client/views/DocumentButtonBar.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/DocumentButtonBar.scss) | SCSS | 89 | 0 | 16 | 105 | +| [src/client/views/DocumentButtonBar.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/DocumentButtonBar.tsx) | TypeScript React | 284 | 4 | 27 | 315 | +| [src/client/views/DocumentDecorations.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/DocumentDecorations.scss) | SCSS | 319 | 0 | 46 | 365 | +| [src/client/views/DocumentDecorations.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/DocumentDecorations.tsx) | TypeScript React | 479 | 2 | 26 | 507 | +| [src/client/views/EditableView.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/EditableView.scss) | SCSS | 22 | 0 | 3 | 25 | +| [src/client/views/EditableView.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/EditableView.tsx) | TypeScript React | 149 | 19 | 16 | 184 | +| [src/client/views/GestureOverlay.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/GestureOverlay.scss) | SCSS | 56 | 0 | 8 | 64 | +| [src/client/views/GestureOverlay.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/GestureOverlay.tsx) | TypeScript React | 711 | 45 | 67 | 823 | +| [src/client/views/GlobalKeyHandler.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/GlobalKeyHandler.ts) | TypeScript | 232 | 10 | 27 | 269 | +| [src/client/views/InkingControl.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/InkingControl.scss) | SCSS | 127 | 4 | 0 | 131 | +| [src/client/views/InkingControl.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/InkingControl.tsx) | TypeScript React | 78 | 3 | 10 | 91 | +| [src/client/views/InkingStroke.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/InkingStroke.scss) | SCSS | 7 | 0 | 0 | 7 | +| [src/client/views/InkingStroke.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/InkingStroke.tsx) | TypeScript React | 63 | 0 | 5 | 68 | +| [src/client/views/KeyphraseQueryView.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/KeyphraseQueryView.scss) | SCSS | 7 | 0 | 1 | 8 | +| [src/client/views/KeyphraseQueryView.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/KeyphraseQueryView.tsx) | TypeScript React | 30 | 2 | 3 | 35 | +| [src/client/views/Main.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/Main.scss) | SCSS | 51 | 8 | 10 | 69 | +| [src/client/views/Main.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/Main.tsx) | TypeScript React | 22 | 1 | 2 | 25 | +| [src/client/views/MainView.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/MainView.scss) | SCSS | 138 | 1 | 21 | 160 | +| [src/client/views/MainView.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/MainView.tsx) | TypeScript React | 553 | 13 | 36 | 602 | +| [src/client/views/MainViewModal.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/MainViewModal.scss) | SCSS | 24 | 0 | 1 | 25 | +| [src/client/views/MainViewModal.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/MainViewModal.tsx) | TypeScript React | 39 | 0 | 5 | 44 | +| [src/client/views/MainViewNotifs.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/MainViewNotifs.scss) | SCSS | 17 | 0 | 1 | 18 | +| [src/client/views/MainViewNotifs.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/MainViewNotifs.tsx) | TypeScript React | 29 | 0 | 4 | 33 | +| [src/client/views/MetadataEntryMenu.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/MetadataEntryMenu.scss) | SCSS | 79 | 0 | 14 | 93 | +| [src/client/views/MetadataEntryMenu.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/MetadataEntryMenu.tsx) | TypeScript React | 207 | 0 | 16 | 223 | +| [src/client/views/OCRUtils.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/OCRUtils.ts) | TypeScript | 2 | 2 | 4 | 8 | +| [src/client/views/OverlayView.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/OverlayView.scss) | SCSS | 41 | 0 | 6 | 47 | +| [src/client/views/OverlayView.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/OverlayView.tsx) | TypeScript React | 194 | 4 | 19 | 217 | +| [src/client/views/Palette.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/Palette.scss) | SCSS | 26 | 0 | 4 | 30 | +| [src/client/views/Palette.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/Palette.tsx) | TypeScript React | 65 | 0 | 5 | 70 | +| [src/client/views/PreviewCursor.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/PreviewCursor.scss) | SCSS | 9 | 0 | 1 | 10 | +| [src/client/views/PreviewCursor.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/PreviewCursor.tsx) | TypeScript React | 115 | 8 | 9 | 132 | +| [src/client/views/RecommendationsBox.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/RecommendationsBox.scss) | SCSS | 52 | 10 | 8 | 70 | +| [src/client/views/RecommendationsBox.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/RecommendationsBox.tsx) | TypeScript React | 116 | 67 | 17 | 200 | +| [src/client/views/ScriptBox.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/ScriptBox.scss) | SCSS | 15 | 0 | 2 | 17 | +| [src/client/views/ScriptBox.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/ScriptBox.tsx) | TypeScript React | 112 | 2 | 12 | 126 | +| [src/client/views/ScriptingRepl.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/ScriptingRepl.scss) | SCSS | 42 | 0 | 9 | 51 | +| [src/client/views/ScriptingRepl.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/ScriptingRepl.tsx) | TypeScript React | 220 | 1 | 24 | 245 | +| [src/client/views/SearchDocBox.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/SearchDocBox.tsx) | TypeScript React | 359 | 17 | 55 | 431 | +| [src/client/views/TemplateMenu.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/TemplateMenu.scss) | SCSS | 46 | 0 | 5 | 51 | +| [src/client/views/TemplateMenu.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/TemplateMenu.tsx) | TypeScript React | 167 | 1 | 14 | 182 | +| [src/client/views/Templates.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/Templates.tsx) | TypeScript React | 34 | 0 | 8 | 42 | +| [src/client/views/TouchScrollableMenu.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/TouchScrollableMenu.tsx) | TypeScript React | 52 | 0 | 7 | 59 | +| [src/client/views/Touchable.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/Touchable.tsx) | TypeScript React | 172 | 28 | 39 | 239 | +| [src/client/views/_nodeModuleOverrides.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/_nodeModuleOverrides.scss) | SCSS | 9 | 9 | 4 | 22 | +| [src/client/views/animationtimeline/Keyframe.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/animationtimeline/Keyframe.scss) | SCSS | 83 | 5 | 17 | 105 | +| [src/client/views/animationtimeline/Keyframe.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/animationtimeline/Keyframe.tsx) | TypeScript React | 468 | 50 | 42 | 560 | +| [src/client/views/animationtimeline/Timeline.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/animationtimeline/Timeline.scss) | SCSS | 264 | 14 | 44 | 322 | +| [src/client/views/animationtimeline/Timeline.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/animationtimeline/Timeline.tsx) | TypeScript React | 467 | 97 | 58 | 622 | +| [src/client/views/animationtimeline/TimelineMenu.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/animationtimeline/TimelineMenu.scss) | SCSS | 75 | 2 | 17 | 94 | +| [src/client/views/animationtimeline/TimelineMenu.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/animationtimeline/TimelineMenu.tsx) | TypeScript React | 68 | 0 | 10 | 78 | +| [src/client/views/animationtimeline/TimelineOverview.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/animationtimeline/TimelineOverview.scss) | SCSS | 89 | 6 | 12 | 107 | +| [src/client/views/animationtimeline/TimelineOverview.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/animationtimeline/TimelineOverview.tsx) | TypeScript React | 155 | 0 | 27 | 182 | +| [src/client/views/animationtimeline/Track.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/animationtimeline/Track.scss) | SCSS | 13 | 0 | 2 | 15 | +| [src/client/views/animationtimeline/Track.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/animationtimeline/Track.tsx) | TypeScript React | 284 | 63 | 33 | 380 | +| [src/client/views/collections/CollectionCarouselView.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/CollectionCarouselView.scss) | SCSS | 37 | 0 | 1 | 38 | +| [src/client/views/collections/CollectionCarouselView.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/CollectionCarouselView.tsx) | TypeScript React | 110 | 1 | 10 | 121 | +| [src/client/views/collections/CollectionDockingView.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/CollectionDockingView.scss) | SCSS | 391 | 7 | 60 | 458 | +| [src/client/views/collections/CollectionDockingView.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/CollectionDockingView.tsx) | TypeScript React | 707 | 61 | 65 | 833 | +| [src/client/views/collections/CollectionLinearView.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/CollectionLinearView.scss) | SCSS | 68 | 0 | 10 | 78 | +| [src/client/views/collections/CollectionLinearView.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/CollectionLinearView.tsx) | TypeScript React | 125 | 1 | 9 | 135 | +| [src/client/views/collections/CollectionMapView.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/CollectionMapView.scss) | SCSS | 27 | 0 | 3 | 30 | +| [src/client/views/collections/CollectionMapView.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/CollectionMapView.tsx) | TypeScript React | 235 | 10 | 18 | 263 | +| [src/client/views/collections/CollectionMasonryViewFieldRow.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/CollectionMasonryViewFieldRow.tsx) | TypeScript React | 308 | 0 | 24 | 332 | +| [src/client/views/collections/CollectionPileView.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/CollectionPileView.scss) | SCSS | 8 | 0 | 1 | 9 | +| [src/client/views/collections/CollectionPileView.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/CollectionPileView.tsx) | TypeScript React | 112 | 5 | 11 | 128 | +| [src/client/views/collections/CollectionSchemaCells.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/CollectionSchemaCells.tsx) | TypeScript React | 274 | 17 | 38 | 329 | +| [src/client/views/collections/CollectionSchemaHeaders.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/CollectionSchemaHeaders.tsx) | TypeScript React | 318 | 5 | 41 | 364 | +| [src/client/views/collections/CollectionSchemaMovableTableHOC.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx) | TypeScript React | 216 | 0 | 27 | 243 | +| [src/client/views/collections/CollectionSchemaView.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/CollectionSchemaView.scss) | SCSS | 406 | 4 | 88 | 498 | +| [src/client/views/collections/CollectionSchemaView.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/CollectionSchemaView.tsx) | TypeScript React | 651 | 20 | 82 | 753 | +| [src/client/views/collections/CollectionStackingView.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/CollectionStackingView.scss) | SCSS | 353 | 1 | 50 | 404 | +| [src/client/views/collections/CollectionStackingView.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/CollectionStackingView.tsx) | TypeScript React | 430 | 5 | 25 | 460 | +| [src/client/views/collections/CollectionStackingViewFieldColumn.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/CollectionStackingViewFieldColumn.tsx) | TypeScript React | 367 | 0 | 27 | 394 | +| [src/client/views/collections/CollectionStaffView.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/CollectionStaffView.scss) | SCSS | 12 | 0 | 1 | 13 | +| [src/client/views/collections/CollectionStaffView.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/CollectionStaffView.tsx) | TypeScript React | 46 | 0 | 7 | 53 | +| [src/client/views/collections/CollectionSubView.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/CollectionSubView.tsx) | TypeScript React | 390 | 7 | 25 | 422 | +| [src/client/views/collections/CollectionTimeView.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/CollectionTimeView.scss) | SCSS | 80 | 0 | 13 | 93 | +| [src/client/views/collections/CollectionTimeView.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/CollectionTimeView.tsx) | TypeScript React | 177 | 0 | 15 | 192 | +| [src/client/views/collections/CollectionTreeView.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/CollectionTreeView.scss) | SCSS | 125 | 4 | 23 | 152 | +| [src/client/views/collections/CollectionTreeView.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/CollectionTreeView.tsx) | TypeScript React | 801 | 19 | 40 | 860 | +| [src/client/views/collections/CollectionView.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/CollectionView.scss) | SCSS | 70 | 0 | 8 | 78 | +| [src/client/views/collections/CollectionView.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/CollectionView.tsx) | TypeScript React | 457 | 13 | 34 | 504 | +| [src/client/views/collections/CollectionViewChromes.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/CollectionViewChromes.scss) | SCSS | 308 | 4 | 45 | 357 | +| [src/client/views/collections/CollectionViewChromes.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/CollectionViewChromes.tsx) | TypeScript React | 393 | 67 | 47 | 507 | +| [src/client/views/collections/KeyRestrictionRow.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/KeyRestrictionRow.tsx) | TypeScript React | 49 | 2 | 4 | 55 | +| [src/client/views/collections/ParentDocumentSelector.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/ParentDocumentSelector.scss) | SCSS | 54 | 0 | 2 | 56 | +| [src/client/views/collections/ParentDocumentSelector.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/ParentDocumentSelector.tsx) | TypeScript React | 120 | 0 | 11 | 131 | +| [src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx) | TypeScript React | 422 | 10 | 27 | 459 | +| [src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss) | SCSS | 19 | 0 | 1 | 20 | +| [src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx) | TypeScript React | 110 | 5 | 4 | 119 | +| [src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.scss) | SCSS | 11 | 0 | 0 | 11 | +| [src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx) | TypeScript React | 44 | 0 | 2 | 46 | +| [src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.scss) | SCSS | 20 | 1 | 3 | 24 | +| [src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx) | TypeScript React | 67 | 0 | 12 | 79 | +| [src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss) | SCSS | 95 | 9 | 17 | 121 | +| [src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx) | TypeScript React | 1,186 | 47 | 97 | 1,330 | +| [src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx) | TypeScript React | 52 | 0 | 5 | 57 | +| [src/client/views/collections/collectionFreeForm/MarqueeView.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/collectionFreeForm/MarqueeView.scss) | SCSS | 30 | 0 | 2 | 32 | +| [src/client/views/collections/collectionFreeForm/MarqueeView.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/collectionFreeForm/MarqueeView.tsx) | TypeScript React | 484 | 105 | 33 | 622 | +| [src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss) | SCSS | 28 | 0 | 6 | 34 | +| [src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx) | TypeScript React | 202 | 72 | 23 | 297 | +| [src/client/views/collections/collectionMulticolumn/CollectionMultirowView.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.scss) | SCSS | 29 | 0 | 6 | 35 | +| [src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx) | TypeScript React | 204 | 72 | 22 | 298 | +| [src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx) | TypeScript React | 94 | 0 | 9 | 103 | +| [src/client/views/collections/collectionMulticolumn/MulticolumnWidthLabel.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/collectionMulticolumn/MulticolumnWidthLabel.tsx) | TypeScript React | 51 | 0 | 5 | 56 | +| [src/client/views/collections/collectionMulticolumn/MultirowHeightLabel.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/collectionMulticolumn/MultirowHeightLabel.tsx) | TypeScript React | 51 | 0 | 5 | 56 | +| [src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx) | TypeScript React | 92 | 0 | 9 | 101 | +| [src/client/views/globalCssVariables.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/globalCssVariables.scss) | SCSS | 30 | 10 | 3 | 43 | +| [src/client/views/globalCssVariables.scss.d.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/globalCssVariables.scss.d.ts) | TypeScript | 9 | 0 | 2 | 11 | +| [src/client/views/linking/LinkEditor.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/linking/LinkEditor.scss) | SCSS | 124 | 1 | 25 | 150 | +| [src/client/views/linking/LinkEditor.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/linking/LinkEditor.tsx) | TypeScript React | 252 | 7 | 50 | 309 | +| [src/client/views/linking/LinkMenu.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/linking/LinkMenu.scss) | SCSS | 40 | 0 | 13 | 53 | +| [src/client/views/linking/LinkMenu.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/linking/LinkMenu.tsx) | TypeScript React | 65 | 1 | 10 | 76 | +| [src/client/views/linking/LinkMenuGroup.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/linking/LinkMenuGroup.tsx) | TypeScript React | 84 | 0 | 10 | 94 | +| [src/client/views/linking/LinkMenuItem.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/linking/LinkMenuItem.scss) | SCSS | 75 | 1 | 11 | 87 | +| [src/client/views/linking/LinkMenuItem.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/linking/LinkMenuItem.tsx) | TypeScript React | 107 | 0 | 19 | 126 | +| [src/client/views/nodes/AudioBox.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/AudioBox.scss) | SCSS | 146 | 0 | 0 | 146 | +| [src/client/views/nodes/AudioBox.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/AudioBox.tsx) | TypeScript React | 261 | 2 | 24 | 287 | +| [src/client/views/nodes/CollectionFreeFormDocumentView.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/CollectionFreeFormDocumentView.scss) | SCSS | 8 | 0 | 0 | 8 | +| [src/client/views/nodes/CollectionFreeFormDocumentView.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/CollectionFreeFormDocumentView.tsx) | TypeScript React | 124 | 0 | 7 | 131 | +| [src/client/views/nodes/ColorBox.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/ColorBox.scss) | SCSS | 22 | 0 | 1 | 23 | +| [src/client/views/nodes/ColorBox.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/ColorBox.tsx) | TypeScript React | 28 | 0 | 4 | 32 | +| [src/client/views/nodes/ContentFittingDocumentView.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/ContentFittingDocumentView.scss) | SCSS | 20 | 0 | 4 | 24 | +| [src/client/views/nodes/ContentFittingDocumentView.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/ContentFittingDocumentView.tsx) | TypeScript React | 117 | 0 | 7 | 124 | +| [src/client/views/nodes/DocumentBox.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/DocumentBox.scss) | SCSS | 14 | 0 | 0 | 14 | +| [src/client/views/nodes/DocumentBox.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/DocumentBox.tsx) | TypeScript React | 154 | 0 | 4 | 158 | +| [src/client/views/nodes/DocumentContentsView.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/DocumentContentsView.tsx) | TypeScript React | 183 | 10 | 17 | 210 | +| [src/client/views/nodes/DocumentIcon.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/DocumentIcon.tsx) | TypeScript React | 60 | 0 | 5 | 65 | +| [src/client/views/nodes/DocumentView.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/DocumentView.scss) | SCSS | 110 | 1 | 15 | 126 | +| [src/client/views/nodes/DocumentView.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/DocumentView.tsx) | TypeScript React | 1,041 | 54 | 94 | 1,189 | +| [src/client/views/nodes/FaceRectangle.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/FaceRectangle.tsx) | TypeScript React | 25 | 0 | 4 | 29 | +| [src/client/views/nodes/FaceRectangles.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/FaceRectangles.tsx) | TypeScript React | 41 | 0 | 5 | 46 | +| [src/client/views/nodes/FieldTextBox.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/FieldTextBox.scss) | SCSS | 12 | 0 | 3 | 15 | +| [src/client/views/nodes/FieldView.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/FieldView.tsx) | TypeScript React | 89 | 43 | 4 | 136 | +| [src/client/views/nodes/FontIconBox.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/FontIconBox.scss) | SCSS | 25 | 0 | 2 | 27 | +| [src/client/views/nodes/FontIconBox.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/FontIconBox.tsx) | TypeScript React | 58 | 0 | 5 | 63 | +| [src/client/views/nodes/ImageBox.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/ImageBox.scss) | SCSS | 135 | 0 | 17 | 152 | +| [src/client/views/nodes/ImageBox.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/ImageBox.tsx) | TypeScript React | 430 | 10 | 35 | 475 | +| [src/client/views/nodes/KeyValueBox.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/KeyValueBox.scss) | SCSS | 120 | 0 | 3 | 123 | +| [src/client/views/nodes/KeyValueBox.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/KeyValueBox.tsx) | TypeScript React | 244 | 1 | 26 | 271 | +| [src/client/views/nodes/KeyValuePair.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/KeyValuePair.scss) | SCSS | 55 | 1 | 4 | 60 | +| [src/client/views/nodes/KeyValuePair.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/KeyValuePair.tsx) | TypeScript React | 125 | 2 | 8 | 135 | +| [src/client/views/nodes/LabelBox.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/LabelBox.scss) | SCSS | 31 | 0 | 4 | 35 | +| [src/client/views/nodes/LabelBox.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/LabelBox.tsx) | TypeScript React | 86 | 1 | 9 | 96 | +| [src/client/views/nodes/LinkAnchorBox.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/LinkAnchorBox.scss) | SCSS | 27 | 0 | 2 | 29 | +| [src/client/views/nodes/LinkAnchorBox.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/LinkAnchorBox.tsx) | TypeScript React | 141 | 0 | 9 | 150 | +| [src/client/views/nodes/LinkBox.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/LinkBox.scss) | SCSS | 3 | 0 | 0 | 3 | +| [src/client/views/nodes/LinkBox.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/LinkBox.tsx) | TypeScript React | 33 | 0 | 3 | 36 | +| [src/client/views/nodes/PDFBox.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/PDFBox.scss) | SCSS | 200 | 0 | 19 | 219 | +| [src/client/views/nodes/PDFBox.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/PDFBox.tsx) | TypeScript React | 246 | 0 | 19 | 265 | +| [src/client/views/nodes/PresBox.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/PresBox.scss) | SCSS | 52 | 0 | 1 | 53 | +| [src/client/views/nodes/PresBox.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/PresBox.tsx) | TypeScript React | 268 | 31 | 32 | 331 | +| [src/client/views/nodes/QueryBox.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/QueryBox.scss) | SCSS | 5 | 0 | 0 | 5 | +| [src/client/views/nodes/QueryBox.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/QueryBox.tsx) | TypeScript React | 37 | 0 | 4 | 41 | +| [src/client/views/nodes/RadialMenu.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/RadialMenu.scss) | SCSS | 60 | 3 | 7 | 70 | +| [src/client/views/nodes/RadialMenu.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/RadialMenu.tsx) | TypeScript React | 174 | 26 | 36 | 236 | +| [src/client/views/nodes/RadialMenuItem.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/RadialMenuItem.tsx) | TypeScript React | 101 | 0 | 16 | 117 | +| [src/client/views/nodes/ScreenshotBox.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/ScreenshotBox.scss) | SCSS | 40 | 6 | 5 | 51 | +| [src/client/views/nodes/ScreenshotBox.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/ScreenshotBox.tsx) | TypeScript React | 174 | 2 | 18 | 194 | +| [src/client/views/nodes/ScriptingBox.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/ScriptingBox.scss) | SCSS | 33 | 0 | 3 | 36 | +| [src/client/views/nodes/ScriptingBox.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/ScriptingBox.tsx) | TypeScript React | 87 | 0 | 12 | 99 | +| [src/client/views/nodes/SliderBox-components.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/SliderBox-components.tsx) | TypeScript React | 220 | 12 | 25 | 257 | +| [src/client/views/nodes/SliderBox-tooltip.css](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/SliderBox-tooltip.css) | CSS | 30 | 0 | 3 | 33 | +| [src/client/views/nodes/SliderBox.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/SliderBox.scss) | SCSS | 7 | 0 | 0 | 7 | +| [src/client/views/nodes/SliderBox.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/SliderBox.tsx) | TypeScript React | 117 | 0 | 8 | 125 | +| [src/client/views/nodes/VideoBox.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/VideoBox.scss) | SCSS | 65 | 3 | 6 | 74 | +| [src/client/views/nodes/VideoBox.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/VideoBox.tsx) | TypeScript React | 343 | 2 | 34 | 379 | +| [src/client/views/nodes/WebBox.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/WebBox.scss) | SCSS | 109 | 0 | 18 | 127 | +| [src/client/views/nodes/WebBox.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/WebBox.tsx) | TypeScript React | 345 | 15 | 35 | 395 | +| [src/client/views/nodes/formattedText/DashDocCommentView.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/formattedText/DashDocCommentView.tsx) | TypeScript React | 82 | 0 | 13 | 95 | +| [src/client/views/nodes/formattedText/DashDocView.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/formattedText/DashDocView.tsx) | TypeScript React | 223 | 9 | 37 | 269 | +| [src/client/views/nodes/formattedText/DashFieldView.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/formattedText/DashFieldView.scss) | SCSS | 34 | 0 | 2 | 36 | +| [src/client/views/nodes/formattedText/DashFieldView.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/formattedText/DashFieldView.tsx) | TypeScript React | 178 | 13 | 20 | 211 | +| [src/client/views/nodes/formattedText/FootnoteView.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/formattedText/FootnoteView.tsx) | TypeScript React | 131 | 13 | 19 | 163 | +| [src/client/views/nodes/formattedText/FormattedTextBox.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/formattedText/FormattedTextBox.scss) | SCSS | 220 | 11 | 34 | 265 | +| [src/client/views/nodes/formattedText/FormattedTextBox.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/formattedText/FormattedTextBox.tsx) | TypeScript React | 1,169 | 68 | 93 | 1,330 | +| [src/client/views/nodes/formattedText/FormattedTextBoxComment.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/formattedText/FormattedTextBoxComment.scss) | SCSS | 33 | 0 | 0 | 33 | +| [src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx) | TypeScript React | 218 | 11 | 8 | 237 | +| [src/client/views/nodes/formattedText/ImageResizeView.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/formattedText/ImageResizeView.tsx) | TypeScript React | 113 | 0 | 25 | 138 | +| [src/client/views/nodes/formattedText/ParagraphNodeSpec.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/formattedText/ParagraphNodeSpec.ts) | TypeScript | 108 | 9 | 26 | 143 | +| [src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts) | TypeScript | 231 | 0 | 11 | 242 | +| [src/client/views/nodes/formattedText/RichTextMenu.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/formattedText/RichTextMenu.scss) | SCSS | 100 | 2 | 19 | 121 | +| [src/client/views/nodes/formattedText/RichTextMenu.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/formattedText/RichTextMenu.tsx) | TypeScript React | 754 | 12 | 109 | 875 | +| [src/client/views/nodes/formattedText/RichTextRules.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/formattedText/RichTextRules.ts) | TypeScript | 308 | 7 | 5 | 320 | +| [src/client/views/nodes/formattedText/RichTextSchema.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/formattedText/RichTextSchema.tsx) | TypeScript React | 465 | 33 | 39 | 537 | +| [src/client/views/nodes/formattedText/SummaryView.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/formattedText/SummaryView.tsx) | TypeScript React | 67 | 0 | 14 | 81 | +| [src/client/views/nodes/formattedText/TooltipTextMenu.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/formattedText/TooltipTextMenu.scss) | SCSS | 306 | 6 | 61 | 373 | +| [src/client/views/nodes/formattedText/marks_rts.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/formattedText/marks_rts.ts) | TypeScript | 259 | 15 | 23 | 297 | +| [src/client/views/nodes/formattedText/nodes_rts.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/formattedText/nodes_rts.ts) | TypeScript | 224 | 21 | 19 | 264 | +| [src/client/views/nodes/formattedText/prosemirrorPatches.js](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/formattedText/prosemirrorPatches.js) | JavaScript | 118 | 12 | 9 | 139 | +| [src/client/views/nodes/formattedText/schema_rts.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/nodes/formattedText/schema_rts.ts) | TypeScript | 12 | 8 | 6 | 26 | +| [src/client/views/pdf/Annotation.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/pdf/Annotation.scss) | SCSS | 6 | 0 | 0 | 6 | +| [src/client/views/pdf/Annotation.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/pdf/Annotation.tsx) | TypeScript React | 114 | 0 | 16 | 130 | +| [src/client/views/pdf/PDFMenu.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/pdf/PDFMenu.scss) | SCSS | 6 | 0 | 0 | 6 | +| [src/client/views/pdf/PDFMenu.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/pdf/PDFMenu.tsx) | TypeScript React | 102 | 0 | 21 | 123 | +| [src/client/views/pdf/PDFViewer.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/pdf/PDFViewer.scss) | SCSS | 74 | 4 | 10 | 88 | +| [src/client/views/pdf/PDFViewer.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/pdf/PDFViewer.tsx) | TypeScript React | 662 | 23 | 46 | 731 | +| [src/client/views/presentationview/PresElementBox.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/presentationview/PresElementBox.scss) | SCSS | 93 | 0 | 10 | 103 | +| [src/client/views/presentationview/PresElementBox.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/presentationview/PresElementBox.tsx) | TypeScript React | 179 | 31 | 14 | 224 | +| [src/client/views/search/CheckBox.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/search/CheckBox.scss) | SCSS | 50 | 1 | 8 | 59 | +| [src/client/views/search/CheckBox.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/search/CheckBox.tsx) | TypeScript React | 42 | 74 | 15 | 131 | +| [src/client/views/search/CollectionFilters.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/search/CollectionFilters.scss) | SCSS | 17 | 0 | 3 | 20 | +| [src/client/views/search/CollectionFilters.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/search/CollectionFilters.tsx) | TypeScript React | 69 | 0 | 14 | 83 | +| [src/client/views/search/FieldFilters.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/search/FieldFilters.scss) | SCSS | 10 | 1 | 1 | 12 | +| [src/client/views/search/FieldFilters.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/search/FieldFilters.tsx) | TypeScript React | 34 | 0 | 7 | 41 | +| [src/client/views/search/FilterBox.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/search/FilterBox.scss) | SCSS | 153 | 0 | 25 | 178 | +| [src/client/views/search/FilterBox.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/search/FilterBox.tsx) | TypeScript React | 354 | 24 | 54 | 432 | +| [src/client/views/search/IconBar.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/search/IconBar.scss) | SCSS | 9 | 0 | 1 | 10 | +| [src/client/views/search/IconBar.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/search/IconBar.tsx) | TypeScript React | 69 | 1 | 17 | 87 | +| [src/client/views/search/IconButton.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/search/IconButton.scss) | SCSS | 46 | 1 | 6 | 53 | +| [src/client/views/search/IconButton.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/search/IconButton.tsx) | TypeScript React | 170 | 2 | 19 | 191 | +| [src/client/views/search/NaviconButton.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/search/NaviconButton.scss) | SCSS | 58 | 0 | 11 | 69 | +| [src/client/views/search/NaviconButton.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/search/NaviconButton.tsx) | TypeScript React | 32 | 0 | 5 | 37 | +| [src/client/views/search/SearchBox.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/search/SearchBox.scss) | SCSS | 203 | 82 | 51 | 336 | +| [src/client/views/search/SearchBox.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/search/SearchBox.tsx) | TypeScript React | 530 | 47 | 94 | 671 | +| [src/client/views/search/SearchItem.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/search/SearchItem.scss) | SCSS | 138 | 0 | 25 | 163 | +| [src/client/views/search/SearchItem.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/search/SearchItem.tsx) | TypeScript React | 272 | 2 | 29 | 303 | +| [src/client/views/search/SelectorContextMenu.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/search/SelectorContextMenu.scss) | SCSS | 12 | 1 | 3 | 16 | +| [src/client/views/search/ToggleBar.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/search/ToggleBar.scss) | SCSS | 35 | 2 | 4 | 41 | +| [src/client/views/search/ToggleBar.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/search/ToggleBar.tsx) | TypeScript React | 77 | 0 | 9 | 86 | +| [src/client/views/webcam/DashWebRTCVideo.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/webcam/DashWebRTCVideo.scss) | SCSS | 70 | 4 | 9 | 83 | +| [src/client/views/webcam/DashWebRTCVideo.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/webcam/DashWebRTCVideo.tsx) | TypeScript React | 67 | 6 | 16 | 89 | +| [src/client/views/webcam/WebCamLogic.js](file:///Users/bcz/Documents/GitHub/Dash-Web/src/client/views/webcam/WebCamLogic.js) | JavaScript | 234 | 7 | 51 | 292 | +| [src/debug/Repl.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/debug/Repl.tsx) | TypeScript React | 59 | 0 | 7 | 66 | +| [src/debug/Test.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/debug/Test.tsx) | TypeScript React | 12 | 0 | 2 | 14 | +| [src/debug/Viewer.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/debug/Viewer.tsx) | TypeScript React | 173 | 0 | 19 | 192 | +| [src/extensions/ArrayExtensions.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/extensions/ArrayExtensions.ts) | TypeScript | 26 | 5 | 6 | 37 | +| [src/extensions/General/Extensions.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/extensions/General/Extensions.ts) | TypeScript | 7 | 0 | 2 | 9 | +| [src/extensions/General/ExtensionsTypings.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/extensions/General/ExtensionsTypings.ts) | TypeScript | 7 | 0 | 1 | 8 | +| [src/extensions/StringExtensions.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/extensions/StringExtensions.ts) | TypeScript | 13 | 0 | 4 | 17 | +| [src/mobile/ImageUpload.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/mobile/ImageUpload.scss) | SCSS | 30 | 0 | 4 | 34 | +| [src/mobile/ImageUpload.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/mobile/ImageUpload.tsx) | TypeScript React | 78 | 41 | 12 | 131 | +| [src/mobile/InkControls.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/mobile/InkControls.tsx) | TypeScript React | 0 | 0 | 1 | 1 | +| [src/mobile/MobileInkOverlay.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/mobile/MobileInkOverlay.scss) | SCSS | 33 | 1 | 5 | 39 | +| [src/mobile/MobileInkOverlay.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/mobile/MobileInkOverlay.tsx) | TypeScript React | 162 | 3 | 26 | 191 | +| [src/mobile/MobileInterface.scss](file:///Users/bcz/Documents/GitHub/Dash-Web/src/mobile/MobileInterface.scss) | SCSS | 17 | 0 | 2 | 19 | +| [src/mobile/MobileInterface.tsx](file:///Users/bcz/Documents/GitHub/Dash-Web/src/mobile/MobileInterface.tsx) | TypeScript React | 297 | 15 | 32 | 344 | +| [src/new_fields/CursorField.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/new_fields/CursorField.ts) | TypeScript | 54 | 0 | 12 | 66 | +| [src/new_fields/DateField.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/new_fields/DateField.ts) | TypeScript | 30 | 0 | 7 | 37 | +| [src/new_fields/Doc.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/new_fields/Doc.ts) | TypeScript | 897 | 85 | 76 | 1,058 | +| [src/new_fields/FieldSymbols.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/new_fields/FieldSymbols.ts) | TypeScript | 11 | 0 | 2 | 13 | +| [src/new_fields/HtmlField.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/new_fields/HtmlField.ts) | TypeScript | 22 | 0 | 5 | 27 | +| [src/new_fields/IconField.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/new_fields/IconField.ts) | TypeScript | 22 | 0 | 5 | 27 | +| [src/new_fields/InkField.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/new_fields/InkField.ts) | TypeScript | 41 | 0 | 10 | 51 | +| [src/new_fields/List.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/new_fields/List.ts) | TypeScript | 244 | 38 | 20 | 302 | +| [src/new_fields/ListSpec.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/new_fields/ListSpec.ts) | TypeScript | 0 | 0 | 1 | 1 | +| [src/new_fields/ObjectField.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/new_fields/ObjectField.ts) | TypeScript | 16 | 0 | 4 | 20 | +| [src/new_fields/PresField.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/new_fields/PresField.ts) | TypeScript | 3 | 1 | 2 | 6 | +| [src/new_fields/Proxy.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/new_fields/Proxy.ts) | TypeScript | 95 | 2 | 14 | 111 | +| [src/new_fields/RefField.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/new_fields/RefField.ts) | TypeScript | 17 | 0 | 5 | 22 | +| [src/new_fields/RichTextField.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/new_fields/RichTextField.ts) | TypeScript | 33 | 0 | 8 | 41 | +| [src/new_fields/RichTextUtils.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/new_fields/RichTextUtils.ts) | TypeScript | 455 | 8 | 56 | 519 | +| [src/new_fields/Schema.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/new_fields/Schema.ts) | TypeScript | 107 | 5 | 8 | 120 | +| [src/new_fields/SchemaHeaderField.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/new_fields/SchemaHeaderField.ts) | TypeScript | 104 | 4 | 14 | 122 | +| [src/new_fields/ScriptField.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/new_fields/ScriptField.ts) | TypeScript | 137 | 21 | 19 | 177 | +| [src/new_fields/Types.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/new_fields/Types.ts) | TypeScript | 86 | 5 | 17 | 108 | +| [src/new_fields/URLField.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/new_fields/URLField.ts) | TypeScript | 45 | 0 | 9 | 54 | +| [src/new_fields/documentSchemas.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/new_fields/documentSchemas.ts) | TypeScript | 87 | 0 | 6 | 93 | +| [src/new_fields/util.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/new_fields/util.ts) | TypeScript | 176 | 3 | 15 | 194 | +| [src/pen-gestures/GestureUtils.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/pen-gestures/GestureUtils.ts) | TypeScript | 41 | 0 | 5 | 46 | +| [src/pen-gestures/ndollar.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/pen-gestures/ndollar.ts) | TypeScript | 356 | 172 | 22 | 550 | +| [src/scraping/acm/.gitignore](file:///Users/bcz/Documents/GitHub/Dash-Web/src/scraping/acm/.gitignore) | Ignore | 2 | 0 | 0 | 2 | +| [src/scraping/acm/debug.log](file:///Users/bcz/Documents/GitHub/Dash-Web/src/scraping/acm/debug.log) | log | 38 | 0 | 1 | 39 | +| [src/scraping/acm/index.js](file:///Users/bcz/Documents/GitHub/Dash-Web/src/scraping/acm/index.js) | JavaScript | 82 | 185 | 13 | 280 | +| [src/scraping/acm/package.json](file:///Users/bcz/Documents/GitHub/Dash-Web/src/scraping/acm/package.json) | JSON | 17 | 0 | 1 | 18 | +| [src/scraping/buxton/.idea/buxton.iml](file:///Users/bcz/Documents/GitHub/Dash-Web/src/scraping/buxton/.idea/buxton.iml) | XML | 8 | 0 | 0 | 8 | +| [src/scraping/buxton/.idea/inspectionProfiles/profiles_settings.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/src/scraping/buxton/.idea/inspectionProfiles/profiles_settings.xml) | XML | 6 | 0 | 0 | 6 | +| [src/scraping/buxton/.idea/misc.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/src/scraping/buxton/.idea/misc.xml) | XML | 4 | 0 | 0 | 4 | +| [src/scraping/buxton/.idea/modules.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/src/scraping/buxton/.idea/modules.xml) | XML | 8 | 0 | 0 | 8 | +| [src/scraping/buxton/.idea/vcs.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/src/scraping/buxton/.idea/vcs.xml) | XML | 6 | 0 | 0 | 6 | +| [src/scraping/buxton/.idea/workspace.xml](file:///Users/bcz/Documents/GitHub/Dash-Web/src/scraping/buxton/.idea/workspace.xml) | XML | 173 | 0 | 0 | 173 | +| [src/scraping/buxton/final/BuxtonImporter.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/scraping/buxton/final/BuxtonImporter.ts) | TypeScript | 228 | 142 | 26 | 396 | +| [src/scraping/buxton/jsonifier.py](file:///Users/bcz/Documents/GitHub/Dash-Web/src/scraping/buxton/jsonifier.py) | Python | 183 | 1 | 48 | 232 | +| [src/scraping/buxton/narratives.py](file:///Users/bcz/Documents/GitHub/Dash-Web/src/scraping/buxton/narratives.py) | Python | 11 | 19 | 9 | 39 | +| [src/scraping/buxton/narratives/chord_keyboards.json](file:///Users/bcz/Documents/GitHub/Dash-Web/src/scraping/buxton/narratives/chord_keyboards.json) | JSON | 39 | 0 | 0 | 39 | +| [src/scraping/buxton/scraper.py](file:///Users/bcz/Documents/GitHub/Dash-Web/src/scraping/buxton/scraper.py) | Python | 350 | 5 | 78 | 433 | +| [src/server/ActionUtilities.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/ActionUtilities.ts) | TypeScript | 136 | 1 | 23 | 160 | +| [src/server/ApiManagers/ApiManager.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/ApiManagers/ApiManager.ts) | TypeScript | 8 | 0 | 3 | 11 | +| [src/server/ApiManagers/DeleteManager.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/ApiManagers/DeleteManager.ts) | TypeScript | 71 | 0 | 11 | 82 | +| [src/server/ApiManagers/DownloadManager.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/ApiManagers/DownloadManager.ts) | TypeScript | 173 | 80 | 16 | 269 | +| [src/server/ApiManagers/GeneralGoogleManager.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/ApiManagers/GeneralGoogleManager.ts) | TypeScript | 53 | 0 | 8 | 61 | +| [src/server/ApiManagers/GooglePhotosManager.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/ApiManagers/GooglePhotosManager.ts) | TypeScript | 190 | 119 | 22 | 331 | +| [src/server/ApiManagers/PDFManager.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/ApiManagers/PDFManager.ts) | TypeScript | 103 | 0 | 12 | 115 | +| [src/server/ApiManagers/SearchManager.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/ApiManagers/SearchManager.ts) | TypeScript | 200 | 0 | 15 | 215 | +| [src/server/ApiManagers/SessionManager.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/ApiManagers/SessionManager.ts) | TypeScript | 56 | 0 | 11 | 67 | +| [src/server/ApiManagers/UploadManager.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/ApiManagers/UploadManager.ts) | TypeScript | 226 | 1 | 20 | 247 | +| [src/server/ApiManagers/UserManager.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/ApiManagers/UserManager.ts) | TypeScript | 101 | 4 | 21 | 126 | +| [src/server/ApiManagers/UtilManager.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/ApiManagers/UtilManager.ts) | TypeScript | 42 | 22 | 10 | 74 | +| [src/server/Client.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/Client.ts) | TypeScript | 8 | 0 | 3 | 11 | +| [src/server/DashSession/DashSessionAgent.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/DashSession/DashSessionAgent.ts) | TypeScript | 155 | 52 | 23 | 230 | +| [src/server/DashSession/Session/agents/applied_session_agent.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/DashSession/Session/agents/applied_session_agent.ts) | TypeScript | 47 | 2 | 9 | 58 | +| [src/server/DashSession/Session/agents/monitor.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/DashSession/Session/agents/monitor.ts) | TypeScript | 213 | 59 | 26 | 298 | +| [src/server/DashSession/Session/agents/process_message_router.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/DashSession/Session/agents/process_message_router.ts) | TypeScript | 24 | 10 | 7 | 41 | +| [src/server/DashSession/Session/agents/promisified_ipc_manager.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/DashSession/Session/agents/promisified_ipc_manager.ts) | TypeScript | 106 | 52 | 15 | 173 | +| [src/server/DashSession/Session/agents/server_worker.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/DashSession/Session/agents/server_worker.ts) | TypeScript | 99 | 46 | 15 | 160 | +| [src/server/DashSession/Session/utilities/repl.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/DashSession/Session/utilities/repl.ts) | TypeScript | 116 | 0 | 12 | 128 | +| [src/server/DashSession/Session/utilities/session_config.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/DashSession/Session/utilities/session_config.ts) | TypeScript | 119 | 0 | 10 | 129 | +| [src/server/DashSession/Session/utilities/utilities.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/DashSession/Session/utilities/utilities.ts) | TypeScript | 24 | 8 | 5 | 37 | +| [src/server/DashUploadUtils.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/DashUploadUtils.ts) | TypeScript | 285 | 52 | 30 | 367 | +| [src/server/GarbageCollector.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/GarbageCollector.ts) | TypeScript | 138 | 2 | 11 | 151 | +| [src/server/IDatabase.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/IDatabase.ts) | TypeScript | 17 | 0 | 8 | 25 | +| [src/server/MemoryDatabase.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/MemoryDatabase.ts) | TypeScript | 87 | 0 | 14 | 101 | +| [src/server/Message.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/Message.ts) | TypeScript | 86 | 0 | 18 | 104 | +| [src/server/PdfTypes.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/PdfTypes.ts) | TypeScript | 19 | 0 | 2 | 21 | +| [src/server/ProcessFactory.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/ProcessFactory.ts) | TypeScript | 34 | 0 | 10 | 44 | +| [src/server/Recommender.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/Recommender.ts) | TypeScript | 0 | 120 | 18 | 138 | +| [src/server/RouteManager.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/RouteManager.ts) | TypeScript | 187 | 4 | 19 | 210 | +| [src/server/RouteSubscriber.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/RouteSubscriber.ts) | TypeScript | 21 | 0 | 5 | 26 | +| [src/server/Search.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/Search.ts) | TypeScript | 71 | 2 | 8 | 81 | +| [src/server/SharedMediaTypes.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/SharedMediaTypes.ts) | TypeScript | 41 | 0 | 10 | 51 | +| [src/server/Websocket/Websocket.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/Websocket/Websocket.ts) | TypeScript | 263 | 5 | 46 | 314 | +| [src/server/apis/google/GoogleApiServerUtils.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/apis/google/GoogleApiServerUtils.ts) | TypeScript | 172 | 168 | 25 | 365 | +| [src/server/apis/google/SharedTypes.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/apis/google/SharedTypes.ts) | TypeScript | 19 | 0 | 2 | 21 | +| [src/server/apis/youtube/youtubeApiSample.d.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/apis/youtube/youtubeApiSample.d.ts) | TypeScript | 2 | 0 | 0 | 2 | +| [src/server/apis/youtube/youtubeApiSample.js](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/apis/youtube/youtubeApiSample.js) | JavaScript | 135 | 30 | 14 | 179 | +| [src/server/authentication/config/passport.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/authentication/config/passport.ts) | TypeScript | 23 | 2 | 4 | 29 | +| [src/server/authentication/controllers/user_controller.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/authentication/controllers/user_controller.ts) | TypeScript | 218 | 25 | 25 | 268 | +| [src/server/authentication/models/current_user_utils.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/authentication/models/current_user_utils.ts) | TypeScript | 586 | 30 | 57 | 673 | +| [src/server/authentication/models/user_model.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/authentication/models/user_model.ts) | TypeScript | 63 | 9 | 14 | 86 | +| [src/server/credentials/CredentialsLoader.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/credentials/CredentialsLoader.ts) | TypeScript | 24 | 0 | 6 | 30 | +| [src/server/credentials/google_project_credentials.json](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/credentials/google_project_credentials.json) | JSON | 11 | 0 | 0 | 11 | +| [src/server/database.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/database.ts) | TypeScript | 312 | 0 | 38 | 350 | +| [src/server/downsize.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/downsize.ts) | TypeScript | 34 | 5 | 1 | 40 | +| [src/server/index.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/index.ts) | TypeScript | 107 | 36 | 16 | 159 | +| [src/server/remapUrl.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/remapUrl.ts) | TypeScript | 53 | 4 | 6 | 63 | +| [src/server/server_Initialization.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/server_Initialization.ts) | TypeScript | 138 | 6 | 24 | 168 | +| [src/server/slides.json](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/slides.json) | JSON | 10,820 | 0 | 0 | 10,820 | +| [src/server/updateProtos.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/server/updateProtos.ts) | TypeScript | 11 | 0 | 3 | 14 | +| [src/typings/index.d.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/src/typings/index.d.ts) | TypeScript | 219 | 72 | 38 | 329 | +| [test/test.ts](file:///Users/bcz/Documents/GitHub/Dash-Web/test/test.ts) | TypeScript | 141 | 0 | 20 | 161 | +| [tsconfig.json](file:///Users/bcz/Documents/GitHub/Dash-Web/tsconfig.json) | JSON | 21 | 5 | 0 | 26 | +| [tslint.json](file:///Users/bcz/Documents/GitHub/Dash-Web/tslint.json) | JSON | 30 | 32 | 1 | 63 | +| [views/forgot.pug](file:///Users/bcz/Documents/GitHub/Dash-Web/views/forgot.pug) | Pug | 19 | 1 | 2 | 22 | +| [views/layout.pug](file:///Users/bcz/Documents/GitHub/Dash-Web/views/layout.pug) | Pug | 13 | 0 | 1 | 14 | +| [views/login.pug](file:///Users/bcz/Documents/GitHub/Dash-Web/views/login.pug) | Pug | 24 | 0 | 2 | 26 | +| [views/reset.pug](file:///Users/bcz/Documents/GitHub/Dash-Web/views/reset.pug) | Pug | 20 | 0 | 2 | 22 | +| [views/signup.pug](file:///Users/bcz/Documents/GitHub/Dash-Web/views/signup.pug) | Pug | 25 | 0 | 2 | 27 | +| [views/stylesheets/authentication.css](file:///Users/bcz/Documents/GitHub/Dash-Web/views/stylesheets/authentication.css) | CSS | 185 | 4 | 34 | 223 | +| [views/user_activity.pug](file:///Users/bcz/Documents/GitHub/Dash-Web/views/user_activity.pug) | Pug | 18 | 0 | 1 | 19 | +| [webpack.config.js](file:///Users/bcz/Documents/GitHub/Dash-Web/webpack.config.js) | JavaScript | 116 | 0 | 5 | 121 | + +[summary](results.md) \ No newline at end of file diff --git a/.VSCodeCounter/results.csv b/.VSCodeCounter/results.csv new file mode 100644 index 000000000..b31bc8262 --- /dev/null +++ b/.VSCodeCounter/results.csv @@ -0,0 +1,648 @@ +filename, language, Markdown, JavaScript, JSON, Batch, Python, TypeScript, HTML, Pug, Shell Script, CSS, TypeScript React, SCSS, XML, Properties, Ignore, log, XSL, comment, blank, total +README.md, Markdown, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 9 +build/index.html, HTML, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 12 +dash.bat, Batch, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3 +deploy/assets/env.json, JSON, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15 +deploy/assets/pdf.worker.js, JavaScript, 0, 55662, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 174, 686, 56522 +deploy/debug/repl.html, HTML, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 14 +deploy/debug/test.html, HTML, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 13 +deploy/debug/viewer.html, HTML, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 14 +deploy/index.html, HTML, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 16 +deploy/mobile/image.html, HTML, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 15 +deploy/mobile/ink.html, HTML, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 13 +package-lock.json, JSON, 0, 0, 18689, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 18690 +package.json, JSON, 0, 0, 266, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 267 +sentence_parser.py, Python, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 7 +session.config.json, JSON, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 13 +solr-8.3.1/bin/install_solr_service.sh, Shell Script, 0, 0, 0, 0, 0, 0, 0, 0, 307, 0, 0, 0, 0, 0, 0, 0, 0, 29, 35, 371 +solr-8.3.1/bin/oom_solr.sh, Shell Script, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 15, 3, 31 +solr-8.3.1/bin/solr.cmd, Batch, 0, 0, 0, 1782, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 210, 2035 +solr-8.3.1/bin/solr.in.cmd, Batch, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 133, 29, 178 +solr-8.3.1/bin/solr.in.sh, Shell Script, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 34, 206 +solr-8.3.1/contrib/prometheus-exporter/bin/solr-exporter.cmd, Batch, 0, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 108 +solr-8.3.1/contrib/prometheus-exporter/conf/grafana-solr-dashboard.json, JSON, 0, 0, 4465, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4466 +solr-8.3.1/contrib/prometheus-exporter/conf/solr-exporter-config.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1734, 0, 0, 0, 0, 63, 10, 1807 +solr-8.3.1/docs/images/solr.svg, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0, 0, 0, 0, 1, 40 +solr-8.3.1/docs/index.html, HTML, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 21 +solr-8.3.1/example/example-DIH/solr/atom/conf/atom-data-config.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 6, 9, 36 +solr-8.3.1/example/example-DIH/solr/atom/conf/solrconfig.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 37, 8, 65 +solr-8.3.1/example/example-DIH/solr/atom/core.properties, Properties, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2 +solr-8.3.1/example/example-DIH/solr/db/conf/clustering/carrot2/kmeans-attributes.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 6, 1, 20 +solr-8.3.1/example/example-DIH/solr/db/conf/clustering/carrot2/lingo-attributes.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 11, 1, 25 +solr-8.3.1/example/example-DIH/solr/db/conf/clustering/carrot2/stc-attributes.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 6, 1, 20 +solr-8.3.1/example/example-DIH/solr/db/conf/currency.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 0, 0, 0, 0, 19, 4, 68 +solr-8.3.1/example/example-DIH/solr/db/conf/db-data-config.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 4, 30 +solr-8.3.1/example/example-DIH/solr/db/conf/elevate.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 37, 3, 43 +solr-8.3.1/example/example-DIH/solr/db/conf/solrconfig.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 292, 0, 0, 0, 0, 958, 104, 1354 +solr-8.3.1/example/example-DIH/solr/db/conf/update-script.js, JavaScript, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 13, 54 +solr-8.3.1/example/example-DIH/solr/db/conf/xslt/example.xsl, XSL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, 20, 15, 133 +solr-8.3.1/example/example-DIH/solr/db/conf/xslt/example_atom.xsl, XSL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 20, 8, 68 +solr-8.3.1/example/example-DIH/solr/db/conf/xslt/example_rss.xsl, XSL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 20, 6, 67 +solr-8.3.1/example/example-DIH/solr/db/conf/xslt/luke.xsl, XSL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 301, 19, 18, 338 +solr-8.3.1/example/example-DIH/solr/db/conf/xslt/updateXml.xsl, XSL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 25, 11, 71 +solr-8.3.1/example/example-DIH/solr/db/core.properties, Properties, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2 +solr-8.3.1/example/example-DIH/solr/mail/conf/clustering/carrot2/kmeans-attributes.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 6, 1, 20 +solr-8.3.1/example/example-DIH/solr/mail/conf/clustering/carrot2/lingo-attributes.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 11, 1, 25 +solr-8.3.1/example/example-DIH/solr/mail/conf/clustering/carrot2/stc-attributes.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 6, 1, 20 +solr-8.3.1/example/example-DIH/solr/mail/conf/currency.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 0, 0, 0, 0, 19, 4, 68 +solr-8.3.1/example/example-DIH/solr/mail/conf/elevate.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 37, 3, 43 +solr-8.3.1/example/example-DIH/solr/mail/conf/mail-data-config.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 4, 1, 13 +solr-8.3.1/example/example-DIH/solr/mail/conf/solrconfig.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 294, 0, 0, 0, 0, 958, 105, 1357 +solr-8.3.1/example/example-DIH/solr/mail/conf/update-script.js, JavaScript, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 13, 54 +solr-8.3.1/example/example-DIH/solr/mail/conf/xslt/example.xsl, XSL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, 20, 15, 133 +solr-8.3.1/example/example-DIH/solr/mail/conf/xslt/example_atom.xsl, XSL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 20, 8, 68 +solr-8.3.1/example/example-DIH/solr/mail/conf/xslt/example_rss.xsl, XSL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 20, 6, 67 +solr-8.3.1/example/example-DIH/solr/mail/conf/xslt/luke.xsl, XSL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 301, 19, 18, 338 +solr-8.3.1/example/example-DIH/solr/mail/conf/xslt/updateXml.xsl, XSL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 25, 11, 71 +solr-8.3.1/example/example-DIH/solr/mail/core.properties, Properties, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2 +solr-8.3.1/example/example-DIH/solr/solr.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 1, 3 +solr-8.3.1/example/example-DIH/solr/solr/conf/clustering/carrot2/kmeans-attributes.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 6, 1, 20 +solr-8.3.1/example/example-DIH/solr/solr/conf/clustering/carrot2/lingo-attributes.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 11, 1, 25 +solr-8.3.1/example/example-DIH/solr/solr/conf/clustering/carrot2/stc-attributes.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 6, 1, 20 +solr-8.3.1/example/example-DIH/solr/solr/conf/currency.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 0, 0, 0, 0, 19, 4, 68 +solr-8.3.1/example/example-DIH/solr/solr/conf/elevate.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 37, 3, 43 +solr-8.3.1/example/example-DIH/solr/solr/conf/solr-data-config.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 16, 2, 26 +solr-8.3.1/example/example-DIH/solr/solr/conf/solrconfig.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 292, 0, 0, 0, 0, 958, 102, 1352 +solr-8.3.1/example/example-DIH/solr/solr/conf/update-script.js, JavaScript, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 13, 54 +solr-8.3.1/example/example-DIH/solr/solr/conf/xslt/example.xsl, XSL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, 20, 15, 133 +solr-8.3.1/example/example-DIH/solr/solr/conf/xslt/example_atom.xsl, XSL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 20, 8, 68 +solr-8.3.1/example/example-DIH/solr/solr/conf/xslt/example_rss.xsl, XSL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 20, 6, 67 +solr-8.3.1/example/example-DIH/solr/solr/conf/xslt/luke.xsl, XSL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 301, 19, 18, 338 +solr-8.3.1/example/example-DIH/solr/solr/conf/xslt/updateXml.xsl, XSL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 25, 11, 71 +solr-8.3.1/example/example-DIH/solr/solr/core.properties, Properties, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2 +solr-8.3.1/example/example-DIH/solr/tika/conf/solrconfig.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 38, 7, 62 +solr-8.3.1/example/example-DIH/solr/tika/conf/tika-data-config.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 3, 7, 27 +solr-8.3.1/example/example-DIH/solr/tika/core.properties, Properties, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2 +solr-8.3.1/example/exampledocs/books.json, JSON, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 52 +solr-8.3.1/example/exampledocs/gb18030-example.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 16, 3, 33 +solr-8.3.1/example/exampledocs/hd.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 20, 4, 57 +solr-8.3.1/example/exampledocs/ipod_other.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 20, 9, 61 +solr-8.3.1/example/exampledocs/ipod_video.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 18, 2, 41 +solr-8.3.1/example/exampledocs/manufacturers.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, 16, 3, 76 +solr-8.3.1/example/exampledocs/mem.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 0, 0, 0, 0, 24, 9, 78 +solr-8.3.1/example/exampledocs/money.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 17, 7, 66 +solr-8.3.1/example/exampledocs/monitor.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 18, 3, 35 +solr-8.3.1/example/exampledocs/monitor2.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 18, 3, 34 +solr-8.3.1/example/exampledocs/mp500.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 18, 3, 44 +solr-8.3.1/example/exampledocs/sample.html, HTML, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 14 +solr-8.3.1/example/exampledocs/sd500.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 18, 2, 39 +solr-8.3.1/example/exampledocs/solr.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 16, 3, 39 +solr-8.3.1/example/exampledocs/test_utf8.sh, Shell Script, 0, 0, 0, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 21, 16, 94 +solr-8.3.1/example/exampledocs/utf8-example.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 20, 4, 43 +solr-8.3.1/example/exampledocs/vidcard.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 21, 2, 63 +solr-8.3.1/example/files/browse-resources/velocity/resources.properties, Properties, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, 0, 0, 0, 6, 5, 83 +solr-8.3.1/example/files/browse-resources/velocity/resources_de_DE.properties, Properties, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 1, 19 +solr-8.3.1/example/files/browse-resources/velocity/resources_fr_FR.properties, Properties, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 3, 21 +solr-8.3.1/example/files/conf/currency.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 0, 0, 0, 0, 19, 4, 68 +solr-8.3.1/example/files/conf/elevate.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 37, 3, 43 +solr-8.3.1/example/files/conf/params.json, JSON, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 35 +solr-8.3.1/example/files/conf/solrconfig.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 298, 0, 0, 0, 0, 979, 102, 1379 +solr-8.3.1/example/files/conf/update-script.js, JavaScript, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 23, 116 +solr-8.3.1/example/files/conf/velocity/dropit.js, JavaScript, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2 +solr-8.3.1/example/files/conf/velocity/jquery.tx3-tag-cloud.js, JavaScript, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2 +solr-8.3.1/example/files/conf/velocity/js/dropit.js, JavaScript, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 19, 98 +solr-8.3.1/example/files/conf/velocity/js/jquery.autocomplete.js, JavaScript, 0, 620, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 76, 764 +solr-8.3.1/example/files/conf/velocity/js/jquery.tx3-tag-cloud.js, JavaScript, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 9, 71 +solr-8.3.1/example/films/film_data_generator.py, Python, 0, 0, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 12, 118 +solr-8.3.1/example/films/films.json, JSON, 0, 0, 15830, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 15831 +solr-8.3.1/example/films/films.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11438, 0, 0, 0, 0, 0, 1, 11439 +solr-8.3.1/server/contexts/solr-jetty-context.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 1, 9 +solr-8.3.1/server/etc/jetty-http.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 15, 4, 52 +solr-8.3.1/server/etc/jetty-https.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 16, 5, 77 +solr-8.3.1/server/etc/jetty-https8.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, 0, 32, 4, 70 +solr-8.3.1/server/etc/jetty-ssl.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 11, 4, 38 +solr-8.3.1/server/etc/jetty.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 110, 0, 0, 0, 0, 94, 18, 222 +solr-8.3.1/server/etc/webdefault.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 272, 0, 0, 0, 0, 232, 24, 528 +solr-8.3.1/server/resources/jetty-logging.properties, Properties, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 2 +solr-8.3.1/server/resources/log4j2-console.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 43, 6, 68 +solr-8.3.1/server/resources/log4j2.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0, 0, 80, 9, 143 +solr-8.3.1/server/scripts/cloud-scripts/snapshotscli.sh, Shell Script, 0, 0, 0, 0, 0, 0, 0, 0, 152, 0, 0, 0, 0, 0, 0, 0, 0, 2, 23, 177 +solr-8.3.1/server/scripts/cloud-scripts/zkcli.bat, Batch, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 7, 26 +solr-8.3.1/server/scripts/cloud-scripts/zkcli.sh, Shell Script, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 27 +solr-8.3.1/server/solr-webapp/webapp/WEB-INF/web.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 0, 42, 11, 115 +solr-8.3.1/server/solr-webapp/webapp/css/angular/analysis.css, CSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 237, 0, 0, 0, 0, 0, 0, 0, 19, 48, 304 +solr-8.3.1/server/solr-webapp/webapp/css/angular/chosen.css, CSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 402, 0, 0, 0, 0, 0, 0, 0, 55, 9, 466 +solr-8.3.1/server/solr-webapp/webapp/css/angular/cloud.css, CSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 594, 0, 0, 0, 0, 0, 0, 0, 23, 106, 723 +solr-8.3.1/server/solr-webapp/webapp/css/angular/collections.css, CSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 296, 0, 0, 0, 0, 0, 0, 0, 18, 65, 379 +solr-8.3.1/server/solr-webapp/webapp/css/angular/common.css, CSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 647, 0, 0, 0, 0, 0, 0, 0, 19, 106, 772 +solr-8.3.1/server/solr-webapp/webapp/css/angular/cores.css, CSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 171, 0, 0, 0, 0, 0, 0, 0, 18, 37, 226 +solr-8.3.1/server/solr-webapp/webapp/css/angular/dashboard.css, CSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 0, 0, 0, 0, 0, 0, 0, 18, 28, 180 +solr-8.3.1/server/solr-webapp/webapp/css/angular/dataimport.css, CSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 292, 0, 0, 0, 0, 0, 0, 0, 18, 61, 371 +solr-8.3.1/server/solr-webapp/webapp/css/angular/documents.css, CSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 131, 0, 0, 0, 0, 0, 0, 0, 23, 26, 180 +solr-8.3.1/server/solr-webapp/webapp/css/angular/files.css, CSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 18, 7, 54 +solr-8.3.1/server/solr-webapp/webapp/css/angular/index.css, CSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 164, 0, 0, 0, 0, 0, 0, 0, 18, 35, 217 +solr-8.3.1/server/solr-webapp/webapp/css/angular/java-properties.css, CSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 18, 6, 48 +solr-8.3.1/server/solr-webapp/webapp/css/angular/jquery-ui.min.css, CSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 26, 2, 29 +solr-8.3.1/server/solr-webapp/webapp/css/angular/jquery-ui.structure.min.css, CSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 22, 2, 25 +solr-8.3.1/server/solr-webapp/webapp/css/angular/logging.css, CSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 303, 0, 0, 0, 0, 0, 0, 0, 19, 63, 385 +solr-8.3.1/server/solr-webapp/webapp/css/angular/login.css, CSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 18, 12, 110 +solr-8.3.1/server/solr-webapp/webapp/css/angular/menu.css, CSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 257, 0, 0, 0, 0, 0, 0, 0, 18, 56, 331 +solr-8.3.1/server/solr-webapp/webapp/css/angular/overview.css, CSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 18, 5, 43 +solr-8.3.1/server/solr-webapp/webapp/css/angular/plugins.css, CSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 0, 0, 0, 0, 0, 0, 0, 18, 31, 221 +solr-8.3.1/server/solr-webapp/webapp/css/angular/query.css, CSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 18, 25, 163 +solr-8.3.1/server/solr-webapp/webapp/css/angular/replication.css, CSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 404, 0, 0, 0, 0, 0, 0, 0, 18, 79, 501 +solr-8.3.1/server/solr-webapp/webapp/css/angular/schema.css, CSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 596, 0, 0, 0, 0, 0, 0, 0, 20, 112, 728 +solr-8.3.1/server/solr-webapp/webapp/css/angular/segments.css, CSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 133, 0, 0, 0, 0, 0, 0, 0, 18, 22, 173 +solr-8.3.1/server/solr-webapp/webapp/css/angular/stream.css, CSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 178, 0, 0, 0, 0, 0, 0, 0, 22, 34, 234 +solr-8.3.1/server/solr-webapp/webapp/css/angular/suggestions.css, CSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 18, 4, 65 +solr-8.3.1/server/solr-webapp/webapp/css/angular/threads.css, CSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 119, 0, 0, 0, 0, 0, 0, 0, 18, 24, 161 +solr-8.3.1/server/solr-webapp/webapp/img/solr.svg, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0, 0, 0, 0, 1, 40 +solr-8.3.1/server/solr-webapp/webapp/index.html, HTML, 0, 0, 0, 0, 0, 0, 203, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 38, 257 +solr-8.3.1/server/solr-webapp/webapp/js/angular/app.js, JavaScript, 0, 512, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 31, 562 +solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/alias-overview.js, JavaScript, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 4, 28 +solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/analysis.js, JavaScript, 0, 161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 23, 202 +solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/cloud.js, JavaScript, 0, 847, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 124, 1022 +solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/cluster-suggestions.js, JavaScript, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 2, 63 +solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/collection-overview.js, JavaScript, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 6, 40 +solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/collections.js, JavaScript, 0, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 27, 290 +solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/core-overview.js, JavaScript, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 9, 94 +solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/cores.js, JavaScript, 0, 151, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 14, 181 +solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/dataimport.js, JavaScript, 0, 234, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 44, 303 +solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/documents.js, JavaScript, 0, 107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 13, 138 +solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/files.js, JavaScript, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 13, 101 +solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/index.js, JavaScript, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 14, 98 +solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/java-properties.js, JavaScript, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 3, 46 +solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/logging.js, JavaScript, 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 12, 159 +solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/login.js, JavaScript, 0, 269, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 19, 318 +solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/plugins.js, JavaScript, 0, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 168 +solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/query.js, JavaScript, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 14, 121 +solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/replication.js, JavaScript, 0, 178, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 40, 236 +solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/schema.js, JavaScript, 0, 524, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 69, 612 +solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/segments.js, JavaScript, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 20, 100 +solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/stream.js, JavaScript, 0, 173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 51, 240 +solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/threads.js, JavaScript, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 2, 51 +solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/unknown.js, JavaScript, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 2, 38 +solr-8.3.1/server/solr-webapp/webapp/js/angular/services.js, JavaScript, 0, 311, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 11, 340 +solr-8.3.1/server/solr-webapp/webapp/libs/angular-chosen.js, JavaScript, 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 4, 140 +solr-8.3.1/server/solr-webapp/webapp/libs/angular-cookies.js, JavaScript, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 135, 22, 230 +solr-8.3.1/server/solr-webapp/webapp/libs/angular-cookies.min.js, JavaScript, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 1, 32 +solr-8.3.1/server/solr-webapp/webapp/libs/angular-resource.min.js, JavaScript, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 1, 37 +solr-8.3.1/server/solr-webapp/webapp/libs/angular-route.js, JavaScript, 0, 316, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 636, 67, 1019 +solr-8.3.1/server/solr-webapp/webapp/libs/angular-route.min.js, JavaScript, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 1, 39 +solr-8.3.1/server/solr-webapp/webapp/libs/angular-sanitize.js, JavaScript, 0, 311, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 328, 65, 704 +solr-8.3.1/server/solr-webapp/webapp/libs/angular-sanitize.min.js, JavaScript, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 1, 40 +solr-8.3.1/server/solr-webapp/webapp/libs/angular-utf8-base64.js, JavaScript, 0, 157, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 13, 218 +solr-8.3.1/server/solr-webapp/webapp/libs/angular-utf8-base64.min.js, JavaScript, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 3, 46 +solr-8.3.1/server/solr-webapp/webapp/libs/angular.js, JavaScript, 0, 10845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13211, 2038, 26094 +solr-8.3.1/server/solr-webapp/webapp/libs/angular.min.js, JavaScript, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 201, 0, 274 +solr-8.3.1/server/solr-webapp/webapp/libs/chosen.jquery.js, JavaScript, 0, 1151, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 8, 1195 +solr-8.3.1/server/solr-webapp/webapp/libs/chosen.jquery.min.js, JavaScript, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 31 +solr-8.3.1/server/solr-webapp/webapp/libs/d3.js, JavaScript, 0, 7720, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 519, 1135, 9374 +solr-8.3.1/server/solr-webapp/webapp/libs/highlight.js, JavaScript, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 1, 32 +solr-8.3.1/server/solr-webapp/webapp/libs/jquery-1.7.2.min.js, JavaScript, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 2, 31 +solr-8.3.1/server/solr-webapp/webapp/libs/jquery-2.1.3.min.js, JavaScript, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 1, 30 +solr-8.3.1/server/solr-webapp/webapp/libs/jquery-ui.min.js, JavaScript, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 3, 31 +solr-8.3.1/server/solr-webapp/webapp/libs/jquery.jstree.js, JavaScript, 0, 3222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 228, 85, 3535 +solr-8.3.1/server/solr-webapp/webapp/libs/ngtimeago.js, JavaScript, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 13, 102 +solr-8.3.1/server/solr-webapp/webapp/partials/alias_overview.html, HTML, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 10, 47 +solr-8.3.1/server/solr-webapp/webapp/partials/analysis.html, HTML, 0, 0, 0, 0, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 26, 129 +solr-8.3.1/server/solr-webapp/webapp/partials/cloud.html, HTML, 0, 0, 0, 0, 0, 0, 263, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 24, 303 +solr-8.3.1/server/solr-webapp/webapp/partials/cluster_suggestions.html, HTML, 0, 0, 0, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 4, 50 +solr-8.3.1/server/solr-webapp/webapp/partials/collection_overview.html, HTML, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 22, 86 +solr-8.3.1/server/solr-webapp/webapp/partials/collections.html, HTML, 0, 0, 0, 0, 0, 0, 301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 79, 396 +solr-8.3.1/server/solr-webapp/webapp/partials/core_overview.html, HTML, 0, 0, 0, 0, 0, 0, 125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 66, 207 +solr-8.3.1/server/solr-webapp/webapp/partials/cores.html, HTML, 0, 0, 0, 0, 0, 0, 142, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 67, 225 +solr-8.3.1/server/solr-webapp/webapp/partials/dataimport.html, HTML, 0, 0, 0, 0, 0, 0, 142, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 52, 210 +solr-8.3.1/server/solr-webapp/webapp/partials/documents.html, HTML, 0, 0, 0, 0, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 9, 112 +solr-8.3.1/server/solr-webapp/webapp/partials/files.html, HTML, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 15, 48 +solr-8.3.1/server/solr-webapp/webapp/partials/index.html, HTML, 0, 0, 0, 0, 0, 0, 135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 85, 262 +solr-8.3.1/server/solr-webapp/webapp/partials/java-properties.html, HTML, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 2, 28 +solr-8.3.1/server/solr-webapp/webapp/partials/logging-levels.html, HTML, 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 6, 57 +solr-8.3.1/server/solr-webapp/webapp/partials/logging.html, HTML, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 2, 58 +solr-8.3.1/server/solr-webapp/webapp/partials/login.html, HTML, 0, 0, 0, 0, 0, 0, 134, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 11, 161 +solr-8.3.1/server/solr-webapp/webapp/partials/plugins.html, HTML, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 8, 73 +solr-8.3.1/server/solr-webapp/webapp/partials/query.html, HTML, 0, 0, 0, 0, 0, 0, 270, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 84, 370 +solr-8.3.1/server/solr-webapp/webapp/partials/replication.html, HTML, 0, 0, 0, 0, 0, 0, 153, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 71, 240 +solr-8.3.1/server/solr-webapp/webapp/partials/schema.html, HTML, 0, 0, 0, 0, 0, 0, 336, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 104, 456 +solr-8.3.1/server/solr-webapp/webapp/partials/segments.html, HTML, 0, 0, 0, 0, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 14, 100 +solr-8.3.1/server/solr-webapp/webapp/partials/stream.html, HTML, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 9, 65 +solr-8.3.1/server/solr-webapp/webapp/partials/threads.html, HTML, 0, 0, 0, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 14, 66 +solr-8.3.1/server/solr-webapp/webapp/partials/unknown.html, HTML, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 3, 24 +solr-8.3.1/server/solr/configsets/_default/conf/params.json, JSON, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 21 +solr-8.3.1/server/solr/configsets/_default/conf/solrconfig.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 296, 0, 0, 0, 0, 976, 98, 1370 +solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/_rest_managed.json, JSON, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2 +solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/_schema_analysis_stopwords_english.json, JSON, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 39 +solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/_schema_analysis_synonyms_english.json, JSON, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 12 +solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/clustering/carrot2/kmeans-attributes.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 6, 1, 20 +solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/clustering/carrot2/lingo-attributes.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 11, 1, 25 +solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/clustering/carrot2/stc-attributes.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 6, 1, 20 +solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/currency.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 0, 0, 0, 0, 19, 4, 68 +solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/elevate.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 37, 3, 43 +solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/params.json, JSON, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 12 +solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/solrconfig.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 410, 0, 0, 0, 0, 1097, 124, 1631 +solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/update-script.js, JavaScript, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 13, 54 +solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/velocity/jquery.autocomplete.css, CSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 9, 6, 49 +solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/velocity/jquery.autocomplete.js, JavaScript, 0, 620, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 76, 764 +solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/velocity/main.css, CSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 185, 0, 0, 0, 0, 0, 0, 0, 0, 47, 232 +solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/xslt/example.xsl, XSL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, 20, 15, 133 +solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/xslt/example_atom.xsl, XSL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 20, 8, 68 +solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/xslt/example_rss.xsl, XSL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 20, 6, 67 +solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/xslt/luke.xsl, XSL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 301, 19, 18, 338 +solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/xslt/updateXml.xsl, XSL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 25, 11, 71 +solr-8.3.1/server/solr/dash/conf/params.json, JSON, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20 +solr-8.3.1/server/solr/dash/conf/schema.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 0, 0, 0, 0, 4, 7, 62 +solr-8.3.1/server/solr/dash/conf/solrconfig.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 270, 0, 0, 0, 0, 962, 97, 1329 +solr-8.3.1/server/solr/dash/core.properties, Properties, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 2, 1, 7 +solr-8.3.1/server/solr/solr.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 25, 11, 57 +solr-8.3.1/server/solr/zoo.cfg, Properties, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 25, 4, 32 +solr-8.3.1/server/tmp/start_3204295554151338130.properties, Properties, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 2, 1, 12 +solr-8.3.1/server/tmp/start_5812170489311981381.properties, Properties, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 2, 1, 12 +solr-8.3.1/server/tmp/start_6476327636763392575.properties, Properties, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 2, 1, 12 +solr-8.3.1/server/tmp/start_7329004517204835686.properties, Properties, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 2, 1, 12 +solr-8.3.1/server/tmp/start_9067375725008958788.properties, Properties, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 2, 1, 12 +src/Utils.ts, TypeScript, 0, 0, 0, 0, 0, 441, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 81, 545 +src/client/ClientRecommender.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 1, 2, 12 +src/client/ClientRecommender.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 320, 0, 0, 0, 0, 0, 0, 61, 44, 425 +src/client/DocServer.ts, TypeScript, 0, 0, 0, 0, 0, 279, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 65, 480 +src/client/Network.ts, TypeScript, 0, 0, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 39 +src/client/apis/GoogleAuthenticationManager.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 3, 19 +src/client/apis/GoogleAuthenticationManager.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 115, 0, 0, 0, 0, 0, 0, 2, 11, 128 +src/client/apis/IBM_Recommender.ts, TypeScript, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 7, 40 +src/client/apis/google_docs/GoogleApiClientUtils.ts, TypeScript, 0, 0, 0, 0, 0, 225, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 27, 261 +src/client/apis/google_docs/GooglePhotosClientUtils.ts, TypeScript, 0, 0, 0, 0, 0, 318, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 364 +src/client/apis/youtube/YoutubeBox.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 105, 0, 0, 0, 0, 0, 5, 16, 126 +src/client/apis/youtube/YoutubeBox.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 274, 0, 0, 0, 0, 0, 0, 48, 40, 362 +src/client/cognitive_services/CognitiveServices.ts, TypeScript, 0, 0, 0, 0, 0, 342, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 57, 409 +src/client/documents/DocumentTypes.ts, TypeScript, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 37 +src/client/documents/Documents.ts, TypeScript, 0, 0, 0, 0, 0, 807, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 141, 87, 1035 +src/client/goldenLayout.d.ts, TypeScript, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3 +src/client/goldenLayout.js, JavaScript, 0, 3084, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1571, 720, 5375 +src/client/util/DictationManager.ts, TypeScript, 0, 0, 0, 0, 0, 312, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 51, 388 +src/client/util/DocumentManager.ts, TypeScript, 0, 0, 0, 0, 0, 207, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 21, 244 +src/client/util/DragManager.ts, TypeScript, 0, 0, 0, 0, 0, 504, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 35, 550 +src/client/util/DropConverter.ts, TypeScript, 0, 0, 0, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 2, 78 +src/client/util/History.ts, TypeScript, 0, 0, 0, 0, 0, 166, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 27, 206 +src/client/util/Import & Export/DirectoryImportBox.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 6 +src/client/util/Import & Export/DirectoryImportBox.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 393, 0, 0, 0, 0, 0, 0, 0, 31, 424 +src/client/util/Import & Export/ImageUtils.ts, TypeScript, 0, 0, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 39 +src/client/util/Import & Export/ImportMetadataEntry.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 132, 0, 0, 0, 0, 0, 0, 0, 17, 149 +src/client/util/InteractionUtils.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 0, 0, 0, 0, 0, 0, 112, 21, 255 +src/client/util/KeyCodes.ts, TypeScript, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, 136 +src/client/util/LinkManager.ts, TypeScript, 0, 0, 0, 0, 0, 161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 23, 214 +src/client/util/ProsemirrorCopy/prompt.js, JavaScript, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 22, 180 +src/client/util/Scripting.ts, TypeScript, 0, 0, 0, 0, 0, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 30, 292 +src/client/util/ScrollBox.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 2, 21 +src/client/util/SearchUtil.ts, TypeScript, 0, 0, 0, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 18, 145 +src/client/util/SelectionManager.ts, TypeScript, 0, 0, 0, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 15, 89 +src/client/util/SerializationHelper.ts, TypeScript, 0, 0, 0, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 143 +src/client/util/SettingsManager.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 111, 0, 0, 0, 0, 0, 0, 25, 136 +src/client/util/SettingsManager.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 114, 0, 0, 0, 0, 0, 0, 0, 17, 131 +src/client/util/SharingManager.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 0, 0, 0, 0, 0, 0, 18, 140 +src/client/util/SharingManager.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 273, 0, 0, 0, 0, 0, 0, 0, 25, 298 +src/client/util/Transform.ts, TypeScript, 0, 0, 0, 0, 0, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 99 +src/client/util/TypedEvent.ts, TypeScript, 0, 0, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 8, 40 +src/client/util/UndoManager.ts, TypeScript, 0, 0, 0, 0, 0, 167, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 27, 195 +src/client/util/clamp.js, JavaScript, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 15 +src/client/util/convertToCSSPTValue.js, JavaScript, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 8, 43 +src/client/util/jsx-decl.d.ts, TypeScript, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2 +src/client/util/request-image-size.js, JavaScript, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 14, 75 +src/client/util/toCSSLineSpacing.js, JavaScript, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 14, 64 +src/client/views/AntimodeMenu.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 0, 0, 1, 6, 42 +src/client/views/AntimodeMenu.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 121, 0, 0, 0, 0, 0, 0, 14, 22, 157 +src/client/views/ContextMenu.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 0, 0, 0, 0, 0, 17, 14, 161 +src/client/views/ContextMenu.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 258, 0, 0, 0, 0, 0, 0, 3, 33, 294 +src/client/views/ContextMenuItem.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 107, 0, 0, 0, 0, 0, 0, 0, 10, 117 +src/client/views/DictationOverlay.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 7, 71 +src/client/views/DocComponent.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 87, 0, 0, 0, 0, 0, 0, 20, 15, 122 +src/client/views/DocumentButtonBar.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 89, 0, 0, 0, 0, 0, 0, 16, 105 +src/client/views/DocumentButtonBar.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 284, 0, 0, 0, 0, 0, 0, 4, 27, 315 +src/client/views/DocumentDecorations.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 319, 0, 0, 0, 0, 0, 0, 46, 365 +src/client/views/DocumentDecorations.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 479, 0, 0, 0, 0, 0, 0, 2, 26, 507 +src/client/views/EditableView.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 3, 25 +src/client/views/EditableView.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 149, 0, 0, 0, 0, 0, 0, 19, 16, 184 +src/client/views/GestureOverlay.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 8, 64 +src/client/views/GestureOverlay.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 711, 0, 0, 0, 0, 0, 0, 45, 67, 823 +src/client/views/GlobalKeyHandler.ts, TypeScript, 0, 0, 0, 0, 0, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 27, 269 +src/client/views/InkingControl.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 0, 0, 0, 4, 0, 131 +src/client/views/InkingControl.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 78, 0, 0, 0, 0, 0, 0, 3, 10, 91 +src/client/views/InkingStroke.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 7 +src/client/views/InkingStroke.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 5, 68 +src/client/views/KeyphraseQueryView.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 1, 8 +src/client/views/KeyphraseQueryView.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 2, 3, 35 +src/client/views/Main.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 0, 0, 0, 0, 0, 8, 10, 69 +src/client/views/Main.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 1, 2, 25 +src/client/views/MainView.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 138, 0, 0, 0, 0, 0, 1, 21, 160 +src/client/views/MainView.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 553, 0, 0, 0, 0, 0, 0, 13, 36, 602 +src/client/views/MainViewModal.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 1, 25 +src/client/views/MainViewModal.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 5, 44 +src/client/views/MainViewNotifs.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 1, 18 +src/client/views/MainViewNotifs.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 4, 33 +src/client/views/MetadataEntryMenu.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79, 0, 0, 0, 0, 0, 0, 14, 93 +src/client/views/MetadataEntryMenu.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 207, 0, 0, 0, 0, 0, 0, 0, 16, 223 +src/client/views/OCRUtils.ts, TypeScript, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 8 +src/client/views/OverlayView.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 6, 47 +src/client/views/OverlayView.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 194, 0, 0, 0, 0, 0, 0, 4, 19, 217 +src/client/views/Palette.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 4, 30 +src/client/views/Palette.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 5, 70 +src/client/views/PreviewCursor.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 1, 10 +src/client/views/PreviewCursor.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 115, 0, 0, 0, 0, 0, 0, 8, 9, 132 +src/client/views/RecommendationsBox.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 10, 8, 70 +src/client/views/RecommendationsBox.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, 0, 0, 0, 0, 0, 0, 67, 17, 200 +src/client/views/ScriptBox.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 2, 17 +src/client/views/ScriptBox.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 112, 0, 0, 0, 0, 0, 0, 2, 12, 126 +src/client/views/ScriptingRepl.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 9, 51 +src/client/views/ScriptingRepl.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 0, 0, 0, 0, 0, 1, 24, 245 +src/client/views/SearchDocBox.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 359, 0, 0, 0, 0, 0, 0, 17, 55, 431 +src/client/views/TemplateMenu.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 0, 0, 0, 0, 0, 0, 5, 51 +src/client/views/TemplateMenu.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 167, 0, 0, 0, 0, 0, 0, 1, 14, 182 +src/client/views/Templates.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 8, 42 +src/client/views/TouchScrollableMenu.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 7, 59 +src/client/views/Touchable.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 0, 0, 0, 0, 0, 0, 28, 39, 239 +src/client/views/_nodeModuleOverrides.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 9, 4, 22 +src/client/views/animationtimeline/Keyframe.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 0, 0, 0, 0, 0, 5, 17, 105 +src/client/views/animationtimeline/Keyframe.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 468, 0, 0, 0, 0, 0, 0, 50, 42, 560 +src/client/views/animationtimeline/Timeline.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 264, 0, 0, 0, 0, 0, 14, 44, 322 +src/client/views/animationtimeline/Timeline.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 467, 0, 0, 0, 0, 0, 0, 97, 58, 622 +src/client/views/animationtimeline/TimelineMenu.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 75, 0, 0, 0, 0, 0, 2, 17, 94 +src/client/views/animationtimeline/TimelineMenu.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 10, 78 +src/client/views/animationtimeline/TimelineOverview.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 89, 0, 0, 0, 0, 0, 6, 12, 107 +src/client/views/animationtimeline/TimelineOverview.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 155, 0, 0, 0, 0, 0, 0, 0, 27, 182 +src/client/views/animationtimeline/Track.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 2, 15 +src/client/views/animationtimeline/Track.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 284, 0, 0, 0, 0, 0, 0, 63, 33, 380 +src/client/views/collections/CollectionCarouselView.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 1, 38 +src/client/views/collections/CollectionCarouselView.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 110, 0, 0, 0, 0, 0, 0, 1, 10, 121 +src/client/views/collections/CollectionDockingView.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 391, 0, 0, 0, 0, 0, 7, 60, 458 +src/client/views/collections/CollectionDockingView.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 707, 0, 0, 0, 0, 0, 0, 61, 65, 833 +src/client/views/collections/CollectionLinearView.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 10, 78 +src/client/views/collections/CollectionLinearView.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 125, 0, 0, 0, 0, 0, 0, 1, 9, 135 +src/client/views/collections/CollectionMapView.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 0, 0, 0, 3, 30 +src/client/views/collections/CollectionMapView.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 235, 0, 0, 0, 0, 0, 0, 10, 18, 263 +src/client/views/collections/CollectionMasonryViewFieldRow.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 308, 0, 0, 0, 0, 0, 0, 0, 24, 332 +src/client/views/collections/CollectionPileView.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 1, 9 +src/client/views/collections/CollectionPileView.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 112, 0, 0, 0, 0, 0, 0, 5, 11, 128 +src/client/views/collections/CollectionSchemaCells.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 274, 0, 0, 0, 0, 0, 0, 17, 38, 329 +src/client/views/collections/CollectionSchemaHeaders.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 318, 0, 0, 0, 0, 0, 0, 5, 41, 364 +src/client/views/collections/CollectionSchemaMovableTableHOC.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, 27, 243 +src/client/views/collections/CollectionSchemaView.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 406, 0, 0, 0, 0, 0, 4, 88, 498 +src/client/views/collections/CollectionSchemaView.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 651, 0, 0, 0, 0, 0, 0, 20, 82, 753 +src/client/views/collections/CollectionStackingView.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 353, 0, 0, 0, 0, 0, 1, 50, 404 +src/client/views/collections/CollectionStackingView.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 430, 0, 0, 0, 0, 0, 0, 5, 25, 460 +src/client/views/collections/CollectionStackingViewFieldColumn.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 367, 0, 0, 0, 0, 0, 0, 0, 27, 394 +src/client/views/collections/CollectionStaffView.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 1, 13 +src/client/views/collections/CollectionStaffView.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 7, 53 +src/client/views/collections/CollectionSubView.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 390, 0, 0, 0, 0, 0, 0, 7, 25, 422 +src/client/views/collections/CollectionTimeView.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 13, 93 +src/client/views/collections/CollectionTimeView.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 177, 0, 0, 0, 0, 0, 0, 0, 15, 192 +src/client/views/collections/CollectionTreeView.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 125, 0, 0, 0, 0, 0, 4, 23, 152 +src/client/views/collections/CollectionTreeView.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 801, 0, 0, 0, 0, 0, 0, 19, 40, 860 +src/client/views/collections/CollectionView.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70, 0, 0, 0, 0, 0, 0, 8, 78 +src/client/views/collections/CollectionView.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 457, 0, 0, 0, 0, 0, 0, 13, 34, 504 +src/client/views/collections/CollectionViewChromes.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 308, 0, 0, 0, 0, 0, 4, 45, 357 +src/client/views/collections/CollectionViewChromes.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 393, 0, 0, 0, 0, 0, 0, 67, 47, 507 +src/client/views/collections/KeyRestrictionRow.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 2, 4, 55 +src/client/views/collections/ParentDocumentSelector.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0, 0, 0, 0, 2, 56 +src/client/views/collections/ParentDocumentSelector.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 11, 131 +src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 422, 0, 0, 0, 0, 0, 0, 10, 27, 459 +src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 1, 20 +src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 110, 0, 0, 0, 0, 0, 0, 5, 4, 119 +src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 11 +src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 2, 46 +src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 1, 3, 24 +src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 12, 79 +src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 9, 17, 121 +src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1186, 0, 0, 0, 0, 0, 0, 47, 97, 1330 +src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 5, 57 +src/client/views/collections/collectionFreeForm/MarqueeView.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 2, 32 +src/client/views/collections/collectionFreeForm/MarqueeView.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 484, 0, 0, 0, 0, 0, 0, 105, 33, 622 +src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 6, 34 +src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 202, 0, 0, 0, 0, 0, 0, 72, 23, 297 +src/client/views/collections/collectionMulticolumn/CollectionMultirowView.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 6, 35 +src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 204, 0, 0, 0, 0, 0, 0, 72, 22, 298 +src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 9, 103 +src/client/views/collections/collectionMulticolumn/MulticolumnWidthLabel.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 5, 56 +src/client/views/collections/collectionMulticolumn/MultirowHeightLabel.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 5, 56 +src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 9, 101 +src/client/views/globalCssVariables.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 0, 0, 0, 0, 10, 3, 43 +src/client/views/globalCssVariables.scss.d.ts, TypeScript, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 11 +src/client/views/linking/LinkEditor.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 124, 0, 0, 0, 0, 0, 1, 25, 150 +src/client/views/linking/LinkEditor.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 252, 0, 0, 0, 0, 0, 0, 7, 50, 309 +src/client/views/linking/LinkMenu.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 13, 53 +src/client/views/linking/LinkMenu.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 1, 10, 76 +src/client/views/linking/LinkMenuGroup.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 10, 94 +src/client/views/linking/LinkMenuItem.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 75, 0, 0, 0, 0, 0, 1, 11, 87 +src/client/views/linking/LinkMenuItem.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 107, 0, 0, 0, 0, 0, 0, 0, 19, 126 +src/client/views/nodes/AudioBox.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 146, 0, 0, 0, 0, 0, 0, 0, 146 +src/client/views/nodes/AudioBox.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 261, 0, 0, 0, 0, 0, 0, 2, 24, 287 +src/client/views/nodes/CollectionFreeFormDocumentView.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 8 +src/client/views/nodes/CollectionFreeFormDocumentView.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 124, 0, 0, 0, 0, 0, 0, 0, 7, 131 +src/client/views/nodes/ColorBox.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 1, 23 +src/client/views/nodes/ColorBox.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 4, 32 +src/client/views/nodes/ContentFittingDocumentView.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 4, 24 +src/client/views/nodes/ContentFittingDocumentView.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 117, 0, 0, 0, 0, 0, 0, 0, 7, 124 +src/client/views/nodes/DocumentBox.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 14 +src/client/views/nodes/DocumentBox.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 154, 0, 0, 0, 0, 0, 0, 0, 4, 158 +src/client/views/nodes/DocumentContentsView.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 183, 0, 0, 0, 0, 0, 0, 10, 17, 210 +src/client/views/nodes/DocumentIcon.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 5, 65 +src/client/views/nodes/DocumentView.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 110, 0, 0, 0, 0, 0, 1, 15, 126 +src/client/views/nodes/DocumentView.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1041, 0, 0, 0, 0, 0, 0, 54, 94, 1189 +src/client/views/nodes/FaceRectangle.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 4, 29 +src/client/views/nodes/FaceRectangles.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 5, 46 +src/client/views/nodes/FieldTextBox.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 3, 15 +src/client/views/nodes/FieldView.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 89, 0, 0, 0, 0, 0, 0, 43, 4, 136 +src/client/views/nodes/FontIconBox.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 2, 27 +src/client/views/nodes/FontIconBox.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 5, 63 +src/client/views/nodes/ImageBox.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 135, 0, 0, 0, 0, 0, 0, 17, 152 +src/client/views/nodes/ImageBox.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 430, 0, 0, 0, 0, 0, 0, 10, 35, 475 +src/client/views/nodes/KeyValueBox.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120, 0, 0, 0, 0, 0, 0, 3, 123 +src/client/views/nodes/KeyValueBox.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 244, 0, 0, 0, 0, 0, 0, 1, 26, 271 +src/client/views/nodes/KeyValuePair.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 0, 0, 1, 4, 60 +src/client/views/nodes/KeyValuePair.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 125, 0, 0, 0, 0, 0, 0, 2, 8, 135 +src/client/views/nodes/LabelBox.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 0, 0, 0, 0, 0, 4, 35 +src/client/views/nodes/LabelBox.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 86, 0, 0, 0, 0, 0, 0, 1, 9, 96 +src/client/views/nodes/LinkAnchorBox.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 0, 0, 0, 2, 29 +src/client/views/nodes/LinkAnchorBox.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 141, 0, 0, 0, 0, 0, 0, 0, 9, 150 +src/client/views/nodes/LinkBox.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3 +src/client/views/nodes/LinkBox.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 3, 36 +src/client/views/nodes/PDFBox.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 0, 0, 0, 0, 0, 0, 19, 219 +src/client/views/nodes/PDFBox.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 246, 0, 0, 0, 0, 0, 0, 0, 19, 265 +src/client/views/nodes/PresBox.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 1, 53 +src/client/views/nodes/PresBox.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 268, 0, 0, 0, 0, 0, 0, 31, 32, 331 +src/client/views/nodes/QueryBox.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 5 +src/client/views/nodes/QueryBox.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 4, 41 +src/client/views/nodes/RadialMenu.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 0, 0, 0, 0, 0, 3, 7, 70 +src/client/views/nodes/RadialMenu.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 174, 0, 0, 0, 0, 0, 0, 26, 36, 236 +src/client/views/nodes/RadialMenuItem.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 16, 117 +src/client/views/nodes/ScreenshotBox.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 6, 5, 51 +src/client/views/nodes/ScreenshotBox.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 174, 0, 0, 0, 0, 0, 0, 2, 18, 194 +src/client/views/nodes/ScriptingBox.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 3, 36 +src/client/views/nodes/ScriptingBox.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 12, 99 +src/client/views/nodes/SliderBox-components.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 0, 0, 0, 0, 0, 12, 25, 257 +src/client/views/nodes/SliderBox-tooltip.css, CSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 3, 33 +src/client/views/nodes/SliderBox.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 7 +src/client/views/nodes/SliderBox.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 117, 0, 0, 0, 0, 0, 0, 0, 8, 125 +src/client/views/nodes/VideoBox.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 0, 0, 0, 0, 3, 6, 74 +src/client/views/nodes/VideoBox.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 343, 0, 0, 0, 0, 0, 0, 2, 34, 379 +src/client/views/nodes/WebBox.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 109, 0, 0, 0, 0, 0, 0, 18, 127 +src/client/views/nodes/WebBox.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 345, 0, 0, 0, 0, 0, 0, 15, 35, 395 +src/client/views/nodes/formattedText/DashDocCommentView.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 13, 95 +src/client/views/nodes/formattedText/DashDocView.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 0, 0, 0, 0, 0, 0, 9, 37, 269 +src/client/views/nodes/formattedText/DashFieldView.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 2, 36 +src/client/views/nodes/formattedText/DashFieldView.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 178, 0, 0, 0, 0, 0, 0, 13, 20, 211 +src/client/views/nodes/formattedText/FootnoteView.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 131, 0, 0, 0, 0, 0, 0, 13, 19, 163 +src/client/views/nodes/formattedText/FormattedTextBox.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 0, 0, 0, 0, 11, 34, 265 +src/client/views/nodes/formattedText/FormattedTextBox.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1169, 0, 0, 0, 0, 0, 0, 68, 93, 1330 +src/client/views/nodes/formattedText/FormattedTextBoxComment.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 33 +src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 218, 0, 0, 0, 0, 0, 0, 11, 8, 237 +src/client/views/nodes/formattedText/ImageResizeView.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 25, 138 +src/client/views/nodes/formattedText/ParagraphNodeSpec.ts, TypeScript, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 26, 143 +src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts, TypeScript, 0, 0, 0, 0, 0, 231, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 242 +src/client/views/nodes/formattedText/RichTextMenu.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 2, 19, 121 +src/client/views/nodes/formattedText/RichTextMenu.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 754, 0, 0, 0, 0, 0, 0, 12, 109, 875 +src/client/views/nodes/formattedText/RichTextRules.ts, TypeScript, 0, 0, 0, 0, 0, 308, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 5, 320 +src/client/views/nodes/formattedText/RichTextSchema.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 465, 0, 0, 0, 0, 0, 0, 33, 39, 537 +src/client/views/nodes/formattedText/SummaryView.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 14, 81 +src/client/views/nodes/formattedText/TooltipTextMenu.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 306, 0, 0, 0, 0, 0, 6, 61, 373 +src/client/views/nodes/formattedText/marks_rts.ts, TypeScript, 0, 0, 0, 0, 0, 259, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 23, 297 +src/client/views/nodes/formattedText/nodes_rts.ts, TypeScript, 0, 0, 0, 0, 0, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 19, 264 +src/client/views/nodes/formattedText/prosemirrorPatches.js, JavaScript, 0, 118, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 9, 139 +src/client/views/nodes/formattedText/schema_rts.ts, TypeScript, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 6, 26 +src/client/views/pdf/Annotation.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 6 +src/client/views/pdf/Annotation.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 114, 0, 0, 0, 0, 0, 0, 0, 16, 130 +src/client/views/pdf/PDFMenu.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 6 +src/client/views/pdf/PDFMenu.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 102, 0, 0, 0, 0, 0, 0, 0, 21, 123 +src/client/views/pdf/PDFViewer.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 74, 0, 0, 0, 0, 0, 4, 10, 88 +src/client/views/pdf/PDFViewer.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 662, 0, 0, 0, 0, 0, 0, 23, 46, 731 +src/client/views/presentationview/PresElementBox.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 93, 0, 0, 0, 0, 0, 0, 10, 103 +src/client/views/presentationview/PresElementBox.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 179, 0, 0, 0, 0, 0, 0, 31, 14, 224 +src/client/views/search/CheckBox.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 0, 0, 0, 0, 0, 1, 8, 59 +src/client/views/search/CheckBox.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 74, 15, 131 +src/client/views/search/CollectionFilters.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 3, 20 +src/client/views/search/CollectionFilters.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 14, 83 +src/client/views/search/FieldFilters.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 1, 1, 12 +src/client/views/search/FieldFilters.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 7, 41 +src/client/views/search/FilterBox.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 0, 0, 0, 0, 0, 0, 25, 178 +src/client/views/search/FilterBox.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 354, 0, 0, 0, 0, 0, 0, 24, 54, 432 +src/client/views/search/IconBar.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 1, 10 +src/client/views/search/IconBar.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 0, 0, 0, 1, 17, 87 +src/client/views/search/IconButton.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 0, 0, 0, 0, 0, 1, 6, 53 +src/client/views/search/IconButton.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 170, 0, 0, 0, 0, 0, 0, 2, 19, 191 +src/client/views/search/NaviconButton.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, 0, 0, 0, 0, 0, 0, 11, 69 +src/client/views/search/NaviconButton.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 5, 37 +src/client/views/search/SearchBox.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 203, 0, 0, 0, 0, 0, 82, 51, 336 +src/client/views/search/SearchBox.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 530, 0, 0, 0, 0, 0, 0, 47, 94, 671 +src/client/views/search/SearchItem.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 138, 0, 0, 0, 0, 0, 0, 25, 163 +src/client/views/search/SearchItem.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 272, 0, 0, 0, 0, 0, 0, 2, 29, 303 +src/client/views/search/SelectorContextMenu.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 1, 3, 16 +src/client/views/search/ToggleBar.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 0, 0, 2, 4, 41 +src/client/views/search/ToggleBar.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 9, 86 +src/client/views/webcam/DashWebRTCVideo.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70, 0, 0, 0, 0, 0, 4, 9, 83 +src/client/views/webcam/DashWebRTCVideo.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, 0, 0, 0, 6, 16, 89 +src/client/views/webcam/WebCamLogic.js, JavaScript, 0, 234, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 51, 292 +src/debug/Repl.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 7, 66 +src/debug/Test.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 2, 14 +src/debug/Viewer.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 173, 0, 0, 0, 0, 0, 0, 0, 19, 192 +src/extensions/ArrayExtensions.ts, TypeScript, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 6, 37 +src/extensions/General/Extensions.ts, TypeScript, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 9 +src/extensions/General/ExtensionsTypings.ts, TypeScript, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 8 +src/extensions/StringExtensions.ts, TypeScript, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 17 +src/mobile/ImageUpload.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 4, 34 +src/mobile/ImageUpload.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 78, 0, 0, 0, 0, 0, 0, 41, 12, 131 +src/mobile/InkControls.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 +src/mobile/MobileInkOverlay.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 1, 5, 39 +src/mobile/MobileInkOverlay.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 162, 0, 0, 0, 0, 0, 0, 3, 26, 191 +src/mobile/MobileInterface.scss, SCSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 2, 19 +src/mobile/MobileInterface.tsx, TypeScript React, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 297, 0, 0, 0, 0, 0, 0, 15, 32, 344 +src/new_fields/CursorField.ts, TypeScript, 0, 0, 0, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 66 +src/new_fields/DateField.ts, TypeScript, 0, 0, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 37 +src/new_fields/Doc.ts, TypeScript, 0, 0, 0, 0, 0, 897, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 76, 1058 +src/new_fields/FieldSymbols.ts, TypeScript, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 13 +src/new_fields/HtmlField.ts, TypeScript, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 27 +src/new_fields/IconField.ts, TypeScript, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 27 +src/new_fields/InkField.ts, TypeScript, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 51 +src/new_fields/List.ts, TypeScript, 0, 0, 0, 0, 0, 244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 20, 302 +src/new_fields/ListSpec.ts, TypeScript, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 +src/new_fields/ObjectField.ts, TypeScript, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 20 +src/new_fields/PresField.ts, TypeScript, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 6 +src/new_fields/Proxy.ts, TypeScript, 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 14, 111 +src/new_fields/RefField.ts, TypeScript, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 22 +src/new_fields/RichTextField.ts, TypeScript, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 41 +src/new_fields/RichTextUtils.ts, TypeScript, 0, 0, 0, 0, 0, 455, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 56, 519 +src/new_fields/Schema.ts, TypeScript, 0, 0, 0, 0, 0, 107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 8, 120 +src/new_fields/SchemaHeaderField.ts, TypeScript, 0, 0, 0, 0, 0, 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 14, 122 +src/new_fields/ScriptField.ts, TypeScript, 0, 0, 0, 0, 0, 137, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 19, 177 +src/new_fields/Types.ts, TypeScript, 0, 0, 0, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 17, 108 +src/new_fields/URLField.ts, TypeScript, 0, 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 54 +src/new_fields/documentSchemas.ts, TypeScript, 0, 0, 0, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 93 +src/new_fields/util.ts, TypeScript, 0, 0, 0, 0, 0, 176, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 15, 194 +src/pen-gestures/GestureUtils.ts, TypeScript, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 46 +src/pen-gestures/ndollar.ts, TypeScript, 0, 0, 0, 0, 0, 356, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 22, 550 +src/scraping/acm/.gitignore, Ignore, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2 +src/scraping/acm/debug.log, log, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 1, 39 +src/scraping/acm/index.js, JavaScript, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 185, 13, 280 +src/scraping/acm/package.json, JSON, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 18 +src/scraping/buxton/.idea/buxton.iml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 8 +src/scraping/buxton/.idea/inspectionProfiles/profiles_settings.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 6 +src/scraping/buxton/.idea/misc.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 4 +src/scraping/buxton/.idea/modules.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 8 +src/scraping/buxton/.idea/vcs.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 6 +src/scraping/buxton/.idea/workspace.xml, XML, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 173, 0, 0, 0, 0, 0, 0, 173 +src/scraping/buxton/final/BuxtonImporter.ts, TypeScript, 0, 0, 0, 0, 0, 228, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 142, 26, 396 +src/scraping/buxton/jsonifier.py, Python, 0, 0, 0, 0, 183, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 48, 232 +src/scraping/buxton/narratives.py, Python, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 9, 39 +src/scraping/buxton/narratives/chord_keyboards.json, JSON, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39 +src/scraping/buxton/scraper.py, Python, 0, 0, 0, 0, 350, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 78, 433 +src/server/ActionUtilities.ts, TypeScript, 0, 0, 0, 0, 0, 136, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 23, 160 +src/server/ApiManagers/ApiManager.ts, TypeScript, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 11 +src/server/ApiManagers/DeleteManager.ts, TypeScript, 0, 0, 0, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 82 +src/server/ApiManagers/DownloadManager.ts, TypeScript, 0, 0, 0, 0, 0, 173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 16, 269 +src/server/ApiManagers/GeneralGoogleManager.ts, TypeScript, 0, 0, 0, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 61 +src/server/ApiManagers/GooglePhotosManager.ts, TypeScript, 0, 0, 0, 0, 0, 190, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 119, 22, 331 +src/server/ApiManagers/PDFManager.ts, TypeScript, 0, 0, 0, 0, 0, 103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 115 +src/server/ApiManagers/SearchManager.ts, TypeScript, 0, 0, 0, 0, 0, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 215 +src/server/ApiManagers/SessionManager.ts, TypeScript, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 67 +src/server/ApiManagers/UploadManager.ts, TypeScript, 0, 0, 0, 0, 0, 226, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 20, 247 +src/server/ApiManagers/UserManager.ts, TypeScript, 0, 0, 0, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 21, 126 +src/server/ApiManagers/UtilManager.ts, TypeScript, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 10, 74 +src/server/Client.ts, TypeScript, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 11 +src/server/DashSession/DashSessionAgent.ts, TypeScript, 0, 0, 0, 0, 0, 155, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 23, 230 +src/server/DashSession/Session/agents/applied_session_agent.ts, TypeScript, 0, 0, 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 9, 58 +src/server/DashSession/Session/agents/monitor.ts, TypeScript, 0, 0, 0, 0, 0, 213, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 26, 298 +src/server/DashSession/Session/agents/process_message_router.ts, TypeScript, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 7, 41 +src/server/DashSession/Session/agents/promisified_ipc_manager.ts, TypeScript, 0, 0, 0, 0, 0, 106, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 15, 173 +src/server/DashSession/Session/agents/server_worker.ts, TypeScript, 0, 0, 0, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 15, 160 +src/server/DashSession/Session/utilities/repl.ts, TypeScript, 0, 0, 0, 0, 0, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 128 +src/server/DashSession/Session/utilities/session_config.ts, TypeScript, 0, 0, 0, 0, 0, 119, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 129 +src/server/DashSession/Session/utilities/utilities.ts, TypeScript, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 5, 37 +src/server/DashUploadUtils.ts, TypeScript, 0, 0, 0, 0, 0, 285, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 30, 367 +src/server/GarbageCollector.ts, TypeScript, 0, 0, 0, 0, 0, 138, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 11, 151 +src/server/IDatabase.ts, TypeScript, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 25 +src/server/MemoryDatabase.ts, TypeScript, 0, 0, 0, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 101 +src/server/Message.ts, TypeScript, 0, 0, 0, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 104 +src/server/PdfTypes.ts, TypeScript, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 21 +src/server/ProcessFactory.ts, TypeScript, 0, 0, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 44 +src/server/Recommender.ts, TypeScript, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120, 18, 138 +src/server/RouteManager.ts, TypeScript, 0, 0, 0, 0, 0, 187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 19, 210 +src/server/RouteSubscriber.ts, TypeScript, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 26 +src/server/Search.ts, TypeScript, 0, 0, 0, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 8, 81 +src/server/SharedMediaTypes.ts, TypeScript, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 51 +src/server/Websocket/Websocket.ts, TypeScript, 0, 0, 0, 0, 0, 263, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 46, 314 +src/server/apis/google/GoogleApiServerUtils.ts, TypeScript, 0, 0, 0, 0, 0, 172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 168, 25, 365 +src/server/apis/google/SharedTypes.ts, TypeScript, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 21 +src/server/apis/youtube/youtubeApiSample.d.ts, TypeScript, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 +src/server/apis/youtube/youtubeApiSample.js, JavaScript, 0, 135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 14, 179 +src/server/authentication/config/passport.ts, TypeScript, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 29 +src/server/authentication/controllers/user_controller.ts, TypeScript, 0, 0, 0, 0, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 25, 268 +src/server/authentication/models/current_user_utils.ts, TypeScript, 0, 0, 0, 0, 0, 586, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 57, 673 +src/server/authentication/models/user_model.ts, TypeScript, 0, 0, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 14, 86 +src/server/credentials/CredentialsLoader.ts, TypeScript, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 30 +src/server/credentials/google_project_credentials.json, JSON, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11 +src/server/database.ts, TypeScript, 0, 0, 0, 0, 0, 312, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 350 +src/server/downsize.ts, TypeScript, 0, 0, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 1, 40 +src/server/index.ts, TypeScript, 0, 0, 0, 0, 0, 107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 16, 159 +src/server/remapUrl.ts, TypeScript, 0, 0, 0, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 6, 63 +src/server/server_Initialization.ts, TypeScript, 0, 0, 0, 0, 0, 138, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 24, 168 +src/server/slides.json, JSON, 0, 0, 10820, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10820 +src/server/updateProtos.ts, TypeScript, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 14 +src/typings/index.d.ts, TypeScript, 0, 0, 0, 0, 0, 219, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, 38, 329 +test/test.ts, TypeScript, 0, 0, 0, 0, 0, 141, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 161 +tsconfig.json, JSON, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 26 +tslint.json, JSON, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 1, 63 +views/forgot.pug, Pug, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 22 +views/layout.pug, Pug, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 14 +views/login.pug, Pug, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 26 +views/reset.pug, Pug, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 22 +views/signup.pug, Pug, 0, 0, 0, 0, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 27 +views/stylesheets/authentication.css, CSS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 185, 0, 0, 0, 0, 0, 0, 0, 4, 34, 223 +views/user_activity.pug, Pug, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 19 +webpack.config.js, JavaScript, 0, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 121 +Total, -, 6, 89717, 50401, 1893, 632, 15246, 2883, 119, 538, 5982, 30250, 7726, 17257, 161, 2, 38, 2060, 32987, 15880, 273778 \ No newline at end of file diff --git a/.VSCodeCounter/results.md b/.VSCodeCounter/results.md new file mode 100644 index 000000000..3265d800b --- /dev/null +++ b/.VSCodeCounter/results.md @@ -0,0 +1,164 @@ +# Summary + +Date : 2020-04-30 14:40:17 + +Directory /Users/bcz/Documents/GitHub/Dash-Web + +Total : 646 files, 224911 codes, 32987 comments, 15880 blanks, all 273778 lines + +[details](details.md) + +## Languages +| language | files | code | comment | blank | total | +| :--- | ---: | ---: | ---: | ---: | ---: | +| JavaScript | 69 | 89,717 | 18,520 | 5,866 | 114,103 | +| JSON | 20 | 50,401 | 37 | 14 | 50,452 | +| TypeScript React | 140 | 30,250 | 1,878 | 3,154 | 35,282 | +| XML | 73 | 17,257 | 8,281 | 992 | 26,530 | +| TypeScript | 115 | 15,246 | 2,095 | 1,958 | 19,299 | +| SCSS | 104 | 7,726 | 255 | 1,136 | 9,117 | +| CSS | 30 | 5,982 | 549 | 1,095 | 7,626 | +| HTML | 34 | 2,883 | 431 | 848 | 4,162 | +| XSL | 20 | 2,060 | 416 | 232 | 2,708 | +| Batch | 5 | 1,893 | 184 | 273 | 2,350 | +| Python | 5 | 632 | 49 | 148 | 829 | +| Shell Script | 6 | 538 | 248 | 120 | 906 | +| Properties | 16 | 161 | 43 | 30 | 234 | +| Pug | 6 | 119 | 1 | 10 | 130 | +| log | 1 | 38 | 0 | 1 | 39 | +| Markdown | 1 | 6 | 0 | 3 | 9 | +| Ignore | 1 | 2 | 0 | 0 | 2 | + +## Directories +| path | files | code | comment | blank | total | +| :--- | ---: | ---: | ---: | ---: | ---: | +| . | 646 | 224,911 | 32,987 | 15,880 | 273,778 | +| build | 1 | 9 | 0 | 3 | 12 | +| deploy | 8 | 55,744 | 174 | 704 | 56,622 | +| deploy/assets | 2 | 55,677 | 174 | 686 | 56,537 | +| deploy/debug | 3 | 32 | 0 | 9 | 41 | +| deploy/mobile | 2 | 22 | 0 | 6 | 28 | +| solr-8.3.1 | 236 | 80,866 | 26,654 | 7,861 | 115,381 | +| solr-8.3.1/bin | 5 | 2,118 | 392 | 311 | 2,821 | +| solr-8.3.1/contrib | 3 | 6,281 | 63 | 37 | 6,381 | +| solr-8.3.1/contrib/prometheus-exporter | 3 | 6,281 | 63 | 37 | 6,381 | +| solr-8.3.1/contrib/prometheus-exporter/bin | 1 | 82 | 0 | 26 | 108 | +| solr-8.3.1/contrib/prometheus-exporter/conf | 2 | 6,199 | 63 | 11 | 6,273 | +| solr-8.3.1/docs | 2 | 59 | 0 | 2 | 61 | +| solr-8.3.1/docs/images | 1 | 39 | 0 | 1 | 40 | +| solr-8.3.1/example | 82 | 32,009 | 5,063 | 942 | 38,014 | +| solr-8.3.1/example/example-DIH | 49 | 2,848 | 3,605 | 603 | 7,056 | +| solr-8.3.1/example/example-DIH/solr | 49 | 2,848 | 3,605 | 603 | 7,056 | +| solr-8.3.1/example/example-DIH/solr/atom | 3 | 41 | 43 | 19 | 103 | +| solr-8.3.1/example/example-DIH/solr/atom/conf | 2 | 41 | 43 | 17 | 101 | +| solr-8.3.1/example/example-DIH/solr/db | 14 | 935 | 1,167 | 191 | 2,293 | +| solr-8.3.1/example/example-DIH/solr/db/conf | 13 | 935 | 1,167 | 189 | 2,291 | +| solr-8.3.1/example/example-DIH/solr/db/conf/clustering | 3 | 39 | 23 | 3 | 65 | +| solr-8.3.1/example/example-DIH/solr/db/conf/clustering/carrot2 | 3 | 39 | 23 | 3 | 65 | +| solr-8.3.1/example/example-DIH/solr/db/conf/xslt | 5 | 515 | 104 | 58 | 677 | +| solr-8.3.1/example/example-DIH/solr/mail | 14 | 919 | 1,171 | 189 | 2,279 | +| solr-8.3.1/example/example-DIH/solr/mail/conf | 13 | 919 | 1,171 | 187 | 2,277 | +| solr-8.3.1/example/example-DIH/solr/mail/conf/clustering | 3 | 39 | 23 | 3 | 65 | +| solr-8.3.1/example/example-DIH/solr/mail/conf/clustering/carrot2 | 3 | 39 | 23 | 3 | 65 | +| solr-8.3.1/example/example-DIH/solr/mail/conf/xslt | 5 | 515 | 104 | 58 | 677 | +| solr-8.3.1/example/example-DIH/solr/solr | 14 | 917 | 1,183 | 187 | 2,287 | +| solr-8.3.1/example/example-DIH/solr/solr/conf | 13 | 917 | 1,183 | 185 | 2,285 | +| solr-8.3.1/example/example-DIH/solr/solr/conf/clustering | 3 | 39 | 23 | 3 | 65 | +| solr-8.3.1/example/example-DIH/solr/solr/conf/clustering/carrot2 | 3 | 39 | 23 | 3 | 65 | +| solr-8.3.1/example/example-DIH/solr/solr/conf/xslt | 5 | 515 | 104 | 58 | 677 | +| solr-8.3.1/example/example-DIH/solr/tika | 3 | 34 | 41 | 16 | 91 | +| solr-8.3.1/example/example-DIH/solr/tika/conf | 2 | 34 | 41 | 14 | 89 | +| solr-8.3.1/example/exampledocs | 17 | 513 | 281 | 75 | 869 | +| solr-8.3.1/example/files | 13 | 1,298 | 1,153 | 250 | 2,701 | +| solr-8.3.1/example/files/browse-resources | 3 | 108 | 6 | 9 | 123 | +| solr-8.3.1/example/files/browse-resources/velocity | 3 | 108 | 6 | 9 | 123 | +| solr-8.3.1/example/files/conf | 10 | 1,190 | 1,147 | 241 | 2,578 | +| solr-8.3.1/example/files/conf/velocity | 5 | 730 | 99 | 108 | 937 | +| solr-8.3.1/example/files/conf/velocity/js | 3 | 730 | 99 | 104 | 933 | +| solr-8.3.1/example/films | 3 | 27,350 | 24 | 14 | 27,388 | +| solr-8.3.1/server | 144 | 40,399 | 21,136 | 6,569 | 68,104 | +| solr-8.3.1/server/contexts | 1 | 8 | 0 | 1 | 9 | +| solr-8.3.1/server/etc | 6 | 528 | 400 | 59 | 987 | +| solr-8.3.1/server/resources | 3 | 74 | 123 | 16 | 213 | +| solr-8.3.1/server/scripts | 3 | 172 | 19 | 39 | 230 | +| solr-8.3.1/server/scripts/cloud-scripts | 3 | 172 | 19 | 39 | 230 | +| solr-8.3.1/server/solr | 27 | 2,612 | 3,377 | 557 | 6,546 | +| solr-8.3.1/server/solr-webapp | 99 | 36,960 | 17,207 | 5,892 | 60,059 | +| solr-8.3.1/server/solr-webapp/webapp | 99 | 36,960 | 17,207 | 5,892 | 60,059 | +| solr-8.3.1/server/solr-webapp/webapp/WEB-INF | 1 | 62 | 42 | 11 | 115 | +| solr-8.3.1/server/solr-webapp/webapp/css | 26 | 5,548 | 536 | 1,005 | 7,089 | +| solr-8.3.1/server/solr-webapp/webapp/css/angular | 26 | 5,548 | 536 | 1,005 | 7,089 | +| solr-8.3.1/server/solr-webapp/webapp/img | 1 | 39 | 0 | 1 | 40 | +| solr-8.3.1/server/solr-webapp/webapp/js | 25 | 4,450 | 515 | 586 | 5,551 | +| solr-8.3.1/server/solr-webapp/webapp/js/angular | 25 | 4,450 | 515 | 586 | 5,551 | +| solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers | 23 | 3,627 | 478 | 544 | 4,649 | +| solr-8.3.1/server/solr-webapp/webapp/libs | 21 | 24,087 | 15,683 | 3,464 | 43,234 | +| solr-8.3.1/server/solr-webapp/webapp/partials | 24 | 2,571 | 415 | 787 | 3,773 | +| solr-8.3.1/server/solr/configsets | 21 | 2,243 | 2,359 | 437 | 5,039 | +| solr-8.3.1/server/solr/configsets/_default | 2 | 316 | 976 | 99 | 1,391 | +| solr-8.3.1/server/solr/configsets/_default/conf | 2 | 316 | 976 | 99 | 1,391 | +| solr-8.3.1/server/solr/configsets/sample_techproducts_configs | 19 | 1,927 | 1,383 | 338 | 3,648 | +| solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf | 19 | 1,927 | 1,383 | 338 | 3,648 | +| solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/clustering | 3 | 39 | 23 | 3 | 65 | +| solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/clustering/carrot2 | 3 | 39 | 23 | 3 | 65 | +| solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/velocity | 3 | 839 | 77 | 129 | 1,045 | +| solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/xslt | 5 | 515 | 104 | 58 | 677 | +| solr-8.3.1/server/solr/dash | 4 | 345 | 968 | 105 | 1,418 | +| solr-8.3.1/server/solr/dash/conf | 3 | 341 | 966 | 104 | 1,411 | +| solr-8.3.1/server/tmp | 5 | 45 | 10 | 5 | 60 | +| src | 384 | 68,699 | 6,117 | 7,234 | 82,050 | +| src/client | 277 | 46,644 | 4,305 | 5,743 | 56,692 | +| src/client/apis | 7 | 1,053 | 97 | 150 | 1,300 | +| src/client/apis/google_docs | 2 | 543 | 9 | 73 | 625 | +| src/client/apis/youtube | 2 | 379 | 53 | 56 | 488 | +| src/client/cognitive_services | 1 | 342 | 10 | 57 | 409 | +| src/client/documents | 2 | 839 | 143 | 90 | 1,072 | +| src/client/util | 30 | 3,931 | 351 | 515 | 4,797 | +| src/client/util/Import & Export | 4 | 566 | 0 | 52 | 618 | +| src/client/util/ProsemirrorCopy | 1 | 128 | 30 | 22 | 180 | +| src/client/views | 231 | 36,751 | 1,935 | 4,094 | 42,780 | +| src/client/views/animationtimeline | 10 | 1,966 | 237 | 262 | 2,465 | +| src/client/views/collections | 53 | 11,516 | 574 | 1,153 | 13,243 | +| src/client/views/collections/collectionFreeForm | 12 | 2,540 | 177 | 203 | 2,920 | +| src/client/views/collections/collectionMulticolumn | 8 | 751 | 144 | 85 | 980 | +| src/client/views/linking | 7 | 747 | 10 | 138 | 895 | +| src/client/views/nodes | 75 | 12,034 | 475 | 1,218 | 13,727 | +| src/client/views/nodes/formattedText | 22 | 5,353 | 250 | 592 | 6,195 | +| src/client/views/pdf | 6 | 964 | 27 | 93 | 1,084 | +| src/client/views/presentationview | 2 | 272 | 31 | 24 | 327 | +| src/client/views/search | 21 | 2,380 | 238 | 401 | 3,019 | +| src/client/views/webcam | 3 | 371 | 17 | 76 | 464 | +| src/debug | 3 | 244 | 0 | 28 | 272 | +| src/extensions | 4 | 53 | 5 | 13 | 71 | +| src/extensions/General | 2 | 14 | 0 | 3 | 17 | +| src/mobile | 7 | 617 | 60 | 82 | 759 | +| src/new_fields | 22 | 2,682 | 172 | 315 | 3,169 | +| src/pen-gestures | 2 | 397 | 172 | 27 | 596 | +| src/scraping | 15 | 1,155 | 352 | 176 | 1,683 | +| src/scraping/acm | 4 | 139 | 185 | 15 | 339 | +| src/scraping/buxton | 11 | 1,016 | 167 | 161 | 1,344 | +| src/scraping/buxton/.idea | 6 | 205 | 0 | 0 | 205 | +| src/scraping/buxton/.idea/inspectionProfiles | 1 | 6 | 0 | 0 | 6 | +| src/scraping/buxton/final | 1 | 228 | 142 | 26 | 396 | +| src/scraping/buxton/narratives | 1 | 39 | 0 | 0 | 39 | +| src/server | 52 | 16,247 | 956 | 731 | 17,934 | +| src/server/ApiManagers | 11 | 1,223 | 226 | 149 | 1,598 | +| src/server/DashSession | 9 | 903 | 229 | 122 | 1,254 | +| src/server/DashSession/Session | 8 | 748 | 177 | 99 | 1,024 | +| src/server/DashSession/Session/agents | 5 | 489 | 169 | 72 | 730 | +| src/server/DashSession/Session/utilities | 3 | 259 | 8 | 27 | 294 | +| src/server/Websocket | 1 | 263 | 5 | 46 | 314 | +| src/server/apis | 4 | 328 | 198 | 41 | 567 | +| src/server/apis/google | 2 | 191 | 168 | 27 | 386 | +| src/server/apis/youtube | 2 | 137 | 30 | 14 | 181 | +| src/server/authentication | 4 | 890 | 66 | 100 | 1,056 | +| src/server/authentication/config | 1 | 23 | 2 | 4 | 29 | +| src/server/authentication/controllers | 1 | 218 | 25 | 25 | 268 | +| src/server/authentication/models | 2 | 649 | 39 | 71 | 759 | +| src/server/credentials | 2 | 35 | 0 | 6 | 41 | +| src/typings | 1 | 219 | 72 | 38 | 329 | +| test | 1 | 141 | 0 | 20 | 161 | +| views | 7 | 304 | 5 | 44 | 353 | +| views/stylesheets | 1 | 185 | 4 | 34 | 223 | + +[details](details.md) \ No newline at end of file diff --git a/.VSCodeCounter/results.txt b/.VSCodeCounter/results.txt new file mode 100644 index 000000000..aaf54b147 --- /dev/null +++ b/.VSCodeCounter/results.txt @@ -0,0 +1,813 @@ +Date : 2020-04-30 14:40:16 +Directory : /Users/bcz/Documents/GitHub/Dash-Web +Total : 646 files, 224911 codes, 32987 comments, 15880 blanks, all 273778 lines + +Languages ++------------------+------------+------------+------------+------------+------------+ +| language | files | code | comment | blank | total | ++------------------+------------+------------+------------+------------+------------+ +| JavaScript | 69 | 89,717 | 18,520 | 5,866 | 114,103 | +| JSON | 20 | 50,401 | 37 | 14 | 50,452 | +| TypeScript React | 140 | 30,250 | 1,878 | 3,154 | 35,282 | +| XML | 73 | 17,257 | 8,281 | 992 | 26,530 | +| TypeScript | 115 | 15,246 | 2,095 | 1,958 | 19,299 | +| SCSS | 104 | 7,726 | 255 | 1,136 | 9,117 | +| CSS | 30 | 5,982 | 549 | 1,095 | 7,626 | +| HTML | 34 | 2,883 | 431 | 848 | 4,162 | +| XSL | 20 | 2,060 | 416 | 232 | 2,708 | +| Batch | 5 | 1,893 | 184 | 273 | 2,350 | +| Python | 5 | 632 | 49 | 148 | 829 | +| Shell Script | 6 | 538 | 248 | 120 | 906 | +| Properties | 16 | 161 | 43 | 30 | 234 | +| Pug | 6 | 119 | 1 | 10 | 130 | +| log | 1 | 38 | 0 | 1 | 39 | +| Markdown | 1 | 6 | 0 | 3 | 9 | +| Ignore | 1 | 2 | 0 | 0 | 2 | ++------------------+------------+------------+------------+------------+------------+ + +Directories ++-------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+ +| path | files | code | comment | blank | total | ++-------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+ +| . | 646 | 224,911 | 32,987 | 15,880 | 273,778 | +| solr-8.3.1 | 236 | 80,866 | 26,654 | 7,861 | 115,381 | +| src | 384 | 68,699 | 6,117 | 7,234 | 82,050 | +| deploy | 8 | 55,744 | 174 | 704 | 56,622 | +| deploy/assets | 2 | 55,677 | 174 | 686 | 56,537 | +| src/client | 277 | 46,644 | 4,305 | 5,743 | 56,692 | +| solr-8.3.1/server | 144 | 40,399 | 21,136 | 6,569 | 68,104 | +| solr-8.3.1/server/solr-webapp/webapp | 99 | 36,960 | 17,207 | 5,892 | 60,059 | +| solr-8.3.1/server/solr-webapp | 99 | 36,960 | 17,207 | 5,892 | 60,059 | +| src/client/views | 231 | 36,751 | 1,935 | 4,094 | 42,780 | +| solr-8.3.1/example | 82 | 32,009 | 5,063 | 942 | 38,014 | +| solr-8.3.1/example/films | 3 | 27,350 | 24 | 14 | 27,388 | +| solr-8.3.1/server/solr-webapp/webapp/libs | 21 | 24,087 | 15,683 | 3,464 | 43,234 | +| src/server | 52 | 16,247 | 956 | 731 | 17,934 | +| src/client/views/nodes | 75 | 12,034 | 475 | 1,218 | 13,727 | +| src/client/views/collections | 53 | 11,516 | 574 | 1,153 | 13,243 | +| solr-8.3.1/contrib | 3 | 6,281 | 63 | 37 | 6,381 | +| solr-8.3.1/contrib/prometheus-exporter | 3 | 6,281 | 63 | 37 | 6,381 | +| solr-8.3.1/contrib/prometheus-exporter/conf | 2 | 6,199 | 63 | 11 | 6,273 | +| solr-8.3.1/server/solr-webapp/webapp/css/angular | 26 | 5,548 | 536 | 1,005 | 7,089 | +| solr-8.3.1/server/solr-webapp/webapp/css | 26 | 5,548 | 536 | 1,005 | 7,089 | +| src/client/views/nodes/formattedText | 22 | 5,353 | 250 | 592 | 6,195 | +| solr-8.3.1/server/solr-webapp/webapp/js/angular | 25 | 4,450 | 515 | 586 | 5,551 | +| solr-8.3.1/server/solr-webapp/webapp/js | 25 | 4,450 | 515 | 586 | 5,551 | +| src/client/util | 30 | 3,931 | 351 | 515 | 4,797 | +| solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers | 23 | 3,627 | 478 | 544 | 4,649 | +| solr-8.3.1/example/example-DIH/solr | 49 | 2,848 | 3,605 | 603 | 7,056 | +| solr-8.3.1/example/example-DIH | 49 | 2,848 | 3,605 | 603 | 7,056 | +| src/new_fields | 22 | 2,682 | 172 | 315 | 3,169 | +| solr-8.3.1/server/solr | 27 | 2,612 | 3,377 | 557 | 6,546 | +| solr-8.3.1/server/solr-webapp/webapp/partials | 24 | 2,571 | 415 | 787 | 3,773 | +| src/client/views/collections/collectionFreeForm | 12 | 2,540 | 177 | 203 | 2,920 | +| src/client/views/search | 21 | 2,380 | 238 | 401 | 3,019 | +| solr-8.3.1/server/solr/configsets | 21 | 2,243 | 2,359 | 437 | 5,039 | +| solr-8.3.1/bin | 5 | 2,118 | 392 | 311 | 2,821 | +| src/client/views/animationtimeline | 10 | 1,966 | 237 | 262 | 2,465 | +| solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf | 19 | 1,927 | 1,383 | 338 | 3,648 | +| solr-8.3.1/server/solr/configsets/sample_techproducts_configs | 19 | 1,927 | 1,383 | 338 | 3,648 | +| solr-8.3.1/example/files | 13 | 1,298 | 1,153 | 250 | 2,701 | +| src/server/ApiManagers | 11 | 1,223 | 226 | 149 | 1,598 | +| solr-8.3.1/example/files/conf | 10 | 1,190 | 1,147 | 241 | 2,578 | +| src/scraping | 15 | 1,155 | 352 | 176 | 1,683 | +| src/client/apis | 7 | 1,053 | 97 | 150 | 1,300 | +| src/scraping/buxton | 11 | 1,016 | 167 | 161 | 1,344 | +| src/client/views/pdf | 6 | 964 | 27 | 93 | 1,084 | +| solr-8.3.1/example/example-DIH/solr/db | 14 | 935 | 1,167 | 191 | 2,293 | +| solr-8.3.1/example/example-DIH/solr/db/conf | 13 | 935 | 1,167 | 189 | 2,291 | +| solr-8.3.1/example/example-DIH/solr/mail | 14 | 919 | 1,171 | 189 | 2,279 | +| solr-8.3.1/example/example-DIH/solr/mail/conf | 13 | 919 | 1,171 | 187 | 2,277 | +| solr-8.3.1/example/example-DIH/solr/solr/conf | 13 | 917 | 1,183 | 185 | 2,285 | +| solr-8.3.1/example/example-DIH/solr/solr | 14 | 917 | 1,183 | 187 | 2,287 | +| src/server/DashSession | 9 | 903 | 229 | 122 | 1,254 | +| src/server/authentication | 4 | 890 | 66 | 100 | 1,056 | +| solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/velocity | 3 | 839 | 77 | 129 | 1,045 | +| src/client/documents | 2 | 839 | 143 | 90 | 1,072 | +| src/client/views/collections/collectionMulticolumn | 8 | 751 | 144 | 85 | 980 | +| src/server/DashSession/Session | 8 | 748 | 177 | 99 | 1,024 | +| src/client/views/linking | 7 | 747 | 10 | 138 | 895 | +| solr-8.3.1/example/files/conf/velocity | 5 | 730 | 99 | 108 | 937 | +| solr-8.3.1/example/files/conf/velocity/js | 3 | 730 | 99 | 104 | 933 | +| src/server/authentication/models | 2 | 649 | 39 | 71 | 759 | +| src/mobile | 7 | 617 | 60 | 82 | 759 | +| src/client/util/Import & Export | 4 | 566 | 0 | 52 | 618 | +| src/client/apis/google_docs | 2 | 543 | 9 | 73 | 625 | +| solr-8.3.1/server/etc | 6 | 528 | 400 | 59 | 987 | +| solr-8.3.1/example/example-DIH/solr/mail/conf/xslt | 5 | 515 | 104 | 58 | 677 | +| solr-8.3.1/example/example-DIH/solr/db/conf/xslt | 5 | 515 | 104 | 58 | 677 | +| solr-8.3.1/example/example-DIH/solr/solr/conf/xslt | 5 | 515 | 104 | 58 | 677 | +| solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/xslt | 5 | 515 | 104 | 58 | 677 | +| solr-8.3.1/example/exampledocs | 17 | 513 | 281 | 75 | 869 | +| src/server/DashSession/Session/agents | 5 | 489 | 169 | 72 | 730 | +| src/pen-gestures | 2 | 397 | 172 | 27 | 596 | +| src/client/apis/youtube | 2 | 379 | 53 | 56 | 488 | +| src/client/views/webcam | 3 | 371 | 17 | 76 | 464 | +| solr-8.3.1/server/solr/dash | 4 | 345 | 968 | 105 | 1,418 | +| src/client/cognitive_services | 1 | 342 | 10 | 57 | 409 | +| solr-8.3.1/server/solr/dash/conf | 3 | 341 | 966 | 104 | 1,411 | +| src/server/apis | 4 | 328 | 198 | 41 | 567 | +| solr-8.3.1/server/solr/configsets/_default/conf | 2 | 316 | 976 | 99 | 1,391 | +| solr-8.3.1/server/solr/configsets/_default | 2 | 316 | 976 | 99 | 1,391 | +| views | 7 | 304 | 5 | 44 | 353 | +| src/client/views/presentationview | 2 | 272 | 31 | 24 | 327 | +| src/server/Websocket | 1 | 263 | 5 | 46 | 314 | +| src/server/DashSession/Session/utilities | 3 | 259 | 8 | 27 | 294 | +| src/debug | 3 | 244 | 0 | 28 | 272 | +| src/scraping/buxton/final | 1 | 228 | 142 | 26 | 396 | +| src/typings | 1 | 219 | 72 | 38 | 329 | +| src/server/authentication/controllers | 1 | 218 | 25 | 25 | 268 | +| src/scraping/buxton/.idea | 6 | 205 | 0 | 0 | 205 | +| src/server/apis/google | 2 | 191 | 168 | 27 | 386 | +| views/stylesheets | 1 | 185 | 4 | 34 | 223 | +| solr-8.3.1/server/scripts/cloud-scripts | 3 | 172 | 19 | 39 | 230 | +| solr-8.3.1/server/scripts | 3 | 172 | 19 | 39 | 230 | +| test | 1 | 141 | 0 | 20 | 161 | +| src/scraping/acm | 4 | 139 | 185 | 15 | 339 | +| src/server/apis/youtube | 2 | 137 | 30 | 14 | 181 | +| src/client/util/ProsemirrorCopy | 1 | 128 | 30 | 22 | 180 | +| solr-8.3.1/example/files/browse-resources/velocity | 3 | 108 | 6 | 9 | 123 | +| solr-8.3.1/example/files/browse-resources | 3 | 108 | 6 | 9 | 123 | +| solr-8.3.1/contrib/prometheus-exporter/bin | 1 | 82 | 0 | 26 | 108 | +| solr-8.3.1/server/resources | 3 | 74 | 123 | 16 | 213 | +| solr-8.3.1/server/solr-webapp/webapp/WEB-INF | 1 | 62 | 42 | 11 | 115 | +| solr-8.3.1/docs | 2 | 59 | 0 | 2 | 61 | +| src/extensions | 4 | 53 | 5 | 13 | 71 | +| solr-8.3.1/server/tmp | 5 | 45 | 10 | 5 | 60 | +| solr-8.3.1/example/example-DIH/solr/atom/conf | 2 | 41 | 43 | 17 | 101 | +| solr-8.3.1/example/example-DIH/solr/atom | 3 | 41 | 43 | 19 | 103 | +| solr-8.3.1/server/solr-webapp/webapp/img | 1 | 39 | 0 | 1 | 40 | +| solr-8.3.1/docs/images | 1 | 39 | 0 | 1 | 40 | +| src/scraping/buxton/narratives | 1 | 39 | 0 | 0 | 39 | +| solr-8.3.1/example/example-DIH/solr/mail/conf/clustering/carrot2 | 3 | 39 | 23 | 3 | 65 | +| solr-8.3.1/example/example-DIH/solr/mail/conf/clustering | 3 | 39 | 23 | 3 | 65 | +| solr-8.3.1/example/example-DIH/solr/solr/conf/clustering/carrot2 | 3 | 39 | 23 | 3 | 65 | +| solr-8.3.1/example/example-DIH/solr/solr/conf/clustering | 3 | 39 | 23 | 3 | 65 | +| solr-8.3.1/example/example-DIH/solr/db/conf/clustering/carrot2 | 3 | 39 | 23 | 3 | 65 | +| solr-8.3.1/example/example-DIH/solr/db/conf/clustering | 3 | 39 | 23 | 3 | 65 | +| solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/clustering/carrot2 | 3 | 39 | 23 | 3 | 65 | +| solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/clustering | 3 | 39 | 23 | 3 | 65 | +| src/server/credentials | 2 | 35 | 0 | 6 | 41 | +| solr-8.3.1/example/example-DIH/solr/tika | 3 | 34 | 41 | 16 | 91 | +| solr-8.3.1/example/example-DIH/solr/tika/conf | 2 | 34 | 41 | 14 | 89 | +| deploy/debug | 3 | 32 | 0 | 9 | 41 | +| src/server/authentication/config | 1 | 23 | 2 | 4 | 29 | +| deploy/mobile | 2 | 22 | 0 | 6 | 28 | +| src/extensions/General | 2 | 14 | 0 | 3 | 17 | +| build | 1 | 9 | 0 | 3 | 12 | +| solr-8.3.1/server/contexts | 1 | 8 | 0 | 1 | 9 | +| src/scraping/buxton/.idea/inspectionProfiles | 1 | 6 | 0 | 0 | 6 | ++-------------------------------------------------------------------------------------------------------------+------------+------------+------------+------------+------------+ + +Files ++-------------------------------------------------------------------------------------------------------------+------------------+------------+------------+------------+------------+ +| filename | language | code | comment | blank | total | ++-------------------------------------------------------------------------------------------------------------+------------------+------------+------------+------------+------------+ +| README.md | Markdown | 6 | 0 | 3 | 9 | +| build/index.html | HTML | 9 | 0 | 3 | 12 | +| dash.bat | Batch | 2 | 0 | 1 | 3 | +| deploy/assets/env.json | JSON | 15 | 0 | 0 | 15 | +| deploy/assets/pdf.worker.js | JavaScript | 55,662 | 174 | 686 | 56,522 | +| deploy/debug/repl.html | HTML | 11 | 0 | 3 | 14 | +| deploy/debug/test.html | HTML | 10 | 0 | 3 | 13 | +| deploy/debug/viewer.html | HTML | 11 | 0 | 3 | 14 | +| deploy/index.html | HTML | 13 | 0 | 3 | 16 | +| deploy/mobile/image.html | HTML | 12 | 0 | 3 | 15 | +| deploy/mobile/ink.html | HTML | 10 | 0 | 3 | 13 | +| package-lock.json | JSON | 18,689 | 0 | 1 | 18,690 | +| package.json | JSON | 266 | 0 | 1 | 267 | +| sentence_parser.py | Python | 6 | 0 | 1 | 7 | +| session.config.json | JSON | 12 | 0 | 1 | 13 | +| solr-8.3.1/bin/install_solr_service.sh | Shell Script | 307 | 29 | 35 | 371 | +| solr-8.3.1/bin/oom_solr.sh | Shell Script | 13 | 15 | 3 | 31 | +| solr-8.3.1/bin/solr.cmd | Batch | 1,782 | 43 | 210 | 2,035 | +| solr-8.3.1/bin/solr.in.cmd | Batch | 16 | 133 | 29 | 178 | +| solr-8.3.1/bin/solr.in.sh | Shell Script | 0 | 172 | 34 | 206 | +| solr-8.3.1/contrib/prometheus-exporter/bin/solr-exporter.cmd | Batch | 82 | 0 | 26 | 108 | +| solr-8.3.1/contrib/prometheus-exporter/conf/grafana-solr-dashboard.json | JSON | 4,465 | 0 | 1 | 4,466 | +| solr-8.3.1/contrib/prometheus-exporter/conf/solr-exporter-config.xml | XML | 1,734 | 63 | 10 | 1,807 | +| solr-8.3.1/docs/images/solr.svg | XML | 39 | 0 | 1 | 40 | +| solr-8.3.1/docs/index.html | HTML | 20 | 0 | 1 | 21 | +| solr-8.3.1/example/example-DIH/solr/atom/conf/atom-data-config.xml | XML | 21 | 6 | 9 | 36 | +| solr-8.3.1/example/example-DIH/solr/atom/conf/solrconfig.xml | XML | 20 | 37 | 8 | 65 | +| solr-8.3.1/example/example-DIH/solr/atom/core.properties | Properties | 0 | 0 | 2 | 2 | +| solr-8.3.1/example/example-DIH/solr/db/conf/clustering/carrot2/kmeans-attributes.xml | XML | 13 | 6 | 1 | 20 | +| solr-8.3.1/example/example-DIH/solr/db/conf/clustering/carrot2/lingo-attributes.xml | XML | 13 | 11 | 1 | 25 | +| solr-8.3.1/example/example-DIH/solr/db/conf/clustering/carrot2/stc-attributes.xml | XML | 13 | 6 | 1 | 20 | +| solr-8.3.1/example/example-DIH/solr/db/conf/currency.xml | XML | 45 | 19 | 4 | 68 | +| solr-8.3.1/example/example-DIH/solr/db/conf/db-data-config.xml | XML | 26 | 0 | 4 | 30 | +| solr-8.3.1/example/example-DIH/solr/db/conf/elevate.xml | XML | 3 | 37 | 3 | 43 | +| solr-8.3.1/example/example-DIH/solr/db/conf/solrconfig.xml | XML | 292 | 958 | 104 | 1,354 | +| solr-8.3.1/example/example-DIH/solr/db/conf/update-script.js | JavaScript | 15 | 26 | 13 | 54 | +| solr-8.3.1/example/example-DIH/solr/db/conf/xslt/example.xsl | XSL | 98 | 20 | 15 | 133 | +| solr-8.3.1/example/example-DIH/solr/db/conf/xslt/example_atom.xsl | XSL | 40 | 20 | 8 | 68 | +| solr-8.3.1/example/example-DIH/solr/db/conf/xslt/example_rss.xsl | XSL | 41 | 20 | 6 | 67 | +| solr-8.3.1/example/example-DIH/solr/db/conf/xslt/luke.xsl | XSL | 301 | 19 | 18 | 338 | +| solr-8.3.1/example/example-DIH/solr/db/conf/xslt/updateXml.xsl | XSL | 35 | 25 | 11 | 71 | +| solr-8.3.1/example/example-DIH/solr/db/core.properties | Properties | 0 | 0 | 2 | 2 | +| solr-8.3.1/example/example-DIH/solr/mail/conf/clustering/carrot2/kmeans-attributes.xml | XML | 13 | 6 | 1 | 20 | +| solr-8.3.1/example/example-DIH/solr/mail/conf/clustering/carrot2/lingo-attributes.xml | XML | 13 | 11 | 1 | 25 | +| solr-8.3.1/example/example-DIH/solr/mail/conf/clustering/carrot2/stc-attributes.xml | XML | 13 | 6 | 1 | 20 | +| solr-8.3.1/example/example-DIH/solr/mail/conf/currency.xml | XML | 45 | 19 | 4 | 68 | +| solr-8.3.1/example/example-DIH/solr/mail/conf/elevate.xml | XML | 3 | 37 | 3 | 43 | +| solr-8.3.1/example/example-DIH/solr/mail/conf/mail-data-config.xml | XML | 8 | 4 | 1 | 13 | +| solr-8.3.1/example/example-DIH/solr/mail/conf/solrconfig.xml | XML | 294 | 958 | 105 | 1,357 | +| solr-8.3.1/example/example-DIH/solr/mail/conf/update-script.js | JavaScript | 15 | 26 | 13 | 54 | +| solr-8.3.1/example/example-DIH/solr/mail/conf/xslt/example.xsl | XSL | 98 | 20 | 15 | 133 | +| solr-8.3.1/example/example-DIH/solr/mail/conf/xslt/example_atom.xsl | XSL | 40 | 20 | 8 | 68 | +| solr-8.3.1/example/example-DIH/solr/mail/conf/xslt/example_rss.xsl | XSL | 41 | 20 | 6 | 67 | +| solr-8.3.1/example/example-DIH/solr/mail/conf/xslt/luke.xsl | XSL | 301 | 19 | 18 | 338 | +| solr-8.3.1/example/example-DIH/solr/mail/conf/xslt/updateXml.xsl | XSL | 35 | 25 | 11 | 71 | +| solr-8.3.1/example/example-DIH/solr/mail/core.properties | Properties | 0 | 0 | 2 | 2 | +| solr-8.3.1/example/example-DIH/solr/solr.xml | XML | 2 | 0 | 1 | 3 | +| solr-8.3.1/example/example-DIH/solr/solr/conf/clustering/carrot2/kmeans-attributes.xml | XML | 13 | 6 | 1 | 20 | +| solr-8.3.1/example/example-DIH/solr/solr/conf/clustering/carrot2/lingo-attributes.xml | XML | 13 | 11 | 1 | 25 | +| solr-8.3.1/example/example-DIH/solr/solr/conf/clustering/carrot2/stc-attributes.xml | XML | 13 | 6 | 1 | 20 | +| solr-8.3.1/example/example-DIH/solr/solr/conf/currency.xml | XML | 45 | 19 | 4 | 68 | +| solr-8.3.1/example/example-DIH/solr/solr/conf/elevate.xml | XML | 3 | 37 | 3 | 43 | +| solr-8.3.1/example/example-DIH/solr/solr/conf/solr-data-config.xml | XML | 8 | 16 | 2 | 26 | +| solr-8.3.1/example/example-DIH/solr/solr/conf/solrconfig.xml | XML | 292 | 958 | 102 | 1,352 | +| solr-8.3.1/example/example-DIH/solr/solr/conf/update-script.js | JavaScript | 15 | 26 | 13 | 54 | +| solr-8.3.1/example/example-DIH/solr/solr/conf/xslt/example.xsl | XSL | 98 | 20 | 15 | 133 | +| solr-8.3.1/example/example-DIH/solr/solr/conf/xslt/example_atom.xsl | XSL | 40 | 20 | 8 | 68 | +| solr-8.3.1/example/example-DIH/solr/solr/conf/xslt/example_rss.xsl | XSL | 41 | 20 | 6 | 67 | +| solr-8.3.1/example/example-DIH/solr/solr/conf/xslt/luke.xsl | XSL | 301 | 19 | 18 | 338 | +| solr-8.3.1/example/example-DIH/solr/solr/conf/xslt/updateXml.xsl | XSL | 35 | 25 | 11 | 71 | +| solr-8.3.1/example/example-DIH/solr/solr/core.properties | Properties | 0 | 0 | 2 | 2 | +| solr-8.3.1/example/example-DIH/solr/tika/conf/solrconfig.xml | XML | 17 | 38 | 7 | 62 | +| solr-8.3.1/example/example-DIH/solr/tika/conf/tika-data-config.xml | XML | 17 | 3 | 7 | 27 | +| solr-8.3.1/example/example-DIH/solr/tika/core.properties | Properties | 0 | 0 | 2 | 2 | +| solr-8.3.1/example/exampledocs/books.json | JSON | 51 | 0 | 1 | 52 | +| solr-8.3.1/example/exampledocs/gb18030-example.xml | XML | 14 | 16 | 3 | 33 | +| solr-8.3.1/example/exampledocs/hd.xml | XML | 33 | 20 | 4 | 57 | +| solr-8.3.1/example/exampledocs/ipod_other.xml | XML | 32 | 20 | 9 | 61 | +| solr-8.3.1/example/exampledocs/ipod_video.xml | XML | 21 | 18 | 2 | 41 | +| solr-8.3.1/example/exampledocs/manufacturers.xml | XML | 57 | 16 | 3 | 76 | +| solr-8.3.1/example/exampledocs/mem.xml | XML | 45 | 24 | 9 | 78 | +| solr-8.3.1/example/exampledocs/money.xml | XML | 42 | 17 | 7 | 66 | +| solr-8.3.1/example/exampledocs/monitor.xml | XML | 14 | 18 | 3 | 35 | +| solr-8.3.1/example/exampledocs/monitor2.xml | XML | 13 | 18 | 3 | 34 | +| solr-8.3.1/example/exampledocs/mp500.xml | XML | 23 | 18 | 3 | 44 | +| solr-8.3.1/example/exampledocs/sample.html | HTML | 13 | 0 | 1 | 14 | +| solr-8.3.1/example/exampledocs/sd500.xml | XML | 19 | 18 | 2 | 39 | +| solr-8.3.1/example/exampledocs/solr.xml | XML | 20 | 16 | 3 | 39 | +| solr-8.3.1/example/exampledocs/test_utf8.sh | Shell Script | 57 | 21 | 16 | 94 | +| solr-8.3.1/example/exampledocs/utf8-example.xml | XML | 19 | 20 | 4 | 43 | +| solr-8.3.1/example/exampledocs/vidcard.xml | XML | 40 | 21 | 2 | 63 | +| solr-8.3.1/example/files/browse-resources/velocity/resources.properties | Properties | 72 | 6 | 5 | 83 | +| solr-8.3.1/example/files/browse-resources/velocity/resources_de_DE.properties | Properties | 18 | 0 | 1 | 19 | +| solr-8.3.1/example/files/browse-resources/velocity/resources_fr_FR.properties | Properties | 18 | 0 | 3 | 21 | +| solr-8.3.1/example/files/conf/currency.xml | XML | 45 | 19 | 4 | 68 | +| solr-8.3.1/example/files/conf/elevate.xml | XML | 3 | 37 | 3 | 43 | +| solr-8.3.1/example/files/conf/params.json | JSON | 34 | 0 | 1 | 35 | +| solr-8.3.1/example/files/conf/solrconfig.xml | XML | 298 | 979 | 102 | 1,379 | +| solr-8.3.1/example/files/conf/update-script.js | JavaScript | 80 | 13 | 23 | 116 | +| solr-8.3.1/example/files/conf/velocity/dropit.js | JavaScript | 0 | 0 | 2 | 2 | +| solr-8.3.1/example/files/conf/velocity/jquery.tx3-tag-cloud.js | JavaScript | 0 | 0 | 2 | 2 | +| solr-8.3.1/example/files/conf/velocity/js/dropit.js | JavaScript | 64 | 15 | 19 | 98 | +| solr-8.3.1/example/files/conf/velocity/js/jquery.autocomplete.js | JavaScript | 620 | 68 | 76 | 764 | +| solr-8.3.1/example/files/conf/velocity/js/jquery.tx3-tag-cloud.js | JavaScript | 46 | 16 | 9 | 71 | +| solr-8.3.1/example/films/film_data_generator.py | Python | 82 | 24 | 12 | 118 | +| solr-8.3.1/example/films/films.json | JSON | 15,830 | 0 | 1 | 15,831 | +| solr-8.3.1/example/films/films.xml | XML | 11,438 | 0 | 1 | 11,439 | +| solr-8.3.1/server/contexts/solr-jetty-context.xml | XML | 8 | 0 | 1 | 9 | +| solr-8.3.1/server/etc/jetty-http.xml | XML | 33 | 15 | 4 | 52 | +| solr-8.3.1/server/etc/jetty-https.xml | XML | 56 | 16 | 5 | 77 | +| solr-8.3.1/server/etc/jetty-https8.xml | XML | 34 | 32 | 4 | 70 | +| solr-8.3.1/server/etc/jetty-ssl.xml | XML | 23 | 11 | 4 | 38 | +| solr-8.3.1/server/etc/jetty.xml | XML | 110 | 94 | 18 | 222 | +| solr-8.3.1/server/etc/webdefault.xml | XML | 272 | 232 | 24 | 528 | +| solr-8.3.1/server/resources/jetty-logging.properties | Properties | 1 | 0 | 1 | 2 | +| solr-8.3.1/server/resources/log4j2-console.xml | XML | 19 | 43 | 6 | 68 | +| solr-8.3.1/server/resources/log4j2.xml | XML | 54 | 80 | 9 | 143 | +| solr-8.3.1/server/scripts/cloud-scripts/snapshotscli.sh | Shell Script | 152 | 2 | 23 | 177 | +| solr-8.3.1/server/scripts/cloud-scripts/zkcli.bat | Batch | 11 | 8 | 7 | 26 | +| solr-8.3.1/server/scripts/cloud-scripts/zkcli.sh | Shell Script | 9 | 9 | 9 | 27 | +| solr-8.3.1/server/solr-webapp/webapp/WEB-INF/web.xml | XML | 62 | 42 | 11 | 115 | +| solr-8.3.1/server/solr-webapp/webapp/css/angular/analysis.css | CSS | 237 | 19 | 48 | 304 | +| solr-8.3.1/server/solr-webapp/webapp/css/angular/chosen.css | CSS | 402 | 55 | 9 | 466 | +| solr-8.3.1/server/solr-webapp/webapp/css/angular/cloud.css | CSS | 594 | 23 | 106 | 723 | +| solr-8.3.1/server/solr-webapp/webapp/css/angular/collections.css | CSS | 296 | 18 | 65 | 379 | +| solr-8.3.1/server/solr-webapp/webapp/css/angular/common.css | CSS | 647 | 19 | 106 | 772 | +| solr-8.3.1/server/solr-webapp/webapp/css/angular/cores.css | CSS | 171 | 18 | 37 | 226 | +| solr-8.3.1/server/solr-webapp/webapp/css/angular/dashboard.css | CSS | 134 | 18 | 28 | 180 | +| solr-8.3.1/server/solr-webapp/webapp/css/angular/dataimport.css | CSS | 292 | 18 | 61 | 371 | +| solr-8.3.1/server/solr-webapp/webapp/css/angular/documents.css | CSS | 131 | 23 | 26 | 180 | +| solr-8.3.1/server/solr-webapp/webapp/css/angular/files.css | CSS | 29 | 18 | 7 | 54 | +| solr-8.3.1/server/solr-webapp/webapp/css/angular/index.css | CSS | 164 | 18 | 35 | 217 | +| solr-8.3.1/server/solr-webapp/webapp/css/angular/java-properties.css | CSS | 24 | 18 | 6 | 48 | +| solr-8.3.1/server/solr-webapp/webapp/css/angular/jquery-ui.min.css | CSS | 1 | 26 | 2 | 29 | +| solr-8.3.1/server/solr-webapp/webapp/css/angular/jquery-ui.structure.min.css | CSS | 1 | 22 | 2 | 25 | +| solr-8.3.1/server/solr-webapp/webapp/css/angular/logging.css | CSS | 303 | 19 | 63 | 385 | +| solr-8.3.1/server/solr-webapp/webapp/css/angular/login.css | CSS | 80 | 18 | 12 | 110 | +| solr-8.3.1/server/solr-webapp/webapp/css/angular/menu.css | CSS | 257 | 18 | 56 | 331 | +| solr-8.3.1/server/solr-webapp/webapp/css/angular/overview.css | CSS | 20 | 18 | 5 | 43 | +| solr-8.3.1/server/solr-webapp/webapp/css/angular/plugins.css | CSS | 172 | 18 | 31 | 221 | +| solr-8.3.1/server/solr-webapp/webapp/css/angular/query.css | CSS | 120 | 18 | 25 | 163 | +| solr-8.3.1/server/solr-webapp/webapp/css/angular/replication.css | CSS | 404 | 18 | 79 | 501 | +| solr-8.3.1/server/solr-webapp/webapp/css/angular/schema.css | CSS | 596 | 20 | 112 | 728 | +| solr-8.3.1/server/solr-webapp/webapp/css/angular/segments.css | CSS | 133 | 18 | 22 | 173 | +| solr-8.3.1/server/solr-webapp/webapp/css/angular/stream.css | CSS | 178 | 22 | 34 | 234 | +| solr-8.3.1/server/solr-webapp/webapp/css/angular/suggestions.css | CSS | 43 | 18 | 4 | 65 | +| solr-8.3.1/server/solr-webapp/webapp/css/angular/threads.css | CSS | 119 | 18 | 24 | 161 | +| solr-8.3.1/server/solr-webapp/webapp/img/solr.svg | XML | 39 | 0 | 1 | 40 | +| solr-8.3.1/server/solr-webapp/webapp/index.html | HTML | 203 | 16 | 38 | 257 | +| solr-8.3.1/server/solr-webapp/webapp/js/angular/app.js | JavaScript | 512 | 19 | 31 | 562 | +| solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/alias-overview.js | JavaScript | 8 | 16 | 4 | 28 | +| solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/analysis.js | JavaScript | 161 | 18 | 23 | 202 | +| solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/cloud.js | JavaScript | 847 | 51 | 124 | 1,022 | +| solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/cluster-suggestions.js | JavaScript | 43 | 18 | 2 | 63 | +| solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/collection-overview.js | JavaScript | 18 | 16 | 6 | 40 | +| solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/collections.js | JavaScript | 244 | 19 | 27 | 290 | +| solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/core-overview.js | JavaScript | 69 | 16 | 9 | 94 | +| solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/cores.js | JavaScript | 151 | 16 | 14 | 181 | +| solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/dataimport.js | JavaScript | 234 | 25 | 44 | 303 | +| solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/documents.js | JavaScript | 107 | 18 | 13 | 138 | +| solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/files.js | JavaScript | 72 | 16 | 13 | 101 | +| solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/index.js | JavaScript | 61 | 23 | 14 | 98 | +| solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/java-properties.js | JavaScript | 27 | 16 | 3 | 46 | +| solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/logging.js | JavaScript | 112 | 35 | 12 | 159 | +| solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/login.js | JavaScript | 269 | 30 | 19 | 318 | +| solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/plugins.js | JavaScript | 130 | 19 | 19 | 168 | +| solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/query.js | JavaScript | 88 | 19 | 14 | 121 | +| solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/replication.js | JavaScript | 178 | 18 | 40 | 236 | +| solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/schema.js | JavaScript | 524 | 19 | 69 | 612 | +| solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/segments.js | JavaScript | 64 | 16 | 20 | 100 | +| solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/stream.js | JavaScript | 173 | 16 | 51 | 240 | +| solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/threads.js | JavaScript | 33 | 16 | 2 | 51 | +| solr-8.3.1/server/solr-webapp/webapp/js/angular/controllers/unknown.js | JavaScript | 14 | 22 | 2 | 38 | +| solr-8.3.1/server/solr-webapp/webapp/js/angular/services.js | JavaScript | 311 | 18 | 11 | 340 | +| solr-8.3.1/server/solr-webapp/webapp/libs/angular-chosen.js | JavaScript | 112 | 24 | 4 | 140 | +| solr-8.3.1/server/solr-webapp/webapp/libs/angular-cookies.js | JavaScript | 73 | 135 | 22 | 230 | +| solr-8.3.1/server/solr-webapp/webapp/libs/angular-cookies.min.js | JavaScript | 2 | 29 | 1 | 32 | +| solr-8.3.1/server/solr-webapp/webapp/libs/angular-resource.min.js | JavaScript | 7 | 29 | 1 | 37 | +| solr-8.3.1/server/solr-webapp/webapp/libs/angular-route.js | JavaScript | 316 | 636 | 67 | 1,019 | +| solr-8.3.1/server/solr-webapp/webapp/libs/angular-route.min.js | JavaScript | 9 | 29 | 1 | 39 | +| solr-8.3.1/server/solr-webapp/webapp/libs/angular-sanitize.js | JavaScript | 311 | 328 | 65 | 704 | +| solr-8.3.1/server/solr-webapp/webapp/libs/angular-sanitize.min.js | JavaScript | 10 | 29 | 1 | 40 | +| solr-8.3.1/server/solr-webapp/webapp/libs/angular-utf8-base64.js | JavaScript | 157 | 48 | 13 | 218 | +| solr-8.3.1/server/solr-webapp/webapp/libs/angular-utf8-base64.min.js | JavaScript | 1 | 42 | 3 | 46 | +| solr-8.3.1/server/solr-webapp/webapp/libs/angular.js | JavaScript | 10,845 | 13,211 | 2,038 | 26,094 | +| solr-8.3.1/server/solr-webapp/webapp/libs/angular.min.js | JavaScript | 73 | 201 | 0 | 274 | +| solr-8.3.1/server/solr-webapp/webapp/libs/chosen.jquery.js | JavaScript | 1,151 | 36 | 8 | 1,195 | +| solr-8.3.1/server/solr-webapp/webapp/libs/chosen.jquery.min.js | JavaScript | 2 | 29 | 0 | 31 | +| solr-8.3.1/server/solr-webapp/webapp/libs/d3.js | JavaScript | 7,720 | 519 | 1,135 | 9,374 | +| solr-8.3.1/server/solr-webapp/webapp/libs/highlight.js | JavaScript | 2 | 29 | 1 | 32 | +| solr-8.3.1/server/solr-webapp/webapp/libs/jquery-1.7.2.min.js | JavaScript | 3 | 26 | 2 | 31 | +| solr-8.3.1/server/solr-webapp/webapp/libs/jquery-2.1.3.min.js | JavaScript | 3 | 26 | 1 | 30 | +| solr-8.3.1/server/solr-webapp/webapp/libs/jquery-ui.min.js | JavaScript | 2 | 26 | 3 | 31 | +| solr-8.3.1/server/solr-webapp/webapp/libs/jquery.jstree.js | JavaScript | 3,222 | 228 | 85 | 3,535 | +| solr-8.3.1/server/solr-webapp/webapp/libs/ngtimeago.js | JavaScript | 66 | 23 | 13 | 102 | +| solr-8.3.1/server/solr-webapp/webapp/partials/alias_overview.html | HTML | 21 | 16 | 10 | 47 | +| solr-8.3.1/server/solr-webapp/webapp/partials/analysis.html | HTML | 87 | 16 | 26 | 129 | +| solr-8.3.1/server/solr-webapp/webapp/partials/cloud.html | HTML | 263 | 16 | 24 | 303 | +| solr-8.3.1/server/solr-webapp/webapp/partials/cluster_suggestions.html | HTML | 30 | 16 | 4 | 50 | +| solr-8.3.1/server/solr-webapp/webapp/partials/collection_overview.html | HTML | 48 | 16 | 22 | 86 | +| solr-8.3.1/server/solr-webapp/webapp/partials/collections.html | HTML | 301 | 16 | 79 | 396 | +| solr-8.3.1/server/solr-webapp/webapp/partials/core_overview.html | HTML | 125 | 16 | 66 | 207 | +| solr-8.3.1/server/solr-webapp/webapp/partials/cores.html | HTML | 142 | 16 | 67 | 225 | +| solr-8.3.1/server/solr-webapp/webapp/partials/dataimport.html | HTML | 142 | 16 | 52 | 210 | +| solr-8.3.1/server/solr-webapp/webapp/partials/documents.html | HTML | 83 | 20 | 9 | 112 | +| solr-8.3.1/server/solr-webapp/webapp/partials/files.html | HTML | 17 | 16 | 15 | 48 | +| solr-8.3.1/server/solr-webapp/webapp/partials/index.html | HTML | 135 | 42 | 85 | 262 | +| solr-8.3.1/server/solr-webapp/webapp/partials/java-properties.html | HTML | 10 | 16 | 2 | 28 | +| solr-8.3.1/server/solr-webapp/webapp/partials/logging-levels.html | HTML | 35 | 16 | 6 | 57 | +| solr-8.3.1/server/solr-webapp/webapp/partials/logging.html | HTML | 40 | 16 | 2 | 58 | +| solr-8.3.1/server/solr-webapp/webapp/partials/login.html | HTML | 134 | 16 | 11 | 161 | +| solr-8.3.1/server/solr-webapp/webapp/partials/plugins.html | HTML | 48 | 17 | 8 | 73 | +| solr-8.3.1/server/solr-webapp/webapp/partials/query.html | HTML | 270 | 16 | 84 | 370 | +| solr-8.3.1/server/solr-webapp/webapp/partials/replication.html | HTML | 153 | 16 | 71 | 240 | +| solr-8.3.1/server/solr-webapp/webapp/partials/schema.html | HTML | 336 | 16 | 104 | 456 | +| solr-8.3.1/server/solr-webapp/webapp/partials/segments.html | HTML | 70 | 16 | 14 | 100 | +| solr-8.3.1/server/solr-webapp/webapp/partials/stream.html | HTML | 40 | 16 | 9 | 65 | +| solr-8.3.1/server/solr-webapp/webapp/partials/threads.html | HTML | 36 | 16 | 14 | 66 | +| solr-8.3.1/server/solr-webapp/webapp/partials/unknown.html | HTML | 5 | 16 | 3 | 24 | +| solr-8.3.1/server/solr/configsets/_default/conf/params.json | JSON | 20 | 0 | 1 | 21 | +| solr-8.3.1/server/solr/configsets/_default/conf/solrconfig.xml | XML | 296 | 976 | 98 | 1,370 | +| solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/_rest_managed.json | JSON | 1 | 0 | 1 | 2 | +| solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/_schema_analysis_stopwords_english.json | JSON | 38 | 0 | 1 | 39 | +| solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/_schema_analysis_synonyms_english.json | JSON | 11 | 0 | 1 | 12 | +| solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/clustering/carrot2/kmeans-attributes.xml | XML | 13 | 6 | 1 | 20 | +| solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/clustering/carrot2/lingo-attributes.xml | XML | 13 | 11 | 1 | 25 | +| solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/clustering/carrot2/stc-attributes.xml | XML | 13 | 6 | 1 | 20 | +| solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/currency.xml | XML | 45 | 19 | 4 | 68 | +| solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/elevate.xml | XML | 3 | 37 | 3 | 43 | +| solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/params.json | JSON | 11 | 0 | 1 | 12 | +| solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/solrconfig.xml | XML | 410 | 1,097 | 124 | 1,631 | +| solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/update-script.js | JavaScript | 15 | 26 | 13 | 54 | +| solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/velocity/jquery.autocomplete.css | CSS | 34 | 9 | 6 | 49 | +| solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/velocity/jquery.autocomplete.js | JavaScript | 620 | 68 | 76 | 764 | +| solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/velocity/main.css | CSS | 185 | 0 | 47 | 232 | +| solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/xslt/example.xsl | XSL | 98 | 20 | 15 | 133 | +| solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/xslt/example_atom.xsl | XSL | 40 | 20 | 8 | 68 | +| solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/xslt/example_rss.xsl | XSL | 41 | 20 | 6 | 67 | +| solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/xslt/luke.xsl | XSL | 301 | 19 | 18 | 338 | +| solr-8.3.1/server/solr/configsets/sample_techproducts_configs/conf/xslt/updateXml.xsl | XSL | 35 | 25 | 11 | 71 | +| solr-8.3.1/server/solr/dash/conf/params.json | JSON | 20 | 0 | 0 | 20 | +| solr-8.3.1/server/solr/dash/conf/schema.xml | XML | 51 | 4 | 7 | 62 | +| solr-8.3.1/server/solr/dash/conf/solrconfig.xml | XML | 270 | 962 | 97 | 1,329 | +| solr-8.3.1/server/solr/dash/core.properties | Properties | 4 | 2 | 1 | 7 | +| solr-8.3.1/server/solr/solr.xml | XML | 21 | 25 | 11 | 57 | +| solr-8.3.1/server/solr/zoo.cfg | Properties | 3 | 25 | 4 | 32 | +| solr-8.3.1/server/tmp/start_3204295554151338130.properties | Properties | 9 | 2 | 1 | 12 | +| solr-8.3.1/server/tmp/start_5812170489311981381.properties | Properties | 9 | 2 | 1 | 12 | +| solr-8.3.1/server/tmp/start_6476327636763392575.properties | Properties | 9 | 2 | 1 | 12 | +| solr-8.3.1/server/tmp/start_7329004517204835686.properties | Properties | 9 | 2 | 1 | 12 | +| solr-8.3.1/server/tmp/start_9067375725008958788.properties | Properties | 9 | 2 | 1 | 12 | +| src/Utils.ts | TypeScript | 441 | 23 | 81 | 545 | +| src/client/ClientRecommender.scss | SCSS | 9 | 1 | 2 | 12 | +| src/client/ClientRecommender.tsx | TypeScript React | 320 | 61 | 44 | 425 | +| src/client/DocServer.ts | TypeScript | 279 | 136 | 65 | 480 | +| src/client/Network.ts | TypeScript | 34 | 0 | 5 | 39 | +| src/client/apis/GoogleAuthenticationManager.scss | SCSS | 16 | 0 | 3 | 19 | +| src/client/apis/GoogleAuthenticationManager.tsx | TypeScript React | 115 | 2 | 11 | 128 | +| src/client/apis/IBM_Recommender.ts | TypeScript | 0 | 33 | 7 | 40 | +| src/client/apis/google_docs/GoogleApiClientUtils.ts | TypeScript | 225 | 9 | 27 | 261 | +| src/client/apis/google_docs/GooglePhotosClientUtils.ts | TypeScript | 318 | 0 | 46 | 364 | +| src/client/apis/youtube/YoutubeBox.scss | SCSS | 105 | 5 | 16 | 126 | +| src/client/apis/youtube/YoutubeBox.tsx | TypeScript React | 274 | 48 | 40 | 362 | +| src/client/cognitive_services/CognitiveServices.ts | TypeScript | 342 | 10 | 57 | 409 | +| src/client/documents/DocumentTypes.ts | TypeScript | 32 | 2 | 3 | 37 | +| src/client/documents/Documents.ts | TypeScript | 807 | 141 | 87 | 1,035 | +| src/client/goldenLayout.d.ts | TypeScript | 2 | 0 | 1 | 3 | +| src/client/goldenLayout.js | JavaScript | 3,084 | 1,571 | 720 | 5,375 | +| src/client/util/DictationManager.ts | TypeScript | 312 | 25 | 51 | 388 | +| src/client/util/DocumentManager.ts | TypeScript | 207 | 16 | 21 | 244 | +| src/client/util/DragManager.ts | TypeScript | 504 | 11 | 35 | 550 | +| src/client/util/DropConverter.ts | TypeScript | 70 | 6 | 2 | 78 | +| src/client/util/History.ts | TypeScript | 166 | 13 | 27 | 206 | +| src/client/util/Import & Export/DirectoryImportBox.scss | SCSS | 6 | 0 | 0 | 6 | +| src/client/util/Import & Export/DirectoryImportBox.tsx | TypeScript React | 393 | 0 | 31 | 424 | +| src/client/util/Import & Export/ImageUtils.ts | TypeScript | 35 | 0 | 4 | 39 | +| src/client/util/Import & Export/ImportMetadataEntry.tsx | TypeScript React | 132 | 0 | 17 | 149 | +| src/client/util/InteractionUtils.tsx | TypeScript React | 122 | 112 | 21 | 255 | +| src/client/util/KeyCodes.ts | TypeScript | 100 | 36 | 0 | 136 | +| src/client/util/LinkManager.ts | TypeScript | 161 | 30 | 23 | 214 | +| src/client/util/ProsemirrorCopy/prompt.js | JavaScript | 128 | 30 | 22 | 180 | +| src/client/util/Scripting.ts | TypeScript | 247 | 15 | 30 | 292 | +| src/client/util/ScrollBox.tsx | TypeScript React | 19 | 0 | 2 | 21 | +| src/client/util/SearchUtil.ts | TypeScript | 123 | 4 | 18 | 145 | +| src/client/util/SelectionManager.ts | TypeScript | 69 | 5 | 15 | 89 | +| src/client/util/SerializationHelper.ts | TypeScript | 113 | 15 | 15 | 143 | +| src/client/util/SettingsManager.scss | SCSS | 111 | 0 | 25 | 136 | +| src/client/util/SettingsManager.tsx | TypeScript React | 114 | 0 | 17 | 131 | +| src/client/util/SharingManager.scss | SCSS | 122 | 0 | 18 | 140 | +| src/client/util/SharingManager.tsx | TypeScript React | 273 | 0 | 25 | 298 | +| src/client/util/Transform.ts | TypeScript | 76 | 0 | 23 | 99 | +| src/client/util/TypedEvent.ts | TypeScript | 29 | 3 | 8 | 40 | +| src/client/util/UndoManager.ts | TypeScript | 167 | 1 | 27 | 195 | +| src/client/util/clamp.js | JavaScript | 14 | 0 | 1 | 15 | +| src/client/util/convertToCSSPTValue.js | JavaScript | 31 | 4 | 8 | 43 | +| src/client/util/jsx-decl.d.ts | TypeScript | 1 | 0 | 1 | 2 | +| src/client/util/request-image-size.js | JavaScript | 51 | 10 | 14 | 75 | +| src/client/util/toCSSLineSpacing.js | JavaScript | 35 | 15 | 14 | 64 | +| src/client/views/AntimodeMenu.scss | SCSS | 35 | 1 | 6 | 42 | +| src/client/views/AntimodeMenu.tsx | TypeScript React | 121 | 14 | 22 | 157 | +| src/client/views/ContextMenu.scss | SCSS | 130 | 17 | 14 | 161 | +| src/client/views/ContextMenu.tsx | TypeScript React | 258 | 3 | 33 | 294 | +| src/client/views/ContextMenuItem.tsx | TypeScript React | 107 | 0 | 10 | 117 | +| src/client/views/DictationOverlay.tsx | TypeScript React | 64 | 0 | 7 | 71 | +| src/client/views/DocComponent.tsx | TypeScript React | 87 | 20 | 15 | 122 | +| src/client/views/DocumentButtonBar.scss | SCSS | 89 | 0 | 16 | 105 | +| src/client/views/DocumentButtonBar.tsx | TypeScript React | 284 | 4 | 27 | 315 | +| src/client/views/DocumentDecorations.scss | SCSS | 319 | 0 | 46 | 365 | +| src/client/views/DocumentDecorations.tsx | TypeScript React | 479 | 2 | 26 | 507 | +| src/client/views/EditableView.scss | SCSS | 22 | 0 | 3 | 25 | +| src/client/views/EditableView.tsx | TypeScript React | 149 | 19 | 16 | 184 | +| src/client/views/GestureOverlay.scss | SCSS | 56 | 0 | 8 | 64 | +| src/client/views/GestureOverlay.tsx | TypeScript React | 711 | 45 | 67 | 823 | +| src/client/views/GlobalKeyHandler.ts | TypeScript | 232 | 10 | 27 | 269 | +| src/client/views/InkingControl.scss | SCSS | 127 | 4 | 0 | 131 | +| src/client/views/InkingControl.tsx | TypeScript React | 78 | 3 | 10 | 91 | +| src/client/views/InkingStroke.scss | SCSS | 7 | 0 | 0 | 7 | +| src/client/views/InkingStroke.tsx | TypeScript React | 63 | 0 | 5 | 68 | +| src/client/views/KeyphraseQueryView.scss | SCSS | 7 | 0 | 1 | 8 | +| src/client/views/KeyphraseQueryView.tsx | TypeScript React | 30 | 2 | 3 | 35 | +| src/client/views/Main.scss | SCSS | 51 | 8 | 10 | 69 | +| src/client/views/Main.tsx | TypeScript React | 22 | 1 | 2 | 25 | +| src/client/views/MainView.scss | SCSS | 138 | 1 | 21 | 160 | +| src/client/views/MainView.tsx | TypeScript React | 553 | 13 | 36 | 602 | +| src/client/views/MainViewModal.scss | SCSS | 24 | 0 | 1 | 25 | +| src/client/views/MainViewModal.tsx | TypeScript React | 39 | 0 | 5 | 44 | +| src/client/views/MainViewNotifs.scss | SCSS | 17 | 0 | 1 | 18 | +| src/client/views/MainViewNotifs.tsx | TypeScript React | 29 | 0 | 4 | 33 | +| src/client/views/MetadataEntryMenu.scss | SCSS | 79 | 0 | 14 | 93 | +| src/client/views/MetadataEntryMenu.tsx | TypeScript React | 207 | 0 | 16 | 223 | +| src/client/views/OCRUtils.ts | TypeScript | 2 | 2 | 4 | 8 | +| src/client/views/OverlayView.scss | SCSS | 41 | 0 | 6 | 47 | +| src/client/views/OverlayView.tsx | TypeScript React | 194 | 4 | 19 | 217 | +| src/client/views/Palette.scss | SCSS | 26 | 0 | 4 | 30 | +| src/client/views/Palette.tsx | TypeScript React | 65 | 0 | 5 | 70 | +| src/client/views/PreviewCursor.scss | SCSS | 9 | 0 | 1 | 10 | +| src/client/views/PreviewCursor.tsx | TypeScript React | 115 | 8 | 9 | 132 | +| src/client/views/RecommendationsBox.scss | SCSS | 52 | 10 | 8 | 70 | +| src/client/views/RecommendationsBox.tsx | TypeScript React | 116 | 67 | 17 | 200 | +| src/client/views/ScriptBox.scss | SCSS | 15 | 0 | 2 | 17 | +| src/client/views/ScriptBox.tsx | TypeScript React | 112 | 2 | 12 | 126 | +| src/client/views/ScriptingRepl.scss | SCSS | 42 | 0 | 9 | 51 | +| src/client/views/ScriptingRepl.tsx | TypeScript React | 220 | 1 | 24 | 245 | +| src/client/views/SearchDocBox.tsx | TypeScript React | 359 | 17 | 55 | 431 | +| src/client/views/TemplateMenu.scss | SCSS | 46 | 0 | 5 | 51 | +| src/client/views/TemplateMenu.tsx | TypeScript React | 167 | 1 | 14 | 182 | +| src/client/views/Templates.tsx | TypeScript React | 34 | 0 | 8 | 42 | +| src/client/views/TouchScrollableMenu.tsx | TypeScript React | 52 | 0 | 7 | 59 | +| src/client/views/Touchable.tsx | TypeScript React | 172 | 28 | 39 | 239 | +| src/client/views/_nodeModuleOverrides.scss | SCSS | 9 | 9 | 4 | 22 | +| src/client/views/animationtimeline/Keyframe.scss | SCSS | 83 | 5 | 17 | 105 | +| src/client/views/animationtimeline/Keyframe.tsx | TypeScript React | 468 | 50 | 42 | 560 | +| src/client/views/animationtimeline/Timeline.scss | SCSS | 264 | 14 | 44 | 322 | +| src/client/views/animationtimeline/Timeline.tsx | TypeScript React | 467 | 97 | 58 | 622 | +| src/client/views/animationtimeline/TimelineMenu.scss | SCSS | 75 | 2 | 17 | 94 | +| src/client/views/animationtimeline/TimelineMenu.tsx | TypeScript React | 68 | 0 | 10 | 78 | +| src/client/views/animationtimeline/TimelineOverview.scss | SCSS | 89 | 6 | 12 | 107 | +| src/client/views/animationtimeline/TimelineOverview.tsx | TypeScript React | 155 | 0 | 27 | 182 | +| src/client/views/animationtimeline/Track.scss | SCSS | 13 | 0 | 2 | 15 | +| src/client/views/animationtimeline/Track.tsx | TypeScript React | 284 | 63 | 33 | 380 | +| src/client/views/collections/CollectionCarouselView.scss | SCSS | 37 | 0 | 1 | 38 | +| src/client/views/collections/CollectionCarouselView.tsx | TypeScript React | 110 | 1 | 10 | 121 | +| src/client/views/collections/CollectionDockingView.scss | SCSS | 391 | 7 | 60 | 458 | +| src/client/views/collections/CollectionDockingView.tsx | TypeScript React | 707 | 61 | 65 | 833 | +| src/client/views/collections/CollectionLinearView.scss | SCSS | 68 | 0 | 10 | 78 | +| src/client/views/collections/CollectionLinearView.tsx | TypeScript React | 125 | 1 | 9 | 135 | +| src/client/views/collections/CollectionMapView.scss | SCSS | 27 | 0 | 3 | 30 | +| src/client/views/collections/CollectionMapView.tsx | TypeScript React | 235 | 10 | 18 | 263 | +| src/client/views/collections/CollectionMasonryViewFieldRow.tsx | TypeScript React | 308 | 0 | 24 | 332 | +| src/client/views/collections/CollectionPileView.scss | SCSS | 8 | 0 | 1 | 9 | +| src/client/views/collections/CollectionPileView.tsx | TypeScript React | 112 | 5 | 11 | 128 | +| src/client/views/collections/CollectionSchemaCells.tsx | TypeScript React | 274 | 17 | 38 | 329 | +| src/client/views/collections/CollectionSchemaHeaders.tsx | TypeScript React | 318 | 5 | 41 | 364 | +| src/client/views/collections/CollectionSchemaMovableTableHOC.tsx | TypeScript React | 216 | 0 | 27 | 243 | +| src/client/views/collections/CollectionSchemaView.scss | SCSS | 406 | 4 | 88 | 498 | +| src/client/views/collections/CollectionSchemaView.tsx | TypeScript React | 651 | 20 | 82 | 753 | +| src/client/views/collections/CollectionStackingView.scss | SCSS | 353 | 1 | 50 | 404 | +| src/client/views/collections/CollectionStackingView.tsx | TypeScript React | 430 | 5 | 25 | 460 | +| src/client/views/collections/CollectionStackingViewFieldColumn.tsx | TypeScript React | 367 | 0 | 27 | 394 | +| src/client/views/collections/CollectionStaffView.scss | SCSS | 12 | 0 | 1 | 13 | +| src/client/views/collections/CollectionStaffView.tsx | TypeScript React | 46 | 0 | 7 | 53 | +| src/client/views/collections/CollectionSubView.tsx | TypeScript React | 390 | 7 | 25 | 422 | +| src/client/views/collections/CollectionTimeView.scss | SCSS | 80 | 0 | 13 | 93 | +| src/client/views/collections/CollectionTimeView.tsx | TypeScript React | 177 | 0 | 15 | 192 | +| src/client/views/collections/CollectionTreeView.scss | SCSS | 125 | 4 | 23 | 152 | +| src/client/views/collections/CollectionTreeView.tsx | TypeScript React | 801 | 19 | 40 | 860 | +| src/client/views/collections/CollectionView.scss | SCSS | 70 | 0 | 8 | 78 | +| src/client/views/collections/CollectionView.tsx | TypeScript React | 457 | 13 | 34 | 504 | +| src/client/views/collections/CollectionViewChromes.scss | SCSS | 308 | 4 | 45 | 357 | +| src/client/views/collections/CollectionViewChromes.tsx | TypeScript React | 393 | 67 | 47 | 507 | +| src/client/views/collections/KeyRestrictionRow.tsx | TypeScript React | 49 | 2 | 4 | 55 | +| src/client/views/collections/ParentDocumentSelector.scss | SCSS | 54 | 0 | 2 | 56 | +| src/client/views/collections/ParentDocumentSelector.tsx | TypeScript React | 120 | 0 | 11 | 131 | +| src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx | TypeScript React | 422 | 10 | 27 | 459 | +| src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss | SCSS | 19 | 0 | 1 | 20 | +| src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx | TypeScript React | 110 | 5 | 4 | 119 | +| src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.scss | SCSS | 11 | 0 | 0 | 11 | +| src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx | TypeScript React | 44 | 0 | 2 | 46 | +| src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.scss | SCSS | 20 | 1 | 3 | 24 | +| src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx | TypeScript React | 67 | 0 | 12 | 79 | +| src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss | SCSS | 95 | 9 | 17 | 121 | +| src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx | TypeScript React | 1,186 | 47 | 97 | 1,330 | +| src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx | TypeScript React | 52 | 0 | 5 | 57 | +| src/client/views/collections/collectionFreeForm/MarqueeView.scss | SCSS | 30 | 0 | 2 | 32 | +| src/client/views/collections/collectionFreeForm/MarqueeView.tsx | TypeScript React | 484 | 105 | 33 | 622 | +| src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss | SCSS | 28 | 0 | 6 | 34 | +| src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx | TypeScript React | 202 | 72 | 23 | 297 | +| src/client/views/collections/collectionMulticolumn/CollectionMultirowView.scss | SCSS | 29 | 0 | 6 | 35 | +| src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx | TypeScript React | 204 | 72 | 22 | 298 | +| src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx | TypeScript React | 94 | 0 | 9 | 103 | +| src/client/views/collections/collectionMulticolumn/MulticolumnWidthLabel.tsx | TypeScript React | 51 | 0 | 5 | 56 | +| src/client/views/collections/collectionMulticolumn/MultirowHeightLabel.tsx | TypeScript React | 51 | 0 | 5 | 56 | +| src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx | TypeScript React | 92 | 0 | 9 | 101 | +| src/client/views/globalCssVariables.scss | SCSS | 30 | 10 | 3 | 43 | +| src/client/views/globalCssVariables.scss.d.ts | TypeScript | 9 | 0 | 2 | 11 | +| src/client/views/linking/LinkEditor.scss | SCSS | 124 | 1 | 25 | 150 | +| src/client/views/linking/LinkEditor.tsx | TypeScript React | 252 | 7 | 50 | 309 | +| src/client/views/linking/LinkMenu.scss | SCSS | 40 | 0 | 13 | 53 | +| src/client/views/linking/LinkMenu.tsx | TypeScript React | 65 | 1 | 10 | 76 | +| src/client/views/linking/LinkMenuGroup.tsx | TypeScript React | 84 | 0 | 10 | 94 | +| src/client/views/linking/LinkMenuItem.scss | SCSS | 75 | 1 | 11 | 87 | +| src/client/views/linking/LinkMenuItem.tsx | TypeScript React | 107 | 0 | 19 | 126 | +| src/client/views/nodes/AudioBox.scss | SCSS | 146 | 0 | 0 | 146 | +| src/client/views/nodes/AudioBox.tsx | TypeScript React | 261 | 2 | 24 | 287 | +| src/client/views/nodes/CollectionFreeFormDocumentView.scss | SCSS | 8 | 0 | 0 | 8 | +| src/client/views/nodes/CollectionFreeFormDocumentView.tsx | TypeScript React | 124 | 0 | 7 | 131 | +| src/client/views/nodes/ColorBox.scss | SCSS | 22 | 0 | 1 | 23 | +| src/client/views/nodes/ColorBox.tsx | TypeScript React | 28 | 0 | 4 | 32 | +| src/client/views/nodes/ContentFittingDocumentView.scss | SCSS | 20 | 0 | 4 | 24 | +| src/client/views/nodes/ContentFittingDocumentView.tsx | TypeScript React | 117 | 0 | 7 | 124 | +| src/client/views/nodes/DocumentBox.scss | SCSS | 14 | 0 | 0 | 14 | +| src/client/views/nodes/DocumentBox.tsx | TypeScript React | 154 | 0 | 4 | 158 | +| src/client/views/nodes/DocumentContentsView.tsx | TypeScript React | 183 | 10 | 17 | 210 | +| src/client/views/nodes/DocumentIcon.tsx | TypeScript React | 60 | 0 | 5 | 65 | +| src/client/views/nodes/DocumentView.scss | SCSS | 110 | 1 | 15 | 126 | +| src/client/views/nodes/DocumentView.tsx | TypeScript React | 1,041 | 54 | 94 | 1,189 | +| src/client/views/nodes/FaceRectangle.tsx | TypeScript React | 25 | 0 | 4 | 29 | +| src/client/views/nodes/FaceRectangles.tsx | TypeScript React | 41 | 0 | 5 | 46 | +| src/client/views/nodes/FieldTextBox.scss | SCSS | 12 | 0 | 3 | 15 | +| src/client/views/nodes/FieldView.tsx | TypeScript React | 89 | 43 | 4 | 136 | +| src/client/views/nodes/FontIconBox.scss | SCSS | 25 | 0 | 2 | 27 | +| src/client/views/nodes/FontIconBox.tsx | TypeScript React | 58 | 0 | 5 | 63 | +| src/client/views/nodes/ImageBox.scss | SCSS | 135 | 0 | 17 | 152 | +| src/client/views/nodes/ImageBox.tsx | TypeScript React | 430 | 10 | 35 | 475 | +| src/client/views/nodes/KeyValueBox.scss | SCSS | 120 | 0 | 3 | 123 | +| src/client/views/nodes/KeyValueBox.tsx | TypeScript React | 244 | 1 | 26 | 271 | +| src/client/views/nodes/KeyValuePair.scss | SCSS | 55 | 1 | 4 | 60 | +| src/client/views/nodes/KeyValuePair.tsx | TypeScript React | 125 | 2 | 8 | 135 | +| src/client/views/nodes/LabelBox.scss | SCSS | 31 | 0 | 4 | 35 | +| src/client/views/nodes/LabelBox.tsx | TypeScript React | 86 | 1 | 9 | 96 | +| src/client/views/nodes/LinkAnchorBox.scss | SCSS | 27 | 0 | 2 | 29 | +| src/client/views/nodes/LinkAnchorBox.tsx | TypeScript React | 141 | 0 | 9 | 150 | +| src/client/views/nodes/LinkBox.scss | SCSS | 3 | 0 | 0 | 3 | +| src/client/views/nodes/LinkBox.tsx | TypeScript React | 33 | 0 | 3 | 36 | +| src/client/views/nodes/PDFBox.scss | SCSS | 200 | 0 | 19 | 219 | +| src/client/views/nodes/PDFBox.tsx | TypeScript React | 246 | 0 | 19 | 265 | +| src/client/views/nodes/PresBox.scss | SCSS | 52 | 0 | 1 | 53 | +| src/client/views/nodes/PresBox.tsx | TypeScript React | 268 | 31 | 32 | 331 | +| src/client/views/nodes/QueryBox.scss | SCSS | 5 | 0 | 0 | 5 | +| src/client/views/nodes/QueryBox.tsx | TypeScript React | 37 | 0 | 4 | 41 | +| src/client/views/nodes/RadialMenu.scss | SCSS | 60 | 3 | 7 | 70 | +| src/client/views/nodes/RadialMenu.tsx | TypeScript React | 174 | 26 | 36 | 236 | +| src/client/views/nodes/RadialMenuItem.tsx | TypeScript React | 101 | 0 | 16 | 117 | +| src/client/views/nodes/ScreenshotBox.scss | SCSS | 40 | 6 | 5 | 51 | +| src/client/views/nodes/ScreenshotBox.tsx | TypeScript React | 174 | 2 | 18 | 194 | +| src/client/views/nodes/ScriptingBox.scss | SCSS | 33 | 0 | 3 | 36 | +| src/client/views/nodes/ScriptingBox.tsx | TypeScript React | 87 | 0 | 12 | 99 | +| src/client/views/nodes/SliderBox-components.tsx | TypeScript React | 220 | 12 | 25 | 257 | +| src/client/views/nodes/SliderBox-tooltip.css | CSS | 30 | 0 | 3 | 33 | +| src/client/views/nodes/SliderBox.scss | SCSS | 7 | 0 | 0 | 7 | +| src/client/views/nodes/SliderBox.tsx | TypeScript React | 117 | 0 | 8 | 125 | +| src/client/views/nodes/VideoBox.scss | SCSS | 65 | 3 | 6 | 74 | +| src/client/views/nodes/VideoBox.tsx | TypeScript React | 343 | 2 | 34 | 379 | +| src/client/views/nodes/WebBox.scss | SCSS | 109 | 0 | 18 | 127 | +| src/client/views/nodes/WebBox.tsx | TypeScript React | 345 | 15 | 35 | 395 | +| src/client/views/nodes/formattedText/DashDocCommentView.tsx | TypeScript React | 82 | 0 | 13 | 95 | +| src/client/views/nodes/formattedText/DashDocView.tsx | TypeScript React | 223 | 9 | 37 | 269 | +| src/client/views/nodes/formattedText/DashFieldView.scss | SCSS | 34 | 0 | 2 | 36 | +| src/client/views/nodes/formattedText/DashFieldView.tsx | TypeScript React | 178 | 13 | 20 | 211 | +| src/client/views/nodes/formattedText/FootnoteView.tsx | TypeScript React | 131 | 13 | 19 | 163 | +| src/client/views/nodes/formattedText/FormattedTextBox.scss | SCSS | 220 | 11 | 34 | 265 | +| src/client/views/nodes/formattedText/FormattedTextBox.tsx | TypeScript React | 1,169 | 68 | 93 | 1,330 | +| src/client/views/nodes/formattedText/FormattedTextBoxComment.scss | SCSS | 33 | 0 | 0 | 33 | +| src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx | TypeScript React | 218 | 11 | 8 | 237 | +| src/client/views/nodes/formattedText/ImageResizeView.tsx | TypeScript React | 113 | 0 | 25 | 138 | +| src/client/views/nodes/formattedText/ParagraphNodeSpec.ts | TypeScript | 108 | 9 | 26 | 143 | +| src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts | TypeScript | 231 | 0 | 11 | 242 | +| src/client/views/nodes/formattedText/RichTextMenu.scss | SCSS | 100 | 2 | 19 | 121 | +| src/client/views/nodes/formattedText/RichTextMenu.tsx | TypeScript React | 754 | 12 | 109 | 875 | +| src/client/views/nodes/formattedText/RichTextRules.ts | TypeScript | 308 | 7 | 5 | 320 | +| src/client/views/nodes/formattedText/RichTextSchema.tsx | TypeScript React | 465 | 33 | 39 | 537 | +| src/client/views/nodes/formattedText/SummaryView.tsx | TypeScript React | 67 | 0 | 14 | 81 | +| src/client/views/nodes/formattedText/TooltipTextMenu.scss | SCSS | 306 | 6 | 61 | 373 | +| src/client/views/nodes/formattedText/marks_rts.ts | TypeScript | 259 | 15 | 23 | 297 | +| src/client/views/nodes/formattedText/nodes_rts.ts | TypeScript | 224 | 21 | 19 | 264 | +| src/client/views/nodes/formattedText/prosemirrorPatches.js | JavaScript | 118 | 12 | 9 | 139 | +| src/client/views/nodes/formattedText/schema_rts.ts | TypeScript | 12 | 8 | 6 | 26 | +| src/client/views/pdf/Annotation.scss | SCSS | 6 | 0 | 0 | 6 | +| src/client/views/pdf/Annotation.tsx | TypeScript React | 114 | 0 | 16 | 130 | +| src/client/views/pdf/PDFMenu.scss | SCSS | 6 | 0 | 0 | 6 | +| src/client/views/pdf/PDFMenu.tsx | TypeScript React | 102 | 0 | 21 | 123 | +| src/client/views/pdf/PDFViewer.scss | SCSS | 74 | 4 | 10 | 88 | +| src/client/views/pdf/PDFViewer.tsx | TypeScript React | 662 | 23 | 46 | 731 | +| src/client/views/presentationview/PresElementBox.scss | SCSS | 93 | 0 | 10 | 103 | +| src/client/views/presentationview/PresElementBox.tsx | TypeScript React | 179 | 31 | 14 | 224 | +| src/client/views/search/CheckBox.scss | SCSS | 50 | 1 | 8 | 59 | +| src/client/views/search/CheckBox.tsx | TypeScript React | 42 | 74 | 15 | 131 | +| src/client/views/search/CollectionFilters.scss | SCSS | 17 | 0 | 3 | 20 | +| src/client/views/search/CollectionFilters.tsx | TypeScript React | 69 | 0 | 14 | 83 | +| src/client/views/search/FieldFilters.scss | SCSS | 10 | 1 | 1 | 12 | +| src/client/views/search/FieldFilters.tsx | TypeScript React | 34 | 0 | 7 | 41 | +| src/client/views/search/FilterBox.scss | SCSS | 153 | 0 | 25 | 178 | +| src/client/views/search/FilterBox.tsx | TypeScript React | 354 | 24 | 54 | 432 | +| src/client/views/search/IconBar.scss | SCSS | 9 | 0 | 1 | 10 | +| src/client/views/search/IconBar.tsx | TypeScript React | 69 | 1 | 17 | 87 | +| src/client/views/search/IconButton.scss | SCSS | 46 | 1 | 6 | 53 | +| src/client/views/search/IconButton.tsx | TypeScript React | 170 | 2 | 19 | 191 | +| src/client/views/search/NaviconButton.scss | SCSS | 58 | 0 | 11 | 69 | +| src/client/views/search/NaviconButton.tsx | TypeScript React | 32 | 0 | 5 | 37 | +| src/client/views/search/SearchBox.scss | SCSS | 203 | 82 | 51 | 336 | +| src/client/views/search/SearchBox.tsx | TypeScript React | 530 | 47 | 94 | 671 | +| src/client/views/search/SearchItem.scss | SCSS | 138 | 0 | 25 | 163 | +| src/client/views/search/SearchItem.tsx | TypeScript React | 272 | 2 | 29 | 303 | +| src/client/views/search/SelectorContextMenu.scss | SCSS | 12 | 1 | 3 | 16 | +| src/client/views/search/ToggleBar.scss | SCSS | 35 | 2 | 4 | 41 | +| src/client/views/search/ToggleBar.tsx | TypeScript React | 77 | 0 | 9 | 86 | +| src/client/views/webcam/DashWebRTCVideo.scss | SCSS | 70 | 4 | 9 | 83 | +| src/client/views/webcam/DashWebRTCVideo.tsx | TypeScript React | 67 | 6 | 16 | 89 | +| src/client/views/webcam/WebCamLogic.js | JavaScript | 234 | 7 | 51 | 292 | +| src/debug/Repl.tsx | TypeScript React | 59 | 0 | 7 | 66 | +| src/debug/Test.tsx | TypeScript React | 12 | 0 | 2 | 14 | +| src/debug/Viewer.tsx | TypeScript React | 173 | 0 | 19 | 192 | +| src/extensions/ArrayExtensions.ts | TypeScript | 26 | 5 | 6 | 37 | +| src/extensions/General/Extensions.ts | TypeScript | 7 | 0 | 2 | 9 | +| src/extensions/General/ExtensionsTypings.ts | TypeScript | 7 | 0 | 1 | 8 | +| src/extensions/StringExtensions.ts | TypeScript | 13 | 0 | 4 | 17 | +| src/mobile/ImageUpload.scss | SCSS | 30 | 0 | 4 | 34 | +| src/mobile/ImageUpload.tsx | TypeScript React | 78 | 41 | 12 | 131 | +| src/mobile/InkControls.tsx | TypeScript React | 0 | 0 | 1 | 1 | +| src/mobile/MobileInkOverlay.scss | SCSS | 33 | 1 | 5 | 39 | +| src/mobile/MobileInkOverlay.tsx | TypeScript React | 162 | 3 | 26 | 191 | +| src/mobile/MobileInterface.scss | SCSS | 17 | 0 | 2 | 19 | +| src/mobile/MobileInterface.tsx | TypeScript React | 297 | 15 | 32 | 344 | +| src/new_fields/CursorField.ts | TypeScript | 54 | 0 | 12 | 66 | +| src/new_fields/DateField.ts | TypeScript | 30 | 0 | 7 | 37 | +| src/new_fields/Doc.ts | TypeScript | 897 | 85 | 76 | 1,058 | +| src/new_fields/FieldSymbols.ts | TypeScript | 11 | 0 | 2 | 13 | +| src/new_fields/HtmlField.ts | TypeScript | 22 | 0 | 5 | 27 | +| src/new_fields/IconField.ts | TypeScript | 22 | 0 | 5 | 27 | +| src/new_fields/InkField.ts | TypeScript | 41 | 0 | 10 | 51 | +| src/new_fields/List.ts | TypeScript | 244 | 38 | 20 | 302 | +| src/new_fields/ListSpec.ts | TypeScript | 0 | 0 | 1 | 1 | +| src/new_fields/ObjectField.ts | TypeScript | 16 | 0 | 4 | 20 | +| src/new_fields/PresField.ts | TypeScript | 3 | 1 | 2 | 6 | +| src/new_fields/Proxy.ts | TypeScript | 95 | 2 | 14 | 111 | +| src/new_fields/RefField.ts | TypeScript | 17 | 0 | 5 | 22 | +| src/new_fields/RichTextField.ts | TypeScript | 33 | 0 | 8 | 41 | +| src/new_fields/RichTextUtils.ts | TypeScript | 455 | 8 | 56 | 519 | +| src/new_fields/Schema.ts | TypeScript | 107 | 5 | 8 | 120 | +| src/new_fields/SchemaHeaderField.ts | TypeScript | 104 | 4 | 14 | 122 | +| src/new_fields/ScriptField.ts | TypeScript | 137 | 21 | 19 | 177 | +| src/new_fields/Types.ts | TypeScript | 86 | 5 | 17 | 108 | +| src/new_fields/URLField.ts | TypeScript | 45 | 0 | 9 | 54 | +| src/new_fields/documentSchemas.ts | TypeScript | 87 | 0 | 6 | 93 | +| src/new_fields/util.ts | TypeScript | 176 | 3 | 15 | 194 | +| src/pen-gestures/GestureUtils.ts | TypeScript | 41 | 0 | 5 | 46 | +| src/pen-gestures/ndollar.ts | TypeScript | 356 | 172 | 22 | 550 | +| src/scraping/acm/.gitignore | Ignore | 2 | 0 | 0 | 2 | +| src/scraping/acm/debug.log | log | 38 | 0 | 1 | 39 | +| src/scraping/acm/index.js | JavaScript | 82 | 185 | 13 | 280 | +| src/scraping/acm/package.json | JSON | 17 | 0 | 1 | 18 | +| src/scraping/buxton/.idea/buxton.iml | XML | 8 | 0 | 0 | 8 | +| src/scraping/buxton/.idea/inspectionProfiles/profiles_settings.xml | XML | 6 | 0 | 0 | 6 | +| src/scraping/buxton/.idea/misc.xml | XML | 4 | 0 | 0 | 4 | +| src/scraping/buxton/.idea/modules.xml | XML | 8 | 0 | 0 | 8 | +| src/scraping/buxton/.idea/vcs.xml | XML | 6 | 0 | 0 | 6 | +| src/scraping/buxton/.idea/workspace.xml | XML | 173 | 0 | 0 | 173 | +| src/scraping/buxton/final/BuxtonImporter.ts | TypeScript | 228 | 142 | 26 | 396 | +| src/scraping/buxton/jsonifier.py | Python | 183 | 1 | 48 | 232 | +| src/scraping/buxton/narratives.py | Python | 11 | 19 | 9 | 39 | +| src/scraping/buxton/narratives/chord_keyboards.json | JSON | 39 | 0 | 0 | 39 | +| src/scraping/buxton/scraper.py | Python | 350 | 5 | 78 | 433 | +| src/server/ActionUtilities.ts | TypeScript | 136 | 1 | 23 | 160 | +| src/server/ApiManagers/ApiManager.ts | TypeScript | 8 | 0 | 3 | 11 | +| src/server/ApiManagers/DeleteManager.ts | TypeScript | 71 | 0 | 11 | 82 | +| src/server/ApiManagers/DownloadManager.ts | TypeScript | 173 | 80 | 16 | 269 | +| src/server/ApiManagers/GeneralGoogleManager.ts | TypeScript | 53 | 0 | 8 | 61 | +| src/server/ApiManagers/GooglePhotosManager.ts | TypeScript | 190 | 119 | 22 | 331 | +| src/server/ApiManagers/PDFManager.ts | TypeScript | 103 | 0 | 12 | 115 | +| src/server/ApiManagers/SearchManager.ts | TypeScript | 200 | 0 | 15 | 215 | +| src/server/ApiManagers/SessionManager.ts | TypeScript | 56 | 0 | 11 | 67 | +| src/server/ApiManagers/UploadManager.ts | TypeScript | 226 | 1 | 20 | 247 | +| src/server/ApiManagers/UserManager.ts | TypeScript | 101 | 4 | 21 | 126 | +| src/server/ApiManagers/UtilManager.ts | TypeScript | 42 | 22 | 10 | 74 | +| src/server/Client.ts | TypeScript | 8 | 0 | 3 | 11 | +| src/server/DashSession/DashSessionAgent.ts | TypeScript | 155 | 52 | 23 | 230 | +| src/server/DashSession/Session/agents/applied_session_agent.ts | TypeScript | 47 | 2 | 9 | 58 | +| src/server/DashSession/Session/agents/monitor.ts | TypeScript | 213 | 59 | 26 | 298 | +| src/server/DashSession/Session/agents/process_message_router.ts | TypeScript | 24 | 10 | 7 | 41 | +| src/server/DashSession/Session/agents/promisified_ipc_manager.ts | TypeScript | 106 | 52 | 15 | 173 | +| src/server/DashSession/Session/agents/server_worker.ts | TypeScript | 99 | 46 | 15 | 160 | +| src/server/DashSession/Session/utilities/repl.ts | TypeScript | 116 | 0 | 12 | 128 | +| src/server/DashSession/Session/utilities/session_config.ts | TypeScript | 119 | 0 | 10 | 129 | +| src/server/DashSession/Session/utilities/utilities.ts | TypeScript | 24 | 8 | 5 | 37 | +| src/server/DashUploadUtils.ts | TypeScript | 285 | 52 | 30 | 367 | +| src/server/GarbageCollector.ts | TypeScript | 138 | 2 | 11 | 151 | +| src/server/IDatabase.ts | TypeScript | 17 | 0 | 8 | 25 | +| src/server/MemoryDatabase.ts | TypeScript | 87 | 0 | 14 | 101 | +| src/server/Message.ts | TypeScript | 86 | 0 | 18 | 104 | +| src/server/PdfTypes.ts | TypeScript | 19 | 0 | 2 | 21 | +| src/server/ProcessFactory.ts | TypeScript | 34 | 0 | 10 | 44 | +| src/server/Recommender.ts | TypeScript | 0 | 120 | 18 | 138 | +| src/server/RouteManager.ts | TypeScript | 187 | 4 | 19 | 210 | +| src/server/RouteSubscriber.ts | TypeScript | 21 | 0 | 5 | 26 | +| src/server/Search.ts | TypeScript | 71 | 2 | 8 | 81 | +| src/server/SharedMediaTypes.ts | TypeScript | 41 | 0 | 10 | 51 | +| src/server/Websocket/Websocket.ts | TypeScript | 263 | 5 | 46 | 314 | +| src/server/apis/google/GoogleApiServerUtils.ts | TypeScript | 172 | 168 | 25 | 365 | +| src/server/apis/google/SharedTypes.ts | TypeScript | 19 | 0 | 2 | 21 | +| src/server/apis/youtube/youtubeApiSample.d.ts | TypeScript | 2 | 0 | 0 | 2 | +| src/server/apis/youtube/youtubeApiSample.js | JavaScript | 135 | 30 | 14 | 179 | +| src/server/authentication/config/passport.ts | TypeScript | 23 | 2 | 4 | 29 | +| src/server/authentication/controllers/user_controller.ts | TypeScript | 218 | 25 | 25 | 268 | +| src/server/authentication/models/current_user_utils.ts | TypeScript | 586 | 30 | 57 | 673 | +| src/server/authentication/models/user_model.ts | TypeScript | 63 | 9 | 14 | 86 | +| src/server/credentials/CredentialsLoader.ts | TypeScript | 24 | 0 | 6 | 30 | +| src/server/credentials/google_project_credentials.json | JSON | 11 | 0 | 0 | 11 | +| src/server/database.ts | TypeScript | 312 | 0 | 38 | 350 | +| src/server/downsize.ts | TypeScript | 34 | 5 | 1 | 40 | +| src/server/index.ts | TypeScript | 107 | 36 | 16 | 159 | +| src/server/remapUrl.ts | TypeScript | 53 | 4 | 6 | 63 | +| src/server/server_Initialization.ts | TypeScript | 138 | 6 | 24 | 168 | +| src/server/slides.json | JSON | 10,820 | 0 | 0 | 10,820 | +| src/server/updateProtos.ts | TypeScript | 11 | 0 | 3 | 14 | +| src/typings/index.d.ts | TypeScript | 219 | 72 | 38 | 329 | +| test/test.ts | TypeScript | 141 | 0 | 20 | 161 | +| tsconfig.json | JSON | 21 | 5 | 0 | 26 | +| tslint.json | JSON | 30 | 32 | 1 | 63 | +| views/forgot.pug | Pug | 19 | 1 | 2 | 22 | +| views/layout.pug | Pug | 13 | 0 | 1 | 14 | +| views/login.pug | Pug | 24 | 0 | 2 | 26 | +| views/reset.pug | Pug | 20 | 0 | 2 | 22 | +| views/signup.pug | Pug | 25 | 0 | 2 | 27 | +| views/stylesheets/authentication.css | CSS | 185 | 4 | 34 | 223 | +| views/user_activity.pug | Pug | 18 | 0 | 1 | 19 | +| webpack.config.js | JavaScript | 116 | 0 | 5 | 121 | +| Total | | 224,911 | 32,987 | 15,880 | 273,778 | ++-------------------------------------------------------------------------------------------------------------+------------------+------------+------------+------------+------------+ \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index bc8ca01f5..959fc41ef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2723,6 +2723,43 @@ } } }, + "canvas": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.6.1.tgz", + "integrity": "sha512-S98rKsPcuhfTcYbtF53UIJhcbgIAK533d1kJKMwsMwAIFgfd58MOyxRud3kktlzWiEkFliaJtvyZCBtud/XVEA==", + "requires": { + "nan": "^2.14.0", + "node-pre-gyp": "^0.11.0", + "simple-get": "^3.0.3" + }, + "dependencies": { + "node-pre-gyp": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz", + "integrity": "sha512-TwWAOZb0j7e9eGaf9esRx3ZcLaE5tQ2lvYy1pb5IAaG1a2e2Kv5Lms1Y4hpj+ciXJRofIxxlt5haeQ/2ANeE0Q==", + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + } + } + }, "capture-stack-trace": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz", @@ -2848,8 +2885,7 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true, - "optional": true + "bundled": true }, "aproba": { "version": "1.2.0", @@ -2867,13 +2903,11 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true, - "optional": true + "bundled": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2886,18 +2920,15 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "concat-map": { "version": "0.0.1", - "bundled": true, - "optional": true + "bundled": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "core-util-is": { "version": "1.0.2", @@ -3000,8 +3031,7 @@ }, "inherits": { "version": "2.0.4", - "bundled": true, - "optional": true + "bundled": true }, "ini": { "version": "1.3.5", @@ -3011,7 +3041,6 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -3024,20 +3053,17 @@ "minimatch": { "version": "3.0.4", "bundled": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "1.2.5", - "bundled": true, - "optional": true + "bundled": true }, "minipass": { "version": "2.9.0", "bundled": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -3054,7 +3080,6 @@ "mkdirp": { "version": "0.5.3", "bundled": true, - "optional": true, "requires": { "minimist": "^1.2.5" } @@ -3110,8 +3135,7 @@ }, "npm-normalize-package-bin": { "version": "1.0.1", - "bundled": true, - "optional": true + "bundled": true }, "npm-packlist": { "version": "1.4.8", @@ -3136,8 +3160,7 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true, - "optional": true + "bundled": true }, "object-assign": { "version": "4.1.1", @@ -3147,7 +3170,6 @@ "once": { "version": "1.4.0", "bundled": true, - "optional": true, "requires": { "wrappy": "1" } @@ -3216,8 +3238,7 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true, - "optional": true + "bundled": true }, "safer-buffer": { "version": "2.1.2", @@ -3247,7 +3268,6 @@ "string-width": { "version": "1.0.2", "bundled": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -3265,7 +3285,6 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -3304,13 +3323,11 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true, - "optional": true + "bundled": true }, "yallist": { "version": "3.1.1", - "bundled": true, - "optional": true + "bundled": true } } } diff --git a/src/Utils.ts b/src/Utils.ts index ad12c68a1..23b59ac9d 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -4,7 +4,7 @@ import { Socket, Room } from 'socket.io'; import { Message } from './server/Message'; export namespace Utils { - export const DRAG_THRESHOLD = 4; + export let DRAG_THRESHOLD = 4; export function GenerateGuid(): string { return v4(); @@ -512,7 +512,7 @@ export function setupMoveUpEvents( (target as any)._downY = (target as any)._lastY = e.clientY; const _moveEvent = (e: PointerEvent): void => { - if (Math.abs(e.clientX - (target as any)._downX) > 4 || Math.abs(e.clientY - (target as any)._downY) > 4) { + if (Math.abs(e.clientX - (target as any)._downX) > Utils.DRAG_THRESHOLD || Math.abs(e.clientY - (target as any)._downY) > Utils.DRAG_THRESHOLD) { if (moveEvent(e, [(target as any)._downX, (target as any)._downY], [e.clientX - (target as any)._lastX, e.clientY - (target as any)._lastY])) { document.removeEventListener("pointermove", _moveEvent); diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index c03d9ea1b..c48611eff 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -1,5 +1,5 @@ import { Doc, Field, DocListCast } from "../../new_fields/Doc"; -import { Cast, ScriptCast, StrCast } from "../../new_fields/Types"; +import { Cast, ScriptCast, StrCast, NumCast } from "../../new_fields/Types"; import { emptyFunction } from "../../Utils"; import { CollectionDockingView } from "../views/collections/CollectionDockingView"; import * as globalCssVariables from "../views/globalCssVariables.scss"; @@ -305,33 +305,20 @@ export namespace DragManager { } export function snapDrag(e: PointerEvent, xFromLeft: number, yFromTop: number, xFromRight: number, yFromBottom: number) { - let thisX = e.pageX; - let thisY = e.pageY; - const currLeft = e.pageX - xFromLeft; - const currTop = e.pageY - yFromTop; - const currRight = e.pageX + xFromRight; - const currBottom = e.pageY + yFromBottom; - const closestLeft = vertSnapLines.length ? vertSnapLines.reduce((prev, curr) => Math.abs(prev - currLeft) > Math.abs(curr - currLeft) ? curr : prev) : currLeft; - const closestTop = horizSnapLines.length ? horizSnapLines.reduce((prev, curr) => Math.abs(prev - currTop) > Math.abs(curr - currTop) ? curr : prev) : currTop; - const closestRight = vertSnapLines.length ? vertSnapLines.reduce((prev, curr) => Math.abs(prev - currRight) > Math.abs(curr - currRight) ? curr : prev) : currRight; - const closestBottom = horizSnapLines.length ? horizSnapLines.reduce((prev, curr) => Math.abs(prev - currBottom) > Math.abs(curr - currBottom) ? curr : prev) : currBottom; - const distFromClosestLeft = Math.abs(e.pageX - xFromLeft - closestLeft); - const distFromClosestTop = Math.abs(e.pageY - yFromTop - closestTop); - const distFromClosestRight = Math.abs(e.pageX + xFromRight - closestRight); - const distFromClosestBottom = Math.abs(e.pageY + yFromBottom - closestBottom); - if (distFromClosestLeft < 10 && distFromClosestLeft < distFromClosestRight) { - thisX = closestLeft + xFromLeft; - } - else if (distFromClosestRight < 10) { - thisX = closestRight - xFromRight; - } - if (distFromClosestTop < 10 && distFromClosestTop < distFromClosestBottom) { - thisY = closestTop + yFromTop; - } - else if (distFromClosestBottom < 10) { - thisY = closestBottom - yFromBottom; + const snapThreshold = NumCast(Doc.UserDoc()["constants-snapThreshold"], 10); + const snapVal = (pts: number[], drag: number, snapLines: number[]) => { + if (snapLines.length) { + const offs = [pts[0], (pts[0] - pts[1]) / 2, -pts[1]]; // offsets from drag pt + const rangePts = [drag - offs[0], drag - offs[1], drag - offs[2]]; // left, mid, right or top, mid, bottom pts to try to snap to snaplines + const closestPts = rangePts.map(pt => snapLines.reduce((nearest, curr) => Math.abs(nearest - pt) > Math.abs(curr - pt) ? curr : nearest)); + const closestDists = rangePts.map((pt, i) => Math.abs(pt - closestPts[i])); + const minIndex = closestDists[0] < closestDists[1] && closestDists[0] < closestDists[2] ? 0 : closestDists[1] < closestDists[2] ? 1 : 2; + return closestDists[minIndex] < snapThreshold ? closestPts[minIndex] + offs[minIndex] : drag; + } + return drag; } - return { thisX, thisY }; + + return { thisX: snapVal([xFromLeft, xFromRight], e.pageX, vertSnapLines), thisY: snapVal([yFromTop, yFromBottom], e.pageY, horizSnapLines) }; } export let docsBeingDragged: Doc[] = []; function StartDrag(eles: HTMLElement[], dragData: { [id: string]: any }, downX: number, downY: number, options?: DragOptions, finishDrag?: (dropData: DragCompleteEvent) => void) { diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index e5a8ebcb5..72dfdf75c 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -588,12 +588,12 @@ export class MainView extends React.Component { {// TO VIEW SNAP LINES - /*
+
- {this._hLines?.map(l => )} - {this._vLines?.map(l => )} + {this._hLines?.map(l => )} + {this._vLines?.map(l => )} -
*/} +
}
); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 11d0f298d..763a6c605 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -869,6 +869,7 @@ export class CollectionFreeFormView extends CollectionSubView { + const size = this.props.ScreenToLocalTransform().transformDirection(this.props.PanelWidth(), this.props.PanelHeight()); + const selRect = { left: this.panX() - size[0] / 2, top: this.panY() - size[1] / 2, width: size[0], height: size[1] }; + const docDims = (doc: Doc) => ({ left: NumCast(doc.x), top: NumCast(doc.y), width: NumCast(doc._width), height: NumCast(doc._height) }); + const isDocInView = (doc: Doc, rect: { left: number, top: number, width: number, height: number }) => { + if (this.intersectRect(docDims(doc), rect)) { + snappableDocs.push(doc); + } + } + const snappableDocs: Doc[] = []; // the set of documents in the visible viewport that we will try to snap to; + const otherBounds = { left: this.panX(), top: this.panY(), width: Math.abs(size[0]), height: Math.abs(size[1]) }; + this.getActiveDocuments().filter(doc => !doc.isBackground && doc.z === undefined).map(doc => isDocInView(doc, selRect)); // first see if there are any foreground docs to snap to + !snappableDocs.length && this.getActiveDocuments().filter(doc => doc.z === undefined).map(doc => isDocInView(doc, selRect)); // if not, see if there are background docs to snap to + !snappableDocs.length && this.getActiveDocuments().filter(doc => doc.z !== undefined).map(doc => isDocInView(doc, otherBounds)); // if not, then why not snap to floating docs + + const horizLines: number[] = []; + const vertLines: number[] = []; + snappableDocs.filter(doc => !DragManager.docsBeingDragged.includes(Cast(doc.rootDocument, Doc, null) || doc)).forEach(doc => { + const { left, top, width, height } = docDims(doc); + const topLeftInScreen = this.getTransform().inverse().transformPoint(left, top); + const docSize = this.getTransform().inverse().transformDirection(width, height); + + horizLines.push(topLeftInScreen[1], topLeftInScreen[1] + docSize[1] / 2, topLeftInScreen[1] + docSize[1]); // horiz center line + vertLines.push(topLeftInScreen[0], topLeftInScreen[0] + docSize[0] / 2, topLeftInScreen[0] + docSize[0]);// right line + }); + DragManager.SetSnapLines(horizLines, vertLines); + } onPointerOver = (e: React.PointerEvent) => { if (SelectionManager.GetIsDragging()) { - const size = this.props.ScreenToLocalTransform().transformDirection(this.props.PanelWidth(), this.props.PanelHeight()); - const selRect = { left: this.panX() - size[0] / 2, top: this.panY() - size[1] / 2, width: size[0], height: size[1] }; - const selection: Doc[] = []; - const docDims = (doc: Doc, layoutDoc: Doc) => ({ left: NumCast(doc.x), top: NumCast(doc.y), width: NumCast(layoutDoc._width), height: NumCast(layoutDoc._height) }); - const compareDoc = (doc: Doc, rect: { left: number, top: number, width: number, height: number }) => { - if (this.intersectRect(docDims(doc, Doc.Layout(doc)), rect)) { - selection.push(doc); - } - } - const otherBounds = { left: this.panX(), top: this.panY(), width: Math.abs(size[0]), height: Math.abs(size[1]) }; - this.getActiveDocuments().filter(doc => !doc.isBackground && doc.z === undefined).map(doc => compareDoc(doc, selRect)); // first try foreground docs - !selection.length && this.getActiveDocuments().filter(doc => doc.z === undefined).map(doc => compareDoc(doc, selRect)); // then background docs - !selection.length && this.getActiveDocuments().filter(doc => doc.z !== undefined).map(doc => compareDoc(doc, otherBounds)); // then floating docs - - const horizLines: number[] = []; - const vertLines: number[] = []; - selection.filter(doc => !DragManager.docsBeingDragged.includes(doc)).forEach(doc => { - const { left, top, width, height } = docDims(doc, Doc.Layout(doc)); - const topLeftInScreen = this.getTransform().inverse().transformPoint(left, top); - const docSize = this.getTransform().inverse().transformDirection(width, height); - - horizLines.push(topLeftInScreen[1]); // top line - horizLines.push(topLeftInScreen[1] + docSize[1]); // bottom line - horizLines.push(topLeftInScreen[1] + docSize[1] / 2); // horiz center line - vertLines.push(topLeftInScreen[0]);//left line - vertLines.push(topLeftInScreen[0] + docSize[0]);// right line - vertLines.push(topLeftInScreen[0] + docSize[0] / 2);// vert center line - }); - DragManager.SetSnapLines(horizLines, vertLines); + this.setupDragLines(e); } e.stopPropagation(); } @@ -1273,12 +1273,12 @@ export class CollectionFreeFormView extends CollectionSubView
{// uncomment to show snap lines - /*
- - {this._hLines?.map(l => )} - {this._vLines?.map(l => )} - -
*/} +
+ + {this._hLines?.map(l => )} + {this._vLines?.map(l => )} + +
}
; } } diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx index 422710c3e..1b22ed4cd 100644 --- a/src/client/views/nodes/formattedText/DashFieldView.tsx +++ b/src/client/views/nodes/formattedText/DashFieldView.tsx @@ -34,8 +34,6 @@ export class DashFieldView { docid={node.attrs.docid} width={node.attrs.width} height={node.attrs.height} - view={view} - getPos={getPos} tbox={tbox} />, this._fieldWrapper); (this as any).dom = this._fieldWrapper; @@ -49,8 +47,6 @@ export class DashFieldView { interface IDashFieldViewInternal { fieldKey: string; docid: string; - view: any; - getPos: any; tbox: FormattedTextBox; width: number; height: number; diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index e49cc4804..663343f47 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -1,5 +1,6 @@ import { action, computed, observable, reaction } from "mobx"; import * as rp from 'request-promise'; +import { Utils } from "../../../Utils"; import { DocServer } from "../../../client/DocServer"; import { Docs, DocumentOptions } from "../../../client/documents/Documents"; import { UndoManager } from "../../../client/util/UndoManager"; @@ -7,7 +8,7 @@ import { Doc, DocListCast, DocListCastAsync } from "../../../new_fields/Doc"; import { List } from "../../../new_fields/List"; import { listSpec } from "../../../new_fields/Schema"; import { ScriptField, ComputedField } from "../../../new_fields/ScriptField"; -import { Cast, PromiseValue, StrCast } from "../../../new_fields/Types"; +import { Cast, PromiseValue, StrCast, NumCast } from "../../../new_fields/Types"; import { Utils } from "../../../Utils"; import { nullAudio, ImageField } from "../../../new_fields/URLField"; import { DragManager } from "../../../client/util/DragManager"; @@ -628,6 +629,9 @@ export class CurrentUserUtils { new InkingControl(); doc.title = Doc.CurrentUserEmail; doc.activePen = doc; + doc["constants-snapThreshold"] = NumCast(doc["constants-snapThreshold"], 10); // + doc["constants-dragThreshold"] = NumCast(doc["constants-dragThreshold"], 4); // + Utils.DRAG_THRESHOLD = NumCast(doc["constants-dragThreshold"]); this.setupDefaultIconTemplates(doc); // creates a set of icon templates triggered by the document deoration icon this.setupDocTemplates(doc); // sets up the template menu of templates this.setupRightSidebar(doc); // sets up the right sidebar collection for mobile upload documents and sharing -- cgit v1.2.3-70-g09d2 From 1660defc561c904217ed5be34cd6e0fe64736fe1 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Thu, 30 Apr 2020 19:06:42 -0700 Subject: commented Buxton importer --- src/scraping/buxton/final/BuxtonImporter.ts | 212 +++++++++++++++++---- .../authentication/models/current_user_utils.ts | 1 - 2 files changed, 179 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/scraping/buxton/final/BuxtonImporter.ts b/src/scraping/buxton/final/BuxtonImporter.ts index 713207a07..21363f848 100644 --- a/src/scraping/buxton/final/BuxtonImporter.ts +++ b/src/scraping/buxton/final/BuxtonImporter.ts @@ -10,6 +10,10 @@ import { parseXml } from "libxmljs"; import { strictEqual } from "assert"; import { Readable, PassThrough } from "stream"; +/** + * This is an arbitrary bundle of data that gets populated + * in extractFileContents + */ interface DocumentContents { body: string; imageData: ImageData[]; @@ -19,6 +23,10 @@ interface DocumentContents { longDescription: string; } +/** + * A rough schema for everything that Bill has + * included for each document + */ export interface DeviceDocument { title: string; shortDescription: string; @@ -33,36 +41,65 @@ export interface DeviceDocument { attribute: string; __images: ImageData[]; hyperlinks: string[]; - captions: string[]; - embeddedFileNames: string[]; + captions: string[]; // from the table column + embeddedFileNames: string[]; // from the table column } +/** + * A layer of abstraction around a single parsing + * attempt. The error is not a TypeScript error, but + * rather an invalidly formatted value for a given key. + */ export interface AnalysisResult { device?: DeviceDocument; - errors?: { [key: string]: string }; + invalid?: { [deviceProperty: string]: string }; } +/** + * A mini API that takes in a string and returns + * either the given T or an error indicating that the + * transformation was rejected. + */ type Transformer = (raw: string) => TransformResult; interface TransformResult { transformed?: T; error?: string; } +/** + * Simple bundle counting successful and failed imports + */ export interface ImportResults { deviceCount: number; errorCount: number; } +/** + * Definitions for callback functions. Such instances are + * just invoked by when a single document has been parsed + * or the entire import is over. As of this writing, these + * callbacks are supplied by WebSocket.ts and used to inform + * the client of these events. + */ type ResultCallback = (result: AnalysisResult) => void; type TerminatorCallback = (result: ImportResults) => void; -interface Processor { - exp: RegExp; - matchIndex?: number; - transformer?: Transformer; - required?: boolean; +/** + * Defines everything needed to define how a single key should be + * formatted within the plain body text. The association between + * keys and their format definitions is stored FormatMap + */ +interface ValueFormatDefinition { + exp: RegExp; // the expression that the key's value should match + matchIndex?: number; // defaults to 0, but can be overridden to account for grouping in @param exp + transformer?: Transformer; // if desirable, how to transform the Regex match + required?: boolean; // defaults to true, confirms that for a whole document to be counted successful, + // all of its required values should be present and properly formatted } +/** + * The basic data we extract from each image in the document + */ interface ImageData { url: string; nativeWidth: number; @@ -71,6 +108,10 @@ interface ImageData { namespace Utilities { + /** + * Numeric 'try parse', fits with the Transformer API + * @param raw the serialized number + */ export function numberValue(raw: string): TransformResult { const transformed = Number(raw); if (isNaN(transformed)) { @@ -79,18 +120,32 @@ namespace Utilities { return { transformed }; } + /** + * A simple tokenizer that splits along 'and' and commas, and removes duplicates + * Helpful mainly for attribute and primary key lists + * @param raw the string to tokenize + */ export function collectUniqueTokens(raw: string): TransformResult { const pieces = raw.replace(/,|\s+and\s+/g, " ").split(/\s+/).filter(piece => piece.length); const unique = new Set(pieces.map(token => token.toLowerCase().trim())); return { transformed: Array.from(unique).map(capitalize).sort() }; } + /** + * Tries to correct XML text parsing artifact where some sentences lose their separating space, + * and others gain excess whitespace + * @param raw + */ export function correctSentences(raw: string): TransformResult { raw = raw.replace(/\./g, ". ").replace(/\:/g, ": ").replace(/\,/g, ", ").replace(/\?/g, "? ").trimRight(); raw = raw.replace(/\s{2,}/g, " "); return { transformed: raw }; } + /** + * Simple capitalization + * @param word to capitalize + */ export function capitalize(word: string): string { const clean = word.trim(); if (!clean.length) { @@ -99,6 +154,12 @@ namespace Utilities { return word.charAt(0).toUpperCase() + word.slice(1); } + /** + * Streams the requeted file at the relative path to the + * root of the zip, then parses it with a library + * @param zip the zip instance data source + * @param relativePath the path to a .xml file within the zip to parse + */ export async function readAndParseXml(zip: any, relativePath: string) { console.log(`Text streaming ${relativePath}`); const contents = await new Promise((resolve, reject) => { @@ -111,13 +172,17 @@ namespace Utilities { stream.on('end', () => resolve(body)); }); }); - return parseXml(contents); } - } -const RegexMap = new Map>([ +/** + * Defines how device values should be formatted. As you can see, the formatting is + * not super consistent and has changed over time as edge cases have been found, but this + * at least imposes some constraints, and will notify you if a document doesn't match the specifications + * in this map. + */ +const FormatMap = new Map>([ ["title", { exp: /contact\s+(.*)Short Description:/ }], @@ -189,17 +254,25 @@ const RegexMap = new Map>([ }], ]); -const sourceDir = path.resolve(__dirname, "source"); -const outDir = path.resolve(__dirname, "json"); -const imageDir = path.resolve(__dirname, "../../../server/public/files/images/buxton"); -const successOut = "buxton.json"; -const failOut = "incomplete.json"; -const deviceKeys = Array.from(RegexMap.keys()); - +const sourceDir = path.resolve(__dirname, "source"); // where the Word documents are assumed to be stored +const outDir = path.resolve(__dirname, "json"); // where the JSON output of these device documents will be written +const imageDir = path.resolve(__dirname, "../../../server/public/files/images/buxton"); // where, in the server, these images will be written +const successOut = "buxton.json"; // the JSON list representing properly formatted documents +const failOut = "incomplete.json"; // the JSON list representing improperly formatted documents +const deviceKeys = Array.from(FormatMap.keys()); // a way to iterate through all keys of the DeviceDocument interface + +/** + * Starts by REMOVING ALL EXISTING BUXTON RESOURCES. This might need to be + * changed going forward + * @param emitter the callback when each document is completed + * @param terminator the callback when the entire import is completed + */ export default async function executeImport(emitter: ResultCallback, terminator: TerminatorCallback) { try { + // get all Word documents in the source directory const contents = readdirSync(sourceDir); const wordDocuments = contents.filter(file => /.*\.docx?$/.test(file)).map(file => `${sourceDir}/${file}`); + // removal takes place here [outDir, imageDir].forEach(dir => { rimraf.sync(dir); mkdirSync(dir); @@ -216,19 +289,28 @@ export default async function executeImport(emitter: ResultCallback, terminator: } } +/** + * Parse every Word document in the directory, notifying any callers as needed + * at each iteration via the emitter. + * @param wordDocuments the string list of Word document names to parse + * @param emitter the callback when each document is completed + * @param terminator the callback when the entire import is completed + */ async function parseFiles(wordDocuments: string[], emitter: ResultCallback, terminator: TerminatorCallback): Promise { + // execute parent-most parse function const results: AnalysisResult[] = []; for (const filePath of wordDocuments) { - const fileName = path.basename(filePath).replace("Bill_Notes_", ""); + const fileName = path.basename(filePath).replace("Bill_Notes_", ""); // not strictly needed, but cleaner console.log(cyan(`\nExtracting contents from ${fileName}...`)); const result = analyze(fileName, await extractFileContents(filePath)); emitter(result); results.push(result); } + // collect information about errors and successes const masterDevices: DeviceDocument[] = []; const masterErrors: { [key: string]: string }[] = []; - results.forEach(({ device, errors }) => { + results.forEach(({ device, invalid: errors }) => { if (device) { masterDevices.push(device); } else if (errors) { @@ -236,24 +318,45 @@ async function parseFiles(wordDocuments: string[], emitter: ResultCallback, term } }); + // something went wrong, since errors and successes should sum to total inputs const total = wordDocuments.length; if (masterDevices.length + masterErrors.length !== total) { throw new Error(`Encountered a ${masterDevices.length} to ${masterErrors.length} mismatch in device / error split!`); } + // write the external JSON representations of this import console.log(); await writeOutputFile(successOut, masterDevices, total, true); await writeOutputFile(failOut, masterErrors, total, false); console.log(); + // notify the caller that the import has finished terminator({ deviceCount: masterDevices.length, errorCount: masterErrors.length }); return masterDevices; } +/** + * XPath definitions for desired XML targets in respective hierarchies. + * + * For table cells, can be read as: "find me anything that looks like in XML, whose + * parent looks like , whose parent looks like " + * + * + * + * + * + * These are found by trial and error, and using an online XML parser / prettifier + * to inspect the structure, since the Node XML library does not expose the parsed + * structure very well for searching, say in the debug console. + */ const tableCellXPath = '//*[name()="w:tbl"]/*[name()="w:tr"]/*[name()="w:tc"]'; const hyperlinkXPath = '//*[name()="Relationship" and contains(@Type, "hyperlink")]'; +/** + * The meat of the script, images and text content are extracted here + * @param pathToDocument the path to the document relative to the root of the zip + */ async function extractFileContents(pathToDocument: string): Promise { console.log('Extracting text...'); const zip = new StreamZip({ file: pathToDocument, storeEntries: true }); @@ -261,22 +364,30 @@ async function extractFileContents(pathToDocument: string): Promise node.text().trim()); + // preserve paragraph formatting and line breaks that would otherwise get lost in the plain text parsing + // of the XML hierarchy const paragraphs = document.find('//*[name()="w:p"]').map(node => Utilities.correctSentences(node.text()).transformed!); const start = paragraphs.indexOf(paragraphs.find(el => /Bill Buxton[’']s Notes/.test(el))!) + 1; const end = paragraphs.indexOf("Device Details"); const longDescription = paragraphs.slice(start, end).filter(paragraph => paragraph.length).join("\n\n"); - const { length } = captionTargets; + // extract captions from the table cells + const tableRowsFlattened = document.find(tableCellXPath).map(node => node.text().trim()); + const { length } = tableRowsFlattened; strictEqual(length > 3, true, "No captions written."); strictEqual(length % 3 === 0, true, "Improper caption formatting."); - for (let i = 3; i < captionTargets.length; i += 3) { - const row = captionTargets.slice(i, i + 3); + // break the flat list of strings into groups of three, since there + // currently are three columns in the table. Thus, each group represents + // a row in the table, where the first row has no text content since it's + // the image, the second has the file name and the third has the caption + for (let i = 3; i < tableRowsFlattened.length; i += 3) { + const row = tableRowsFlattened.slice(i, i + 3); embeddedFileNames.push(row[1]); captions.push(row[2]); } @@ -286,23 +397,34 @@ async function extractFileContents(pathToDocument: string): Promise el.attrs()[2].value()); console.log("Text extracted."); + // write out the images for this document console.log("Beginning image extraction..."); const imageData = await writeImages(zip); console.log(`Extracted ${imageData.length} images.`); + // cleanup zip.close(); return { body, longDescription, imageData, captions, embeddedFileNames, hyperlinks }; } +// zip relative path from root expression / filter used to isolate only media assets const imageEntry = /^word\/media\/\w+\.(jpeg|jpg|png|gif)/; -interface Dimensions { +/** + * Image dimensions and file suffix, + */ +interface ImageAttrs { width: number; height: number; type: string; } +/** + * For each image, stream the file, get its size, check if it's an icon + * (if it is, ignore it) + * @param zip the zip instance data source + */ async function writeImages(zip: any): Promise { const allEntries = Object.values(zip.entries()).map(({ name }) => name); const imageEntries = allEntries.filter(name => imageEntry.test(name)); @@ -315,8 +437,8 @@ async function writeImages(zip: any): Promise { }); for (const mediaPath of imageEntries) { - const { width, height, type } = await new Promise(async resolve => { - const sizeStream = (createImageSizeStream() as PassThrough).on('size', (dimensions: Dimensions) => { + const { width, height, type } = await new Promise(async resolve => { + const sizeStream = (createImageSizeStream() as PassThrough).on('size', (dimensions: ImageAttrs) => { readStream.destroy(); resolve(dimensions); }).on("error", () => readStream.destroy()); @@ -324,11 +446,14 @@ async function writeImages(zip: any): Promise { readStream.pipe(sizeStream); }); + // if it's not an icon, by this rough heuristic, i.e. is it not square if (Math.abs(width - height) > 10) { valid.push({ width, height, type, mediaPath }); } } + // for each valid image, output the _o, _l, _m, and _s files + // THIS IS WHERE THE SCRIPT SPENDS MOST OF ITS TIME for (const { type, width, height, mediaPath } of valid) { const generatedFileName = `upload_${Utils.GenerateGuid()}.${type.toLowerCase()}`; await DashUploadUtils.outputResizedImages(() => getImageStream(mediaPath), generatedFileName, imageDir); @@ -342,6 +467,14 @@ async function writeImages(zip: any): Promise { return imageUrls; } +/** + * Takes the results of extractFileContents, which relative to this is sort of the + * external media / preliminary text processing, and now tests the given file name to + * with those value definitions to make sure the body of the document contains all + * required fields, properly formatted + * @param fileName the file whose body to inspect + * @param contents the data already computed / parsed by extractFileContents + */ function analyze(fileName: string, contents: DocumentContents): AnalysisResult { const { body, imageData, captions, hyperlinks, embeddedFileNames, longDescription } = contents; const device: any = { @@ -354,43 +487,56 @@ function analyze(fileName: string, contents: DocumentContents): AnalysisResult { const errors: { [key: string]: string } = { fileName }; for (const key of deviceKeys) { - const { exp, transformer, matchIndex, required } = RegexMap.get(key)!; + const { exp, transformer, matchIndex, required } = FormatMap.get(key)!; const matches = exp.exec(body); let captured: string; - if (matches && (captured = matches[matchIndex ?? 1])) { - captured = captured.replace(/\s{2,}/g, " "); + // if we matched and we got the specific match we're after + if (matches && (captured = matches[matchIndex ?? 1])) { // matchIndex defaults to 1 + captured = captured.replace(/\s{2,}/g, " "); // remove excess whitespace + // if supplied, apply the required transformation (recall this is specified in FormatMap) if (transformer) { const { error, transformed } = transformer(captured); if (error) { + // we hit a snag trying to transform the valid match + // still counts as a fundamental error errors[key] = `__ERR__${key.toUpperCase()}__TRANSFORM__: ${error}`; continue; } captured = transformed; } - device[key] = captured; } else if (required ?? true) { + // the field was either implicitly or explicitly required, and failed to match the definition in + // FormatMap errors[key] = `ERR__${key.toUpperCase()}__: outer match ${matches === null ? "wasn't" : "was"} captured.`; continue; } } + // print errors - this can be removed const errorKeys = Object.keys(errors); if (errorKeys.length > 1) { console.log(red(`@ ${cyan(fileName.toUpperCase())}...`)); errorKeys.forEach(key => key !== "filename" && console.log(red(errors[key]))); - return { errors }; + return { invalid: errors }; } return { device }; } +/** + * A utility function that writes the JSON results for this import out to the desired path + * @param relativePath where to write the JSON file + * @param data valid device document objects, or errors + * @param total used for more informative printing + * @param success whether or not the caller is writing the successful parses or the failures + */ async function writeOutputFile(relativePath: string, data: any[], total: number, success: boolean) { console.log(yellow(`Encountered ${data.length} ${success ? "valid" : "invalid"} documents out of ${total} candidates. Writing ${relativePath}...`)); return new Promise((resolve, reject) => { const destination = path.resolve(outDir, relativePath); - const contents = JSON.stringify(data, undefined, 4); + const contents = JSON.stringify(data, undefined, 4); // format the JSON writeFile(destination, contents, err => err ? reject(err) : resolve()); }); } \ No newline at end of file diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 663343f47..d7cc1e6bf 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -9,7 +9,6 @@ import { List } from "../../../new_fields/List"; import { listSpec } from "../../../new_fields/Schema"; import { ScriptField, ComputedField } from "../../../new_fields/ScriptField"; import { Cast, PromiseValue, StrCast, NumCast } from "../../../new_fields/Types"; -import { Utils } from "../../../Utils"; import { nullAudio, ImageField } from "../../../new_fields/URLField"; import { DragManager } from "../../../client/util/DragManager"; import { InkingControl } from "../../../client/views/InkingControl"; -- cgit v1.2.3-70-g09d2 From 3c6162ce8f88fed8e9c84fd77423e858aa6cc7b4 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Thu, 30 Apr 2020 19:13:06 -0700 Subject: commented corrollary functions --- src/client/documents/Documents.ts | 24 +++++++++++++++++++++--- src/server/Websocket/Websocket.ts | 7 ++++++- 2 files changed, 27 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 0809ae24f..2e81d5fa6 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -379,6 +379,15 @@ export namespace Docs { */ export namespace Create { + /** + * Synchronously returns a collection into which + * the device documents will be put. This is initially empty, + * but gets populated by updates from the web socket. When everything is over, + * this function cleans up after itself. + * s + * Look at Websocket.ts for the server-side counterpart to this + * function. + */ export function Buxton() { let responded = false; const loading = new Doc; @@ -391,9 +400,13 @@ export namespace Docs { }); const parentProto = Doc.GetProto(parent); const { _socket } = DocServer; + + // just in case, clean up _socket.off(MessageStore.BuxtonDocumentResult.Message); _socket.off(MessageStore.BuxtonImportComplete.Message); - Utils.AddServerHandler(_socket, MessageStore.BuxtonDocumentResult, ({ device, errors }) => { + + // this is where the client handles the receipt of a new valid parsed document + Utils.AddServerHandler(_socket, MessageStore.BuxtonDocumentResult, ({ device, invalid: errors }) => { if (!responded) { responded = true; parentProto.data = new List(); @@ -408,9 +421,11 @@ export namespace Docs { _nativeWidth: nativeWidth, _nativeHeight: nativeHeight })); + // the main document we create const doc = StackingDocument(deviceImages, { title: device.title, _LODdisable: true }); const deviceProto = Doc.GetProto(doc); deviceProto.hero = new ImageField(constructed[0].url); + // add the parsed attributes to this main document Docs.Get.FromJson({ data: device, appendToExisting: { targetDoc: deviceProto } }); Doc.AddDocToList(parentProto, "data", doc); } else if (errors) { @@ -419,14 +434,17 @@ export namespace Docs { alert("A Buxton document import was completely empty (??)"); } }); + + // when the import is complete, we stop listening for these creation + // and termination events and alert the user Utils.AddServerHandler(_socket, MessageStore.BuxtonImportComplete, ({ deviceCount, errorCount }) => { _socket.off(MessageStore.BuxtonDocumentResult.Message); _socket.off(MessageStore.BuxtonImportComplete.Message); alert(`Successfully imported ${deviceCount} device${deviceCount === 1 ? "" : "s"}, with ${errorCount} error${errorCount === 1 ? "" : "s"}, in ${(Date.now() - startTime) / 1000} seconds.`); }); const startTime = Date.now(); - Utils.Emit(_socket, MessageStore.BeginBuxtonImport, ""); - return parent; + Utils.Emit(_socket, MessageStore.BeginBuxtonImport, ""); // signal the server to start importing + return parent; // synchronously return the collection, to be populateds } Scripting.addGlobal(Buxton); diff --git a/src/server/Websocket/Websocket.ts b/src/server/Websocket/Websocket.ts index 947aa4289..be895c4bc 100644 --- a/src/server/Websocket/Websocket.ts +++ b/src/server/Websocket/Websocket.ts @@ -10,7 +10,6 @@ import { GoogleCredentialsLoader } from "../credentials/CredentialsLoader"; import { logPort } from "../ActionUtilities"; import { timeMap } from "../ApiManagers/UserManager"; import { green } from "colors"; -import { serverPathToFile, Directory } from "../ApiManagers/UploadManager"; import { networkInterfaces } from "os"; import executeImport from "../../scraping/buxton/final/BuxtonImporter"; @@ -111,6 +110,12 @@ export namespace WebSocket { Utils.AddServerHandler(socket, MessageStore.MobileDocumentUpload, content => processMobileDocumentUpload(socket, content)); Utils.AddServerHandlerCallback(socket, MessageStore.GetRefField, GetRefField); Utils.AddServerHandlerCallback(socket, MessageStore.GetRefFields, GetRefFields); + + /** + * Whenever we receive the go-ahead, invoke the import script and pass in + * as an emitter and a terminator the functions that simply broadcast a result + * or indicate termination to the client via the web socket + */ Utils.AddServerHandler(socket, MessageStore.BeginBuxtonImport, () => { executeImport( deviceOrError => Utils.Emit(socket, MessageStore.BuxtonDocumentResult, deviceOrError), -- cgit v1.2.3-70-g09d2 From 8dcc7bff9430fe3cca8271501595ff89b36f7005 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 30 Apr 2020 23:20:13 -0400 Subject: cleaned up presbox and preselementbox --- src/client/views/MainView.tsx | 9 +- src/client/views/nodes/PresBox.scss | 29 +++- src/client/views/nodes/PresBox.tsx | 167 ++++++++++----------- .../views/nodes/formattedText/RichTextMenu.scss | 40 ++--- .../views/presentationview/PresElementBox.scss | 43 +++--- .../views/presentationview/PresElementBox.tsx | 106 ++++++------- 6 files changed, 200 insertions(+), 194 deletions(-) (limited to 'src') diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 72dfdf75c..65e4eb036 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -1,5 +1,5 @@ import { library } from '@fortawesome/fontawesome-svg-core'; -import { faTerminal, faCalculator, faWindowMaximize, faAddressCard, faQuestionCircle, faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt, faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter, faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote, faThumbtack, faTree, faTv, faUndoAlt, faVideo } from '@fortawesome/free-solid-svg-icons'; +import { faTerminal, faFile as fileSolid, faLocationArrow, faSearch, faFileDownload, faStop, faCalculator, faWindowMaximize, faAddressCard, faQuestionCircle, faArrowLeft, faArrowRight, faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt, faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter, faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote, faThumbtack, faTree, faTv, faUndoAlt, faVideo } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, configure, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; @@ -104,6 +104,11 @@ export class MainView extends React.Component { } library.add(faTerminal); + library.add(faLocationArrow); + library.add(faSearch); + library.add(fileSolid); + library.add(faFileDownload); + library.add(faStop); library.add(faCalculator); library.add(faWindowMaximize); library.add(faFileAlt); @@ -142,6 +147,8 @@ export class MainView extends React.Component { library.add(faCaretUp); library.add(faFilter); library.add(faBullseye); + library.add(faArrowLeft); + library.add(faArrowRight); library.add(faArrowDown); library.add(faArrowUp); library.add(faCloudUploadAlt); diff --git a/src/client/views/nodes/PresBox.scss b/src/client/views/nodes/PresBox.scss index 78c19f351..d48000e16 100644 --- a/src/client/views/nodes/PresBox.scss +++ b/src/client/views/nodes/PresBox.scss @@ -1,10 +1,10 @@ .presBox-cont { position: absolute; + pointer-events: inherit; z-index: 2; box-shadow: #AAAAAA .2vw .2vw .4vw; - bottom: 0; width: 100%; - min-width: 120px; + min-width: 20px; height: 100%; min-height: 41px; letter-spacing: 2px; @@ -17,17 +17,36 @@ width: 100%; } .presBox-buttons { - padding: 10px; width: 100%; background: gray; - padding-right: 10px; padding-top: 5px; padding-bottom: 5px; + display: grid; + grid-column-end: 4; + grid-column-start: 1; + .presBox-viewPicker { + height: 25; + position: relative; + display: inline-block; + grid-column: 1/2; + min-width: 15px; + } + select { + background: #323232; + color: white; + } .presBox-button { margin-right: 2.5%; margin-left: 2.5%; - width: 20%; + height: 25px; border-radius: 5px; + display: flex; + align-items: center; + background: #323232; + color: white; + svg { + margin: auto; + } } .collectionViewBaseChrome-viewPicker { min-width: 50; diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index 80d043db1..f91a809bb 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -1,12 +1,10 @@ import React = require("react"); -import { library } from '@fortawesome/fontawesome-svg-core'; -import { faArrowLeft, faArrowRight, faEdit, faMinus, faPlay, faPlus, faStop, faHandPointLeft, faTimes } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; import { Doc, DocListCast, DocCastAsync } from "../../../new_fields/Doc"; import { InkTool } from "../../../new_fields/InkField"; -import { BoolCast, Cast, FieldValue, NumCast, StrCast } from "../../../new_fields/Types"; +import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types"; import { returnFalse } from "../../../Utils"; import { documentSchema } from "../../../new_fields/documentSchemas"; import { DocumentManager } from "../../util/DocumentManager"; @@ -19,38 +17,30 @@ import "./PresBox.scss"; import { ViewBoxBaseComponent } from "../DocComponent"; import { makeInterface } from "../../../new_fields/Schema"; -library.add(faArrowLeft); -library.add(faArrowRight); -library.add(faPlay); -library.add(faStop); -library.add(faHandPointLeft); -library.add(faPlus); -library.add(faTimes); -library.add(faMinus); -library.add(faEdit); - type PresBoxSchema = makeInterface<[typeof documentSchema]>; const PresBoxDocument = makeInterface(documentSchema); @observer export class PresBox extends ViewBoxBaseComponent(PresBoxDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PresBox, fieldKey); } - _childReaction: IReactionDisposer | undefined; + private _childReaction: IReactionDisposer | undefined; @observable _isChildActive = false; + @computed get childDocs() { return DocListCast(this.dataDoc[this.fieldKey]); } + @computed get currentIndex() { return NumCast(this.rootDoc._itemIndex); } + componentDidMount() { - this.layoutDoc._forceRenderEngine = "timeline"; - this.layoutDoc._replacedChrome = "replaced"; + this.rootDoc._forceRenderEngine = "timeline"; + this.rootDoc._replacedChrome = "replaced"; this._childReaction = reaction(() => this.childDocs.slice(), (children) => children.forEach((child, i) => child.presentationIndex = i), { fireImmediately: true }); } componentWillUnmount() { this._childReaction?.(); } - @computed get childDocs() { return DocListCast(this.dataDoc[this.fieldKey]); } - @computed get currentIndex() { return NumCast(this.layoutDoc._itemIndex); } - - updateCurrentPresentation = action(() => Doc.UserDoc().activePresentation = this.rootDoc); + updateCurrentPresentation = () => Doc.UserDoc().activePresentation = this.rootDoc; + @undoBatch + @action next = () => { this.updateCurrentPresentation(); if (this.childDocs[this.currentIndex + 1] !== undefined) { @@ -66,6 +56,9 @@ export class PresBox extends ViewBoxBaseComponent } } } + + @undoBatch + @action back = () => { this.updateCurrentPresentation(); const docAtCurrent = this.childDocs[this.currentIndex]; @@ -83,10 +76,6 @@ export class PresBox extends ViewBoxBaseComponent } } - whenActiveChanged = action((isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive)); - active = (outsideReaction?: boolean) => ((InkingControl.Instance.selectedTool === InkTool.None && !this.layoutDoc.isBackground) && - (this.layoutDoc.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false) - /** * This is the method that checks for the actions that need to be performed * after the document has been presented, which involves 3 button options: @@ -95,15 +84,16 @@ export class PresBox extends ViewBoxBaseComponent showAfterPresented = (index: number) => { this.updateCurrentPresentation(); this.childDocs.forEach((doc, ind) => { + const presTargetDoc = doc.presentationTargetDoc as Doc; //the order of cases is aligned based on priority - if (doc.hideTillShownButton && ind <= index) { - (doc.presentationTargetDoc as Doc).opacity = 1; + if (doc.presHideTillShownButton && ind <= index) { + presTargetDoc.opacity = 1; } - if (doc.hideAfterButton && ind < index) { - (doc.presentationTargetDoc as Doc).opacity = 0; + if (doc.presHideAfterButton && ind < index) { + presTargetDoc.opacity = 0; } - if (doc.fadeButton && ind < index) { - (doc.presentationTargetDoc as Doc).opacity = 0.5; + if (doc.presFadeButton && ind < index) { + presTargetDoc.opacity = 0.5; } }); } @@ -117,15 +107,15 @@ export class PresBox extends ViewBoxBaseComponent this.updateCurrentPresentation(); this.childDocs.forEach((key, ind) => { //the order of cases is aligned based on priority - + const presTargetDoc = key.presentationTargetDoc as Doc; if (key.hideAfterButton && ind >= index) { - (key.presentationTargetDoc as Doc).opacity = 1; + presTargetDoc.opacity = 1; } if (key.fadeButton && ind >= index) { - (key.presentationTargetDoc as Doc).opacity = 1; + presTargetDoc.opacity = 1; } if (key.hideTillShownButton && ind > index) { - (key.presentationTargetDoc as Doc).opacity = 0; + presTargetDoc.opacity = 0; } }); } @@ -151,11 +141,11 @@ export class PresBox extends ViewBoxBaseComponent } currentDocGroups.forEach((doc: Doc, index: number) => { - if (doc.navButton) { + if (doc.presNavButton) { docToJump = doc; willZoom = false; } - if (doc.zoomButton) { + if (doc.presZoomButton) { docToJump = doc; willZoom = true; } @@ -167,9 +157,9 @@ export class PresBox extends ViewBoxBaseComponent if (docToJump === curDoc) { //checking if curDoc has navigation open const target = await DocCastAsync(curDoc.presentationTargetDoc); - if (curDoc.navButton && target) { + if (curDoc.presNavButton && target) { DocumentManager.Instance.jumpToDocument(target, false, undefined, srcContext); - } else if (curDoc.zoomButton && target) { + } else if (curDoc.presZoomButton && target) { //awaiting jump so that new scale can be found, since jumping is async await DocumentManager.Instance.jumpToDocument(target, true, undefined, srcContext); } @@ -181,18 +171,13 @@ export class PresBox extends ViewBoxBaseComponent } - @undoBatch - public removeDocument = (doc: Doc) => { - return Doc.RemoveDocFromList(this.dataDoc, this.fieldKey, doc); - } - //The function that is called when a document is clicked or reached through next or back. //it'll also execute the necessary actions if presentation is playing. public gotoDocument = (index: number, fromDoc: number) => { this.updateCurrentPresentation(); Doc.UnBrushAllDocs(); if (index >= 0 && index < this.childDocs.length) { - this.layoutDoc._itemIndex = index; + this.rootDoc._itemIndex = index; if (!this.layoutDoc.presStatus) { this.layoutDoc.presStatus = true; @@ -217,19 +202,12 @@ export class PresBox extends ViewBoxBaseComponent } } - addDocument = (doc: Doc) => { - const newPinDoc = Doc.MakeAlias(doc); - newPinDoc.presentationTargetDoc = doc; - return Doc.AddDocToList(this.dataDoc, this.fieldKey, newPinDoc); - } - - //The function that resets the presentation by removing every action done by it. It also //stops the presentaton. resetPresentation = () => { this.updateCurrentPresentation(); this.childDocs.forEach(doc => (doc.presentationTargetDoc as Doc).opacity = 1); - this.layoutDoc._itemIndex = 0; + this.rootDoc._itemIndex = 0; this.layoutDoc.presStatus = false; } @@ -238,84 +216,99 @@ export class PresBox extends ViewBoxBaseComponent startPresentation = (startIndex: number) => { this.updateCurrentPresentation(); this.childDocs.map(doc => { - if (doc.hideTillShownButton && this.childDocs.indexOf(doc) > startIndex) { - (doc.presentationTargetDoc as Doc).opacity = 0; + const presTargetDoc = doc.presentationTargetDoc as Doc; + if (doc.presHideTillShownButton && this.childDocs.indexOf(doc) > startIndex) { + presTargetDoc.opacity = 0; } - if (doc.hideAfterButton && this.childDocs.indexOf(doc) < startIndex) { - (doc.presentationTargetDoc as Doc).opacity = 0; + if (doc.presHideAfterButton && this.childDocs.indexOf(doc) < startIndex) { + presTargetDoc.opacity = 0; } - if (doc.fadeButton && this.childDocs.indexOf(doc) < startIndex) { - (doc.presentationTargetDoc as Doc).opacity = 0.5; + if (doc.presFadeButton && this.childDocs.indexOf(doc) < startIndex) { + presTargetDoc.opacity = 0.5; } }); } - updateMinimize = undoBatch(action((e: React.ChangeEvent, mode: CollectionViewType) => { + updateMinimize = action((e: React.ChangeEvent, mode: CollectionViewType) => { if (BoolCast(this.layoutDoc.inOverlay) !== (mode === CollectionViewType.Invalid)) { if (this.layoutDoc.inOverlay) { Doc.RemoveDocFromList((Doc.UserDoc().myOverlayDocuments as Doc), undefined, this.rootDoc); CollectionDockingView.AddRightSplit(this.rootDoc); this.layoutDoc.inOverlay = false; } else { - this.layoutDoc.x = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0)[0];// 500;//e.clientX + 25; - this.layoutDoc.y = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0)[1];////e.clientY - 25; + const pt = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0); + this.rootDoc.x = pt[0];// 500;//e.clientX + 25; + this.rootDoc.y = pt[1];////e.clientY - 25; this.props.addDocTab?.(this.rootDoc, "close"); Doc.AddDocToList((Doc.UserDoc().myOverlayDocuments as Doc), undefined, this.rootDoc); } } - })); + }); initializeViewAliases = (docList: Doc[], viewtype: CollectionViewType) => { const hgt = (viewtype === CollectionViewType.Tree) ? 50 : 46; docList.forEach(doc => { doc.presBox = this.rootDoc; // give contained documents a reference to the presentation - doc.collapsedHeight = hgt; // set the collpased height for documents based on the type of view (Tree or Stack) they will be displaye din + doc.presCollapsedHeight = hgt; // set the collpased height for documents based on the type of view (Tree or Stack) they will be displaye din }); } - selectElement = (doc: Doc) => { - this.gotoDocument(this.childDocs.indexOf(doc), NumCast(this.layoutDoc._itemIndex)); + addDocument = (doc: Doc) => { + const newPinDoc = Doc.MakeAlias(doc); + newPinDoc.presentationTargetDoc = doc; + return Doc.AddDocToList(this.dataDoc, this.fieldKey, newPinDoc); } - getTransform = () => { - return this.props.ScreenToLocalTransform().translate(-5, -65);// listBox padding-left and pres-box-cont minHeight - } - panelHeight = () => { - return this.props.PanelHeight() - 20; - } + removeDocument = (doc: Doc) => Doc.RemoveDocFromList(this.dataDoc, this.fieldKey, doc); + + selectElement = (doc: Doc) => this.gotoDocument(this.childDocs.indexOf(doc), NumCast(this.rootDoc._itemIndex)); + + getTransform = () => this.props.ScreenToLocalTransform().translate(-5, -65);// listBox padding-left and pres-box-cont minHeight + + panelHeight = () => this.props.PanelHeight() - 20; + + active = (outsideReaction?: boolean) => ((InkingControl.Instance.selectedTool === InkTool.None && !this.layoutDoc.isBackground) && + (this.layoutDoc.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false); + + whenActiveChanged = action((isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive)); @undoBatch viewChanged = action((e: React.ChangeEvent) => { //@ts-ignore - this.layoutDoc._viewType = e.target.selectedOptions[0].value; - this.layoutDoc._viewType === CollectionViewType.Stacking && (this.layoutDoc._pivotField = undefined); // pivot field may be set by the user in timeline view (or some other way) -- need to reset it here - this.updateMinimize(e, StrCast(this.layoutDoc._viewType)); + const viewType = e.target.selectedOptions[0].value as CollectionViewType; + viewType === CollectionViewType.Stacking && (this.rootDoc._pivotField = undefined); // pivot field may be set by the user in timeline view (or some other way) -- need to reset it here + this.updateMinimize(e, this.rootDoc._viewType = viewType); }); - childLayoutTemplate = () => this.layoutDoc._viewType === CollectionViewType.Stacking ? Cast(Doc.UserDoc()["template-presentation"], Doc, null) : undefined; + childLayoutTemplate = () => this.rootDoc._viewType === CollectionViewType.Stacking ? Cast(Doc.UserDoc()["template-presentation"], Doc, null) : undefined; render() { - const mode = StrCast(this.layoutDoc._viewType) as CollectionViewType; + const mode = StrCast(this.rootDoc._viewType) as CollectionViewType; this.initializeViewAliases(this.childDocs, mode); - return
-
- e.stopPropagation()} onChange={this.viewChanged} value={mode}> - - - - + + + + - - - +
+
+ +
{mode !== CollectionViewType.Invalid ? ; @@ -48,16 +38,14 @@ export class PresElementBox extends ViewBoxBaseComponent [this.presElementDoc.expandInlineButton, this.presElementDoc.collapsedHeight], - params => this.presLayoutDoc._height = NumCast(params[1]) + (Number(params[0]) ? 100 : 0), { fireImmediately: true }); + this._heightDisposer = reaction(() => [this.rootDoc.presExpandInlineButton, this.rootDoc.presCollapsedHeight], + params => this.layoutDoc._height = NumCast(params[1]) + (Number(params[0]) ? 100 : 0), { fireImmediately: true }); } componentWillUnmount() { this._heightDisposer?.(); @@ -70,8 +58,8 @@ export class PresElementBox extends ViewBoxBaseComponent { e.stopPropagation(); - this.presElementDoc.hideTillShownButton = !this.presElementDoc.hideTillShownButton; - if (!this.presElementDoc.hideTillShownButton) { + this.rootDoc.presHideTillShownButton = !this.rootDoc.presHideTillShownButton; + if (!this.rootDoc.presHideTillShownButton) { if (this.indexInPres >= this.currentIndex && this.targetDoc) { this.targetDoc.opacity = 1; } @@ -90,13 +78,13 @@ export class PresElementBox extends ViewBoxBaseComponent { e.stopPropagation(); - this.presElementDoc.hideAfterButton = !this.presElementDoc.hideAfterButton; - if (!this.presElementDoc.hideAfterButton) { + this.rootDoc.presHideAfterButton = !this.rootDoc.presHideAfterButton; + if (!this.rootDoc.presHideAfterButton) { if (this.indexInPres <= this.currentIndex && this.targetDoc) { this.targetDoc.opacity = 1; } } else { - if (this.presElementDoc.fadeButton) this.presElementDoc.fadeButton = false; + if (this.rootDoc.presFadeButton) this.rootDoc.presFadeButton = false; if (this.presBoxDoc.presStatus && this.indexInPres < this.currentIndex && this.targetDoc) { this.targetDoc.opacity = 0; } @@ -111,13 +99,13 @@ export class PresElementBox extends ViewBoxBaseComponent { e.stopPropagation(); - this.presElementDoc.fadeButton = !this.presElementDoc.fadeButton; - if (!this.presElementDoc.fadeButton) { + this.rootDoc.presFadeButton = !this.rootDoc.presFadeButton; + if (!this.rootDoc.presFadeButton) { if (this.indexInPres <= this.currentIndex && this.targetDoc) { this.targetDoc.opacity = 1; } } else { - this.presElementDoc.hideAfterButton = false; + this.rootDoc.presHideAfterButton = false; if (this.presBoxDoc.presStatus && (this.indexInPres < this.currentIndex) && this.targetDoc) { this.targetDoc.opacity = 0.5; } @@ -130,11 +118,11 @@ export class PresElementBox extends ViewBoxBaseComponent { e.stopPropagation(); - this.presElementDoc.navButton = !this.presElementDoc.navButton; - if (this.presElementDoc.navButton) { - this.presElementDoc.zoomButton = false; + this.rootDoc.presNavButton = !this.rootDoc.presNavButton; + if (this.rootDoc.presNavButton) { + this.rootDoc.presZoomButton = false; if (this.currentIndex === this.indexInPres) { - this.props.focus(this.presElementDoc); + this.props.focus(this.rootDoc); } } } @@ -146,13 +134,11 @@ export class PresElementBox extends ViewBoxBaseComponent { e.stopPropagation(); - this.presElementDoc.zoomButton = !this.presElementDoc.zoomButton; - if (!this.presElementDoc.zoomButton) { - this.presElementDoc.viewScale = 1; - } else { - this.presElementDoc.navButton = false; + this.rootDoc.presZoomButton = !this.rootDoc.presZoomButton; + if (this.rootDoc.presZoomButton) { + this.rootDoc.presNavButton = false; if (this.currentIndex === this.indexInPres) { - this.props.focus(this.presElementDoc); + this.props.focus(this.rootDoc); } } } @@ -161,15 +147,15 @@ export class PresElementBox extends ViewBoxBaseComponent [xCord, yCord]; - embedHeight = () => this.props.PanelHeight() - NumCast(this.presElementDoc.collapsedHeight); + embedHeight = () => Math.min(this.props.PanelWidth() - 20, this.props.PanelHeight() - NumCast(this.rootDoc.presCollapsedHeight)); embedWidth = () => this.props.PanelWidth() - 20; /** * The function that is responsible for rendering the a preview or not for this * presentation element. */ - renderEmbeddedInline = () => { - return !this.presElementDoc.expandInlineButton || !this.targetDoc ? (null) : -
+ @computed get renderEmbeddedInline() { + return !this.rootDoc.presExpandInlineButton || !this.targetDoc ? (null) : +
{ this.props.focus(this.presElementDoc); e.stopPropagation(); }}> + onClick={e => { this.props.focus(this.rootDoc); e.stopPropagation(); }}> {treecontainer ? (null) : <> {`${this.indexInPres + 1}. ${this.targetDoc?.title}`} - +
} - - - - - - - - -
- {this.renderEmbeddedInline()} +
+ + + + + + + +
+ {this.renderEmbeddedInline}
); } -- cgit v1.2.3-70-g09d2 From ff7c7d40b1fcdf74b539c7d97f36707ff1521d2e Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 1 May 2020 01:46:07 -0400 Subject: fixed presentations to allow drag and drop. fixed pres box to use RenderData instead of modifying presentation elements with unnecessary info like their containing PresBox and their presentation index position. COnverted COntentFIttingDocumentView to use DocumentView's props --- src/client/documents/Documents.ts | 1 + src/client/views/MainView.tsx | 4 +- src/client/views/SearchDocBox.tsx | 10 ++++- .../views/collections/CollectionCarouselView.tsx | 8 +++- .../views/collections/CollectionSchemaView.tsx | 14 ++++--- .../views/collections/CollectionStackingView.tsx | 15 ++++--- .../views/collections/CollectionTreeView.tsx | 20 +++++---- src/client/views/collections/CollectionView.tsx | 14 ++++--- .../collectionFreeForm/CollectionFreeFormView.tsx | 3 +- .../CollectionMulticolumnView.tsx | 14 ++++--- .../CollectionMultirowView.tsx | 14 ++++--- .../views/nodes/CollectionFreeFormDocumentView.tsx | 8 ++-- .../views/nodes/ContentFittingDocumentView.tsx | 49 ++++------------------ src/client/views/nodes/DocumentBox.tsx | 15 ++++--- src/client/views/nodes/DocumentView.tsx | 20 ++++----- src/client/views/nodes/FieldView.tsx | 1 + src/client/views/nodes/PresBox.tsx | 21 ++++------ .../formattedText/FormattedTextBoxComment.tsx | 12 ++++-- .../views/nodes/formattedText/RichTextMenu.scss | 3 ++ .../views/presentationview/PresElementBox.tsx | 25 +++++++---- src/client/views/search/SearchItem.tsx | 12 ++++-- src/new_fields/documentSchemas.ts | 2 +- .../authentication/models/current_user_utils.ts | 2 +- 23 files changed, 150 insertions(+), 137 deletions(-) (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 2e81d5fa6..228a6af97 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -81,6 +81,7 @@ export interface DocumentOptions { author?: string; dropAction?: dropActionType; childDropAction?: dropActionType; + targetDropAction?: dropActionType; layoutKey?: string; type?: string; title?: string; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 65e4eb036..a29a6baac 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -597,8 +597,8 @@ export class MainView extends React.Component { {// TO VIEW SNAP LINES
- {this._hLines?.map(l => )} - {this._vLines?.map(l => )} + {this._hLines?.map((l: any) => )} + {this._vLines?.map((l: any) => )}
} diff --git a/src/client/views/SearchDocBox.tsx b/src/client/views/SearchDocBox.tsx index 799fa9d85..7bd689b19 100644 --- a/src/client/views/SearchDocBox.tsx +++ b/src/client/views/SearchDocBox.tsx @@ -6,7 +6,7 @@ import { observer } from "mobx-react"; import { Doc, DocListCast } from "../../new_fields/Doc"; import { Id } from "../../new_fields/FieldSymbols"; import { BoolCast, Cast, NumCast, StrCast } from "../../new_fields/Types"; -import { returnFalse } from "../../Utils"; +import { returnFalse, returnZero } from "../../Utils"; import { Docs } from "../documents/Documents"; import { SearchUtil } from "../util/SearchUtil"; import { EditableView } from "./EditableView"; @@ -399,7 +399,13 @@ export class SearchDocBox extends React.Component { + bringToFront={returnFalse} + ContainingCollectionDoc={undefined} + ContainingCollectionView={undefined} + NativeWidth={returnZero} + NativeHeight={returnZero} + parentActive={this.props.active} + ScreenToLocalTransform={this.props.ScreenToLocalTransform}>
; const CarouselDocument = makeInterface(documentSchema); @@ -49,9 +50,12 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument) + ScreenToLocalTransform={this.props.ScreenToLocalTransform} + bringToFront={returnFalse} + parentActive={this.props.active} + />
doc) { {!this.previewDocument ? (null) : doc) { rootSelected={this.rootSelected} PanelWidth={this.previewWidth} PanelHeight={this.previewHeight} - getTransform={this.getPreviewTransform} - CollectionDoc={this.props.CollectionView?.props.Document} - CollectionView={this.props.CollectionView} + ScreenToLocalTransform={this.getPreviewTransform} + ContainingCollectionDoc={this.props.CollectionView?.props.Document} + ContainingCollectionView={this.props.CollectionView} moveDocument={this.props.moveDocument} addDocument={this.props.addDocument} removeDocument={this.props.removeDocument} - active={this.props.active} + parentActive={this.props.active} whenActiveChanged={this.props.whenActiveChanged} addDocTab={this.props.addDocTab} pinToPres={this.props.pinToPres} + bringToFront={returnFalse} + ContentScaling={returnOne} />}
; } diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 556d7df5c..6c230d5b1 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -11,7 +11,7 @@ import { listSpec } from "../../../new_fields/Schema"; import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField"; import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../new_fields/Types"; import { TraceMobx } from "../../../new_fields/util"; -import { Utils, setupMoveUpEvents, emptyFunction, returnZero, returnOne } from "../../../Utils"; +import { Utils, setupMoveUpEvents, emptyFunction, returnZero, returnOne, returnFalse } from "../../../Utils"; import { DragManager, dropActionType } from "../../util/DragManager"; import { Transform } from "../../util/Transform"; import { undoBatch } from "../../util/UndoManager"; @@ -165,12 +165,13 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { const height = () => this.getDocHeight(doc); return doc) { dropAction={StrCast(this.props.Document.childDropAction) as dropActionType} onClick={this.onChildClickHandler} onDoubleClick={this.onChildDoubleClickHandler} - getTransform={dxf} + ScreenToLocalTransform={dxf} focus={this.props.focus} - CollectionDoc={this.props.CollectionView?.props.Document} - CollectionView={this.props.CollectionView} + ContainingCollectionDoc={this.props.CollectionView?.props.Document} + ContainingCollectionView={this.props.CollectionView} addDocument={this.props.addDocument} moveDocument={this.props.moveDocument} removeDocument={this.props.removeDocument} - active={this.props.active} + parentActive={this.props.active} whenActiveChanged={this.props.whenActiveChanged} addDocTab={this.addDocTab} + bringToFront={returnFalse} + ContentScaling={returnOne} pinToPres={this.props.pinToPres} />; } diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index d938bd7ad..71358a8ec 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -353,27 +353,31 @@ class TreeView extends React.Component { return
+ pinToPres={this.props.pinToPres} + bringToFront={returnFalse} + ContentScaling={returnOne} + />
; } } diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 8d8c321e8..561226de5 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -113,12 +113,16 @@ export class CollectionView extends Touchable { @action.bound addDocument(doc: Doc): boolean { - const targetDataDoc = this.props.Document[DataSym]; - const docList = DocListCast(targetDataDoc[this.props.fieldKey]); - !docList.includes(doc) && (targetDataDoc[this.props.fieldKey] = new List([...docList, doc])); // DocAddToList may write to targetdataDoc's parent ... we don't want this. should really change GetProto to GetDataDoc and test for resolvedDataDoc there - // Doc.AddDocToList(targetDataDoc, this.props.fieldKey, doc); + if (this.props.addDocument) { + this.props.addDocument(doc); + } else { + const targetDataDoc = this.props.Document[DataSym]; + const docList = DocListCast(targetDataDoc[this.props.fieldKey]); + !docList.includes(doc) && (targetDataDoc[this.props.fieldKey] = new List([...docList, doc])); // DocAddToList may write to targetdataDoc's parent ... we don't want this. should really change GetProto to GetDataDoc and test for resolvedDataDoc there + // Doc.AddDocToList(targetDataDoc, this.props.fieldKey, doc); + targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now())); + } doc.context = this.props.Document; - targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now())); Doc.GetProto(doc).lastOpened = new DateField; return true; } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 763a6c605..b4eb22444 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -877,6 +877,7 @@ export class CollectionFreeFormView extends CollectionSubView { if (SelectionManager.GetIsDragging()) { - this.setupDragLines(e); + this.setupDragLines(); } e.stopPropagation(); } diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index 66d441115..b3a6a9deb 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -14,7 +14,7 @@ import "./collectionMulticolumnView.scss"; import ResizeBar from './MulticolumnResizer'; import WidthLabel from './MulticolumnWidthLabel'; import { List } from '../../../../new_fields/List'; -import { returnZero } from '../../../../Utils'; +import { returnZero, returnFalse, returnOne } from '../../../../Utils'; type MulticolumnDocument = makeInterface<[typeof documentSchema]>; const MulticolumnDocument = makeInterface(documentSchema); @@ -216,7 +216,7 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu getDisplayDoc(layout: Doc, dxf: () => Transform, width: () => number, height: () => number) { return ; } /** diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx index 615efdb39..0fb29ca61 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx @@ -6,7 +6,7 @@ import * as React from "react"; import { Doc } from '../../../../new_fields/Doc'; import { NumCast, StrCast, BoolCast, ScriptCast } from '../../../../new_fields/Types'; import { ContentFittingDocumentView } from '../../nodes/ContentFittingDocumentView'; -import { Utils, returnZero } from '../../../../Utils'; +import { Utils, returnZero, returnFalse, returnOne } from '../../../../Utils'; import "./collectionMultirowView.scss"; import { computed, trace, observable, action } from 'mobx'; import { Transform } from '../../../util/Transform'; @@ -215,7 +215,7 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument) getDisplayDoc(layout: Doc, dxf: () => Transform, width: () => number, height: () => number) { return ; } /** diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 1c7d116c5..24468dcc1 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -115,13 +115,11 @@ export class CollectionFreeFormDocumentView extends DocComponent : } diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx index d0b0c8ee6..637fd5acc 100644 --- a/src/client/views/nodes/ContentFittingDocumentView.tsx +++ b/src/client/views/nodes/ContentFittingDocumentView.tsx @@ -3,51 +3,16 @@ import { computed } from "mobx"; import { observer } from "mobx-react"; import "react-table/react-table.css"; import { Doc, Opt, WidthSym, HeightSym } from "../../../new_fields/Doc"; -import { ScriptField } from "../../../new_fields/ScriptField"; import { NumCast, StrCast } from "../../../new_fields/Types"; import { TraceMobx } from "../../../new_fields/util"; import { emptyFunction, returnOne } from "../../../Utils"; -import { Transform } from "../../util/Transform"; -import { CollectionView } from "../collections/CollectionView"; import '../DocumentDecorations.scss'; -import { DocumentView } from "../nodes/DocumentView"; +import { DocumentView, DocumentViewProps } from "../nodes/DocumentView"; import "./ContentFittingDocumentView.scss"; -import { dropActionType } from "../../util/DragManager"; -interface ContentFittingDocumentViewProps { - Document: Doc; - DataDocument?: Doc; - LayoutDoc?: () => Opt; - NativeWidth?: () => number; - NativeHeight?: () => number; - FreezeDimensions?: boolean; - LibraryPath: Doc[]; - renderDepth: number; - fitToBox?: boolean; - layoutKey?: string; - dropAction?: dropActionType; - PanelWidth: () => number; - PanelHeight: () => number; - focus?: (doc: Doc) => void; - CollectionView?: CollectionView; - CollectionDoc?: Doc; - onClick?: ScriptField; - onDoubleClick?: ScriptField; - backgroundColor?: (doc: Doc) => string | undefined; - getTransform: () => Transform; - addDocument?: (document: Doc) => boolean; - moveDocument?: (document: Doc, target: Doc | undefined, addDoc: ((doc: Doc) => boolean)) => boolean; - removeDocument?: (document: Doc) => boolean; - active: (outsideReaction: boolean) => boolean; - whenActiveChanged: (isActive: boolean) => void; - addDocTab: (document: Doc, where: string) => boolean; - pinToPres: (document: Doc) => void; - dontRegisterView?: boolean; - rootSelected: (outsideReaction?: boolean) => boolean; -} @observer -export class ContentFittingDocumentView extends React.Component{ +export class ContentFittingDocumentView extends React.Component{ public get displayName() { return "DocumentView(" + this.props.Document?.title + ")"; } // this makes mobx trace() statements more descriptive private get layoutDoc() { return this.props.LayoutDoc?.() || Doc.Layout(this.props.Document); } @computed get freezeDimensions() { return this.props.FreezeDimensions; } @@ -68,7 +33,7 @@ export class ContentFittingDocumentView extends React.Component this.props.getTransform().translate(-this.centeringOffset, -this.centeringYOffset).scale(1 / this.contentScaling()); + private getTransform = () => this.props.ScreenToLocalTransform().translate(-this.centeringOffset, -this.centeringYOffset).scale(1 / this.contentScaling()); private get centeringOffset() { return this.nativeWidth() && !this.props.Document._fitWidth ? (this.props.PanelWidth() - this.nativeWidth() * this.contentScaling()) / 2 : 0; } private get centeringYOffset() { return Math.abs(this.centeringOffset) < 0.001 ? (this.props.PanelHeight() - this.nativeHeight() * this.contentScaling()) / 2 : 0; } @@ -90,7 +55,7 @@ export class ContentFittingDocumentView extends React.Component ; return contents; } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 085637440..f555d6eef 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -77,6 +77,7 @@ export interface DocumentViewProps { setupDragLines?: () => void; renderDepth: number; ContentScaling: () => number; + RenderData?: () => Doc; PanelWidth: () => number; PanelHeight: () => number; pointerEvents?: boolean; @@ -992,6 +993,7 @@ export class DocumentView extends DocComponent(Docu LayoutDoc={this.props.LayoutDoc} makeLink={this.makeLink} rootSelected={this.rootSelected} + RenderData={this.props.RenderData} dontRegisterView={this.props.dontRegisterView} fitToBox={this.props.fitToBox} LibraryPath={this.props.LibraryPath} @@ -1112,17 +1114,13 @@ export class DocumentView extends DocComponent(Docu Doc.makeCustomViewClicked(this.props.Document, Docs.Create.StackingDocument, layout, undefined); } } - @observable _animate = 0; + @observable _animateScalingTo = 0; switchViews = action((custom: boolean, view: string) => { - SelectionManager.SetIsDragging(true); - this._animate = 0.1; + this._animateScalingTo = 0.1; // shrink doc setTimeout(action(() => { this.setCustomView(custom, view); - this._animate = 1; - setTimeout(action(() => { - this._animate = 0; - SelectionManager.SetIsDragging(false); - }), 400); + this._animateScalingTo = 1; // expand it + setTimeout(action(() => this._animateScalingTo = 0), 400); }), 400); }); @@ -1156,9 +1154,9 @@ export class DocumentView extends DocComponent(Docu !entered && Doc.UnBrushDoc(this.props.Document); })} style={{ - transformOrigin: this._animate ? "center center" : undefined, - transform: this._animate ? `scale(${this._animate})` : undefined, - transition: !this._animate ? StrCast(this.Document.transition) : this._animate < 1 ? "transform 0.5s ease-in" : "transform 0.5s ease-out", + transformOrigin: this._animateScalingTo ? "center center" : undefined, + transform: this._animateScalingTo ? `scale(${this._animateScalingTo})` : undefined, + transition: !this._animateScalingTo ? StrCast(this.Document.transition) : this._animateScalingTo < 1 ? "transform 0.5s ease-in" : "transform 0.5s ease-out", pointerEvents: this.ignorePointerEvents ? "none" : undefined, color: StrCast(this.layoutDoc.color, "inherit"), outline: highlighting && !borderRounding ? `${highlightColors[fullDegree]} ${highlightStyles[fullDegree]} ${localScale}px` : "solid 0px", diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 0b9edbcd3..1efee4f5a 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -56,6 +56,7 @@ export interface FieldViewProps { width?: number; background?: string; color?: string; + RenderData?: () => Doc; } @observer diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index f91a809bb..3fcc97473 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -16,6 +16,7 @@ import { FieldView, FieldViewProps } from './FieldView'; import "./PresBox.scss"; import { ViewBoxBaseComponent } from "../DocComponent"; import { makeInterface } from "../../../new_fields/Schema"; +import { List } from "../../../new_fields/List"; type PresBoxSchema = makeInterface<[typeof documentSchema]>; const PresBoxDocument = makeInterface(documentSchema); @@ -23,20 +24,15 @@ const PresBoxDocument = makeInterface(documentSchema); @observer export class PresBox extends ViewBoxBaseComponent(PresBoxDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PresBox, fieldKey); } - private _childReaction: IReactionDisposer | undefined; @observable _isChildActive = false; @computed get childDocs() { return DocListCast(this.dataDoc[this.fieldKey]); } @computed get currentIndex() { return NumCast(this.rootDoc._itemIndex); } componentDidMount() { + this.rootDoc.presBox = this.rootDoc; this.rootDoc._forceRenderEngine = "timeline"; this.rootDoc._replacedChrome = "replaced"; - this._childReaction = reaction(() => this.childDocs.slice(), (children) => children.forEach((child, i) => child.presentationIndex = i), { fireImmediately: true }); } - componentWillUnmount() { - this._childReaction?.(); - } - updateCurrentPresentation = () => Doc.UserDoc().activePresentation = this.rootDoc; @undoBatch @@ -247,16 +243,12 @@ export class PresBox extends ViewBoxBaseComponent initializeViewAliases = (docList: Doc[], viewtype: CollectionViewType) => { const hgt = (viewtype === CollectionViewType.Tree) ? 50 : 46; - docList.forEach(doc => { - doc.presBox = this.rootDoc; // give contained documents a reference to the presentation - doc.presCollapsedHeight = hgt; // set the collpased height for documents based on the type of view (Tree or Stack) they will be displaye din - }); + this.rootDoc.presCollapsedHeight = hgt; } addDocument = (doc: Doc) => { - const newPinDoc = Doc.MakeAlias(doc); - newPinDoc.presentationTargetDoc = doc; - return Doc.AddDocToList(this.dataDoc, this.fieldKey, newPinDoc); + doc.presentationTargetDoc = doc.aliasOf; + return Doc.AddDocToList(this.dataDoc, this.fieldKey, doc); } removeDocument = (doc: Doc) => Doc.RemoveDocFromList(this.dataDoc, this.fieldKey, doc); @@ -280,8 +272,10 @@ export class PresBox extends ViewBoxBaseComponent this.updateMinimize(e, this.rootDoc._viewType = viewType); }); + returnSelf = () => this.rootDoc; childLayoutTemplate = () => this.rootDoc._viewType === CollectionViewType.Stacking ? Cast(Doc.UserDoc()["template-presentation"], Doc, null) : undefined; render() { + this.rootDoc.presOrderedDocs = new List(this.childDocs.map((child, i) => child)); const mode = StrCast(this.rootDoc._viewType) as CollectionViewType; this.initializeViewAliases(this.childDocs, mode); return
@@ -314,6 +308,7 @@ export class PresBox extends ViewBoxBaseComponent childLayoutTemplate={this.childLayoutTemplate} addDocument={this.addDocument} removeDocument={returnFalse} + RenderData={this.returnSelf} focus={this.selectElement} ScreenToLocalTransform={this.getTransform} /> : (null) diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx index f9e4c5210..9ad5aafb8 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx @@ -4,7 +4,7 @@ import { EditorView } from "prosemirror-view"; import * as ReactDOM from 'react-dom'; import { Doc, DocCastAsync } from "../../../../new_fields/Doc"; import { Cast, FieldValue, NumCast } from "../../../../new_fields/Types"; -import { emptyFunction, returnEmptyString, returnFalse, Utils, emptyPath } from "../../../../Utils"; +import { emptyFunction, returnEmptyString, returnFalse, Utils, emptyPath, returnZero, returnOne } from "../../../../Utils"; import { DocServer } from "../../../DocServer"; import { DocumentManager } from "../../../util/DocumentManager"; import { schema } from "./schema_rts"; @@ -192,18 +192,24 @@ export class FormattedTextBoxComment { fitToBox={true} moveDocument={returnFalse} rootSelected={returnFalse} - getTransform={Transform.Identity} - active={returnFalse} + ScreenToLocalTransform={Transform.Identity} + parentActive={returnFalse} addDocument={returnFalse} removeDocument={returnFalse} addDocTab={returnFalse} pinToPres={returnFalse} dontRegisterView={true} + ContainingCollectionDoc={undefined} + ContainingCollectionView={undefined} renderDepth={1} PanelWidth={() => Math.min(350, NumCast(target._width, 350))} PanelHeight={() => Math.min(250, NumCast(target._height, 250))} focus={emptyFunction} whenActiveChanged={returnFalse} + bringToFront={returnFalse} + ContentScaling={returnOne} + NativeWidth={returnZero} + NativeHeight={returnZero} />, FormattedTextBoxComment.tooltipText); FormattedTextBoxComment.tooltip.style.width = NumCast(target.width) ? `${NumCast(target.width)}` : "100%"; FormattedTextBoxComment.tooltip.style.height = NumCast(target.height) ? `${NumCast(target.height)}` : "100%"; diff --git a/src/client/views/nodes/formattedText/RichTextMenu.scss b/src/client/views/nodes/formattedText/RichTextMenu.scss index 3a16171de..7a0718c16 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.scss +++ b/src/client/views/nodes/formattedText/RichTextMenu.scss @@ -55,6 +55,9 @@ color: black; } +} + +.richTextMenu { select { background-color: #323232; color: white; diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx index 66f251b93..1887c8d45 100644 --- a/src/client/views/presentationview/PresElementBox.tsx +++ b/src/client/views/presentationview/PresElementBox.tsx @@ -1,12 +1,12 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed, IReactionDisposer, reaction } from "mobx"; import { observer } from "mobx-react"; -import { Doc, DataSym } from "../../../new_fields/Doc"; +import { Doc, DataSym, DocListCast } from "../../../new_fields/Doc"; import { documentSchema } from '../../../new_fields/documentSchemas'; import { Id } from "../../../new_fields/FieldSymbols"; import { createSchema, makeInterface } from '../../../new_fields/Schema'; import { Cast, NumCast } from "../../../new_fields/Types"; -import { emptyFunction, emptyPath, returnFalse, returnTrue } from "../../../Utils"; +import { emptyFunction, emptyPath, returnFalse, returnTrue, returnOne, returnZero } from "../../../Utils"; import { Transform } from "../../util/Transform"; import { CollectionViewType } from '../collections/CollectionView'; import { ViewBoxBaseComponent } from '../DocComponent'; @@ -38,13 +38,14 @@ export class PresElementBox extends ViewBoxBaseComponent d === this.rootDoc); } + @computed get presBoxDoc() { return Cast(this.props.RenderData?.().presBox, Doc) as Doc; } @computed get targetDoc() { return this.rootDoc.presentationTargetDoc as Doc; } @computed get currentIndex() { return NumCast(this.presBoxDoc?._itemIndex); } + @computed get collapsedHeight() { return NumCast(this.presBoxDoc?.presCollapsedHeight); } componentDidMount() { - this._heightDisposer = reaction(() => [this.rootDoc.presExpandInlineButton, this.rootDoc.presCollapsedHeight], + this._heightDisposer = reaction(() => [this.rootDoc.presExpandInlineButton, this.collapsedHeight], params => this.layoutDoc._height = NumCast(params[1]) + (Number(params[0]) ? 100 : 0), { fireImmediately: true }); } componentWillUnmount() { @@ -147,7 +148,7 @@ export class PresElementBox extends ViewBoxBaseComponent [xCord, yCord]; - embedHeight = () => Math.min(this.props.PanelWidth() - 20, this.props.PanelHeight() - NumCast(this.rootDoc.presCollapsedHeight)); + embedHeight = () => Math.min(this.props.PanelWidth() - 20, this.props.PanelHeight() - this.collapsedHeight); embedWidth = () => this.props.PanelWidth() - 20; /** * The function that is responsible for rendering the a preview or not for this @@ -158,7 +159,7 @@ export class PresElementBox extends ViewBoxBaseComponent
; diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx index fe2000700..96f43e931 100644 --- a/src/client/views/search/SearchItem.tsx +++ b/src/client/views/search/SearchItem.tsx @@ -7,7 +7,7 @@ import { observer } from "mobx-react"; import { Doc } from "../../../new_fields/Doc"; import { Id } from "../../../new_fields/FieldSymbols"; import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; -import { emptyFunction, emptyPath, returnFalse, Utils, returnTrue } from "../../../Utils"; +import { emptyFunction, emptyPath, returnFalse, Utils, returnTrue, returnOne, returnZero } from "../../../Utils"; import { DocumentType } from "../../documents/DocumentTypes"; import { DocumentManager } from "../../util/DocumentManager"; import { DragManager, SetupDrag } from "../../util/DragManager"; @@ -164,14 +164,20 @@ export class SearchItem extends React.Component { removeDocument={returnFalse} addDocTab={returnFalse} pinToPres={returnFalse} - getTransform={Transform.Identity} + ContainingCollectionDoc={undefined} + ContainingCollectionView={undefined} + ScreenToLocalTransform={Transform.Identity} renderDepth={1} PanelWidth={returnXDimension} PanelHeight={returnYDimension} + NativeWidth={returnZero} + NativeHeight={returnZero} focus={emptyFunction} moveDocument={returnFalse} - active={returnFalse} + parentActive={returnFalse} whenActiveChanged={returnFalse} + bringToFront={returnFalse} + ContentScaling={returnOne} />
; return docview; diff --git a/src/new_fields/documentSchemas.ts b/src/new_fields/documentSchemas.ts index 5ca0d681e..cd4b9d591 100644 --- a/src/new_fields/documentSchemas.ts +++ b/src/new_fields/documentSchemas.ts @@ -9,7 +9,7 @@ export const documentSchema = createSchema({ layoutKey: "string", // holds the field key for the field that actually holds the current lyoat title: "string", // document title (can be on either data document or layout) dropAction: "string", // override specifying what should happen when this document is dropped (can be "alias", "copy", "move") - targetDropAction: "string", // allows the target of a drop event to specify the dropAction ("alias", "copy", "move") + targetDropAction: "string", // allows the target of a drop event to specify the dropAction ("alias", "copy", "move") childDropAction: "string", // specify the override for what should happen when the child of a collection is dragged from it and dropped (can be "alias" or "copy") _autoHeight: "boolean", // whether the height of the document should be computed automatically based on its contents _nativeWidth: "number", // native width of document which determines how much document contents are scaled when the document's width is set diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index d7cc1e6bf..f37538252 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -578,7 +578,7 @@ export class CurrentUserUtils { } if (doc.activePresentation === undefined) { doc.activePresentation = Docs.Create.PresDocument(new List(), { - title: "Presentation", _viewType: CollectionViewType.Stacking, + title: "Presentation", _viewType: CollectionViewType.Stacking, targetDropAction: "alias", _LODdisable: true, _chromeStatus: "replaced", _showTitle: "title", boxShadow: "0 0" }); } -- cgit v1.2.3-70-g09d2 From 37324d134c8d788a73b8b1d35afa7ea6b0e88d37 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 1 May 2020 12:47:51 -0400 Subject: cleaned up buxton template. fixed adding docs to collections. --- src/client/documents/Documents.ts | 7 +++---- src/client/views/collections/CollectionPileView.tsx | 4 ++-- .../views/collections/CollectionStackingView.scss | 7 +++++-- .../CollectionStackingViewFieldColumn.tsx | 6 +----- src/client/views/collections/CollectionView.tsx | 21 ++++++++++++--------- .../collections/collectionFreeForm/MarqueeView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 2 +- src/client/views/nodes/PresBox.tsx | 6 +++--- src/new_fields/Doc.ts | 2 +- src/new_fields/documentSchemas.ts | 4 ++-- .../authentication/models/current_user_utils.ts | 7 ++++--- 11 files changed, 35 insertions(+), 33 deletions(-) (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 228a6af97..3d790a485 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -98,6 +98,7 @@ export interface DocumentOptions { isTemplateDoc?: boolean; targetScriptKey?: string; // where to write a template script (used by collections with click templates which need to target onClick, onDoubleClick, etc) templates?: List; + hero?: ImageField; // primary image that best represents a compound document (e.g., for a buxton device document that has multiple images) backgroundColor?: string | ScriptField; // background color for data doc _backgroundColor?: string | ScriptField; // background color for each template layout doc ( overrides backgroundColor ) color?: string; // foreground color data doc @@ -423,11 +424,9 @@ export namespace Docs { _nativeHeight: nativeHeight })); // the main document we create - const doc = StackingDocument(deviceImages, { title: device.title, _LODdisable: true }); - const deviceProto = Doc.GetProto(doc); - deviceProto.hero = new ImageField(constructed[0].url); + const doc = StackingDocument(deviceImages, { title: device.title, _LODdisable: true, hero: new ImageField(constructed[0].url) }); // add the parsed attributes to this main document - Docs.Get.FromJson({ data: device, appendToExisting: { targetDoc: deviceProto } }); + Docs.Get.FromJson({ data: device, appendToExisting: { targetDoc: Doc.GetProto(doc) } }); Doc.AddDocToList(parentProto, "data", doc); } else if (errors) { console.log(errors); diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx index 3bbfcc4d7..8b8cbc6e8 100644 --- a/src/client/views/collections/CollectionPileView.tsx +++ b/src/client/views/collections/CollectionPileView.tsx @@ -53,7 +53,7 @@ export class CollectionPileView extends CollectionSubView(doc => doc) { toggleStarburst = action(() => { if (this._layoutEngine === 'starburst') { const defaultSize = 110; - this.layoutDoc.overflow = undefined; + this.layoutDoc._overflow = undefined; this.rootDoc.x = NumCast(this.rootDoc.x) + this.layoutDoc[WidthSym]() / 2 - NumCast(this.layoutDoc._starburstPileWidth, defaultSize) / 2; this.rootDoc.y = NumCast(this.rootDoc.y) + this.layoutDoc[HeightSym]() / 2 - NumCast(this.layoutDoc._starburstPileHeight, defaultSize) / 2; this.layoutDoc._width = NumCast(this.layoutDoc._starburstPileWidth, defaultSize); @@ -61,7 +61,7 @@ export class CollectionPileView extends CollectionSubView(doc => doc) { this._layoutEngine = 'pass'; } else { const defaultSize = 25; - this.layoutDoc.overflow = 'visible'; + this.layoutDoc._overflow = 'visible'; !this.layoutDoc._starburstRadius && (this.layoutDoc._starburstRadius = 500); !this.layoutDoc._starburstDocScale && (this.layoutDoc._starburstDocScale = 2.5); if (this._layoutEngine === 'pass') { diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss index 47faa9239..5eaf29316 100644 --- a/src/client/views/collections/CollectionStackingView.scss +++ b/src/client/views/collections/CollectionStackingView.scss @@ -180,13 +180,16 @@ .collectionStackingView-sectionHeader-subCont { outline: none; border: 0px; - color: $light-color; width: 100%; - color: grey; letter-spacing: 2px; font-size: 75%; transition: transform 0.2s; position: relative; + height: 30px; + display: flex; + align-items: center; + justify-content: center; + color: lightGray; .editableView-container-editing-oneLine, .editableView-container-editing { diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index 323d7be25..8a9539eb0 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -322,11 +322,7 @@ export class CollectionStackingViewFieldColumn extends React.Component + style={{ background: evContents !== `NO ${key.toUpperCase()} VALUE` ? this._color : "inherit" }}> {evContents === `NO ${key.toUpperCase()} VALUE` ? (null) :
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 561226de5..91018980c 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -71,6 +71,9 @@ export enum CollectionViewType { Map = "map", Pile = "pileup" } +export interface CollectionViewCustomProps { + filterAddDocument: (doc: Doc) => boolean; +} export interface CollectionRenderProps { addDocument: (document: Doc) => boolean; @@ -82,7 +85,7 @@ export interface CollectionRenderProps { } @observer -export class CollectionView extends Touchable { +export class CollectionView extends Touchable { public static LayoutString(fieldStr: string) { return FieldView.LayoutString(CollectionView, fieldStr); } private _isChildActive = false; //TODO should this be observable? @@ -113,15 +116,15 @@ export class CollectionView extends Touchable { @action.bound addDocument(doc: Doc): boolean { - if (this.props.addDocument) { - this.props.addDocument(doc); - } else { - const targetDataDoc = this.props.Document[DataSym]; - const docList = DocListCast(targetDataDoc[this.props.fieldKey]); - !docList.includes(doc) && (targetDataDoc[this.props.fieldKey] = new List([...docList, doc])); // DocAddToList may write to targetdataDoc's parent ... we don't want this. should really change GetProto to GetDataDoc and test for resolvedDataDoc there - // Doc.AddDocToList(targetDataDoc, this.props.fieldKey, doc); - targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now())); + if (this.props.filterAddDocument?.(doc) === false) { + return false; } + + const targetDataDoc = this.props.Document[DataSym]; + const docList = DocListCast(targetDataDoc[this.props.fieldKey]); + !docList.includes(doc) && (targetDataDoc[this.props.fieldKey] = new List([...docList, doc])); // DocAddToList may write to targetdataDoc's parent ... we don't want this. should really change GetProto to GetDataDoc and test for resolvedDataDoc there + // Doc.AddDocToList(targetDataDoc, this.props.fieldKey, doc); + targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now())); doc.context = this.props.Document; Doc.GetProto(doc).lastOpened = new DateField; return true; diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index c70301b2f..5bac075b4 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -613,7 +613,7 @@ export class MarqueeView extends React.Component e.currentTarget.scrollTop = e.currentTarget.scrollLeft = 0} onClick={this.onClick} onPointerDown={this.onPointerDown}> {this._visible ? this.marqueeDiv : null} {this.props.children} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index f555d6eef..f1efa48f4 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -666,7 +666,7 @@ export class DocumentView extends DocComponent(Docu @undoBatch @action toggleBackground = (temporary: boolean): void => { - this.Document.overflow = temporary ? "visible" : "hidden"; + this.Document._overflow = temporary ? "visible" : "hidden"; this.Document.isBackground = !temporary ? !this.Document.isBackground : (this.Document.isBackground ? undefined : true); this.Document.isBackground && this.props.bringToFront(this.Document, true); } diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index 3fcc97473..72bbc9e4b 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -246,9 +246,9 @@ export class PresBox extends ViewBoxBaseComponent this.rootDoc.presCollapsedHeight = hgt; } - addDocument = (doc: Doc) => { + addDocumentFilter = (doc: Doc) => { doc.presentationTargetDoc = doc.aliasOf; - return Doc.AddDocToList(this.dataDoc, this.fieldKey, doc); + return true; } removeDocument = (doc: Doc) => Doc.RemoveDocFromList(this.dataDoc, this.fieldKey, doc); @@ -306,7 +306,7 @@ export class PresBox extends ViewBoxBaseComponent PanelHeight={this.panelHeight} moveDocument={returnFalse} childLayoutTemplate={this.childLayoutTemplate} - addDocument={this.addDocument} + filterAddDocument={this.addDocumentFilter} removeDocument={returnFalse} RenderData={this.returnSelf} focus={this.selectElement} diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 77eee03ce..71325d94f 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -997,7 +997,7 @@ export namespace Doc { //newCollection.borderRounding = "40px"; newCollection._jitterRotation = 10; newCollection._backgroundColor = "gray"; - newCollection.overflow = "visible"; + newCollection._overflow = "visible"; return newCollection; } diff --git a/src/new_fields/documentSchemas.ts b/src/new_fields/documentSchemas.ts index cd4b9d591..7bf1c03c8 100644 --- a/src/new_fields/documentSchemas.ts +++ b/src/new_fields/documentSchemas.ts @@ -20,6 +20,7 @@ export const documentSchema = createSchema({ _yPadding: "number", // pixels of padding on top/bottom of collectionfreeformview contents when fitToBox is set _xMargin: "number", // margin added on left/right of most documents to add separation from their container _yMargin: "number", // margin added on top/bottom of most documents to add separation from their container + _overflow: "string", // sets overflow behvavior for CollectionFreeForm views _showCaption: "string", // whether editable caption text is overlayed at the bottom of the document _showTitle: "string", // the fieldkey whose contents should be displayed at the top of the document _showTitleHover: "string", // the showTitle should be shown only on hover @@ -36,7 +37,6 @@ export const documentSchema = createSchema({ color: "string", // foreground color of document backgroundColor: "string", // background color of document opacity: "number", // opacity of document - overflow: "string", // sets overflow behvavior for CollectionFreeForm views creationDate: DateField, // when the document was created links: listSpec(Doc), // computed (readonly) list of links associated with this document onClick: ScriptField, // script to run when document is clicked (can be overriden by an onClick prop) @@ -46,7 +46,7 @@ export const documentSchema = createSchema({ dragFactory: Doc, // the document that serves as the "template" for the onDragStart script. ie, to drag out copies of the dragFactory document. removeDropProperties: listSpec("string"), // properties that should be removed from the alias/copy/etc of this document when it is dropped isTemplateForField: "string",// when specifies a field key, then the containing document is a template that renders the specified field - isBackground: "boolean", // whether document is a background element and ignores input events (can only selet with marquee) + isBackground: "boolean", // whether document is a background element and ignores input events (can only select with marquee) treeViewOpen: "boolean", // flag denoting whether the documents sub-tree (contents) is visible or hidden treeViewExpandedView: "string", // name of field whose contents are being displayed as the document's subtree treeViewPreventOpen: "boolean", // ignores the treeViewOpen flag (for allowing a view to not be slaved to other views of the document) diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index f37538252..fbb27f9b7 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -89,7 +89,7 @@ export class CurrentUserUtils { const carousel = CarouselDocument([], { title: "data", _height: 350, _itemIndex: 0, backgroundColor: "#9b9b9b3F" }); const details = TextDocument("", { title: "details", _height: 350, _autoHeight: true }); - const short = TextDocument("", { title: "shortDescription", treeViewOpen: true, treeViewExpandedView: "layout", _height: 50, _autoHeight: true }); + const short = TextDocument("", { title: "shortDescription", treeViewOpen: true, treeViewExpandedView: "layout", _height: 100, _autoHeight: true }); const long = TextDocument("", { title: "longDescription", treeViewOpen: false, treeViewExpandedView: "layout", _height: 350, _autoHeight: true }); const buxtonFieldKeys = ["year", "originalPrice", "degreesOfFreedom", "company", "attribute", "primaryKey", "secondaryKey", "dimensions"]; @@ -111,8 +111,9 @@ export class CurrentUserUtils { const descriptionWrapper = MasonryDocument([details, short, long], { ...shared, ...descriptionWrapperOpts }); descriptionWrapper.sectionHeaders = new List([ - new SchemaHeaderField("[Long Description]", "LemonChiffon", undefined, undefined, undefined, true), - new SchemaHeaderField("[Details]", "lightBlue", undefined, undefined, undefined, true), + new SchemaHeaderField("[A Short Description]", "dimGray", undefined, undefined, undefined, false), + new SchemaHeaderField("[Long Description]", "dimGray", undefined, undefined, undefined, true), + new SchemaHeaderField("[Details]", "dimGray", undefined, undefined, undefined, true), ]); const detailView = Docs.Create.StackingDocument([carousel, descriptionWrapper], { ...shared, ...detailViewOpts }); detailView.isTemplateDoc = makeTemplate(detailView); -- cgit v1.2.3-70-g09d2 From 72a838b6a6165c7fa3050d78dbf16bf2cca6b840 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 1 May 2020 13:26:25 -0400 Subject: buxton template tweaks --- src/client/documents/Documents.ts | 2 ++ src/client/views/collections/CollectionCarouselView.tsx | 4 ++-- src/server/authentication/models/current_user_utils.ts | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 3d790a485..732f9303b 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -75,6 +75,8 @@ export interface DocumentOptions { _itemIndex?: number; // which item index the carousel viewer is showing _showSidebar?: boolean; //whether an annotationsidebar should be displayed for text docuemnts _singleLine?: boolean; // whether text document is restricted to a single line (carriage returns make new document) + "_carousel-caption-xMargin"?: number; + "_carousel-caption-yMargin"?: number; x?: number; y?: number; z?: number; diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx index bfb7134b2..08d49f8a5 100644 --- a/src/client/views/collections/CollectionCarouselView.tsx +++ b/src/client/views/collections/CollectionCarouselView.tsx @@ -64,8 +64,8 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument) borderRadius: StrCast(this.layoutDoc._captionBorderRounding), }}>
; diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index fbb27f9b7..3dbe90653 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -86,7 +86,7 @@ export class CurrentUserUtils { if (doc["template-button-detail"] === undefined) { const { TextDocument, MasonryDocument, CarouselDocument } = Docs.Create; - const carousel = CarouselDocument([], { title: "data", _height: 350, _itemIndex: 0, backgroundColor: "#9b9b9b3F" }); + const carousel = CarouselDocument([], { title: "data", _height: 350, _itemIndex: 0, "_carousel-caption-xMargin": 10, "_carousel-caption-yMargin": 10, backgroundColor: "#9b9b9b3F" }); const details = TextDocument("", { title: "details", _height: 350, _autoHeight: true }); const short = TextDocument("", { title: "shortDescription", treeViewOpen: true, treeViewExpandedView: "layout", _height: 100, _autoHeight: true }); -- cgit v1.2.3-70-g09d2 From ae21e365e8ed34060bd94ee04d0d8b3a1f3479f3 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 1 May 2020 16:08:35 -0400 Subject: added doubleClick open on right to detailView template for Buxton --- src/client/documents/Documents.ts | 1 + src/client/views/collections/CollectionCarouselView.tsx | 4 +++- src/server/authentication/models/current_user_utils.ts | 12 ++++++++++-- 3 files changed, 14 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 732f9303b..a8b10bc7b 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -123,6 +123,7 @@ export interface DocumentOptions { borderRounding?: string; boxShadow?: string; dontRegisterChildren?: boolean; + "onDoubleClick-rawScript"?: string // onDoubleClick script in raw text form "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 diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx index 08d49f8a5..4086294ad 100644 --- a/src/client/views/collections/CollectionCarouselView.tsx +++ b/src/client/views/collections/CollectionCarouselView.tsx @@ -4,7 +4,7 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import { documentSchema } from '../../../new_fields/documentSchemas'; import { makeInterface } from '../../../new_fields/Schema'; -import { NumCast, StrCast } from '../../../new_fields/Types'; +import { NumCast, StrCast, ScriptCast } from '../../../new_fields/Types'; import { DragManager } from '../../util/DragManager'; import { ContentFittingDocumentView } from '../nodes/ContentFittingDocumentView'; import "./CollectionCarouselView.scss"; @@ -48,6 +48,8 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument) <>
(["heading", "checked", "containingTreeView"]), isTemplateDoc: true, isTemplateForField: "onCheckedClick", _width: 300, _height: 200 }, "onCheckedClick"); - doc.clickFuncs = Docs.Create.TreeDocument([onClick, onCheckedClick], { title: "onClick funcs" }); + doc.clickFuncs = Docs.Create.TreeDocument([onClick, onDoubleClick, onCheckedClick], { title: "onClick funcs" }); } PromiseValue(Cast(doc.clickFuncs, Doc)).then(func => func && PromiseValue(func.data).then(DocListCast)); -- cgit v1.2.3-70-g09d2 From 5e6352c78be5b2a9fe791bd87da9b2415ced4839 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 1 May 2020 19:35:37 -0400 Subject: added childLayoutTemplate to render collection children w/o modifying them. fixed docComponent's layoutDoc to use LayoutDoc prop. change buxton template to use new template mechanisms. fixed fixed lint errors. --- src/client/documents/Documents.ts | 5 +- src/client/util/DragManager.ts | 2 +- src/client/views/DocComponent.tsx | 2 +- src/client/views/animationtimeline/Timeline.tsx | 4 +- .../views/animationtimeline/TimelineMenu.tsx | 81 +++++++++++----------- src/client/views/animationtimeline/Track.tsx | 50 ++++++------- .../views/collections/CollectionStackingView.tsx | 2 +- src/client/views/collections/CollectionSubView.tsx | 17 ----- .../views/collections/CollectionTreeView.tsx | 36 ++++------ .../collectionFreeForm/CollectionFreeFormView.tsx | 11 ++- src/client/views/nodes/PresBox.tsx | 2 +- .../views/nodes/formattedText/DashFieldView.tsx | 2 +- src/new_fields/documentSchemas.ts | 2 +- 13 files changed, 94 insertions(+), 122 deletions(-) (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index a8b10bc7b..434b26312 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -93,7 +93,8 @@ export interface DocumentOptions { scale?: number; isDisplayPanel?: boolean; // whether the panel functions as GoldenLayout "stack" used to display documents forceActive?: boolean; - layout?: string | Doc; + layout?: string | Doc; // default layout string for a document + childLayoutTemplate?: Doc; // template for collection to use to render its children (see PresBox or Buxton layout in tree view) hideFilterView?: boolean; // whether to hide the filter popout on collections hideHeadings?: boolean; // whether stacking view column headings should be hidden isTemplateForField?: string; // the field key for which the containing document is a rendering template @@ -123,7 +124,7 @@ export interface DocumentOptions { borderRounding?: string; boxShadow?: string; dontRegisterChildren?: boolean; - "onDoubleClick-rawScript"?: string // onDoubleClick script in raw text form + "onDoubleClick-rawScript"?: string; // onDoubleClick script in raw text form "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 diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index c48611eff..c06ad3d60 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -316,7 +316,7 @@ export namespace DragManager { return closestDists[minIndex] < snapThreshold ? closestPts[minIndex] + offs[minIndex] : drag; } return drag; - } + }; return { thisX: snapVal([xFromLeft, xFromRight], e.pageX, vertSnapLines), thisY: snapVal([yFromTop, yFromBottom], e.pageY, horizSnapLines) }; } diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index 0a8f0c9a7..629b0f447 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -20,7 +20,7 @@ export function DocComponent

(schemaCtor: (doc: D // This is the "The Document" -- it encapsulates, data, layout, and any templates @computed get rootDoc() { return Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document; } // This is the rendering data of a document -- it may be "The Document", or it may be some template document that holds the rendering info - @computed get layoutDoc() { return Doc.Layout(this.props.Document); } + @computed get layoutDoc() { return Doc.Layout(this.props.Document, this.props.LayoutDoc?.()); } // This is the data part of a document -- ie, the data that is constant across all views of the document @computed get dataDoc() { return this.props.Document[DataSym] as Doc; } diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 77656b85f..466cbb867 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -525,8 +525,8 @@ export class Timeline extends React.Component { @action.bound changeLengths() { if (this._infoContainer.current) { - this._visibleLength = this._infoContainer.current!.getBoundingClientRect().width; //the visible length of the timeline (the length that you current see) - this._visibleStart = this._infoContainer.current!.scrollLeft; //where the div starts + this._visibleLength = this._infoContainer.current.getBoundingClientRect().width; //the visible length of the timeline (the length that you current see) + this._visibleStart = this._infoContainer.current.scrollLeft; //where the div starts } } diff --git a/src/client/views/animationtimeline/TimelineMenu.tsx b/src/client/views/animationtimeline/TimelineMenu.tsx index 59c25596e..53ca9acad 100644 --- a/src/client/views/animationtimeline/TimelineMenu.tsx +++ b/src/client/views/animationtimeline/TimelineMenu.tsx @@ -1,7 +1,7 @@ import * as React from "react"; -import {observable, action, runInAction} from "mobx"; -import {observer} from "mobx-react"; -import "./TimelineMenu.scss"; +import { observable, action, runInAction } from "mobx"; +import { observer } from "mobx-react"; +import "./TimelineMenu.scss"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faChartLine, faRoad, faClipboard, faPen, faTrash, faTable } from "@fortawesome/free-solid-svg-icons"; import { Utils } from "../../../Utils"; @@ -9,67 +9,66 @@ import { Utils } from "../../../Utils"; @observer export class TimelineMenu extends React.Component { - public static Instance:TimelineMenu; + public static Instance: TimelineMenu; @observable private _opacity = 0; - @observable private _x = 0; - @observable private _y = 0; - @observable private _currentMenu:JSX.Element[] = []; + @observable private _x = 0; + @observable private _y = 0; + @observable private _currentMenu: JSX.Element[] = []; - constructor (props:Readonly<{}>){ - super(props); - TimelineMenu.Instance = this; + constructor(props: Readonly<{}>) { + super(props); + TimelineMenu.Instance = this; } - + @action - openMenu = (x?:number, y?:number) => { - this._opacity = 1; - x ? this._x = x : this._x = 0; - y ? this._y = y : this._y = 0; + openMenu = (x?: number, y?: number) => { + this._opacity = 1; + x ? this._x = x : this._x = 0; + y ? this._y = y : this._y = 0; } @action closeMenu = () => { - this._opacity = 0; - this._currentMenu = []; - this._x = -1000000; - this._y = -1000000; + this._opacity = 0; + this._currentMenu = []; + this._x = -1000000; + this._y = -1000000; } @action - addItem = (type: "input" | "button", title: string, event: (e:any, ...args:any[]) => void) => { - if (type === "input"){ - let inputRef = React.createRef(); - let text = ""; - this._currentMenu.push(

{ + addItem = (type: "input" | "button", title: string, event: (e: any, ...args: any[]) => void) => { + if (type === "input") { + const inputRef = React.createRef(); + let text = ""; + this._currentMenu.push(
{ e.stopPropagation(); text = e.target.value; }} onKeyDown={(e) => { if (e.keyCode === 13) { - event(text); - this.closeMenu(); - e.stopPropagation(); - } - }}/>
); + event(text); + this.closeMenu(); + e.stopPropagation(); + } + }} />
); } else if (type === "button") { - let buttonRef = React.createRef(); - this._currentMenu.push(

{ - e.preventDefault(); - e.stopPropagation(); - event(e); - this.closeMenu(); - }}>{title}

); - } + this._currentMenu.push(

{ + e.preventDefault(); + e.stopPropagation(); + event(e); + this.closeMenu(); + }}>{title}

); + } } - @action - addMenu = (title:string) => { - this._currentMenu.unshift(

{title}

); + @action + addMenu = (title: string) => { + this._currentMenu.unshift(

{title}

); } render() { return ( -
+
{this._currentMenu}
); diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index 79eb60fae..461db4858 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -90,9 +90,9 @@ export class Track extends React.Component { */ @action saveKeyframe = async () => { - let keyframes = Cast(this.saveStateRegion?.keyframes, listSpec(Doc)) as List; - let kfIndex = keyframes.indexOf(this.saveStateKf!); - let kf = keyframes[kfIndex] as Doc; //index in the keyframe + const keyframes = Cast(this.saveStateRegion?.keyframes, listSpec(Doc)) as List; + const kfIndex = keyframes.indexOf(this.saveStateKf!); + const kf = keyframes[kfIndex] as Doc; //index in the keyframe if (this._newKeyframe) { DocListCast(this.saveStateRegion?.keyframes).forEach((kf, index) => { this.copyDocDataToKeyFrame(kf); @@ -103,17 +103,17 @@ export class Track extends React.Component { if (!kf) return; if (kf.type === KeyframeFunc.KeyframeType.default) { // only save for non-fades this.copyDocDataToKeyFrame(kf); - let leftkf = KeyframeFunc.calcMinLeft(this.saveStateRegion!, this.time, kf); // lef keyframe, if it exists - let rightkf = KeyframeFunc.calcMinRight(this.saveStateRegion!, this.time, kf); //right keyframe, if it exists + const leftkf = KeyframeFunc.calcMinLeft(this.saveStateRegion!, this.time, kf); // lef keyframe, if it exists + const rightkf = KeyframeFunc.calcMinRight(this.saveStateRegion!, this.time, kf); //right keyframe, if it exists if (leftkf?.type === KeyframeFunc.KeyframeType.fade) { //replicating this keyframe to fades - let edge = KeyframeFunc.calcMinLeft(this.saveStateRegion!, this.time, leftkf); + const edge = KeyframeFunc.calcMinLeft(this.saveStateRegion!, this.time, leftkf); edge && this.copyDocDataToKeyFrame(edge); leftkf && this.copyDocDataToKeyFrame(leftkf); - edge && (edge!.opacity = 0.1); - leftkf && (leftkf!.opacity = 1); + edge && (edge.opacity = 0.1); + leftkf && (leftkf.opacity = 1); } if (rightkf?.type === KeyframeFunc.KeyframeType.fade) { - let edge = KeyframeFunc.calcMinRight(this.saveStateRegion!, this.time, rightkf); + const edge = KeyframeFunc.calcMinRight(this.saveStateRegion!, this.time, rightkf); edge && this.copyDocDataToKeyFrame(edge); rightkf && this.copyDocDataToKeyFrame(rightkf); edge && (edge.opacity = 0.1); @@ -142,7 +142,7 @@ export class Track extends React.Component { //check for region const region = this.findRegion(this.time); if (region !== undefined) { //if region at scrub time exist - let r = region as RegionData; //for some region is returning undefined... which is not the case + const r = region as RegionData; //for some region is returning undefined... which is not the case if (DocListCast(r.keyframes).find(kf => kf.time === this.time) === undefined) { //basically when there is no additional keyframe at that timespot this.makeKeyData(r, this.time, KeyframeFunc.KeyframeType.default); } @@ -222,11 +222,11 @@ export class Track extends React.Component { } else if (this._newKeyframe) { await this.saveKeyframe(); } - let regiondata = await this.findRegion(Math.round(this.time)); //finds a region that the scrubber is on + const regiondata = await this.findRegion(Math.round(this.time)); //finds a region that the scrubber is on if (regiondata) { - let leftkf: (Doc | undefined) = await KeyframeFunc.calcMinLeft(regiondata, this.time); // lef keyframe, if it exists - let rightkf: (Doc | undefined) = await KeyframeFunc.calcMinRight(regiondata, this.time); //right keyframe, if it exists - let currentkf: (Doc | undefined) = await this.calcCurrent(regiondata); //if the scrubber is on top of the keyframe + const leftkf: (Doc | undefined) = await KeyframeFunc.calcMinLeft(regiondata, this.time); // lef keyframe, if it exists + const rightkf: (Doc | undefined) = await KeyframeFunc.calcMinRight(regiondata, this.time); //right keyframe, if it exists + const currentkf: (Doc | undefined) = await this.calcCurrent(regiondata); //if the scrubber is on top of the keyframe if (currentkf) { console.log("is current"); await this.applyKeys(currentkf); @@ -248,7 +248,7 @@ export class Track extends React.Component { if (!kf[key]) { this.props.node[key] = undefined; } else { - let stored = kf[key]; + const stored = kf[key]; this.props.node[key] = stored instanceof ObjectField ? stored[Copy]() : stored; } }); @@ -261,7 +261,7 @@ export class Track extends React.Component { @action calcCurrent = (region: Doc) => { let currentkf: (Doc | undefined) = undefined; - let keyframes = DocListCast(region.keyframes!); + const keyframes = DocListCast(region.keyframes!); keyframes.forEach((kf) => { if (NumCast(kf.time) === Math.round(this.time)) currentkf = kf; }); @@ -276,12 +276,12 @@ export class Track extends React.Component { interpolate = async (left: Doc, right: Doc) => { this.primitiveWhitelist.forEach(key => { if (left[key] && right[key] && typeof (left[key]) === "number" && typeof (right[key]) === "number") { //if it is number, interpolate - let dif = NumCast(right[key]) - NumCast(left[key]); - let deltaLeft = this.time - NumCast(left.time); - let ratio = deltaLeft / (NumCast(right.time) - NumCast(left.time)); + const dif = NumCast(right[key]) - NumCast(left[key]); + const deltaLeft = this.time - NumCast(left.time); + const ratio = deltaLeft / (NumCast(right.time) - NumCast(left.time)); this.props.node[key] = NumCast(left[key]) + (dif * ratio); } else { // case data - let stored = left[key]; + const stored = left[key]; this.props.node[key] = stored instanceof ObjectField ? stored[Copy]() : stored; } }); @@ -301,8 +301,8 @@ export class Track extends React.Component { */ @action onInnerDoubleClick = (e: React.MouseEvent) => { - let inner = this._inner.current!; - let offsetX = Math.round((e.clientX - inner.getBoundingClientRect().left) * this.props.transform.Scale); + const inner = this._inner.current!; + const offsetX = Math.round((e.clientX - inner.getBoundingClientRect().left) * this.props.transform.Scale); this.createRegion(KeyframeFunc.convertPixelTime(offsetX, "mili", "time", this.props.tickSpacing, this.props.tickIncrement)); } @@ -313,10 +313,10 @@ export class Track extends React.Component { @action createRegion = (time: number) => { if (this.findRegion(time) === undefined) { //check if there is a region where double clicking (prevents phantom regions) - let regiondata = KeyframeFunc.defaultKeyframe(); //create keyframe data + const regiondata = KeyframeFunc.defaultKeyframe(); //create keyframe data regiondata.position = time; //set position - let rightRegion = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.right, regiondata, this.regions); + const rightRegion = KeyframeFunc.findAdjacentRegion(KeyframeFunc.Direction.right, regiondata, this.regions); if (rightRegion && rightRegion.position - regiondata.position <= 4000) { //edge case when there is less than default 4000 duration space between this and right region regiondata.duration = rightRegion.position - regiondata.position; @@ -332,7 +332,7 @@ export class Track extends React.Component { @action makeKeyData = (regiondata: RegionData, time: number, type: KeyframeFunc.KeyframeType = KeyframeFunc.KeyframeType.default) => { //Kfpos is mouse offsetX, representing time - const trackKeyFrames = DocListCast(regiondata.keyframes)!; + const trackKeyFrames = DocListCast(regiondata.keyframes); const existingkf = trackKeyFrames.find(TK => TK.time === time); if (existingkf) return existingkf; //else creates a new doc. diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 6c230d5b1..01766f65f 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -128,7 +128,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { return layoutDoc._fitWidth ? wid * NumCast(layoutDoc.scrollHeight, nh) / (nw || 1) : layoutDoc[HeightSym](); } componentDidMount() { - super.componentDidMount(); + super.componentDidMount?.(); // reset section headers when a new filter is inputted this._pivotFieldDisposer = reaction( diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 8cc1af55b..e44bbae78 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -58,7 +58,6 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: private dropDisposer?: DragManager.DragDropDisposer; private gestureDisposer?: GestureUtils.GestureEventDisposer; protected multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer; - private _childLayoutDisposer?: IReactionDisposer; protected _mainCont?: HTMLDivElement; protected createDashEventsTarget = (ele: HTMLDivElement) => { //used for stacking and masonry view this.dropDisposer?.(); @@ -75,25 +74,9 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: this.createDashEventsTarget(ele); } - componentDidMount() { - this._childLayoutDisposer = reaction(() => ({ childDocs: this.childDocs, childLayout: Cast(this.props.Document.childLayout, Doc) }), - ({ childDocs, childLayout }) => { - if (childLayout instanceof Doc) { - childDocs.map(doc => { - doc.layout_fromParent = childLayout; - doc.layoutKey = "layout_fromParent"; - }); - } - else if (!(childLayout instanceof Promise)) { - childDocs.filter(d => !d.isTemplateForField).map(doc => doc.layoutKey === "layout_fromParent" && (doc.layoutKey = "layout")); - } - }, { fireImmediately: true }); - - } componentWillUnmount() { this.gestureDisposer?.(); this.multiTouchDisposer?.(); - this._childLayoutDisposer?.(); } @computed get dataDoc() { diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 71358a8ec..296c1a39c 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -725,14 +725,6 @@ export class CollectionTreeView extends CollectionSubView { - DocListCast(this.dataDoc[this.props.fieldKey]).map(d => { - DocListCast(d.data).map((img, i) => { - const caption = (d.captions as any)[i]; - if (caption) { - Doc.GetProto(img).caption = caption; - } - }); - }); const { ImageDocument } = Docs.Create; const { Document } = this.props; const fallbackImg = "http://www.cs.brown.edu/~bcz/face.gif"; @@ -742,21 +734,19 @@ export class CollectionTreeView extends CollectionSubView(["dropAction"]), icon: "portrait", - onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), - })); - - Doc.AddDocToList(Doc.UserDoc().dockedBtns as Doc, "data", - Docs.Create.FontIconDocument({ - title: "detail view", _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, dropAction: "alias", - dragFactory: detailView, removeDropProperties: new List(["dropAction"]), icon: "file-alt", - onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), - })); - - Document.childLayout = heroView; + const doubleClickView = ImageDocument("http://cs.brown.edu/~bcz/face.gif", { _width: 400 }); // replace with desired double click target + DocListCast(this.dataDoc[this.props.fieldKey]).map(d => { + DocListCast(d.data).map((img, i) => { + const caption = (d.captions as any)[i]; + if (caption) { + Doc.GetProto(img).caption = caption; + Doc.GetProto(img).doubleClickView = doubleClickView; + } + }); + d.layout = ImageBox.LayoutString("hero"); + }); + + Document.childLayoutTemplate = heroView; Document.childDetailView = detailView; Document._viewType = CollectionViewType.Time; Document._forceActive = true; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index b4eb22444..45ef0455e 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -855,9 +855,10 @@ export class CollectionFreeFormView extends CollectionSubView BoolCast(this.Document.useClusters); @computed get backgroundActive() { return this.layoutDoc.isBackground && (this.props.ContainingCollectionView?.active() || this.props.active()); } + backgroundHalo = () => BoolCast(this.Document.useClusters); parentActive = () => this.props.active() || this.backgroundActive ? true : false; + childLayoutFunc = () => this.props.childLayoutTemplate?.() || Cast(this.props.Document.childLayoutTemplate, Doc, null); getChildDocumentViewProps(childLayout: Doc, childData?: Doc): DocumentViewProps { return { ...this.props, @@ -867,12 +868,12 @@ export class CollectionFreeFormView extends CollectionSubView this.props.childLayoutTemplate?.() || Cast(this.props.Document.childLayoutTemplate, Doc, null); get doLayoutComputation() { const { newPool, computedElementData } = this.doInternalLayoutComputation; runInAction(() => @@ -1025,7 +1025,6 @@ export class CollectionFreeFormView extends CollectionSubView this.doLayoutComputation, (elements) => this._layoutElements = elements || [], { fireImmediately: true, name: "doLayout" }); @@ -1156,7 +1155,7 @@ export class CollectionFreeFormView extends CollectionSubView !doc.isBackground && doc.z === undefined).map(doc => isDocInView(doc, selRect)); // first see if there are any foreground docs to snap to diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index 72bbc9e4b..6e3420f22 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -260,7 +260,7 @@ export class PresBox extends ViewBoxBaseComponent panelHeight = () => this.props.PanelHeight() - 20; active = (outsideReaction?: boolean) => ((InkingControl.Instance.selectedTool === InkTool.None && !this.layoutDoc.isBackground) && - (this.layoutDoc.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false); + (this.layoutDoc.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false) whenActiveChanged = action((isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive)); diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx index 1b22ed4cd..d87d6e424 100644 --- a/src/client/views/nodes/formattedText/DashFieldView.tsx +++ b/src/client/views/nodes/formattedText/DashFieldView.tsx @@ -104,7 +104,7 @@ export class DashFieldViewInternal extends React.Component this._showEnumerables = true)); }} > {strVal} - + ; } } } diff --git a/src/new_fields/documentSchemas.ts b/src/new_fields/documentSchemas.ts index 7bf1c03c8..fd9a304f9 100644 --- a/src/new_fields/documentSchemas.ts +++ b/src/new_fields/documentSchemas.ts @@ -78,7 +78,7 @@ export const positionSchema = createSchema({ }); export const collectionSchema = createSchema({ - childLayout: Doc, // layout template for children of a collecion + childLayoutTemplate: Doc, // layout template for children of a collecion childDetailView: Doc, // layout template to apply to a child when its clicked on in a collection and opened (requires onChildClick or other script to use this field) onChildClick: ScriptField, // script to run for each child when its clicked onChildDoubleClick: ScriptField, // script to run for each child when its clicked -- cgit v1.2.3-70-g09d2 From 40d5c3acab6dbdc67f6d4bfd15c802da9fe08ca0 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 2 May 2020 00:17:21 -0400 Subject: cleaned up a lot of layoutTemplate/String props. fixed link drawing. --- src/client/documents/Documents.ts | 7 +- src/client/util/DocumentManager.ts | 2 +- src/client/views/DocComponent.tsx | 4 +- src/client/views/DocumentDecorations.scss | 24 +++--- src/client/views/DocumentDecorations.tsx | 4 +- src/client/views/MainView.scss | 6 +- .../views/collections/CollectionCarouselView.tsx | 11 +-- .../views/collections/CollectionStackingView.tsx | 29 ++++--- src/client/views/collections/CollectionSubView.tsx | 2 + .../views/collections/CollectionTimeView.tsx | 4 +- .../views/collections/CollectionTreeView.tsx | 8 +- src/client/views/collections/CollectionView.tsx | 14 +++- .../views/collections/CollectionViewChromes.tsx | 6 +- .../CollectionFreeFormLinkView.tsx | 2 +- .../CollectionFreeFormLinksView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 10 +-- .../CollectionMulticolumnView.tsx | 5 +- .../CollectionMultirowView.tsx | 5 +- src/client/views/nodes/AudioBox.tsx | 4 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 4 +- .../views/nodes/ContentFittingDocumentView.tsx | 5 +- src/client/views/nodes/DocumentBox.tsx | 94 ++++++++++++++------- src/client/views/nodes/DocumentContentsView.tsx | 44 +++++----- src/client/views/nodes/DocumentView.tsx | 29 +++---- src/client/views/nodes/FieldView.tsx | 3 +- src/client/views/nodes/KeyValueBox.tsx | 2 +- src/client/views/nodes/LinkAnchorBox.tsx | 1 - src/client/views/nodes/ScreenshotBox.tsx | 6 +- src/client/views/nodes/VideoBox.tsx | 6 +- src/new_fields/Doc.ts | 2 +- src/new_fields/documentSchemas.ts | 95 ++++++++++++---------- .../authentication/models/current_user_utils.ts | 2 +- 32 files changed, 247 insertions(+), 195 deletions(-) (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 434b26312..672f94f75 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -95,6 +95,7 @@ export interface DocumentOptions { forceActive?: boolean; layout?: string | Doc; // default layout string for a document childLayoutTemplate?: Doc; // template for collection to use to render its children (see PresBox or Buxton layout in tree view) + childLayoutString?: string; // template string for collection to use to render its children hideFilterView?: boolean; // whether to hide the filter popout on collections hideHeadings?: boolean; // whether stacking view column headings should be hidden isTemplateForField?: string; // the field key for which the containing document is a rendering template @@ -123,7 +124,7 @@ export interface DocumentOptions { displayTimecode?: number; // the time that a document should be displayed (e.g., time an annotation should be displayed on a video) borderRounding?: string; boxShadow?: string; - dontRegisterChildren?: boolean; + dontRegisterChildViews?: boolean; "onDoubleClick-rawScript"?: string; // onDoubleClick script in raw text form "onClick-rawScript"?: string; // onClick script in raw text form "onCheckedClick-rawScript"?: string; // onChecked script in raw text form @@ -592,9 +593,7 @@ export namespace Docs { linkDocProto.anchor1_timecode = source.doc.currentTimecode || source.doc.displayTimecode; linkDocProto.anchor2_timecode = target.doc.currentTimecode || target.doc.displayTimecode; - if (linkDocProto.layout_key1 === undefined) { - Cast(linkDocProto.proto, Doc, null).layout_key1 = LinkAnchorBox.LayoutString("anchor1"); - Cast(linkDocProto.proto, Doc, null).layout_key2 = LinkAnchorBox.LayoutString("anchor2"); + if (linkDocProto.linkBoxExcludedKeys === undefined) { Cast(linkDocProto.proto, Doc, null).linkBoxExcludedKeys = new List(["treeViewExpandedView", "treeViewHideTitle", "removeDropProperties", "linkBoxExcludedKeys", "treeViewOpen", "aliasNumber", "isPrototype", "lastOpened", "creationDate", "author"]); Cast(linkDocProto.proto, Doc, null).layoutKey = undefined; } diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 4683e77a8..1ba6f0248 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -117,7 +117,7 @@ export class DocumentManager { pairs.push(...linksList.reduce((pairs, link) => { const linkToDoc = link && LinkManager.Instance.getOppositeAnchor(link, dv.props.Document); linkToDoc && DocumentManager.Instance.getDocumentViews(linkToDoc).map(docView1 => { - if (dv.props.Document.type !== DocumentType.LINK || dv.props.layoutKey !== docView1.props.layoutKey) { + if (dv.props.Document.type !== DocumentType.LINK || dv.props.LayoutTemplateString !== docView1.props.LayoutTemplateString) { pairs.push({ a: dv, b: docView1, l: link }); } }); diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index 629b0f447..fd0d2bdbb 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -11,7 +11,7 @@ import { InteractionUtils } from '../util/InteractionUtils'; /// DocComponent returns a generic React base class used by views that don't have 'fieldKey' props (e.g.,CollectionFreeFormDocumentView, DocumentView) interface DocComponentProps { Document: Doc; - LayoutDoc?: () => Opt; + LayoutTemplate?: () => Opt; } export function DocComponent

(schemaCtor: (doc: Doc) => T) { class Component extends Touchable

{ @@ -20,7 +20,7 @@ export function DocComponent

(schemaCtor: (doc: D // This is the "The Document" -- it encapsulates, data, layout, and any templates @computed get rootDoc() { return Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document; } // This is the rendering data of a document -- it may be "The Document", or it may be some template document that holds the rendering info - @computed get layoutDoc() { return Doc.Layout(this.props.Document, this.props.LayoutDoc?.()); } + @computed get layoutDoc() { return Doc.Layout(this.props.Document, this.props.LayoutTemplate?.()); } // This is the data part of a document -- ie, the data that is constant across all views of the document @computed get dataDoc() { return this.props.Document[DataSym] as Doc; } diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss index 61d517d43..4f34eb9e3 100644 --- a/src/client/views/DocumentDecorations.scss +++ b/src/client/views/DocumentDecorations.scss @@ -44,7 +44,6 @@ $linkGap : 3px; .documentDecorations-radius { pointer-events: auto; - background: black; opacity: 1; transform: translate(10px, 10px); grid-row: 4; @@ -88,12 +87,12 @@ $linkGap : 3px; opacity: 1; } #documentDecorations-topLeftResizer { - border-left: black 2px solid; - border-top: black solid 2px; + border-left: 2px solid; + border-top: solid 2px; } #documentDecorations-bottomRightResizer { - border-right: black 2px solid; - border-bottom: black solid 2px; + border-right: 2px solid; + border-bottom: solid 2px; } #documentDecorations-topLeftResizer:hover, #documentDecorations-bottomRightResizer:hover { @@ -111,12 +110,12 @@ $linkGap : 3px; opacity: 1; } #documentDecorations-topRightResizer { - border-right: black 2px solid; - border-top: black 2px solid; + border-right: 2px solid; + border-top: 2px solid; } #documentDecorations-bottomLeftResizer { - border-left: black 2px solid; - border-bottom: black 2px solid; + border-left: 2px solid; + border-bottom: 2px solid; } #documentDecorations-topRightResizer:hover, #documentDecorations-bottomLeftResizer:hover { @@ -136,7 +135,6 @@ $linkGap : 3px; } .documentDecorations-contextMenu { - background: $alt-accent; width: 25px; height: calc(100% + 8px); // 8px for the height of the top resizer bar grid-column-start: 1; @@ -144,14 +142,14 @@ $linkGap : 3px; pointer-events: all; } .documentDecorations-title { - background: $alt-accent; opacity: 1; grid-column-start: 3; grid-column-end: 4; pointer-events: auto; overflow: hidden; text-align: center; - display:flex; + display: flex; + border-bottom: solid 1px; } .publishBox { width: 20px; @@ -168,7 +166,6 @@ $linkGap : 3px; .documentDecorations-closeButton { - background: $alt-accent; opacity: 1; grid-column-start: 4; grid-column-end: 6; @@ -178,7 +175,6 @@ $linkGap : 3px; } .documentDecorations-minimizeButton { - background: $alt-accent; opacity: 1; grid-column-start: 1; grid-column-end: 3; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index e2759291a..396fe12b5 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -4,7 +4,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; import { Doc, DataSym, Field } from "../../new_fields/Doc"; -import { PositionDocument } from '../../new_fields/documentSchemas'; +import { Document } from '../../new_fields/documentSchemas'; import { ScriptField } from '../../new_fields/ScriptField'; import { Cast, StrCast, NumCast } from "../../new_fields/Types"; import { Utils, setupMoveUpEvents, emptyFunction, returnFalse, simulateMouseClick } from "../../Utils"; @@ -301,7 +301,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> SelectionManager.SelectedDocuments().forEach(action((element: DocumentView) => { if (dX !== 0 || dY !== 0 || dW !== 0 || dH !== 0) { - const doc = PositionDocument(element.rootDoc); + const doc = Document(element.rootDoc); let nwidth = doc._nativeWidth || 0; let nheight = doc._nativeHeight || 0; const width = (doc._width || 0); diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss index 81d427f64..04288a9e1 100644 --- a/src/client/views/MainView.scss +++ b/src/client/views/MainView.scss @@ -39,7 +39,12 @@ } } +.mainView-container { + color:dimgray; +} + .mainView-container-dark { + color: lightgray; .lm_goldenlayout { background: dimgray; } @@ -54,7 +59,6 @@ } .contextMenu-cont, .contextMenu-item { background: dimGray; - color: lightgray; } .contextMenu-item:hover { background: gray; diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx index 4086294ad..769b323ae 100644 --- a/src/client/views/collections/CollectionCarouselView.tsx +++ b/src/client/views/collections/CollectionCarouselView.tsx @@ -2,9 +2,9 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { observable, computed } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { documentSchema } from '../../../new_fields/documentSchemas'; +import { documentSchema, collectionSchema } from '../../../new_fields/documentSchemas'; import { makeInterface } from '../../../new_fields/Schema'; -import { NumCast, StrCast, ScriptCast } from '../../../new_fields/Types'; +import { NumCast, StrCast, ScriptCast, Cast } from '../../../new_fields/Types'; import { DragManager } from '../../util/DragManager'; import { ContentFittingDocumentView } from '../nodes/ContentFittingDocumentView'; import "./CollectionCarouselView.scss"; @@ -16,8 +16,8 @@ import { ContextMenu } from '../ContextMenu'; import { ObjectField } from '../../../new_fields/ObjectField'; import { returnFalse } from '../../../Utils'; -type CarouselDocument = makeInterface<[typeof documentSchema,]>; -const CarouselDocument = makeInterface(documentSchema); +type CarouselDocument = makeInterface<[typeof documentSchema, typeof collectionSchema]>; +const CarouselDocument = makeInterface(documentSchema, collectionSchema); @observer export class CollectionCarouselView extends CollectionSubView(CarouselDocument) { @@ -40,7 +40,6 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument) e.stopPropagation(); this.layoutDoc._itemIndex = (NumCast(this.layoutDoc._itemIndex) - 1 + this.childLayoutPairs.length) % this.childLayoutPairs.length; } - panelHeight = () => this.props.PanelHeight() - 50; @computed get content() { const index = NumCast(this.layoutDoc._itemIndex); @@ -51,6 +50,8 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument) onDoubleClick={ScriptCast(this.layoutDoc.onChildDoubleClick)} onClick={ScriptCast(this.layoutDoc.onChildClick)} renderDepth={this.props.renderDepth + 1} + LayoutTemplate={this.props.ChildLayoutTemplate} + LayoutTemplateString={this.props.ChildLayoutString} Document={this.childLayoutPairs[index].layout} DataDoc={this.childLayoutPairs[index].data} PanelHeight={this.panelHeight} diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 01766f65f..eb70cec9d 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -4,15 +4,17 @@ import { CursorProperty } from "csstype"; import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; import Switch from 'rc-switch'; -import { Doc, HeightSym, WidthSym, DataSym } from "../../../new_fields/Doc"; +import { DataSym, Doc, HeightSym, WidthSym } from "../../../new_fields/Doc"; +import { collectionSchema, documentSchema } from "../../../new_fields/documentSchemas"; import { Id } from "../../../new_fields/FieldSymbols"; import { List } from "../../../new_fields/List"; -import { listSpec } from "../../../new_fields/Schema"; +import { listSpec, makeInterface } from "../../../new_fields/Schema"; import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField"; import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../new_fields/Types"; import { TraceMobx } from "../../../new_fields/util"; -import { Utils, setupMoveUpEvents, emptyFunction, returnZero, returnOne, returnFalse } from "../../../Utils"; +import { emptyFunction, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils } from "../../../Utils"; import { DragManager, dropActionType } from "../../util/DragManager"; +import { SelectionManager } from "../../util/SelectionManager"; import { Transform } from "../../util/Transform"; import { undoBatch } from "../../util/UndoManager"; import { ContextMenu } from "../ContextMenu"; @@ -24,11 +26,14 @@ import "./CollectionStackingView.scss"; import { CollectionStackingViewFieldColumn } from "./CollectionStackingViewFieldColumn"; import { CollectionSubView } from "./CollectionSubView"; import { CollectionViewType } from "./CollectionView"; -import { SelectionManager } from "../../util/SelectionManager"; +import { ScriptField } from "../../../new_fields/ScriptField"; const _global = (window /* browser */ || global /* node */) as any; +type StackingDocument = makeInterface<[typeof collectionSchema, typeof documentSchema]>; +const StackingDocument = makeInterface(collectionSchema, documentSchema); + @observer -export class CollectionStackingView extends CollectionSubView(doc => doc) { +export class CollectionStackingView extends CollectionSubView(StackingDocument) { _masonryGridRef: HTMLDivElement | null = null; _draggerRef = React.createRef(); _pivotFieldDisposer?: IReactionDisposer; @@ -116,7 +121,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { getSimpleDocHeight(d?: Doc) { if (!d) return 0; - const layoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.()); + const layoutDoc = Doc.Layout(d, this.props.ChildLayoutTemplate?.()); const nw = NumCast(layoutDoc._nativeWidth); const nh = NumCast(layoutDoc._nativeHeight); let wid = this.columnWidth / (this.isStackingView ? this.numGroupColumns : 1); @@ -160,14 +165,16 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { } return this.props.addDocTab(doc, where); } + getDisplayDoc(doc: Doc, dataDoc: Doc | undefined, dxf: () => Transform, width: () => number) { - const layoutDoc = Doc.Layout(doc, this.props.childLayoutTemplate?.()); + const layoutDoc = Doc.Layout(doc, this.props.ChildLayoutTemplate?.()); const height = () => this.getDocHeight(doc); return doc) { PanelHeight={height} NativeHeight={returnZero} NativeWidth={returnZero} - fitToBox={BoolCast(this.props.Document._freezeChildDimensions)} + fitToBox={false} rootSelected={this.rootSelected} dropAction={StrCast(this.props.Document.childDropAction) as dropActionType} onClick={this.onChildClickHandler} @@ -199,13 +206,13 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { getDocWidth(d?: Doc) { if (!d) return 0; - const layoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.()); + const layoutDoc = Doc.Layout(d, this.props.ChildLayoutTemplate?.()); const nw = NumCast(layoutDoc._nativeWidth); return Math.min(nw && !this.props.Document.fillColumn ? d[WidthSym]() : Number.MAX_VALUE, this.columnWidth / this.numGroupColumns); } getDocHeight(d?: Doc) { if (!d) return 0; - const layoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.()); + const layoutDoc = Doc.Layout(d, this.props.ChildLayoutTemplate?.()); const nw = NumCast(layoutDoc._nativeWidth); const nh = NumCast(layoutDoc._nativeHeight); let wid = this.columnWidth / (this.isStackingView ? this.numGroupColumns : 1); diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index e44bbae78..aaea13ded 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -43,6 +43,8 @@ export interface CollectionViewProps extends FieldViewProps { export interface SubCollectionViewProps extends CollectionViewProps { CollectionView: Opt; children?: never | (() => JSX.Element[]) | React.ReactNode; + ChildLayoutTemplate?: () => Doc; + ChildLayoutString?: string; childClickScript?: ScriptField; childDoubleClickScript?: ScriptField; freezeChildDimensions?: boolean; // used by TimeView to coerce documents to treat their width height as their native width/height diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 045134225..a2d4774c8 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -28,7 +28,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { @observable _childClickedScript: Opt; @observable _viewDefDivClick: Opt; async componentDidMount() { - const detailView = (await DocCastAsync(this.props.Document.childDetailView)) || Doc.findTemplate("detailView", StrCast(this.props.Document.type), ""); + const detailView = (await DocCastAsync(this.props.Document.childClickedOpenTemplateView)) || Doc.findTemplate("detailView", StrCast(this.props.Document.type), ""); 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! }); @@ -84,7 +84,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { @computed get contents() { return

- +
; } diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 296c1a39c..dc9348664 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -6,7 +6,6 @@ import { observer } from "mobx-react"; import { DataSym, Doc, DocListCast, Field, HeightSym, Opt, WidthSym } from '../../../new_fields/Doc'; import { Id } from '../../../new_fields/FieldSymbols'; import { List } from '../../../new_fields/List'; -import { RichTextField } from '../../../new_fields/RichTextField'; import { Document, listSpec } from '../../../new_fields/Schema'; import { ComputedField, ScriptField } from '../../../new_fields/ScriptField'; import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../new_fields/Types'; @@ -15,7 +14,6 @@ import { Docs, DocUtils } from '../../documents/Documents'; import { DocumentType } from "../../documents/DocumentTypes"; import { DocumentManager } from '../../util/DocumentManager'; import { DragManager, dropActionType, SetupDrag } from "../../util/DragManager"; -import { makeTemplate } from '../../util/DropConverter'; import { Scripting } from '../../util/Scripting'; import { SelectionManager } from '../../util/SelectionManager'; import { Transform } from '../../util/Transform'; @@ -481,7 +479,7 @@ class TreeView extends React.Component { parentActive={returnTrue} whenActiveChanged={emptyFunction} bringToFront={emptyFunction} - dontRegisterView={BoolCast(this.props.treeViewId.dontRegisterChildren)} + dontRegisterView={BoolCast(this.props.treeViewId.dontRegisterChildViews)} ContainingCollectionView={undefined} ContainingCollectionDoc={this.props.containingCollection} />} @@ -743,11 +741,11 @@ export class CollectionTreeView extends CollectionSubView boolean; + filterAddDocument: (doc: Doc) => boolean; // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example) + childLayoutTemplate?: () => Opt; // specify a layout Doc template to use for children of the collection } export interface CollectionRenderProps { @@ -82,6 +83,8 @@ export interface CollectionRenderProps { active: () => boolean; whenActiveChanged: (isActive: boolean) => void; PanelWidth: () => number; + ChildLayoutTemplate?: () => Doc; + ChildLayoutString?: string; } @observer @@ -245,8 +248,8 @@ export class CollectionView extends Touchable this.props.addDocTab(this.props.Document.childLayout as Doc, "onRight"), icon: "project-diagram" }); } - if (this.props.Document.childDetailView instanceof Doc) { - layoutItems.push({ description: "View Child Detailed Layout", event: () => this.props.addDocTab(this.props.Document.childDetailView as Doc, "onRight"), icon: "project-diagram" }); + if (this.props.Document.childClickedOpenTemplateView instanceof Doc) { + layoutItems.push({ description: "View Child Detailed Layout", event: () => this.props.addDocTab(this.props.Document.childClickedOpenTemplateView as Doc, "onRight"), icon: "project-diagram" }); } layoutItems.push({ description: `${this.props.Document.isInPlaceContainer ? "Unset" : "Set"} inPlace Container`, event: () => this.props.Document.isInPlaceContainer = !this.props.Document.isInPlaceContainer, icon: "project-diagram" }); @@ -474,6 +477,7 @@ export class CollectionView extends Touchable
; } + childLayoutTemplate = () => this.props.childLayoutTemplate?.() || Cast(this.props.Document.childLayoutTemplate, Doc, null); render() { TraceMobx(); @@ -483,7 +487,9 @@ export class CollectionView extends Touchable click item view", - script: "this.target.childDetailView = getDocTemplate(this.source?.[0])", - immediate: (source: Doc[]) => this.target.childDetailView = Doc.getDocTemplate(source?.[0]), + params: ["target", "source"], title: "=> click clicked open view", + script: "this.target.childClickedOpenTemplateView = getDocTemplate(this.source?.[0])", + immediate: (source: Doc[]) => this.target.childClickedOpenTemplateView = Doc.getDocTemplate(source?.[0]), initialize: emptyFunction, }; _contentCommand = { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index cf12ef382..d67d1993e 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -40,7 +40,7 @@ export class CollectionFreeFormLinkView extends React.Component - c.a.props.layoutKey && c.b.props.layoutKey && c.a.props.Document.type === DocumentType.LINK && + c.a.props.Document.type === DocumentType.LINK && c.a.props.bringToFront !== emptyFunction && c.b.props.bringToFront !== emptyFunction // bcz: this prevents links to be drawn to anchors in CollectionTree views -- this is a hack that should be fixed ).map(c => ); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 45ef0455e..707e103fb 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -5,7 +5,7 @@ import { action, computed, IReactionDisposer, observable, ObservableMap, reactio import { observer } from "mobx-react"; import { computedFn } from "mobx-utils"; import { Doc, HeightSym, Opt, WidthSym, DocListCast } from "../../../../new_fields/Doc"; -import { documentSchema, positionSchema } from "../../../../new_fields/documentSchemas"; +import { documentSchema, collectionSchema } from "../../../../new_fields/documentSchemas"; import { Id } from "../../../../new_fields/FieldSymbols"; import { InkData, InkField, InkTool, PointData } from "../../../../new_fields/InkField"; import { List } from "../../../../new_fields/List"; @@ -66,8 +66,8 @@ export const panZoomSchema = createSchema({ fitH: "number" }); -type PanZoomDocument = makeInterface<[typeof panZoomSchema, typeof documentSchema, typeof positionSchema, typeof pageSchema]>; -const PanZoomDocument = makeInterface(panZoomSchema, documentSchema, positionSchema, pageSchema); +type PanZoomDocument = makeInterface<[typeof panZoomSchema, typeof collectionSchema, typeof documentSchema, typeof pageSchema]>; +const PanZoomDocument = makeInterface(panZoomSchema, collectionSchema, documentSchema, pageSchema); export type collectionFreeformViewProps = { forceScaling?: boolean; // whether to force scaling of content (needed by ImageBox) viewDefDivClick?: ScriptField; @@ -858,7 +858,6 @@ export class CollectionFreeFormView extends CollectionSubView BoolCast(this.Document.useClusters); parentActive = () => this.props.active() || this.backgroundActive ? true : false; - childLayoutFunc = () => this.props.childLayoutTemplate?.() || Cast(this.props.Document.childLayoutTemplate, Doc, null); getChildDocumentViewProps(childLayout: Doc, childData?: Doc): DocumentViewProps { return { ...this.props, @@ -868,7 +867,8 @@ export class CollectionFreeFormView extends CollectionSubView(PositionDocument) { +export class CollectionFreeFormDocumentView extends DocComponent(Document) { @observable _animPos: number[] | undefined = undefined; random(min: number, max: number) { // min should not be equal to max const mseed = Math.abs(this.X * this.Y); diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx index 637fd5acc..3c2c6c87e 100644 --- a/src/client/views/nodes/ContentFittingDocumentView.tsx +++ b/src/client/views/nodes/ContentFittingDocumentView.tsx @@ -14,7 +14,7 @@ import "./ContentFittingDocumentView.scss"; @observer export class ContentFittingDocumentView extends React.Component{ public get displayName() { return "DocumentView(" + this.props.Document?.title + ")"; } // this makes mobx trace() statements more descriptive - private get layoutDoc() { return this.props.LayoutDoc?.() || Doc.Layout(this.props.Document); } + private get layoutDoc() { return this.props.LayoutTemplate?.() || Doc.Layout(this.props.Document); } @computed get freezeDimensions() { return this.props.FreezeDimensions; } nativeWidth = () => NumCast(this.layoutDoc?._nativeWidth, this.props.NativeWidth?.() || (this.freezeDimensions && this.layoutDoc ? this.layoutDoc[WidthSym]() : this.props.PanelWidth())); nativeHeight = () => NumCast(this.layoutDoc?._nativeHeight, this.props.NativeHeight?.() || (this.freezeDimensions && this.layoutDoc ? this.layoutDoc[HeightSym]() : this.props.PanelHeight())); @@ -56,7 +56,8 @@ export class ContentFittingDocumentView extends React.Component; -const DocHolderBoxDocument = makeInterface(documentSchema); +type DocHolderBoxSchema = makeInterface<[typeof documentSchema, typeof collectionSchema]>; +const DocHolderBoxDocument = makeInterface(documentSchema, collectionSchema); @observer export class DocHolderBox extends ViewBoxAnnotatableComponent(DocHolderBoxDocument) { @@ -43,7 +45,7 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent this.toggleLockSelection, icon: "expand-arrows-alt" }); funcs.push({ description: (this.layoutDoc.excludeCollections ? "Include" : "Exclude") + " Collections", event: () => this.layoutDoc.excludeCollections = !this.layoutDoc.excludeCollections, icon: "expand-arrows-alt" }); funcs.push({ description: `${this.layoutDoc.forceActive ? "Select" : "Force"} Contents Active`, event: () => this.layoutDoc.forceActive = !this.layoutDoc.forceActive, icon: "project-diagram" }); - funcs.push({ description: `Show ${this.layoutDoc.childTemplateName !== "keyValue" ? "key values" : "contents"}`, event: () => this.layoutDoc.childTemplateName = this.layoutDoc.childTemplateName ? undefined : "keyValue", icon: "project-diagram" }); + funcs.push({ description: `Show ${this.layoutDoc.childLayoutTemplateName !== "keyValue" ? "key values" : "contents"}`, event: () => this.layoutDoc.childLayoutString = this.layoutDoc.childLayoutString ? undefined : "", icon: "project-diagram" }); ContextMenu.Instance.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" }); } @@ -103,6 +105,7 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent this.props.PanelWidth() - 2 * this.xPad; pheight = () => this.props.PanelHeight() - 2 * this.yPad; getTransform = () => this.props.ScreenToLocalTransform().translate(-this.xPad, -this.yPad); + isActive = () => this.active() || !this.props.renderDepth; get renderContents() { const containedDoc = Cast(this.dataDoc[this.props.fieldKey], Doc, null); const childTemplateName = StrCast(this.layoutDoc.childTemplateName); @@ -112,33 +115,62 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent; + const contents = !(containedDoc instanceof Doc) ? (null) : this.layoutDoc.childLayoutString ? + : + ; return contents; } render() { diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 4d20d3e2c..749fb98be 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -96,8 +96,6 @@ export class DocumentContentsView extends React.Component boolean, select: (ctrl: boolean) => void, layoutKey: string, - forceLayout?: string, - forceFieldKey?: string, hideOnLeave?: boolean, makeLink?: () => Opt, // function to call when a link is made }> { @@ -105,6 +103,7 @@ export class DocumentContentsView extends React.Componentawaiting layout

"; // const layout = Cast(this.layoutDoc[StrCast(this.layoutDoc.layoutKey, this.layoutDoc === this.props.Document ? this.props.layoutKey : "layout")], "string"); // bcz: replaced this with below... is it right? + if (this.props.LayoutTemplateString) return this.props.LayoutTemplateString; const layout = Cast(this.layoutDoc[this.layoutDoc === this.props.Document && this.props.layoutKey ? this.props.layoutKey : StrCast(this.layoutDoc.layoutKey, "layout")], "string"); if (this.props.layoutKey === "layout_keyValue") { return StrCast(this.props.Document.layout_keyValue, KeyValueBox.LayoutString("data")); @@ -127,8 +126,8 @@ export class DocumentContentsView extends React.Component 1 ? splits[0] + splits[1].replace(/{([^{}]|(?R))*}/, replacer4) : ""; // might have been more elegant if javascript supported recursive patterns return (this.props.renderDepth > 12 || !layoutFrame || !this.layoutDoc) ? (null) : - this.props.forceLayout === "FormattedTextBox" && this.props.forceFieldKey ? - - : - { console.log(test); }} - />; + { console.log(test); }} + />; } } \ No newline at end of file diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index f1efa48f4..7c7c03db2 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -5,22 +5,21 @@ import { action, computed, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; import * as rp from "request-promise"; import { Doc, DocListCast, HeightSym, Opt, WidthSym } from "../../../new_fields/Doc"; -import { Document, PositionDocument } from '../../../new_fields/documentSchemas'; +import { Document } from '../../../new_fields/documentSchemas'; import { Id } from '../../../new_fields/FieldSymbols'; import { InkTool } from '../../../new_fields/InkField'; -import { RichTextField } from '../../../new_fields/RichTextField'; import { listSpec } from "../../../new_fields/Schema"; import { SchemaHeaderField } from '../../../new_fields/SchemaHeaderField'; import { ScriptField } from '../../../new_fields/ScriptField'; import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types"; -import { AudioField, ImageField, PdfField, VideoField } from '../../../new_fields/URLField'; +import { ImageField } from '../../../new_fields/URLField'; import { TraceMobx } from '../../../new_fields/util'; import { GestureUtils } from '../../../pen-gestures/GestureUtils'; import { emptyFunction, OmitKeys, returnOne, returnTransparent, Utils } from "../../../Utils"; import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils'; import { ClientRecommender } from '../../ClientRecommender'; import { DocServer } from "../../DocServer"; -import { Docs, DocumentOptions, DocUtils } from "../../documents/Documents"; +import { Docs, DocUtils } from "../../documents/Documents"; import { DocumentType } from '../../documents/DocumentTypes'; import { ClientUtils } from '../../util/ClientUtils'; import { DocumentManager } from "../../util/DocumentManager"; @@ -42,6 +41,7 @@ import { InkingControl } from '../InkingControl'; import { KeyphraseQueryView } from '../KeyphraseQueryView'; import { DocumentContentsView } from "./DocumentContentsView"; import "./DocumentView.scss"; +import { LinkAnchorBox } from './LinkAnchorBox'; import { RadialMenu } from './RadialMenu'; import React = require("react"); @@ -58,7 +58,8 @@ export interface DocumentViewProps { NativeHeight: () => number; Document: Doc; DataDoc?: Doc; - LayoutDoc?: () => Opt; + LayoutTemplateString?: string; + LayoutTemplate?: () => Opt; LibraryPath: Doc[]; fitToBox?: boolean; contextMenuItems?: () => { script: ScriptField, label: string }[]; @@ -454,8 +455,8 @@ export class DocumentView extends DocComponent(Docu const dY = -1 * Math.sign(dH); if (dX !== 0 || dY !== 0 || dW !== 0 || dH !== 0) { - const doc = PositionDocument(this.props.Document); - const layoutDoc = PositionDocument(Doc.Layout(this.props.Document)); + const doc = Document(this.props.Document); + const layoutDoc = Document(Doc.Layout(this.props.Document)); let nwidth = layoutDoc._nativeWidth || 0; let nheight = layoutDoc._nativeHeight || 0; const width = (layoutDoc._width || 0); @@ -984,13 +985,15 @@ export class DocumentView extends DocComponent(Docu @computed get contents() { TraceMobx(); return (<> - (Docu ); } - linkEndpoint = (linkDoc: Doc) => Doc.LinkEndpoint(linkDoc, this.props.Document); // used to decide whether a link anchor view should be created or not. // if it's a tempoarl link (currently just for Audio), then the audioBox will display the anchor and we don't want to display it here. @@ -1049,12 +1051,12 @@ export class DocumentView extends DocComponent(Docu ContainingCollectionDoc={this.props.Document} // bcz: hack this.props.Document is not a collection Need a better prop for passing the containing document to the LinkAnchorBox PanelWidth={this.anchorPanelWidth} PanelHeight={this.anchorPanelHeight} - layoutKey={this.linkEndpoint(d)} ContentScaling={returnOne} backgroundColor={returnTransparent} removeDocument={this.hideLinkAnchor} pointerEvents={false} - LayoutDoc={undefined} + LayoutTemplate={undefined} + LayoutTemplateString={LinkAnchorBox.LayoutString(`anchor${Doc.LinkEndpoint(d, this.props.Document)}`)} />); } @computed get innards() { @@ -1073,8 +1075,7 @@ export class DocumentView extends DocComponent(Docu
`} ContentScaling={this.childScaling} ChromeHeight={this.chromeHeight} isSelected={this.isSelected} diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 1efee4f5a..40d55ce38 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -50,13 +50,12 @@ export interface FieldViewProps { setVideoBox?: (player: VideoBox) => void; ContentScaling: () => number; ChromeHeight?: () => number; - childLayoutTemplate?: () => Opt; + RenderData?: () => Doc; // properties intended to be used from within layout strings (otherwise use the function equivalents that work more efficiently with React) height?: number; width?: number; background?: string; color?: string; - RenderData?: () => Doc; } @observer diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx index 2970674a2..d43936949 100644 --- a/src/client/views/nodes/KeyValueBox.tsx +++ b/src/client/views/nodes/KeyValueBox.tsx @@ -36,7 +36,7 @@ export class KeyValueBox extends React.Component { @observable private _keyInput: string = ""; @observable private _valueInput: string = ""; @computed get splitPercentage() { return NumCast(this.props.Document.schemaSplitPercentage, 50); } - get fieldDocToLayout() { return this.props.fieldKey ? Cast(this.props.Document[this.props.fieldKey], Doc, null) : this.props.Document; } + get fieldDocToLayout() { return this.props.Document; } @action onEnterKey = (e: React.KeyboardEvent): void => { diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx index 6c50abf21..bc36e056e 100644 --- a/src/client/views/nodes/LinkAnchorBox.tsx +++ b/src/client/views/nodes/LinkAnchorBox.tsx @@ -17,7 +17,6 @@ import { LinkEditor } from "../linking/LinkEditor"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { SelectionManager } from "../../util/SelectionManager"; import { TraceMobx } from "../../../new_fields/util"; -import { DocumentView } from "./DocumentView"; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx index 125690dc7..a0ecc9ff5 100644 --- a/src/client/views/nodes/ScreenshotBox.tsx +++ b/src/client/views/nodes/ScreenshotBox.tsx @@ -5,7 +5,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed, IReactionDisposer, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; import * as rp from 'request-promise'; -import { documentSchema, positionSchema } from "../../../new_fields/documentSchemas"; +import { documentSchema } from "../../../new_fields/documentSchemas"; import { makeInterface } from "../../../new_fields/Schema"; import { Cast, NumCast } from "../../../new_fields/Types"; import { VideoField } from "../../../new_fields/URLField"; @@ -20,8 +20,8 @@ import { FieldView, FieldViewProps } from './FieldView'; import "./ScreenshotBox.scss"; const path = require('path'); -type ScreenshotDocument = makeInterface<[typeof documentSchema, typeof positionSchema]>; -const ScreenshotDocument = makeInterface(documentSchema, positionSchema); +type ScreenshotDocument = makeInterface<[typeof documentSchema]>; +const ScreenshotDocument = makeInterface(documentSchema); library.add(faVideo); diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 613929bca..266b7f43f 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -21,14 +21,14 @@ import { DocumentDecorations } from "../DocumentDecorations"; import { InkingControl } from "../InkingControl"; import { FieldView, FieldViewProps } from './FieldView'; import "./VideoBox.scss"; -import { documentSchema, positionSchema } from "../../../new_fields/documentSchemas"; +import { documentSchema } from "../../../new_fields/documentSchemas"; const path = require('path'); export const timeSchema = createSchema({ currentTimecode: "number", // the current time of a video or other linear, time-based document. Note, should really get set on an extension field, but that's more complicated when it needs to be set since the extension doc needs to be found first }); -type VideoDocument = makeInterface<[typeof documentSchema, typeof positionSchema, typeof timeSchema]>; -const VideoDocument = makeInterface(documentSchema, positionSchema, timeSchema); +type VideoDocument = makeInterface<[typeof documentSchema, typeof timeSchema]>; +const VideoDocument = makeInterface(documentSchema, timeSchema); library.add(faVideo); diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 71325d94f..9256f82c2 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -772,7 +772,7 @@ export namespace Doc { export function LinkOtherAnchor(linkDoc: Doc, anchorDoc: Doc) { return Doc.AreProtosEqual(anchorDoc, Cast(linkDoc.anchor1, Doc) as Doc) ? Cast(linkDoc.anchor2, Doc) as Doc : Cast(linkDoc.anchor1, Doc) as Doc; } - export function LinkEndpoint(linkDoc: Doc, anchorDoc: Doc) { return Doc.AreProtosEqual(anchorDoc, Cast(linkDoc.anchor1, Doc) as Doc) ? "layout_key1" : "layout_key2"; } + export function LinkEndpoint(linkDoc: Doc, anchorDoc: Doc) { return Doc.AreProtosEqual(anchorDoc, Cast(linkDoc.anchor1, Doc) as Doc) ? "1" : "2"; } export function linkFollowUnhighlight() { Doc.UnhighlightAll(); diff --git a/src/new_fields/documentSchemas.ts b/src/new_fields/documentSchemas.ts index fd9a304f9..e71fc27f3 100644 --- a/src/new_fields/documentSchemas.ts +++ b/src/new_fields/documentSchemas.ts @@ -4,13 +4,25 @@ import { Doc } from "./Doc"; import { DateField } from "./DateField"; export const documentSchema = createSchema({ + // content properties type: "string", // enumerated type of document -- should be template-specific (ie, start with an '_') - layout: "string", // this is the native layout string for the document. templates can be added using other fields and setting layoutKey below - layoutKey: "string", // holds the field key for the field that actually holds the current lyoat title: "string", // document title (can be on either data document or layout) - dropAction: "string", // override specifying what should happen when this document is dropped (can be "alias", "copy", "move") - targetDropAction: "string", // allows the target of a drop event to specify the dropAction ("alias", "copy", "move") - childDropAction: "string", // specify the override for what should happen when the child of a collection is dragged from it and dropped (can be "alias" or "copy") + isTemplateForField: "string",// if specified, it indicates the document is a template that renders the specified field + creationDate: DateField, // when the document was created + links: listSpec(Doc), // computed (readonly) list of links associated with this document + + // "Location" properties in a very general sense + currentTimecode: "number", // current play back time of a temporal document (video / audio) + displayTimecode: "number", // the time that a document should be displayed (e.g., time an annotation should be displayed on a video) + inOverlay: "boolean", // whether the document is rendered in an OverlayView which handles selection/dragging differently + x: "number", // x coordinate when in a freeform view + y: "number", // y coordinate when in a freeform view + z: "number", // z "coordinate" - non-zero specifies the overlay layer of a freeformview + zIndex: "number", // zIndex of a document in a freeform view + scrollY: "number", // "command" to scroll a document to a position on load (the value will be reset to 0 after that ) + scrollTop: "number", // scroll position of a scrollable document (pdf, text, web) + + // appearance properties on the layout _autoHeight: "boolean", // whether the height of the document should be computed automatically based on its contents _nativeWidth: "number", // native width of document which determines how much document contents are scaled when the document's width is set _nativeHeight: "number", // " @@ -27,59 +39,57 @@ export const documentSchema = createSchema({ _showAudio: "boolean", // whether to show the audio record icon on documents _freeformLayoutEngine: "string",// the string ID for the layout engine to use to layout freeform view documents _LODdisable: "boolean", // whether to disbale LOD switching for CollectionFreeFormViews - _pivotField: "string", // specifies which field should be used as the timeline/pivot axis + _pivotField: "string", // specifies which field key should be used as the timeline/pivot axis _replacedChrome: "string", // what the default chrome is replaced with. Currently only supports the value of 'replaced' for PresBox's. _chromeStatus: "string", // determines the state of the collection chrome. values allowed are 'replaced', 'enabled', 'disabled', 'collapsed' - _freezeChildDimensions: "boolean", // freezes child document dimensions (e.g., used by time/pivot view to make sure all children will be scaled to fit their display rectangle) _fontSize: "number", _fontFamily: "string", - isInPlaceContainer: "boolean",// whether the marked object will display addDocTab() calls that target "inPlace" destinations - color: "string", // foreground color of document + + // appearance properties on the data document backgroundColor: "string", // background color of document + borderRounding: "string", // border radius rounding of document + boxShadow: "string", // the amount of shadow around the perimeter of a document + color: "string", // foreground color of document + fitToBox: "boolean", // whether freeform view contents should be zoomed/panned to fill the area of the document view + fontSize: "string", + layout: "string", // this is the native layout string for the document. templates can be added using other fields and setting layoutKey below + layoutKey: "string", // holds the field key for the field that actually holds the current lyoat + letterSpacing: "string", opacity: "number", // opacity of document - creationDate: DateField, // when the document was created - links: listSpec(Doc), // computed (readonly) list of links associated with this document + strokeWidth: "number", + textTransform: "string", + treeViewOpen: "boolean", // flag denoting whether the documents sub-tree (contents) is visible or hidden + treeViewExpandedView: "string", // name of field whose contents are being displayed as the document's subtree + treeViewPreventOpen: "boolean", // ignores the treeViewOpen flag (for allowing a view to not be slaved to other views of the document) + + // interaction and linking properties + ignoreClick: "boolean", // whether documents ignores input clicks (but does not ignore manipulation and other events) onClick: ScriptField, // script to run when document is clicked (can be overriden by an onClick prop) onPointerDown: ScriptField, // script to run when document is clicked (can be overriden by an onClick prop) onPointerUp: ScriptField, // script to run when document is clicked (can be overriden by an onClick prop) onDragStart: ScriptField, // script to run when document is dragged (without being selected). the script should return the Doc to be dropped. - dragFactory: Doc, // the document that serves as the "template" for the onDragStart script. ie, to drag out copies of the dragFactory document. - removeDropProperties: listSpec("string"), // properties that should be removed from the alias/copy/etc of this document when it is dropped - isTemplateForField: "string",// when specifies a field key, then the containing document is a template that renders the specified field - isBackground: "boolean", // whether document is a background element and ignores input events (can only select with marquee) - treeViewOpen: "boolean", // flag denoting whether the documents sub-tree (contents) is visible or hidden - treeViewExpandedView: "string", // name of field whose contents are being displayed as the document's subtree - treeViewPreventOpen: "boolean", // ignores the treeViewOpen flag (for allowing a view to not be slaved to other views of the document) - currentTimecode: "number", // current play back time of a temporal document (video / audio) followLinkLocation: "string",// flag for where to place content when following a click interaction (e.g., onRight, inPlace, inTab, ) + isInPlaceContainer: "boolean",// whether the marked object will display addDocTab() calls that target "inPlace" destinations + isLinkButton: "boolean", // whether document functions as a link follow button to follow the first link on the document when clicked + isBackground: "boolean", // whether document is a background element and ignores input events (can only select with marquee) lockedPosition: "boolean", // whether the document can be moved (dragged) lockedTransform: "boolean", // whether the document can be panned/zoomed - inOverlay: "boolean", // whether the document is rendered in an OverlayView which handles selection/dragging differently - borderRounding: "string", // border radius rounding of document - heading: "number", // the logical layout 'heading' of this document (used by rule provider to stylize h1 header elements, from h2, etc) - isLinkButton: "boolean", // whether document functions as a link follow button to follow the first link on the document when clicked - ignoreClick: "boolean", // whether documents ignores input clicks (but does not ignore manipulation and other events) - scrollToLinkID: "string", // id of link being traversed. allows this doc to scroll/highlight/etc its link anchor. scrollToLinkID should be set to undefined by this doc after it sets up its scroll,etc. - scrollY: "number", // "command" to scroll a document to a position on load (the value will be reset to 0 after that ) - scrollTop: "number", // scroll position of a scrollable document (pdf, text, web) - strokeWidth: "number", - fontSize: "string", - fitToBox: "boolean", // whether freeform view contents should be zoomed/panned to fill the area of the document view - letterSpacing: "string", - textTransform: "string", - childTemplateName: "string" // the name of a template to use to override the layoutKey when rendering a document in DocHolderBox -}); -export const positionSchema = createSchema({ - zIndex: "number", - x: "number", - y: "number", - z: "number", + // drag drop properties + dragFactory: Doc, // the document that serves as the "template" for the onDragStart script. ie, to drag out copies of the dragFactory document. + dropAction: "string", // override specifying what should happen when this document is dropped (can be "alias", "copy", "move") + targetDropAction: "string", // allows the target of a drop event to specify the dropAction ("alias", "copy", "move") + childDropAction: "string", // specify the override for what should happen when the child of a collection is dragged from it and dropped (can be "alias" or "copy") + removeDropProperties: listSpec("string"), // properties that should be removed from the alias/copy/etc of this document when it is dropped }); + export const collectionSchema = createSchema({ - childLayoutTemplate: Doc, // layout template for children of a collecion - childDetailView: Doc, // layout template to apply to a child when its clicked on in a collection and opened (requires onChildClick or other script to use this field) + childLayoutTemplateName: "string", // the name of a template to use to override the layoutKey when rendering a document -- ONLY used in DocHolderBox + childLayoutTemplate: Doc, // layout template to use to render children of a collecion + childLayoutString: "string", //layout string to use to render children of a collection + childClickedOpenTemplateView: Doc, // layout template to apply to a child when its clicked on in a collection and opened (requires onChildClick or other script to read this value and apply template) + dontRegisterChildViews: "boolean", // whether views made of this document are registered so that they can be found when drawing links scrollToLinkID: "string", // id of link being traversed. allows this doc to scroll/highlight/etc its link anchor. scrollToLinkID should be set to undefined by this doc after it sets up its scroll,etc. onChildClick: ScriptField, // script to run for each child when its clicked onChildDoubleClick: ScriptField, // script to run for each child when its clicked onCheckedClick: ScriptField, // script to run when a checkbox is clicked next to a child in a tree view @@ -87,6 +97,3 @@ export const collectionSchema = createSchema({ export type Document = makeInterface<[typeof documentSchema]>; export const Document = makeInterface(documentSchema); - -export type PositionDocument = makeInterface<[typeof documentSchema, typeof positionSchema]>; -export const PositionDocument = makeInterface(documentSchema, positionSchema); diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 2ae42bf52..b9de93559 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -485,7 +485,7 @@ export class CurrentUserUtils { _width: 50, _height: 25, title: "Library", _fontSize: 10, letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)", sourcePanel: new PrefetchProxy(Docs.Create.TreeDocument([workspaces, documents, recentlyClosed, doc], { - title: "Library", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "move", lockedPosition: true, boxShadow: "0 0", dontRegisterChildren: true + title: "Library", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "move", lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true })) as any as Doc, targetContainer: new PrefetchProxy(sidebarContainer) as any as Doc, onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel;") -- cgit v1.2.3-70-g09d2 From 952bc0d744833ab79f69f2f13abde1e4cee68408 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 2 May 2020 00:21:25 -0400 Subject: prefetch buxton double click view --- src/client/views/collections/CollectionTreeView.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index dc9348664..835dfc637 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -31,6 +31,7 @@ import { CollectionSubView } from "./CollectionSubView"; import "./CollectionTreeView.scss"; import { CollectionViewType } from './CollectionView'; import React = require("react"); +import { PrefetchProxy } from '../../../new_fields/Proxy'; export interface TreeViewProps { @@ -745,7 +746,7 @@ export class CollectionTreeView extends CollectionSubView Date: Sat, 2 May 2020 14:31:16 -0400 Subject: turn off targetDropAction when dropping in same colleciton. cleaned up PresBox stuff to use single template to render all contents (which are otherwise unmodified). --- src/client/util/DragManager.ts | 4 +- .../views/collections/CollectionCarouselView.tsx | 2 +- .../views/collections/CollectionStackingView.tsx | 1 - src/client/views/collections/CollectionSubView.tsx | 11 +++- src/client/views/collections/CollectionView.tsx | 4 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 1 - src/client/views/nodes/DocumentView.tsx | 2 - src/client/views/nodes/FieldView.tsx | 3 +- src/client/views/nodes/PresBox.tsx | 72 ++++++++++++---------- .../views/nodes/formattedText/FormattedTextBox.tsx | 6 +- .../views/presentationview/PresElementBox.tsx | 16 ++--- src/new_fields/documentSchemas.ts | 2 +- .../authentication/models/current_user_utils.ts | 7 +-- 13 files changed, 71 insertions(+), 60 deletions(-) (limited to 'src') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index c06ad3d60..041f2fc2c 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -185,7 +185,8 @@ export namespace DragManager { export function MakeDropTarget( element: HTMLElement, dropFunc: (e: Event, de: DropEvent) => void, - doc?: Doc + doc?: Doc, + preDropFunc?: (e: Event, de: DropEvent) => void, ): DragDropDisposer { if ("canDrop" in element.dataset) { throw new Error( @@ -199,6 +200,7 @@ export namespace DragManager { if (de.complete.docDragData && doc?.targetDropAction) { de.complete.docDragData.dropAction = StrCast(doc.targetDropAction) as dropActionType; } + preDropFunc?.(e, de); }; element.addEventListener("dashOnDrop", handler); doc && element.addEventListener("dashPreDrop", preDropHandler); diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx index 769b323ae..a04136e51 100644 --- a/src/client/views/collections/CollectionCarouselView.tsx +++ b/src/client/views/collections/CollectionCarouselView.tsx @@ -69,7 +69,7 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument) + Document={this.childLayoutPairs[index].layout} DataDoc={undefined} fieldKey={"caption"} />
; } diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index eb70cec9d..1fd5c3f44 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -178,7 +178,6 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument) LibraryPath={this.props.LibraryPath} FreezeDimensions={this.props.freezeChildDimensions} renderDepth={this.props.renderDepth + 1} - RenderData={this.props.RenderData} PanelWidth={width} PanelHeight={height} NativeHeight={returnZero} diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index aaea13ded..af642bc52 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -67,7 +67,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: this.multiTouchDisposer?.(); if (ele) { this._mainCont = ele; - this.dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc); + this.dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc, this.onInternalPreDrop.bind(this)); this.gestureDisposer = GestureUtils.MakeGestureTarget(ele, this.onGesture.bind(this)); this.multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(ele, this.onTouchStart.bind(this)); } @@ -195,6 +195,15 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: protected onGesture(e: Event, ge: GestureUtils.GestureEvent) { } + protected onInternalPreDrop(e: Event, de: DragManager.DropEvent) { + if (de.complete.docDragData) { + if (de.complete.docDragData.draggedDocuments.some(d => this.childDocs.includes(d))) { + de.complete.docDragData.dropAction = "move"; + } + e.stopPropagation(); + } + } + @undoBatch @action protected onInternalDrop(e: Event, de: DragManager.DropEvent): boolean { diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index d2afb4855..cb7d86e00 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -74,6 +74,7 @@ export enum CollectionViewType { export interface CollectionViewCustomProps { filterAddDocument: (doc: Doc) => boolean; // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example) childLayoutTemplate?: () => Opt; // specify a layout Doc template to use for children of the collection + childLayoutString?: string; // specify a layout string to use for children of the collection } export interface CollectionRenderProps { @@ -478,6 +479,7 @@ export class CollectionView extends Touchable; } childLayoutTemplate = () => this.props.childLayoutTemplate?.() || Cast(this.props.Document.childLayoutTemplate, Doc, null); + childLayoutString = this.props.childLayoutString || StrCast(this.props.Document.childLayoutString); render() { TraceMobx(); @@ -489,7 +491,7 @@ export class CollectionView extends Touchable void; renderDepth: number; ContentScaling: () => number; - RenderData?: () => Doc; PanelWidth: () => number; PanelHeight: () => number; pointerEvents?: boolean; @@ -996,7 +995,6 @@ export class DocumentView extends DocComponent(Docu LayoutTemplate={this.props.LayoutTemplate} makeLink={this.makeLink} rootSelected={this.rootSelected} - RenderData={this.props.RenderData} dontRegisterView={this.props.dontRegisterView} fitToBox={this.props.fitToBox} LibraryPath={this.props.LibraryPath} diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 40d55ce38..016d2a1ae 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -50,12 +50,13 @@ export interface FieldViewProps { setVideoBox?: (player: VideoBox) => void; ContentScaling: () => number; ChromeHeight?: () => number; - RenderData?: () => Doc; // properties intended to be used from within layout strings (otherwise use the function equivalents that work more efficiently with React) height?: number; width?: number; background?: string; color?: string; + xMargin?: number; + yMargin?: number; } @observer diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index 6e3420f22..53b6aa408 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -17,6 +17,8 @@ import "./PresBox.scss"; import { ViewBoxBaseComponent } from "../DocComponent"; import { makeInterface } from "../../../new_fields/Schema"; import { List } from "../../../new_fields/List"; +import { Docs } from "../../documents/Documents"; +import { PrefetchProxy } from "../../../new_fields/Proxy"; type PresBoxSchema = makeInterface<[typeof documentSchema]>; const PresBoxDocument = makeInterface(documentSchema); @@ -24,14 +26,32 @@ const PresBoxDocument = makeInterface(documentSchema); @observer export class PresBox extends ViewBoxBaseComponent(PresBoxDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PresBox, fieldKey); } + _docsDisposer: IReactionDisposer | undefined; + _viewDisposer: IReactionDisposer | undefined; @observable _isChildActive = false; @computed get childDocs() { return DocListCast(this.dataDoc[this.fieldKey]); } - @computed get currentIndex() { return NumCast(this.rootDoc._itemIndex); } + @computed get currentIndex() { return NumCast(this.presElement?.currentIndex); } + @computed get presElement() { return Cast(this.rootDoc.presElement, Doc, null); } + constructor(props: any) { + super(props); + if (!this.presElement) { + this.rootDoc.presElement = new PrefetchProxy(Docs.Create.PresElementBoxDocument({ + title: "pres element template", backgroundColor: "transparent", _xMargin: 5, _height: 46, isTemplateDoc: true, isTemplateForField: "data" + })); + } + } + + componentWillUnmount() { + this._docsDisposer?.(); + this._viewDisposer?.(); + } componentDidMount() { this.rootDoc.presBox = this.rootDoc; this.rootDoc._forceRenderEngine = "timeline"; this.rootDoc._replacedChrome = "replaced"; + this._docsDisposer = reaction(() => this.childDocs, docs => this.presElement.presOrderedDocs = new List(docs), { fireImmediately: true }); + this._viewDisposer = reaction(() => this.rootDoc._viewType, viewType => this.presElement.presCollapsedHeight = viewType === CollectionViewType.Tree ? 50 : 46, { fireImmediately: true }); } updateCurrentPresentation = () => Doc.UserDoc().activePresentation = this.rootDoc; @@ -166,17 +186,16 @@ export class PresBox extends ViewBoxBaseComponent } } - //The function that is called when a document is clicked or reached through next or back. //it'll also execute the necessary actions if presentation is playing. public gotoDocument = (index: number, fromDoc: number) => { this.updateCurrentPresentation(); Doc.UnBrushAllDocs(); if (index >= 0 && index < this.childDocs.length) { - this.rootDoc._itemIndex = index; + this.presElement.currentIndex = index; - if (!this.layoutDoc.presStatus) { - this.layoutDoc.presStatus = true; + if (!this.presElement.presStatus) { + this.presElement.presStatus = true; this.startPresentation(index); } @@ -189,10 +208,10 @@ export class PresBox extends ViewBoxBaseComponent //The function that starts or resets presentaton functionally, depending on status flag. startOrResetPres = () => { this.updateCurrentPresentation(); - if (this.layoutDoc.presStatus) { + if (this.presElement.presStatus) { this.resetPresentation(); } else { - this.layoutDoc.presStatus = true; + this.presElement.presStatus = true; this.startPresentation(0); this.gotoDocument(0, this.currentIndex); } @@ -204,7 +223,7 @@ export class PresBox extends ViewBoxBaseComponent this.updateCurrentPresentation(); this.childDocs.forEach(doc => (doc.presentationTargetDoc as Doc).opacity = 1); this.rootDoc._itemIndex = 0; - this.layoutDoc.presStatus = false; + this.presElement.presStatus = false; } //The function that starts the presentation, also checking if actions should be applied @@ -241,43 +260,31 @@ export class PresBox extends ViewBoxBaseComponent } }); - initializeViewAliases = (docList: Doc[], viewtype: CollectionViewType) => { - const hgt = (viewtype === CollectionViewType.Tree) ? 50 : 46; - this.rootDoc.presCollapsedHeight = hgt; - } + @undoBatch + viewChanged = action((e: React.ChangeEvent) => { + //@ts-ignore + const viewType = e.target.selectedOptions[0].value as CollectionViewType; + viewType === CollectionViewType.Stacking && (this.rootDoc._pivotField = undefined); // pivot field may be set by the user in timeline view (or some other way) -- need to reset it here + this.updateMinimize(e, this.rootDoc._viewType = viewType); + }); + whenActiveChanged = action((isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive)); addDocumentFilter = (doc: Doc) => { - doc.presentationTargetDoc = doc.aliasOf; + doc.aliasOf instanceof Doc && (doc.presentationTargetDoc = doc.aliasOf); + !this.childDocs.includes(doc) && (doc.presZoomButton = true); return true; } - + childLayoutTemplate = () => this.rootDoc._viewType !== CollectionViewType.Stacking ? undefined : this.presElement; removeDocument = (doc: Doc) => Doc.RemoveDocFromList(this.dataDoc, this.fieldKey, doc); - selectElement = (doc: Doc) => this.gotoDocument(this.childDocs.indexOf(doc), NumCast(this.rootDoc._itemIndex)); - getTransform = () => this.props.ScreenToLocalTransform().translate(-5, -65);// listBox padding-left and pres-box-cont minHeight - panelHeight = () => this.props.PanelHeight() - 20; - active = (outsideReaction?: boolean) => ((InkingControl.Instance.selectedTool === InkTool.None && !this.layoutDoc.isBackground) && (this.layoutDoc.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false) - whenActiveChanged = action((isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive)); - - @undoBatch - viewChanged = action((e: React.ChangeEvent) => { - //@ts-ignore - const viewType = e.target.selectedOptions[0].value as CollectionViewType; - viewType === CollectionViewType.Stacking && (this.rootDoc._pivotField = undefined); // pivot field may be set by the user in timeline view (or some other way) -- need to reset it here - this.updateMinimize(e, this.rootDoc._viewType = viewType); - }); - - returnSelf = () => this.rootDoc; - childLayoutTemplate = () => this.rootDoc._viewType === CollectionViewType.Stacking ? Cast(Doc.UserDoc()["template-presentation"], Doc, null) : undefined; render() { this.rootDoc.presOrderedDocs = new List(this.childDocs.map((child, i) => child)); const mode = StrCast(this.rootDoc._viewType) as CollectionViewType; - this.initializeViewAliases(this.childDocs, mode); return
this.authenticationCode = e.currentTarget.value)} placeholder={prompt} /> : (null)} - {this.avatar ? : (null)} - {this.username ? Welcome to Dash, {this.username} - : (null)} + {this.credentials ? + <> + + Welcome to Dash, {this.credentials.userInfo.name} + +
{ + await Networking.FetchFromServer("/revokeGoogleAccessToken"); + this.resetState(0, 0); + }} + >Disconnect Account
+ : (null)}
); } @@ -125,4 +162,6 @@ export default class GoogleAuthenticationManager extends React.Component<{}> { ); } -} \ No newline at end of file +} + +Scripting.addGlobal("GoogleAuthenticationManager", GoogleAuthenticationManager); \ No newline at end of file diff --git a/src/client/apis/google_docs/GoogleApiClientUtils.ts b/src/client/apis/google_docs/GoogleApiClientUtils.ts index fa67ddbef..2f3cac8d3 100644 --- a/src/client/apis/google_docs/GoogleApiClientUtils.ts +++ b/src/client/apis/google_docs/GoogleApiClientUtils.ts @@ -95,7 +95,7 @@ export namespace GoogleApiClientUtils { export type ExtractResult = { text: string, paragraphs: DeconstructedParagraph[] }; export const extractText = (document: docs_v1.Schema$Document, removeNewlines = false): ExtractResult => { const paragraphs = extractParagraphs(document); - let text = paragraphs.map(paragraph => paragraph.contents.filter(content => !("inlineObjectId" in content)).map(run => run as docs_v1.Schema$TextRun).join("")).join(""); + let text = paragraphs.map(paragraph => paragraph.contents.filter(content => !("inlineObjectId" in content)).map(run => (run as docs_v1.Schema$TextRun).content).join("")).join(""); text = text.substring(0, text.length - 1); removeNewlines && text.replace(/\n/g, ""); return { text, paragraphs }; diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index 185222541..6cca4d69f 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -12,6 +12,7 @@ import { ScriptField } from "../../new_fields/ScriptField"; import { InkingControl } from "./InkingControl"; import { InkTool } from "../../new_fields/InkField"; import { DocumentView } from "./nodes/DocumentView"; +import GoogleAuthenticationManager from "../apis/GoogleAuthenticationManager"; const modifiers = ["control", "meta", "shift", "alt"]; type KeyHandler = (keycode: string, e: KeyboardEvent) => KeyControlInfo | Promise; @@ -79,6 +80,7 @@ export default class KeyManager { SelectionManager.DeselectAll(); DictationManager.Controls.stop(); // RecommendationsBox.Instance.closeMenu(); + GoogleAuthenticationManager.Instance.cancel(); SharingManager.Instance.close(); break; case "delete": diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index d60a9d64a..1a285d4ec 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -1,5 +1,5 @@ import { library } from '@fortawesome/fontawesome-svg-core'; -import { faTerminal, faToggleOn, faFile as fileSolid, faLocationArrow, faSearch, faFileDownload, faStop, faCalculator, faWindowMaximize, faAddressCard, faQuestionCircle, faArrowLeft, faArrowRight, faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt, faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter, faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote, faThumbtack, faTree, faTv, faUndoAlt, faVideo } from '@fortawesome/free-solid-svg-icons'; +import { faTerminal, faToggleOn, faFile as fileSolid, faExternalLinkAlt, faLocationArrow, faSearch, faFileDownload, faStop, faCalculator, faWindowMaximize, faAddressCard, faQuestionCircle, faArrowLeft, faArrowRight, faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt, faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter, faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote, faThumbtack, faTree, faTv, faUndoAlt, faVideo } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, configure, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; @@ -163,6 +163,7 @@ export class MainView extends React.Component { library.add(faPhone); library.add(faClipboard); library.add(faStamp); + library.add(faExternalLinkAlt); this.initEventListeners(); this.initAuthenticationRouters(); } @@ -583,7 +584,7 @@ export class MainView extends React.Component { {SnappingManager.horizSnapLines().map(l => )} {SnappingManager.vertSnapLines().map(l => )} -
+
; } render() { diff --git a/src/client/views/MainViewModal.tsx b/src/client/views/MainViewModal.tsx index 9198fe3e3..a7bd5882d 100644 --- a/src/client/views/MainViewModal.tsx +++ b/src/client/views/MainViewModal.tsx @@ -4,7 +4,7 @@ import "./MainViewModal.scss"; export interface MainViewOverlayProps { isDisplayed: boolean; interactive: boolean; - contents: string | JSX.Element; + contents: string | JSX.Element | null; dialogueBoxStyle?: React.CSSProperties; overlayStyle?: React.CSSProperties; dialogueBoxDisplayedOpacity?: number; diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx index 20aa14f84..afb6bfb7d 100644 --- a/src/client/views/OverlayView.tsx +++ b/src/client/views/OverlayView.tsx @@ -1,7 +1,7 @@ import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; import * as React from "react"; -import { Doc, DocListCast } from "../../new_fields/Doc"; +import { Doc, DocListCast, Opt } from "../../new_fields/Doc"; import { Id } from "../../new_fields/FieldSymbols"; import { NumCast } from "../../new_fields/Types"; import { emptyFunction, emptyPath, returnEmptyString, returnFalse, returnOne, returnTrue, returnZero, Utils } from "../../Utils"; @@ -214,4 +214,6 @@ export class OverlayView extends React.Component { } } // bcz: ugh ... want to be able to pass ScriptingRepl as tag argument, but that doesn't seem to work.. runtime error -Scripting.addGlobal(function addOverlayWindow(Tag: string, options: OverlayElementOptions) { const x = ; OverlayView.Instance.addWindow(x, options); }); \ No newline at end of file +Scripting.addGlobal(function addOverlayWindow(type: string, options: OverlayElementOptions) { + OverlayView.Instance.addWindow(, options); +}); \ No newline at end of file diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 658a55f51..180cb043b 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -59,6 +59,7 @@ import "./FormattedTextBox.scss"; import { FormattedTextBoxComment, formattedTextBoxCommentPlugin } from './FormattedTextBoxComment'; import React = require("react"); import { ScriptField } from '../../../../new_fields/ScriptField'; +import GoogleAuthenticationManager from '../../../apis/GoogleAuthenticationManager'; library.add(faEdit); library.add(faSmile, faTextHeight, faUpload); @@ -784,7 +785,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp let pullSuccess = false; if (exportState !== undefined) { pullSuccess = true; - dataDoc.data = new RichTextField(JSON.stringify(exportState.state.toJSON())); + dataDoc[this.props.fieldKey] = new RichTextField(JSON.stringify(exportState.state.toJSON())); setTimeout(() => { if (this._editorView) { const state = this._editorView.state; @@ -802,13 +803,15 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } checkState = (exportState: Opt, dataDoc: Doc) => { - if (exportState && this._editorView) { - const equalContent = isEqual(this._editorView.state.doc, exportState.state.doc); - const equalTitles = dataDoc.title === exportState.title; - const unchanged = equalContent && equalTitles; - dataDoc.unchanged = unchanged; - DocumentButtonBar.Instance.setPullState(unchanged); - } + GoogleAuthenticationManager.Instance.fetchOrGenerateAccessToken().then(() => { + if (exportState && this._editorView) { + const equalContent = isEqual(this._editorView.state.doc, exportState.state.doc); + const equalTitles = dataDoc.title === exportState.title; + const unchanged = equalContent && equalTitles; + dataDoc.unchanged = unchanged; + DocumentButtonBar.Instance.setPullState(unchanged); + } + }); } clipboardTextSerializer = (slice: Slice): string => { diff --git a/src/scraping/buxton/scraper.py b/src/scraping/buxton/scraper.py index 1441a8621..ed122e544 100644 --- a/src/scraping/buxton/scraper.py +++ b/src/scraping/buxton/scraper.py @@ -16,7 +16,7 @@ filesPath = "../../server/public/files" image_dist = filesPath + "/images/buxton" db = MongoClient("localhost", 27017)["Dash"] -target_collection = db.newDocuments +target_collection = db.documents target_doc_title = "Collection 1" schema_guids = [] common_proto_id = "" diff --git a/src/server/ApiManagers/DeleteManager.ts b/src/server/ApiManagers/DeleteManager.ts index 9e70af2eb..bd80d6500 100644 --- a/src/server/ApiManagers/DeleteManager.ts +++ b/src/server/ApiManagers/DeleteManager.ts @@ -1,12 +1,12 @@ import ApiManager, { Registration } from "./ApiManager"; -import { Method, _permission_denied, PublicHandler } from "../RouteManager"; +import { Method, _permission_denied } from "../RouteManager"; import { WebSocket } from "../Websocket/Websocket"; import { Database } from "../database"; import rimraf = require("rimraf"); -import { pathToDirectory, Directory } from "./UploadManager"; import { filesDirectory } from ".."; import { DashUploadUtils } from "../DashUploadUtils"; import { mkdirSync } from "fs"; +import RouteSubscriber from "../RouteSubscriber"; export default class DeleteManager extends ApiManager { @@ -14,68 +14,39 @@ export default class DeleteManager extends ApiManager { register({ method: Method.GET, - subscription: "/delete", - secureHandler: async ({ res, isRelease }) => { + subscription: new RouteSubscriber("delete").add("target?"), + secureHandler: async ({ req, res, isRelease }) => { if (isRelease) { - return _permission_denied(res, deletionPermissionError); + return _permission_denied(res, "Cannot perform a delete operation outside of the development environment!"); } - await WebSocket.deleteFields(); - res.redirect("/home"); - } - }); - register({ - method: Method.GET, - subscription: "/deleteAll", - secureHandler: async ({ res, isRelease }) => { - if (isRelease) { - return _permission_denied(res, deletionPermissionError); + const { target } = req.params; + const { doDelete } = WebSocket; + + if (!target) { + await doDelete(); + } else { + let all = false; + switch (target) { + case "all": + all = true; + case "database": + await doDelete(false); + if (!all) break; + case "files": + rimraf.sync(filesDirectory); + mkdirSync(filesDirectory); + await DashUploadUtils.buildFileDirectories(); + break; + default: + await Database.Instance.dropSchema(target); + } } - await WebSocket.deleteAll(); - res.redirect("/home"); - } - }); - register({ - method: Method.GET, - subscription: "/deleteAssets", - secureHandler: async ({ res, isRelease }) => { - if (isRelease) { - return _permission_denied(res, deletionPermissionError); - } - rimraf.sync(filesDirectory); - mkdirSync(filesDirectory); - await DashUploadUtils.buildFileDirectories(); - res.redirect("/delete"); - } - }); - - register({ - method: Method.GET, - subscription: "/deleteWithAux", - secureHandler: async ({ res, isRelease }) => { - if (isRelease) { - return _permission_denied(res, deletionPermissionError); - } - await Database.Auxiliary.DeleteAll(); - res.redirect("/delete"); - } - }); - - register({ - method: Method.GET, - subscription: "/deleteWithGoogleCredentials", - secureHandler: async ({ res, isRelease }) => { - if (isRelease) { - return _permission_denied(res, deletionPermissionError); - } - await Database.Auxiliary.GoogleAuthenticationToken.DeleteAll(); - res.redirect("/delete"); + res.redirect("/home"); } }); } -} - -const deletionPermissionError = "Cannot perform a delete operation outside of the development environment!"; +} \ No newline at end of file diff --git a/src/server/ApiManagers/GeneralGoogleManager.ts b/src/server/ApiManagers/GeneralGoogleManager.ts index a5240edbc..17968cc7d 100644 --- a/src/server/ApiManagers/GeneralGoogleManager.ts +++ b/src/server/ApiManagers/GeneralGoogleManager.ts @@ -1,10 +1,8 @@ import ApiManager, { Registration } from "./ApiManager"; import { Method, _permission_denied } from "../RouteManager"; import { GoogleApiServerUtils } from "../apis/google/GoogleApiServerUtils"; -import { Database } from "../database"; import RouteSubscriber from "../RouteSubscriber"; - -const deletionPermissionError = "Cannot perform specialized delete outside of the development environment!"; +import { Database } from "../database"; const EndpointHandlerMap = new Map([ ["create", (api, params) => api.create(params)], @@ -20,11 +18,11 @@ export default class GeneralGoogleManager extends ApiManager { method: Method.GET, subscription: "/readGoogleAccessToken", secureHandler: async ({ user, res }) => { - const token = await GoogleApiServerUtils.retrieveAccessToken(user.id); - if (!token) { + const { credentials } = (await GoogleApiServerUtils.retrieveCredentials(user.id)); + if (!credentials?.access_token) { return res.send(GoogleApiServerUtils.generateAuthenticationUrl()); } - return res.send(token); + return res.send(credentials); } }); @@ -36,6 +34,15 @@ export default class GeneralGoogleManager extends ApiManager { } }); + register({ + method: Method.GET, + subscription: "/revokeGoogleAccessToken", + secureHandler: async ({ user, res }) => { + await Database.Auxiliary.GoogleAuthenticationToken.Revoke(user.id); + res.send(); + } + }); + register({ method: Method.POST, subscription: new RouteSubscriber("googleDocs").add("sector", "action"), diff --git a/src/server/ApiManagers/GooglePhotosManager.ts b/src/server/ApiManagers/GooglePhotosManager.ts index 88219423d..11841a603 100644 --- a/src/server/ApiManagers/GooglePhotosManager.ts +++ b/src/server/ApiManagers/GooglePhotosManager.ts @@ -56,7 +56,7 @@ export default class GooglePhotosManager extends ApiManager { const { media } = req.body; // first we need to ensure that we know the google account to which these photos will be uploaded - const token = await GoogleApiServerUtils.retrieveAccessToken(user.id); + const token = (await GoogleApiServerUtils.retrieveCredentials(user.id))?.credentials?.access_token; if (!token) { return _error(res, authenticationError); } diff --git a/src/server/ApiManagers/SessionManager.ts b/src/server/ApiManagers/SessionManager.ts index bcaa6598f..fa2f6002a 100644 --- a/src/server/ApiManagers/SessionManager.ts +++ b/src/server/ApiManagers/SessionManager.ts @@ -55,7 +55,7 @@ export default class SessionManager extends ApiManager { register({ method: Method.GET, - subscription: this.secureSubscriber("delete"), + subscription: this.secureSubscriber("deleteSession"), secureHandler: this.authorizedAction(async ({ res }) => { const { error } = await sessionAgent.serverWorker.emit("delete"); res.send(error ? error.message : "Your request was successful: the server successfully deleted the database. Return to /home."); diff --git a/src/server/ApiManagers/UploadManager.ts b/src/server/ApiManagers/UploadManager.ts index 98f029c7d..b185d3b55 100644 --- a/src/server/ApiManagers/UploadManager.ts +++ b/src/server/ApiManagers/UploadManager.ts @@ -171,7 +171,7 @@ export default class UploadManager extends ApiManager { await Promise.all(docs.map((doc: any) => new Promise(res => Database.Instance.replace(doc.id, doc, (err, r) => { err && console.log(err); res(); - }, true, "newDocuments")))); + }, true)))); } catch (e) { console.log(e); } unlink(path_2, () => { }); } diff --git a/src/server/ApiManagers/UserManager.ts b/src/server/ApiManagers/UserManager.ts index d9d346cc1..68b3107ae 100644 --- a/src/server/ApiManagers/UserManager.ts +++ b/src/server/ApiManagers/UserManager.ts @@ -89,8 +89,6 @@ export default class UserManager extends ApiManager { } }); - - register({ method: Method.GET, subscription: "/activity", diff --git a/src/server/DashSession/DashSessionAgent.ts b/src/server/DashSession/DashSessionAgent.ts index 5cbba13de..ef9b88541 100644 --- a/src/server/DashSession/DashSessionAgent.ts +++ b/src/server/DashSession/DashSessionAgent.ts @@ -37,7 +37,7 @@ export class DashSessionAgent extends AppliedSessionAgent { monitor.addReplCommand("debug", [/\S+\@\S+/], async ([to]) => this.dispatchZippedDebugBackup(to)); monitor.on("backup", this.backup); monitor.on("debug", async ({ to }) => this.dispatchZippedDebugBackup(to)); - monitor.on("delete", WebSocket.deleteFields); + monitor.on("delete", WebSocket.doDelete); monitor.coreHooks.onCrashDetected(this.dispatchCrashReport); return sessionKey; } diff --git a/src/server/GarbageCollector.ts b/src/server/GarbageCollector.ts index 5729c3ee5..24745cbb4 100644 --- a/src/server/GarbageCollector.ts +++ b/src/server/GarbageCollector.ts @@ -76,7 +76,7 @@ async function GarbageCollect(full: boolean = true) { if (!fetchIds.length) { continue; } - const docs = await new Promise<{ [key: string]: any }[]>(res => Database.Instance.getDocuments(fetchIds, res, "newDocuments")); + const docs = await new Promise<{ [key: string]: any }[]>(res => Database.Instance.getDocuments(fetchIds, res)); for (const doc of docs) { const id = doc.id; if (doc === undefined) { @@ -116,10 +116,10 @@ async function GarbageCollect(full: boolean = true) { const count = Math.min(toDelete.length, 5000); const toDeleteDocs = toDelete.slice(i, i + count); i += count; - const result = await Database.Instance.delete({ _id: { $in: toDeleteDocs } }, "newDocuments"); + const result = await Database.Instance.delete({ _id: { $in: toDeleteDocs } }); deleted += result.deletedCount || 0; } - // const result = await Database.Instance.delete({ _id: { $in: toDelete } }, "newDocuments"); + // const result = await Database.Instance.delete({ _id: { $in: toDelete } }); console.log(`${deleted} documents deleted`); await Search.deleteDocuments(toDelete); diff --git a/src/server/IDatabase.ts b/src/server/IDatabase.ts index 6a63df485..dd4968579 100644 --- a/src/server/IDatabase.ts +++ b/src/server/IDatabase.ts @@ -2,7 +2,6 @@ import * as mongodb from 'mongodb'; import { Transferable } from './Message'; export const DocumentsCollection = 'documents'; -export const NewDocumentsCollection = 'newDocuments'; export interface IDatabase { update(id: string, value: any, callback: (err: mongodb.MongoError, res: mongodb.UpdateWriteOpResult) => void, upsert?: boolean, collectionName?: string): Promise; updateMany(query: any, update: any, collectionName?: string): Promise; @@ -12,12 +11,13 @@ export interface IDatabase { delete(query: any, collectionName?: string): Promise; delete(id: string, collectionName?: string): Promise; - deleteAll(collectionName?: string, persist?: boolean): Promise; + dropSchema(...schemaNames: string[]): Promise; insert(value: any, collectionName?: string): Promise; getDocument(id: string, fn: (result?: Transferable) => void, collectionName?: string): void; getDocuments(ids: string[], fn: (result: Transferable[]) => void, collectionName?: string): void; + getCollectionNames(): Promise; visit(ids: string[], fn: (result: any) => string[] | Promise, collectionName?: string): Promise; query(query: { [key: string]: any }, projection?: { [key: string]: 0 | 1 }, collectionName?: string): Promise; diff --git a/src/server/MemoryDatabase.ts b/src/server/MemoryDatabase.ts index 543f96e7f..1f1d702d9 100644 --- a/src/server/MemoryDatabase.ts +++ b/src/server/MemoryDatabase.ts @@ -1,4 +1,4 @@ -import { IDatabase, DocumentsCollection, NewDocumentsCollection } from './IDatabase'; +import { IDatabase, DocumentsCollection } from './IDatabase'; import { Transferable } from './Message'; import * as mongodb from 'mongodb'; @@ -15,6 +15,10 @@ export class MemoryDatabase implements IDatabase { } } + public getCollectionNames() { + return Promise.resolve(Object.keys(this.db)); + } + public update(id: string, value: any, callback: (err: mongodb.MongoError, res: mongodb.UpdateWriteOpResult) => void, _upsert?: boolean, collectionName = DocumentsCollection): Promise { const collection = this.getCollection(collectionName); const set = "$set"; @@ -41,7 +45,7 @@ export class MemoryDatabase implements IDatabase { return Promise.resolve(undefined); } - public updateMany(query: any, update: any, collectionName = NewDocumentsCollection): Promise { + public updateMany(query: any, update: any, collectionName = DocumentsCollection): Promise { throw new Error("Can't updateMany a MemoryDatabase"); } @@ -58,8 +62,15 @@ export class MemoryDatabase implements IDatabase { return Promise.resolve({} as any); } - public deleteAll(collectionName = DocumentsCollection, _persist = true): Promise { - delete this.db[collectionName]; + public async dropSchema(...schemaNames: string[]): Promise { + const existing = await this.getCollectionNames(); + let valid: string[]; + if (schemaNames.length) { + valid = schemaNames.filter(collection => existing.includes(collection)); + } else { + valid = existing; + } + valid.forEach(schemaName => delete this.db[schemaName]); return Promise.resolve(); } @@ -69,14 +80,14 @@ export class MemoryDatabase implements IDatabase { return Promise.resolve(); } - public getDocument(id: string, fn: (result?: Transferable) => void, collectionName = NewDocumentsCollection): void { + public getDocument(id: string, fn: (result?: Transferable) => void, collectionName = DocumentsCollection): void { fn(this.getCollection(collectionName)[id]); } public getDocuments(ids: string[], fn: (result: Transferable[]) => void, collectionName = DocumentsCollection): void { fn(ids.map(id => this.getCollection(collectionName)[id])); } - public async visit(ids: string[], fn: (result: any) => string[] | Promise, collectionName = NewDocumentsCollection): Promise { + public async visit(ids: string[], fn: (result: any) => string[] | Promise, collectionName = DocumentsCollection): Promise { const visited = new Set(); while (ids.length) { const count = Math.min(ids.length, 1000); diff --git a/src/server/Websocket/Websocket.ts b/src/server/Websocket/Websocket.ts index be895c4bc..844535056 100644 --- a/src/server/Websocket/Websocket.ts +++ b/src/server/Websocket/Websocket.ts @@ -12,6 +12,7 @@ import { timeMap } from "../ApiManagers/UserManager"; import { green } from "colors"; import { networkInterfaces } from "os"; import executeImport from "../../scraping/buxton/final/BuxtonImporter"; +import { DocumentsCollection } from "../IDatabase"; export namespace WebSocket { @@ -96,7 +97,7 @@ export namespace WebSocket { Utils.AddServerHandlerCallback(socket, MessageStore.GetField, getField); Utils.AddServerHandlerCallback(socket, MessageStore.GetFields, getFields); if (isRelease) { - Utils.AddServerHandler(socket, MessageStore.DeleteAll, deleteFields); + Utils.AddServerHandler(socket, MessageStore.DeleteAll, () => doDelete(false)); } Utils.AddServerHandler(socket, MessageStore.CreateField, CreateField); @@ -163,24 +164,10 @@ export namespace WebSocket { } } - export async function deleteFields() { - await Database.Instance.deleteAll(); - if (process.env.DISABLE_SEARCH !== "true") { - await Search.clear(); - } - await Database.Instance.deleteAll('newDocuments'); - } - - // export async function deleteUserDocuments() { - // await Database.Instance.deleteAll(); - // await Database.Instance.deleteAll('newDocuments'); - // } - - export async function deleteAll() { - await Database.Instance.deleteAll(); - await Database.Instance.deleteAll('newDocuments'); - await Database.Instance.deleteAll('sessions'); - await Database.Instance.deleteAll('users'); + export async function doDelete(onlyFields = true) { + const target: string[] = []; + onlyFields && target.push(DocumentsCollection); + await Database.Instance.dropSchema(...target); if (process.env.DISABLE_SEARCH !== "true") { await Search.clear(); } @@ -210,11 +197,11 @@ export namespace WebSocket { } function GetRefField([id, callback]: [string, (result?: Transferable) => void]) { - Database.Instance.getDocument(id, callback, "newDocuments"); + Database.Instance.getDocument(id, callback); } function GetRefFields([ids, callback]: [string[], (result?: Transferable[]) => void]) { - Database.Instance.getDocuments(ids, callback, "newDocuments"); + Database.Instance.getDocuments(ids, callback); } const suffixMap: { [type: string]: (string | [string, string | ((json: any) => any)]) } = { @@ -271,7 +258,7 @@ export namespace WebSocket { function UpdateField(socket: Socket, diff: Diff) { Database.Instance.update(diff.id, diff.diff, - () => socket.broadcast.emit(MessageStore.UpdateField.Message, diff), false, "newDocuments"); + () => socket.broadcast.emit(MessageStore.UpdateField.Message, diff), false); const docfield = diff.diff.$set || diff.diff.$unset; if (!docfield) { return; @@ -296,7 +283,7 @@ export namespace WebSocket { } function DeleteField(socket: Socket, id: string) { - Database.Instance.delete({ _id: id }, "newDocuments").then(() => { + Database.Instance.delete({ _id: id }).then(() => { socket.broadcast.emit(MessageStore.DeleteField.Message, id); }); @@ -304,14 +291,14 @@ export namespace WebSocket { } function DeleteFields(socket: Socket, ids: string[]) { - Database.Instance.delete({ _id: { $in: ids } }, "newDocuments").then(() => { + Database.Instance.delete({ _id: { $in: ids } }).then(() => { socket.broadcast.emit(MessageStore.DeleteFields.Message, ids); }); Search.deleteDocuments(ids); } function CreateField(newValue: any) { - Database.Instance.insert(newValue, "newDocuments"); + Database.Instance.insert(newValue); } } diff --git a/src/server/apis/google/GoogleApiServerUtils.ts b/src/server/apis/google/GoogleApiServerUtils.ts index 0f75833ee..48a8da89f 100644 --- a/src/server/apis/google/GoogleApiServerUtils.ts +++ b/src/server/apis/google/GoogleApiServerUtils.ts @@ -148,26 +148,6 @@ export namespace GoogleApiServerUtils { }); } - /** - * Returns the lengthy string or access token that can be passed into - * the headers of an API request or into the constructor of the Photos - * client API wrapper. - * @param userId the Dash user id of the user requesting his/her associated - * access_token - * @returns the current access_token associated with the requesting - * Dash user. The access_token is valid for only an hour, and - * is then refreshed. - */ - export async function retrieveAccessToken(userId: string): Promise { - return new Promise(async resolve => { - const { credentials } = await retrieveCredentials(userId); - if (!credentials) { - return resolve(); - } - resolve(credentials.access_token!); - }); - } - /** * Manipulates a mapping such that, in the limit, each Dash user has * an associated authenticated OAuth2 client at their disposal. This @@ -216,18 +196,6 @@ export namespace GoogleApiServerUtils { return worker.generateAuthUrl({ scope, access_type: 'offline' }); } - /** - * This is what we return to the server in processNewUser(), after the - * worker OAuth2Client has used the user-pasted authentication code - * to retrieve an access token and an info token. The avatar is the - * URL to the Google-hosted mono-color, single white letter profile 'image'. - */ - export interface GoogleAuthenticationResult { - access_token: string; - avatar: string; - name: string; - } - /** * This method receives the authentication code that the * user pasted into the overlay in the client side and uses the worker @@ -245,7 +213,7 @@ export namespace GoogleApiServerUtils { * and display basic user information in the overlay on successful authentication. * This can be expanded as needed by adding properties to the interface GoogleAuthenticationResult. */ - export async function processNewUser(userId: string, authenticationCode: string): Promise { + export async function processNewUser(userId: string, authenticationCode: string): Promise { const credentials = await new Promise((resolve, reject) => { worker.getToken(authenticationCode, async (err, credentials) => { if (err || !credentials) { @@ -257,12 +225,7 @@ export namespace GoogleApiServerUtils { }); const enriched = injectUserInfo(credentials); await Database.Auxiliary.GoogleAuthenticationToken.Write(userId, enriched); - const { given_name, picture } = enriched.userInfo; - return { - access_token: enriched.access_token!, - avatar: picture, - name: given_name - }; + return enriched; } /** @@ -316,15 +279,15 @@ export namespace GoogleApiServerUtils { * @returns the credentials, or undefined if the user has no stored associated credentials, * and a flag indicating whether or not they were refreshed during retrieval */ - async function retrieveCredentials(userId: string): Promise<{ credentials: Opt, refreshed: boolean }> { - let credentials: Opt = await Database.Auxiliary.GoogleAuthenticationToken.Fetch(userId); + export async function retrieveCredentials(userId: string): Promise<{ credentials: Opt, refreshed: boolean }> { + let credentials = await Database.Auxiliary.GoogleAuthenticationToken.Fetch(userId); let refreshed = false; if (!credentials) { return { credentials: undefined, refreshed }; } // check for token expiry if (credentials.expiry_date! <= new Date().getTime()) { - credentials = await refreshAccessToken(credentials, userId); + credentials = { ...credentials, ...(await refreshAccessToken(credentials, userId)) }; refreshed = true; } return { credentials, refreshed }; diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index b10c6f119..5afb90c71 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -293,7 +293,7 @@ export class CurrentUserUtils { { _width: 250, _height: 250, title: "container" }); } if (doc.emptyWebpage === undefined) { - doc.emptyWebpage = Docs.Create.WebDocument("", { title: "New Webpage", _width: 600 }) + doc.emptyWebpage = Docs.Create.WebDocument("", { title: "New Webpage", _width: 600 }); } return [ { title: "Drag a collection", label: "Col", icon: "folder", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyCollection as Doc }, @@ -315,7 +315,8 @@ export class CurrentUserUtils { // { title: "use eraser", icon: "eraser", click: 'activateEraser(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this);', ischecked: `sameDocs(this.activePen.inkPen, this)`, backgroundColor: "pink", activePen: doc }, // { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activePen.inkPen = this;', ischecked: `sameDocs(this.activePen.inkPen, this)`, backgroundColor: "white", activePen: doc }, { title: "Drag a document previewer", label: "Prev", icon: "expand", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory,true)', dragFactory: doc.emptyDocHolder as Doc }, - { title: "Drag a Calculator REPL", label: "repl", icon: "calculator", click: 'addOverlayWindow("ScriptingRepl", { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" })' }, + { title: "Toggle a Calculator REPL", label: "repl", icon: "calculator", click: 'addOverlayWindow("ScriptingRepl", { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" })' }, + { title: "Connect a Google Account", label: "Google Account", icon: "external-link-alt", click: 'GoogleAuthenticationManager.Instance.fetchOrGenerateAccessToken(true)' }, ]; } @@ -331,21 +332,22 @@ export class CurrentUserUtils { alreadyCreatedButtons = dragDocs.map(d => StrCast(d.title)); } } - const creatorBtns = CurrentUserUtils.creatorBtnDescriptors(doc).filter(d => !alreadyCreatedButtons?.includes(d.title)). - map(data => Docs.Create.FontIconDocument({ - _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, - icon: data.icon, - title: data.title, - label: data.label, - ignoreClick: data.ignoreClick, - dropAction: "copy", - onDragStart: data.drag ? ScriptField.MakeFunction(data.drag) : undefined, - onClick: data.click ? ScriptField.MakeScript(data.click) : undefined, - ischecked: data.ischecked ? ComputedField.MakeFunction(data.ischecked) : undefined, - activePen: data.activePen, - backgroundColor: data.backgroundColor, removeDropProperties: new List(["dropAction"]), - dragFactory: data.dragFactory, - })); + const buttons = CurrentUserUtils.creatorBtnDescriptors(doc).filter(d => !alreadyCreatedButtons?.includes(d.title)); + const creatorBtns = buttons.map(({ title, label, icon, ignoreClick, drag, click, ischecked, activePen, backgroundColor, dragFactory }) => Docs.Create.FontIconDocument({ + _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, + icon, + title, + label, + ignoreClick, + dropAction: "copy", + onDragStart: drag ? ScriptField.MakeFunction(drag) : undefined, + onClick: click ? ScriptField.MakeScript(click) : undefined, + ischecked: ischecked ? ComputedField.MakeFunction(ischecked) : undefined, + activePen, + backgroundColor, + removeDropProperties: new List(["dropAction"]), + dragFactory, + })); if (dragCreatorSet === undefined) { doc.myItemCreators = new PrefetchProxy(Docs.Create.MasonryDocument(creatorBtns, { diff --git a/src/server/authentication/models/user_model.ts b/src/server/authentication/models/user_model.ts index 78e39dbc1..a0b688328 100644 --- a/src/server/authentication/models/user_model.ts +++ b/src/server/authentication/models/user_model.ts @@ -74,9 +74,9 @@ userSchema.pre("save", function save(next) { const comparePassword: comparePasswordFunction = function (this: DashUserModel, candidatePassword, cb) { // Choose one of the following bodies for authentication logic. - // secure + // secure (expected, default) bcrypt.compare(candidatePassword, this.password, cb); - // bypass password + // bypass password (debugging) // cb(undefined, true); }; diff --git a/src/server/database.ts b/src/server/database.ts index ad285765b..9ba461b65 100644 --- a/src/server/database.ts +++ b/src/server/database.ts @@ -4,7 +4,7 @@ import { Opt } from '../new_fields/Doc'; import { Utils, emptyFunction } from '../Utils'; import { Credentials } from 'google-auth-library'; import { GoogleApiServerUtils } from './apis/google/GoogleApiServerUtils'; -import { IDatabase } from './IDatabase'; +import { IDatabase, DocumentsCollection } from './IDatabase'; import { MemoryDatabase } from './MemoryDatabase'; import * as mongoose from 'mongoose'; import { Upload } from './SharedMediaTypes'; @@ -14,7 +14,7 @@ export namespace Database { export let disconnect: Function; const schema = 'Dash'; const port = 27017; - export const url = `mongodb://localhost:${port}/`; + export const url = `mongodb://localhost:${port}/${schema}`; enum ConnectionStates { disconnected = 0, @@ -47,28 +47,29 @@ export namespace Database { } 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)[] = []; - doConnect() { + async 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("\nMongo connect failed with the error:\n"); - console.log(_err); - process.exit(0); - } - this.db = client.db(); - this.onConnect.forEach(fn => fn()); + return new Promise(resolve => { + this.MongoClient.connect(url, { connectTimeoutMS: 30000, socketTimeoutMS: 30000, useUnifiedTopology: true }, (_err, client) => { + console.error("mongo connect response\n"); + if (!client) { + console.error("\nMongo connect failed with the error:\n"); + console.log(_err); + process.exit(0); + } + this.db = client.db(); + this.onConnect.forEach(fn => fn()); + resolve(); + }); }); } - public async update(id: string, value: any, callback: (err: mongodb.MongoError, res: mongodb.UpdateWriteOpResult) => void, upsert = true, collectionName = Database.DocumentsCollection) { - + public async update(id: string, value: any, callback: (err: mongodb.MongoError, res: mongodb.UpdateWriteOpResult) => void, upsert = true, collectionName = DocumentsCollection) { if (this.db) { const collection = this.db.collection(collectionName); const prom = this.currentWrites[id]; @@ -93,7 +94,7 @@ export namespace Database { } } - public replace(id: string, value: any, callback: (err: mongodb.MongoError, res: mongodb.UpdateWriteOpResult) => void, upsert = true, collectionName = Database.DocumentsCollection) { + public replace(id: string, value: any, callback: (err: mongodb.MongoError, res: mongodb.UpdateWriteOpResult) => void, upsert = true, collectionName = DocumentsCollection) { if (this.db) { const collection = this.db.collection(collectionName); const prom = this.currentWrites[id]; @@ -117,9 +118,25 @@ export namespace Database { } } + public async getCollectionNames() { + const cursor = this.db?.listCollections(); + const collectionNames: string[] = []; + if (cursor) { + while (await cursor.hasNext()) { + const collection: any = await cursor.next(); + collection && collectionNames.push(collection.name); + } + } + return collectionNames; + } + + public async clear() { + return Promise.all((await this.getCollectionNames()).map(collection => this.dropSchema(collection))); + } + public delete(query: any, collectionName?: string): Promise; public delete(id: string, collectionName?: string): Promise; - public delete(id: any, collectionName = Database.DocumentsCollection) { + public delete(id: any, collectionName = DocumentsCollection) { if (typeof id === "string") { id = { _id: id }; } @@ -131,25 +148,26 @@ export namespace Database { } } - public async deleteAll(collectionName = Database.DocumentsCollection, persist = true): Promise { - return new Promise(resolve => { - const executor = async (database: mongodb.Db) => { - if (persist) { - await database.collection(collectionName).deleteMany({}); - } else { - await database.dropCollection(collectionName); - } - resolve(); - }; - if (this.db) { - executor(this.db); + public async dropSchema(...targetSchemas: string[]): Promise { + const executor = async (database: mongodb.Db) => { + const existing = await Instance.getCollectionNames(); + let valid: string[]; + if (targetSchemas.length) { + valid = targetSchemas.filter(collection => existing.includes(collection)); } else { - this.onConnect.push(() => this.db && executor(this.db)); + valid = existing; } - }); + const pending = Promise.all(valid.map(schemaName => database.dropCollection(schemaName))); + return (await pending).every(dropOutcome => dropOutcome); + }; + if (this.db) { + return executor(this.db); + } else { + this.onConnect.push(() => this.db && executor(this.db)); + } } - public async insert(value: any, collectionName = Database.DocumentsCollection) { + public async insert(value: any, collectionName = DocumentsCollection) { if (this.db) { if ("id" in value) { value._id = value.id; @@ -177,7 +195,7 @@ export namespace Database { } } - public getDocument(id: string, fn: (result?: Transferable) => void, collectionName = "newDocuments") { + public getDocument(id: string, fn: (result?: Transferable) => void, collectionName = DocumentsCollection) { if (this.db) { this.db.collection(collectionName).findOne({ _id: id }, (err, result) => { if (result) { @@ -193,7 +211,7 @@ export namespace Database { } } - public getDocuments(ids: string[], fn: (result: Transferable[]) => void, collectionName = Database.DocumentsCollection) { + public getDocuments(ids: string[], fn: (result: Transferable[]) => void, collectionName = DocumentsCollection) { if (this.db) { this.db.collection(collectionName).find({ _id: { "$in": ids } }).toArray((err, docs) => { if (err) { @@ -211,7 +229,7 @@ export namespace Database { } } - public async visit(ids: string[], fn: (result: any) => string[] | Promise, collectionName = "newDocuments"): Promise { + public async visit(ids: string[], fn: (result: any) => string[] | Promise, collectionName = DocumentsCollection): Promise { if (this.db) { const visited = new Set(); while (ids.length) { @@ -238,7 +256,7 @@ export namespace Database { } } - public query(query: { [key: string]: any }, projection?: { [key: string]: 0 | 1 }, collectionName = "newDocuments"): Promise { + public query(query: { [key: string]: any }, projection?: { [key: string]: 0 | 1 }, collectionName = DocumentsCollection): Promise { if (this.db) { let cursor = this.db.collection(collectionName).find(query); if (projection) { @@ -252,7 +270,7 @@ export namespace Database { } } - public updateMany(query: any, update: any, collectionName = "newDocuments") { + public updateMany(query: any, update: any, collectionName = DocumentsCollection) { if (this.db) { const db = this.db; return new Promise(res => db.collection(collectionName).update(query, update, (_, result) => res(result))); @@ -282,7 +300,8 @@ export namespace Database { export namespace Auxiliary { export enum AuxiliaryCollections { - GooglePhotosUploadHistory = "uploadedFromGooglePhotos" + GooglePhotosUploadHistory = "uploadedFromGooglePhotos", + GoogleAuthentication = "googleAuthentication" } const SanitizedCappedQuery = async (query: { [key: string]: any }, collection: string, cap: number, removeId = true) => { @@ -306,27 +325,30 @@ export namespace Database { export namespace GoogleAuthenticationToken { - const GoogleAuthentication = "googleAuthentication"; - - export type StoredCredentials = Credentials & { _id: string }; + type StoredCredentials = GoogleApiServerUtils.EnrichedCredentials & { _id: string }; export const Fetch = async (userId: string, removeId = true): Promise> => { - return SanitizedSingletonQuery({ userId }, GoogleAuthentication, removeId); + return SanitizedSingletonQuery({ userId }, AuxiliaryCollections.GoogleAuthentication, removeId); }; export const Write = async (userId: string, enrichedCredentials: GoogleApiServerUtils.EnrichedCredentials) => { - return Instance.insert({ userId, canAccess: [], ...enrichedCredentials }, GoogleAuthentication); + return Instance.insert({ userId, canAccess: [], ...enrichedCredentials }, AuxiliaryCollections.GoogleAuthentication); }; export const Update = async (userId: string, access_token: string, expiry_date: number) => { const entry = await Fetch(userId, false); if (entry) { const parameters = { $set: { access_token, expiry_date } }; - return Instance.update(entry._id, parameters, emptyFunction, true, GoogleAuthentication); + return Instance.update(entry._id, parameters, emptyFunction, true, AuxiliaryCollections.GoogleAuthentication); } }; - export const DeleteAll = () => Instance.deleteAll(GoogleAuthentication, false); + export const Revoke = async (userId: string) => { + const entry = await Fetch(userId, false); + if (entry) { + Instance.delete({ _id: entry._id }, AuxiliaryCollections.GoogleAuthentication); + } + }; } @@ -338,12 +360,6 @@ export namespace Database { return Instance.insert(bundle, AuxiliaryCollections.GooglePhotosUploadHistory); }; - export const DeleteAll = async (persist = false) => { - const collectionNames = Object.values(AuxiliaryCollections); - const pendingDeletions = collectionNames.map(name => Instance.deleteAll(name, persist)); - return Promise.all(pendingDeletions); - }; - } } diff --git a/src/server/remapUrl.ts b/src/server/remapUrl.ts index 45d2fdd33..91a3cb6bf 100644 --- a/src/server/remapUrl.ts +++ b/src/server/remapUrl.ts @@ -1,6 +1,4 @@ import { Database } from "./database"; -import { Search } from "./Search"; -import * as path from 'path'; //npx ts-node src/server/remapUrl.ts @@ -50,7 +48,7 @@ async function update() { return new Promise(res => Database.Instance.update(doc[0], doc[1], () => { console.log("wrote " + JSON.stringify(doc[1])); res(); - }, false, "newDocuments")); + }, false)); })); console.log("Done"); // await Promise.all(updates.map(update => { -- cgit v1.2.3-70-g09d2 From 82ac34b162013ef6458b575336d529d2bcd0769d Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Tue, 5 May 2020 02:48:52 -0700 Subject: cleanup --- src/server/database.ts | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src') diff --git a/src/server/database.ts b/src/server/database.ts index 9ba461b65..cfd707825 100644 --- a/src/server/database.ts +++ b/src/server/database.ts @@ -130,10 +130,6 @@ export namespace Database { return collectionNames; } - public async clear() { - return Promise.all((await this.getCollectionNames()).map(collection => this.dropSchema(collection))); - } - public delete(query: any, collectionName?: string): Promise; public delete(id: string, collectionName?: string): Promise; public delete(id: any, collectionName = DocumentsCollection) { -- cgit v1.2.3-70-g09d2 From e2c8ca0bf9e9f1c27d333b0b51ae3dd9d6cba05f Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 5 May 2020 13:33:26 -0400 Subject: fixed some interactions with WebDocuments --- src/client/views/DocumentButtonBar.tsx | 9 +++++++-- src/client/views/nodes/WebBox.scss | 4 ++-- src/client/views/nodes/WebBox.tsx | 26 +++++++++++--------------- 3 files changed, 20 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 3624cdb6d..7ba47deb5 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -22,6 +22,7 @@ import React = require("react"); import { DragManager } from '../util/DragManager'; import { MetadataEntryMenu } from './MetadataEntryMenu'; import GoogleAuthenticationManager from '../apis/GoogleAuthenticationManager'; +import { Docs } from '../documents/Documents'; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -167,10 +168,14 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView | return !targetDoc || !dataDoc || !dataDoc[GoogleRef] ? (null) :
e.altKey && runInAction(() => this.openHover = true)} + onPointerEnter={e => (e.altKey || e.shiftKey) && runInAction(() => this.openHover = true)} onPointerLeave={action(() => this.openHover = false)} onClick={e => { - if (e.altKey) { + if (e.shiftKey) { + e.preventDefault(); + CollectionDockingView.AddRightSplit(Docs.Create.WebDocument(`https://docs.google.com/document/d/${dataDoc[GoogleRef]}/edit`, + { _width: 600, _nativeWidth: 960, _nativeHeight: 800, isAnnotating: false })); + } else if (e.altKey) { e.preventDefault(); window.open(`https://docs.google.com/document/d/${dataDoc[GoogleRef]}/edit`); } else { diff --git a/src/client/views/nodes/WebBox.scss b/src/client/views/nodes/WebBox.scss index af84a7d95..4c05d4627 100644 --- a/src/client/views/nodes/WebBox.scss +++ b/src/client/views/nodes/WebBox.scss @@ -3,6 +3,8 @@ .webBox-container, .webBox-container-dragging { transform-origin: top left; + width: 100%; + height: 100%; .webBox-outerContent { width: 100%; height: 100%; @@ -66,8 +68,6 @@ opacity: 0.9; z-index: 9001; transition: top .5s; - padding: 10px; - .urlEditor { display: grid; diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 4e383e468..80e15fd5f 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -51,7 +51,7 @@ export class WebBox extends ViewBoxAnnotatableComponent this.layoutDoc.scrollY, (scrollY) => { @@ -141,14 +141,13 @@ export class WebBox extends ViewBoxAnnotatableComponent
-
+
-
+
; } - const content = -
- {this.urlEditor()} - {view} -
; const decInteracting = DocumentDecorations.Instance?.Interacting; const frozen = !this.props.isSelected() || decInteracting; return (<> -
- {content} -
+
+ {view} +
; {!frozen ? (null) :
@@ -344,6 +339,7 @@ export class WebBox extends ViewBoxAnnotatableComponent
} + {this.urlEditor()} ); } scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.props.Document.scrollTop)); @@ -351,8 +347,8 @@ export class WebBox extends ViewBoxAnnotatableComponent {this.content} -- cgit v1.2.3-70-g09d2 From 269ea1e31959cd279cea91276fb80e9d19116878 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Tue, 5 May 2020 13:46:54 -0700 Subject: slight ux improvements for google docs utility button --- src/client/views/DocumentButtonBar.tsx | 46 +++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 7ba47deb5..8fc4cd4d4 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -1,5 +1,5 @@ import { IconProp, library } from '@fortawesome/fontawesome-svg-core'; -import { faArrowAltCircleDown, faPhotoVideo, faArrowAltCircleUp, faCheckCircle, faCloudUploadAlt, faLink, faShare, faStopCircle, faSyncAlt, faTag, faTimes } from '@fortawesome/free-solid-svg-icons'; +import { faArrowAltCircleDown, faPhotoVideo, faArrowAltCircleUp, faArrowAltCircleRight, faCheckCircle, faCloudUploadAlt, faLink, faShare, faStopCircle, faSyncAlt, faTag, faTimes } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; @@ -32,6 +32,7 @@ library.add(faTag); library.add(faTimes); library.add(faArrowAltCircleDown); library.add(faArrowAltCircleUp); +library.add(faArrowAltCircleRight); library.add(faStopCircle); library.add(faCheckCircle); library.add(faCloudUploadAlt); @@ -42,6 +43,12 @@ library.add(faPhotoVideo); const cloud: IconProp = "cloud-upload-alt"; const fetch: IconProp = "sync-alt"; +enum UtilityButtonState { + Default, + OpenRight, + OpenExternally +} + @observer export class DocumentButtonBar extends React.Component<{ views: (DocumentView | undefined)[], stack?: any }, {}> { private _linkButton = React.createRef(); @@ -58,7 +65,7 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView | @observable public isAnimatingFetch = false; @observable public isAnimatingPulse = false; - @observable private openHover = false; + @observable private openHover: UtilityButtonState = UtilityButtonState.Default; @observable public static Instance: DocumentButtonBar; public static hasPushedHack = false; @@ -166,18 +173,32 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView | const dataDoc = targetDoc && Doc.GetProto(targetDoc); const animation = this.isAnimatingFetch ? "spin 0.5s linear infinite" : "none"; return !targetDoc || !dataDoc || !dataDoc[GoogleRef] ? (null) :
{ + switch (this.openHover) { + default: + case UtilityButtonState.Default: return `${!dataDoc.unchanged ? "Pull from" : "Fetch"} Google Docs`; + case UtilityButtonState.OpenRight: return "Open in Right Split"; + case UtilityButtonState.OpenExternally: return "Open in new Browser Tab"; + } + })()} style={{ backgroundColor: this.pullColor }} - onPointerEnter={e => (e.altKey || e.shiftKey) && runInAction(() => this.openHover = true)} - onPointerLeave={action(() => this.openHover = false)} + onPointerEnter={action(e => { + if (e.altKey) { + this.openHover = UtilityButtonState.OpenExternally; + } else if (e.shiftKey) { + this.openHover = UtilityButtonState.OpenRight; + } + })} + onPointerLeave={action(() => this.openHover = UtilityButtonState.Default)} onClick={e => { + const googleDocUrl = `https://docs.google.com/document/d/${dataDoc[GoogleRef]}/edit`; if (e.shiftKey) { e.preventDefault(); - CollectionDockingView.AddRightSplit(Docs.Create.WebDocument(`https://docs.google.com/document/d/${dataDoc[GoogleRef]}/edit`, - { _width: 600, _nativeWidth: 960, _nativeHeight: 800, isAnnotating: false })); + const options = { _width: 600, _nativeWidth: 960, _nativeHeight: 800, isAnnotating: false }; + CollectionDockingView.AddRightSplit(Docs.Create.WebDocument(googleDocUrl, options)); } else if (e.altKey) { e.preventDefault(); - window.open(`https://docs.google.com/document/d/${dataDoc[GoogleRef]}/edit`); + window.open(googleDocUrl); } else { this.clearPullColor(); DocumentButtonBar.hasPulledHack = false; @@ -187,7 +208,14 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView | }}> { + switch (this.openHover) { + default: + case UtilityButtonState.Default: return dataDoc.unchanged === false ? (this.pullIcon as any) : fetch; + case UtilityButtonState.OpenRight: return "arrow-alt-circle-right"; + case UtilityButtonState.OpenExternally: return "share"; + } + })()} />
; } -- cgit v1.2.3-70-g09d2 From a67dc240024ccb329f2509c70556a7b78ca2c4ab Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 5 May 2020 20:22:49 -0400 Subject: fixed text selection in docHolder boxes by changing formattedTextBox not to stopPropagation on pointerDowns. added a googleDoc field on documents to open the same Dash-googleDoc doc each time. --- src/client/views/DocumentButtonBar.tsx | 13 +- src/client/views/nodes/DocHolderBox.scss | 1 + src/client/views/nodes/DocHolderBox.tsx | 145 +++++++++++---------- src/client/views/nodes/DocumentView.tsx | 2 + src/client/views/nodes/FieldView.tsx | 1 + .../views/nodes/formattedText/FormattedTextBox.tsx | 4 +- 6 files changed, 89 insertions(+), 77 deletions(-) (limited to 'src') diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 7ba47deb5..db566ee48 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -5,7 +5,7 @@ import { action, computed, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; import { Doc, DocListCast } from "../../new_fields/Doc"; import { RichTextField } from '../../new_fields/RichTextField'; -import { NumCast, StrCast } from "../../new_fields/Types"; +import { NumCast, StrCast, Cast } from "../../new_fields/Types"; import { emptyFunction, setupMoveUpEvents } from "../../Utils"; import { Pulls, Pushes } from '../apis/google_docs/GoogleApiClientUtils'; import { UndoManager } from "../util/UndoManager"; @@ -170,11 +170,16 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView | style={{ backgroundColor: this.pullColor }} onPointerEnter={e => (e.altKey || e.shiftKey) && runInAction(() => this.openHover = true)} onPointerLeave={action(() => this.openHover = false)} - onClick={e => { + onClick={async (e: React.MouseEvent) => { if (e.shiftKey) { e.preventDefault(); - CollectionDockingView.AddRightSplit(Docs.Create.WebDocument(`https://docs.google.com/document/d/${dataDoc[GoogleRef]}/edit`, - { _width: 600, _nativeWidth: 960, _nativeHeight: 800, isAnnotating: false })); + let googleDoc = await Cast(dataDoc.googleDoc, Doc); + if (!googleDoc) { + googleDoc = Docs.Create.WebDocument(`https://docs.google.com/document/d/${dataDoc[GoogleRef]}/edit`, + { _width: 600, _nativeWidth: 960, _nativeHeight: 800, isAnnotating: false }); + dataDoc.googleDoc = googleDoc; + } + CollectionDockingView.AddRightSplit(googleDoc); } else if (e.altKey) { e.preventDefault(); window.open(`https://docs.google.com/document/d/${dataDoc[GoogleRef]}/edit`); diff --git a/src/client/views/nodes/DocHolderBox.scss b/src/client/views/nodes/DocHolderBox.scss index 3a27c16c1..4949d16a3 100644 --- a/src/client/views/nodes/DocHolderBox.scss +++ b/src/client/views/nodes/DocHolderBox.scss @@ -8,6 +8,7 @@ margin: auto; color: white; position: absolute; + padding: 3px; } .contentFittingDocumentView { position: absolute; diff --git a/src/client/views/nodes/DocHolderBox.tsx b/src/client/views/nodes/DocHolderBox.tsx index 9787877cc..17b2daabc 100644 --- a/src/client/views/nodes/DocHolderBox.tsx +++ b/src/client/views/nodes/DocHolderBox.tsx @@ -3,7 +3,7 @@ import { action, IReactionDisposer, reaction } from "mobx"; import { observer } from "mobx-react"; import { Doc, Field } from "../../../new_fields/Doc"; import { collectionSchema, documentSchema } from "../../../new_fields/documentSchemas"; -import { makeInterface } from "../../../new_fields/Schema"; +import { makeInterface, listSpec } from "../../../new_fields/Schema"; import { ComputedField } from "../../../new_fields/ScriptField"; import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; import { TraceMobx } from "../../../new_fields/util"; @@ -32,7 +32,7 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent(); _curSelection = -1; componentDidMount() { - this._prevSelectionDisposer = reaction(() => this.layoutDoc[this.props.fieldKey], (data) => { + this._prevSelectionDisposer = reaction(() => this.dataDoc[this.fieldKey], (data) => { if (data instanceof Doc && !this.isSelectionLocked()) { this._selections.indexOf(data) !== -1 && this._selections.splice(this._selections.indexOf(data), 1); this._selections.push(data); @@ -53,13 +53,13 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent { - this.layoutDoc[this.props.fieldKey] = this.layoutDoc[this.props.fieldKey]; + this.dataDoc[this.fieldKey] = this.dataDoc[this.fieldKey]; } showSelection = () => { - this.layoutDoc[this.props.fieldKey] = ComputedField.MakeFunction(`selectedDocs(self,this.excludeCollections,[_last_])?.[0]`); + this.dataDoc[this.fieldKey] = ComputedField.MakeFunction(`selectedDocs(self,this.excludeCollections,[_last_])?.[0]`); } isSelectionLocked = () => { - const kvpstring = Field.toKeyValueString(this.layoutDoc, this.props.fieldKey); + const kvpstring = Field.toKeyValueString(this.dataDoc, this.fieldKey); return !kvpstring || kvpstring.includes("DOC"); } toggleLockSelection = () => { @@ -69,13 +69,13 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent { this.lockSelection(); if (this._curSelection > 0) { - this.layoutDoc[this.props.fieldKey] = this._selections[--this._curSelection]; + this.dataDoc[this.fieldKey] = this._selections[--this._curSelection]; return true; } } nextSelection = () => { if (this._curSelection < this._selections.length - 1 && this._selections.length) { - this.layoutDoc[this.props.fieldKey] = this._selections[++this._curSelection]; + this.dataDoc[this.fieldKey] = this._selections[++this._curSelection]; return true; } } @@ -89,8 +89,8 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent { let hitWidget: boolean | undefined = false; if (this._contRef.current!.getBoundingClientRect().top + this.yPad > e.clientY) hitWidget = (() => { this.props.select(false); return true; })(); @@ -107,67 +107,70 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent this.props.PanelWidth() - 2 * this.xPad; pheight = () => this.props.PanelHeight() - 2 * this.yPad; getTransform = () => this.props.ScreenToLocalTransform().translate(-this.xPad, -this.yPad); - isActive = () => this.active() || !this.props.renderDepth; - layoutTemplateDoc = () => Cast(this.props.Document.childLayoutTemplate, Doc, null); + isActive = (outsideReaction: boolean) => this.active(outsideReaction) || this.props.renderDepth <= 1; + layoutTemplateDoc = () => Cast(this.layoutDoc.childLayoutTemplate, Doc, null); get renderContents() { - const containedDoc = Cast(this.dataDoc[this.props.fieldKey], Doc, null); + const containedDoc = Cast(this.dataDoc[this.fieldKey], Doc, null); const layoutTemplate = StrCast(this.layoutDoc.childLayoutString); - const contents = !(containedDoc instanceof Doc) ? (null) : this.layoutDoc.childLayoutString || this.layoutTemplateDoc() ? - : - ; + const contents = !(containedDoc instanceof Doc) || + Cast(containedDoc[Doc.LayoutFieldKey(containedDoc)], listSpec(Doc), null)?.includes(this.rootDoc) + ? (null) : this.layoutDoc.childLayoutString || this.layoutTemplateDoc() ? + : + ; return contents; } render() { @@ -183,7 +186,7 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent {this.renderContents}
+ style={{ marginTop: - this.yPad, background: "black" }}>
; @@ -195,13 +198,13 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent { this._dropDisposer?.(); - ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.props.Document)); + ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.rootDoc)); } } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 5a2ad8c88..2d5d7d231 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -63,6 +63,7 @@ export interface DocumentViewProps { LayoutTemplate?: () => Opt; LibraryPath: Doc[]; fitToBox?: boolean; + ignoreAutoHeight?: boolean; contextMenuItems?: () => { script: ScriptField, label: string }[]; rootSelected: (outsideReaction?: boolean) => boolean; // whether the root of a template has been selected onClick?: ScriptField; @@ -1009,6 +1010,7 @@ export class DocumentView extends DocComponent(Docu renderDepth={this.props.renderDepth} PanelWidth={this.panelWidth} PanelHeight={this.panelHeight} + ignoreAutoHeight={this.props.ignoreAutoHeight} focus={this.props.focus} parentActive={this.props.parentActive} whenActiveChanged={this.props.whenActiveChanged} diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 016d2a1ae..7db634e74 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -43,6 +43,7 @@ export interface FieldViewProps { whenActiveChanged: (isActive: boolean) => void; dontRegisterView?: boolean; focus: (doc: Doc) => void; + ignoreAutoHeight?: boolean; PanelWidth: () => number; PanelHeight: () => number; NativeHeight: () => number; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index ce096f81b..5dc22d6f6 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -985,7 +985,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } if (e.button === 0 && this.active(true) && !e.altKey && !e.ctrlKey && !e.metaKey) { if (e.clientX < this.ProseRef!.getBoundingClientRect().right) { // don't stop propagation if clicking in the sidebar - e.stopPropagation(); + //e.stopPropagation(); } } if (e.button === 2 || (e.button === 0 && e.ctrlKey)) { @@ -1217,7 +1217,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp @action tryUpdateHeight(limitHeight?: number) { let scrollHeight = this._ref.current?.scrollHeight; - if (this.layoutDoc._autoHeight && scrollHeight && + if (this.layoutDoc._autoHeight && !this.props.ignoreAutoHeight && scrollHeight && getComputedStyle(this._ref.current!.parentElement!).top === "0px") { // if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation if (limitHeight && scrollHeight > limitHeight) { scrollHeight = limitHeight; -- cgit v1.2.3-70-g09d2 From d179ac9a6e01fb7d917b4b5fdb56374c697752ce Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 5 May 2020 21:33:00 -0400 Subject: fixed major performance issue with images --- src/client/views/nodes/ImageBox.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 08917d281..4153c184e 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -249,9 +249,10 @@ export class ImageBox extends ViewBoxAnnotatableComponent { + const basePath = imgPath.replace(/_[oms]./, ""); const cachedNativeSize = { - 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, + width: basePath === this.dataDoc[this.fieldKey + "-path"] ? NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"]) : 0, + height: basePath === 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,7 +266,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent 0.1) { -- cgit v1.2.3-70-g09d2 From fa826d828b0fc20afde675ffb060e4f24ca310d3 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 6 May 2020 02:01:08 -0400 Subject: fixed makeClone to handle text hyperlinks fixed documentBox background color. fixed formattedtextbox sidebar clicking to sto propagation. --- src/client/views/MainView.tsx | 4 +- src/client/views/nodes/DocHolderBox.scss | 1 - src/client/views/nodes/DocHolderBox.tsx | 5 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 123 +++++++-------------- src/new_fields/Doc.ts | 72 +++++++----- src/new_fields/documentSchemas.ts | 1 + 6 files changed, 92 insertions(+), 114 deletions(-) (limited to 'src') diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 1a285d4ec..e67f2f3a2 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -300,7 +300,7 @@ export class MainView extends React.Component { defaultBackgroundColors = (doc: Doc) => { if (this.darkScheme) { - switch (doc.type) { + switch (doc?.type) { case DocumentType.RTF || DocumentType.LABEL || DocumentType.BUTTON: return "#2d2d2d"; case DocumentType.LINK: case DocumentType.COL: { @@ -309,7 +309,7 @@ export class MainView extends React.Component { default: return "black"; } } else { - switch (doc.type) { + switch (doc?.type) { case DocumentType.RTF: return "#f1efeb"; case DocumentType.BUTTON: case DocumentType.LABEL: return "lightgray"; diff --git a/src/client/views/nodes/DocHolderBox.scss b/src/client/views/nodes/DocHolderBox.scss index 4949d16a3..6a9ef0b6f 100644 --- a/src/client/views/nodes/DocHolderBox.scss +++ b/src/client/views/nodes/DocHolderBox.scss @@ -2,7 +2,6 @@ width: 100%; height: 100%; pointer-events: all; - background: rgb(241, 239, 235); position: absolute; .documentBox-lock { margin: auto; diff --git a/src/client/views/nodes/DocHolderBox.tsx b/src/client/views/nodes/DocHolderBox.tsx index 17b2daabc..af8dc704c 100644 --- a/src/client/views/nodes/DocHolderBox.tsx +++ b/src/client/views/nodes/DocHolderBox.tsx @@ -122,6 +122,7 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent; private _applyingChange: boolean = false; private _searchIndex = 0; - private _sidebarMovement = 0; - private _lastX = 0; - private _lastY = 0; private _undoTyping?: UndoManager.Batch; private _disposers: { [name: string]: IReactionDisposer } = {}; private dropDisposer?: DragManager.DragDropDisposer; @@ -161,7 +158,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp this.dataDoc[key] = doc || Docs.Create.FreeformDocument([], { title: value, _width: 500, _height: 500 }, value); DocUtils.Publish(this.dataDoc[key] as Doc, value, this.props.addDocument, this.props.removeDocument); if (linkDoc) { (linkDoc as Doc).anchor2 = this.dataDoc[key] as Doc; } - else DocUtils.MakeLink({ doc: this.props.Document }, { doc: this.dataDoc[key] as Doc }, "link to named target", id); + else DocUtils.MakeLink({ doc: this.rootDoc }, { doc: this.dataDoc[key] as Doc }, "link to named target", id); }); }); }); @@ -199,7 +196,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp const tsel = this._editorView.state.selection.$from; tsel.marks().filter(m => m.type === this._editorView!.state.schema.marks.user_mark).map(m => AudioBox.SetScrubTime(Math.max(0, m.attrs.modified * 1000))); const curText = state.doc.textBetween(0, state.doc.content.size, " \n"); - const curTemp = Cast(this.props.Document[this.props.fieldKey + "-textTemplate"], RichTextField); // the actual text in the text box + const curTemp = Cast(this.layoutDoc[this.props.fieldKey + "-textTemplate"], RichTextField); // the actual text in the text box const curProto = Cast(Cast(this.dataDoc.proto, Doc, null)?.[this.fieldKey], RichTextField, null); // the default text inherited from a prototype const curLayout = this.rootDoc !== this.layoutDoc ? Cast(this.layoutDoc[this.fieldKey], RichTextField, null) : undefined; // the default text stored in a layout template const json = JSON.stringify(state.toJSON()); @@ -207,7 +204,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp this._applyingChange = true; this.dataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now())); if ((!curTemp && !curProto) || curText || curLayout?.Data.includes("dash")) { // if no template, or there's text that didn't come from the layout template, write it to the document. (if this is driven by a template, then this overwrites the template text which is intended) - if (curText !== curLayout?.Text) { + if (json !== curLayout?.Data) { this.dataDoc[this.props.fieldKey] = new RichTextField(json, curText); this.dataDoc[this.props.fieldKey + "-noTemplate"] = (curTemp?.Text || "") !== curText; // mark the data field as being split from the template if it has been edited } @@ -241,7 +238,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp res.map(r => r.map(h => flattened.push(h))); const lastSel = Math.min(flattened.length - 1, this._searchIndex); this._searchIndex = ++this._searchIndex > flattened.length - 1 ? 0 : this._searchIndex; - const alink = DocUtils.MakeLink({ doc: this.props.Document }, { doc: target }, "automatic")!; + const alink = DocUtils.MakeLink({ doc: this.rootDoc }, { doc: target }, "automatic")!; const link = this._editorView.state.schema.marks.link.create({ href: Utils.prepend("/doc/" + alink[Id]), title: "a link", location: location, linkId: alink[Id], targetId: target[Id] @@ -280,7 +277,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp protected createDropTarget = (ele: HTMLDivElement) => { this.ProseRef = ele; this.dropDisposer?.(); - ele && (this.dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.props.Document)); + ele && (this.dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.layoutDoc)); } @undoBatch @@ -399,26 +396,15 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } sidebarDown = (e: React.PointerEvent) => { - this._lastX = e.clientX; - this._lastY = e.clientY; - this._sidebarMovement = 0; - document.addEventListener("pointermove", this.sidebarMove); - document.addEventListener("pointerup", this.sidebarUp); - e.stopPropagation(); - e.preventDefault(); // prevents text from being selected during drag + setupMoveUpEvents(this, e, this.sidebarMove, emptyFunction, + () => (this.layoutDoc._sidebarWidthPercent = StrCast(this.layoutDoc._sidebarWidthPercent, "0%") === "0%" ? "25%" : "0%")); } - sidebarMove = (e: PointerEvent) => { + sidebarMove = (e: PointerEvent, down: number[], delta: number[]) => { const bounds = this.CurrentDiv.getBoundingClientRect(); - this._sidebarMovement += Math.sqrt((e.clientX - this._lastX) * (e.clientX - this._lastX) + (e.clientY - this._lastY) * (e.clientY - this._lastY)); - this.props.Document.sidebarWidthPercent = "" + 100 * (1 - (e.clientX - bounds.left) / bounds.width) + "%"; - } - sidebarUp = (e: PointerEvent) => { - document.removeEventListener("pointermove", this.sidebarMove); - document.removeEventListener("pointerup", this.sidebarUp); + this.layoutDoc._sidebarWidthPercent = "" + 100 * (1 - (e.clientX - bounds.left) / bounds.width) + "%"; + return false; } - toggleSidebar = () => this._sidebarMovement < 5 && (this.props.Document.sidebarWidthPercent = StrCast(this.props.Document.sidebarWidthPercent, "0%") === "0%" ? "25%" : "0%"); - public static get DefaultLayout(): Doc | string | undefined { return Cast(Doc.UserDoc().defaultTextLayout, Doc, null) || StrCast(Doc.UserDoc().defaultTextLayout, null); } @@ -426,12 +412,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp const cm = ContextMenu.Instance; const funcs: ContextMenuProps[] = []; - this.rootDoc.isTemplateDoc && funcs.push({ description: "Make Default Layout", event: async () => Doc.UserDoc().defaultTextLayout = new PrefetchProxy(this.props.Document), icon: "eye" }); + this.rootDoc.isTemplateDoc && funcs.push({ description: "Make Default Layout", event: async () => Doc.UserDoc().defaultTextLayout = new PrefetchProxy(this.rootDoc), icon: "eye" }); funcs.push({ description: "Reset Default Layout", event: () => Doc.UserDoc().defaultTextLayout = undefined, icon: "eye" }); !this.layoutDoc.isTemplateDoc && funcs.push({ description: "Make Template", event: () => { this.rootDoc.isTemplateDoc = makeTemplate(this.rootDoc); - Doc.AddDocToList(Cast(Doc.UserDoc()["template-notes"], Doc, null), "data", this.props.Document); + Doc.AddDocToList(Cast(Doc.UserDoc()["template-notes"], Doc, null), "data", this.rootDoc); }, icon: "eye" }); this.layoutDoc.isTemplateDoc && funcs.push({ @@ -451,9 +437,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp Doc.AddDocToList(Cast(Doc.UserDoc()["template-notes"], Doc, null), "data", this.rootDoc); }, icon: "eye" }); - funcs.push({ description: "Toggle Single Line", event: () => this.props.Document._singleLine = !this.props.Document._singleLine, icon: "expand-arrows-alt" }); - funcs.push({ description: "Toggle Sidebar", event: () => this.props.Document._showSidebar = !this.props.Document._showSidebar, icon: "expand-arrows-alt" }); - funcs.push({ description: "Toggle Dictation Icon", event: () => this.props.Document._showAudio = !this.props.Document._showAudio, icon: "expand-arrows-alt" }); + funcs.push({ description: "Toggle Single Line", event: () => this.layoutDoc._singleLine = !this.layoutDoc._singleLine, icon: "expand-arrows-alt" }); + funcs.push({ description: "Toggle Sidebar", event: () => this.layoutDoc._showSidebar = !this.layoutDoc._showSidebar, icon: "expand-arrows-alt" }); + funcs.push({ description: "Toggle Dictation Icon", event: () => this.layoutDoc._showAudio = !this.layoutDoc._showAudio, icon: "expand-arrows-alt" }); funcs.push({ description: "Toggle Menubar", event: () => this.toggleMenubar(), icon: "expand-arrows-alt" }); const highlighting: ContextMenuProps[] = []; @@ -480,7 +466,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp DocListCast(noteTypesDoc?.data).forEach(note => { changeItems.push({ description: StrCast(note.title), event: undoBatch(() => { - Doc.setNativeView(this.props.Document); + Doc.setNativeView(this.rootDoc); Doc.makeCustomViewClicked(this.rootDoc, Docs.Create.TreeDocument, StrCast(note.title), note); }), icon: "eye" }); @@ -517,7 +503,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp @action toggleMenubar = () => { - this.props.Document._chromeStatus = this.props.Document._chromeStatus === "disabled" ? "enabled" : "disabled"; + this.layoutDoc._chromeStatus = this.layoutDoc._chromeStatus === "disabled" ? "enabled" : "disabled"; } recordBullet = async () => { @@ -630,10 +616,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp ); this._disposers.editorState = reaction( () => { - if (this.dataDoc[this.props.fieldKey + "-noTemplate"] || !this.props.Document[this.props.fieldKey + "-textTemplate"]) { + if (this.dataDoc[this.props.fieldKey + "-noTemplate"] || !this.layoutDoc[this.props.fieldKey + "-textTemplate"]) { return Cast(this.dataDoc[this.props.fieldKey], RichTextField, null)?.Data; } - return Cast(this.props.Document[this.props.fieldKey + "-textTemplate"], RichTextField, null)?.Data; + return Cast(this.layoutDoc[this.props.fieldKey + "-textTemplate"], RichTextField, null)?.Data; }, incomingValue => { if (incomingValue !== undefined && this._editorView && !this._applyingChange) { @@ -690,7 +676,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp const nodes: Node[] = []; frag.forEach((node, index) => { const examinedNode = findLinkNode(node, editor); - if (examinedNode && examinedNode.textContent) { + if (examinedNode?.textContent) { nodes.push(examinedNode); start += index; } @@ -707,7 +693,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp return linkIndex !== -1 && scrollToLinkID === marks[linkIndex].attrs.href.replace(/.*\/doc\//, "") ? node : undefined; }; - let start = -1; + let start = 0; if (this._editorView && scrollToLinkID) { const editor = this._editorView; const ret = findLinkFrag(editor.state.doc.content, editor); @@ -728,7 +714,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp }, { fireImmediately: true } ); - this._disposers.scroll = reaction(() => NumCast(this.props.Document.scrollPos), + this._disposers.scroll = reaction(() => NumCast(this.layoutDoc.scrollPos), pos => this._scrollRef.current && this._scrollRef.current.scrollTo({ top: pos }), { fireImmediately: true } ); @@ -849,7 +835,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp targetAnnotations?.push(pdfRegion); }); - const link = DocUtils.MakeLink({ doc: this.props.Document }, { doc: pdfRegion }, "PDF pasted"); + const link = DocUtils.MakeLink({ doc: this.rootDoc }, { doc: pdfRegion }, "PDF pasted"); if (link) { cbe.clipboardData!.setData("dash/linkDoc", link[Id]); const linkId = link[Id]; @@ -886,8 +872,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp private setupEditor(config: any, fieldKey: string) { const curText = Cast(this.dataDoc[this.props.fieldKey], RichTextField, null); - const useTemplate = !curText?.Text && this.props.Document[this.props.fieldKey + "-textTemplate"]; - const rtfField = Cast((useTemplate && this.props.Document[this.props.fieldKey + "-textTemplate"]) || this.dataDoc[fieldKey], RichTextField); + const useTemplate = !curText?.Text && this.layoutDoc[this.props.fieldKey + "-textTemplate"]; + const rtfField = Cast((useTemplate && this.layoutDoc[this.props.fieldKey + "-textTemplate"]) || this.dataDoc[fieldKey], RichTextField); if (this.ProseRef) { const self = this; this._editorView?.destroy(); @@ -983,9 +969,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp if (this.props.onClick && e.button === 0 && !this.props.isSelected(false)) { e.preventDefault(); } - if (e.button === 0 && this.active(true) && !e.altKey && !e.ctrlKey && !e.metaKey) { - if (e.clientX < this.ProseRef!.getBoundingClientRect().right) { // don't stop propagation if clicking in the sidebar - //e.stopPropagation(); + if (e.button === 0 && this.props.isSelected(true) && !e.altKey && !e.ctrlKey && !e.metaKey) { + if (e.clientX < this.ProseRef!.getBoundingClientRect().right) { // stop propagation if not in sidebar + e.stopPropagation(); // if the text box is selected, then it consumes all down events } } if (e.button === 2 || (e.button === 0 && e.ctrlKey)) { @@ -1023,7 +1009,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp // jump rich text menu to this textbox const bounds = this._ref.current?.getBoundingClientRect(); - if (bounds && this.props.Document._chromeStatus !== "disabled") { + if (bounds && this.layoutDoc._chromeStatus !== "disabled") { const x = Math.min(Math.max(bounds.left, 0), window.innerWidth - RichTextMenu.Instance.width); let y = Math.min(Math.max(0, bounds.top - RichTextMenu.Instance.height - 50), window.innerHeight - RichTextMenu.Instance.height); if (coords && coords.left > x && coords.left < x + RichTextMenu.Instance.width && coords.top > y && coords.top < y + RichTextMenu.Instance.height + 50) { @@ -1059,43 +1045,14 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } if ((e.nativeEvent as any).formattedHandled) { e.stopPropagation(); return; } (e.nativeEvent as any).formattedHandled = true; - // if (e.button === 0 && ((!this.props.isSelected(true) && !e.ctrlKey) || (this.props.isSelected(true) && e.ctrlKey)) && !e.metaKey && e.target) { - // let href = (e.target as any).href; - // let location: string; - // if ((e.target as any).attributes.location) { - // location = (e.target as any).attributes.location.value; - // } - // let pcords = this._editorView!.posAtCoords({ left: e.clientX, top: e.clientY }); - // let node = pcords && this._editorView!.state.doc.nodeAt(pcords.pos); - // if (node) { - // let link = node.marks.find(m => m.type === this._editorView!.state.schema.marks.link); - // if (link && !(link.attrs.docref && link.attrs.title)) { // bcz: getting hacky. this indicates that we clicked on a PDF excerpt quotation. In this case, we don't want to follow the link (we follow only the actual hyperlink for the quotation which is handled above). - // href = link && link.attrs.href; - // location = link && link.attrs.location; - // } - // } - // if (href) { - // if (href.indexOf(Utils.prepend("/doc/")) === 0) { - // let linkClicked = href.replace(Utils.prepend("/doc/"), "").split("?")[0]; - // if (linkClicked) { - // DocServer.GetRefField(linkClicked).then(async linkDoc => { - // (linkDoc instanceof Doc) && - // DocumentManager.Instance.FollowLink(linkDoc, this.props.Document, document => this.props.addDocTab(document, location ? location : "inTab"), false); - // }); - // } - // } else { - // let webDoc = Docs.Create.WebDocument(href, { x: NumCast(this.layoutDoc.x, 0) + NumCast(this.layoutDoc.width, 0), y: NumCast(this.layoutDoc.y) }); - // this.props.addDocument && this.props.addDocument(webDoc); - // } - // e.stopPropagation(); - // e.preventDefault(); - // } - // } if (Math.abs(e.clientX - this._downX) < 4 && Math.abs(e.clientX - this._downX) < 4) { this.props.select(e.ctrlKey); this.hitBulletTargets(e.clientX, e.clientY, e.shiftKey, false); } + if (this.props.isSelected(true)) { // if text box is selected, then it consumes all click events + e.stopPropagation(); + } } // this hackiness handles clicking on the list item bullets to do expand/collapse. the bullets are ::before pseudo elements so there's no real way to hit test against them. @@ -1212,7 +1169,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } onscrolled = (ev: React.UIEvent) => { - this.props.Document.scrollPos = this._scrollRef.current!.scrollTop; + this.layoutDoc.scrollPos = this._scrollRef.current!.scrollTop; } @action tryUpdateHeight(limitHeight?: number) { @@ -1243,7 +1200,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } } - @computed get sidebarWidthPercent() { return StrCast(this.props.Document.sidebarWidthPercent, "0%"); } + @computed get sidebarWidthPercent() { return StrCast(this.layoutDoc._sidebarWidthPercent, "0%"); } sidebarWidth = () => Number(this.sidebarWidthPercent.substring(0, this.sidebarWidthPercent.length - 1)) / 100 * this.props.PanelWidth(); sidebarScreenToLocal = () => this.props.ScreenToLocalTransform().translate(-(this.props.PanelWidth() - this.sidebarWidth()), 0); @computed get sidebarColor() { return StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], "transparent")); } @@ -1306,8 +1263,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp pointerEvents: ((this.layoutDoc.isLinkButton || this.props.onClick) && !this.props.isSelected()) ? "none" : undefined }} />
- {!this.props.Document._showSidebar ? (null) : this.sidebarWidthPercent === "0%" ? -
this.toggleSidebar()} /> : + {!this.layoutDoc._showSidebar ? (null) : this.sidebarWidthPercent === "0%" ? +
:
-
this.toggleSidebar()} /> +
} - {!this.props.Document._showAudio ? (null) : + {!this.layoutDoc._showAudio ? (null) :
{ runInAction(() => this._recording = !this._recording); diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index b41007e9c..2d4a4539e 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -6,7 +6,7 @@ import { DocumentType } from "../client/documents/DocumentTypes"; import { Scripting, scriptingGlobal } from "../client/util/Scripting"; import { afterDocDeserialize, autoObject, Deserializable, SerializationHelper } from "../client/util/SerializationHelper"; import { UndoManager } from "../client/util/UndoManager"; -import { intersectRect } from "../Utils"; +import { intersectRect, Utils } from "../Utils"; import { HandleUpdate, Id, OnUpdate, Parent, Self, SelfProxy, ToScriptString, ToString, Update, Copy } from "./FieldSymbols"; import { List } from "./List"; import { ObjectField } from "./ObjectField"; @@ -20,6 +20,7 @@ import { deleteProperty, getField, getter, makeEditable, makeReadOnly, setter, u import { Docs, DocumentOptions } from "../client/documents/Documents"; import { PdfField, VideoField, AudioField, ImageField } from "./URLField"; import { LinkManager } from "../client/util/LinkManager"; +import { string32 } from "../../deploy/assets/pdf.worker"; export namespace Field { export function toKeyValueString(doc: Doc, key: string): string { @@ -590,47 +591,64 @@ export namespace Doc { return copy; } - export function MakeClone(doc: Doc, cloneMap: Map = new Map()): Doc { + export function MakeClone(doc: Doc): Doc { + let cloneMap = new Map(); + let rtfMap: { copy: Doc, key: string, field: RichTextField }[] = []; + const copy = Doc.makeClone(doc, cloneMap, rtfMap); + rtfMap.map(({ copy, key, field }) => { + const replacer = (match: any, attr: string, id: string, offset: any, string: any) => { + const mapped = cloneMap.get(id); + return attr + "\"" + (mapped ? mapped[Id] : id) + "\""; + }; + const replacer2 = (match: any, href: string, id: string, offset: any, string: any) => { + const mapped = cloneMap.get(id); + return href + (mapped ? mapped[Id] : id); + }; + const regex = `(${Utils.prepend("/doc/")})([^"]*)`; + var re = new RegExp(regex, "g"); + copy[key] = new RichTextField(field.Data.replace(/("docid":|"targetId":|"linkId":)"([^"]+)"/g, replacer).replace(re, replacer2), field.Text); + }); + return copy; + } + + export function makeClone(doc: Doc, cloneMap: Map, rtfs: { copy: Doc, key: string, field: RichTextField }[]): Doc { if (Doc.IsBaseProto(doc)) return doc; - if (cloneMap.get(doc)) return cloneMap.get(doc)!; + if (cloneMap.get(doc[Id])) return cloneMap.get(doc[Id])!; const copy = new Doc(undefined, true); - cloneMap.set(doc, copy); - if (LinkManager.Instance.getAllLinks().includes(doc)) LinkManager.Instance.addLink(copy); + cloneMap.set(doc[Id], copy); + if (LinkManager.Instance.getAllLinks().includes(doc) && LinkManager.Instance.getAllLinks().indexOf(copy) === -1) LinkManager.Instance.addLink(copy); const exclude = Cast(doc.excludeFields, listSpec("string"), []); Object.keys(doc).forEach(key => { if (exclude.includes(key)) return; const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key])); const field = ProxyField.WithoutProxy(() => doc[key]); + const copyObjectField = (field: ObjectField) => { + const list = Cast(doc[key], listSpec(Doc)); + if (list !== undefined && !(list instanceof Promise)) { + copy[key] = new List(list.filter(d => d instanceof Doc).map(d => Doc.makeClone(d as Doc, cloneMap, rtfs))); + } else if (doc[key] instanceof Doc) + copy[key] = key.includes("layout[") ? undefined : Doc.makeClone(doc[key] as Doc, cloneMap, rtfs); // reference documents except copy documents that are expanded teplate fields + else { + copy[key] = ObjectField.MakeCopy(field); + if (field instanceof RichTextField) { + if (field.Data.includes('"docid":') || field.Data.includes('"targetId":') || field.Data.includes('"linkId":')) { + rtfs.push({ copy, key, field }); + } + } + } + } if (key === "proto") { if (doc[key] instanceof Doc) { - copy[key] = Doc.MakeClone(doc[key]!, cloneMap); + copy[key] = Doc.makeClone(doc[key]!, cloneMap, rtfs); } } else { if (field instanceof RefField) { copy[key] = field; } else if (cfield instanceof ComputedField) { copy[key] = ComputedField.MakeFunction(cfield.script.originalScript); - if (field instanceof ObjectField) { - const list = Cast(doc[key], listSpec(Doc)); - if (list !== undefined && !(list instanceof Promise)) { - copy[key] = new List(list.filter(d => d instanceof Doc).map(d => Doc.MakeClone(d as Doc, cloneMap))); - } else { - copy[key] = doc[key] instanceof Doc ? - key.includes("layout[") ? - undefined : Doc.MakeClone(doc[key] as Doc, cloneMap) : // reference documents except copy documents that are expanded teplate fields - ObjectField.MakeCopy(field); - } - } + (key === "links" && field instanceof ObjectField) && copyObjectField(field); } else if (field instanceof ObjectField) { - const list = Cast(doc[key], listSpec(Doc)); - if (list !== undefined && !(list instanceof Promise)) { - copy[key] = new List(list.filter(d => d instanceof Doc).map(d => Doc.MakeClone(d as Doc, cloneMap))); - } else { - copy[key] = doc[key] instanceof Doc ? - key.includes("layout[") ? - undefined : Doc.MakeClone(doc[key] as Doc, cloneMap) : // reference documents except copy documents that are expanded teplate fields - ObjectField.MakeCopy(field); - } + copyObjectField(field); } else if (field instanceof Promise) { debugger; //This shouldn't happend... } else { @@ -640,7 +658,7 @@ export namespace Doc { }); Doc.SetInPlace(copy, "title", "CLONE: " + doc.title, true); copy.cloneOf = doc; - cloneMap.set(doc, copy); + cloneMap.set(doc[Id], copy); return copy; } diff --git a/src/new_fields/documentSchemas.ts b/src/new_fields/documentSchemas.ts index e7d27d81e..cacba43b6 100644 --- a/src/new_fields/documentSchemas.ts +++ b/src/new_fields/documentSchemas.ts @@ -44,6 +44,7 @@ export const documentSchema = createSchema({ _chromeStatus: "string", // determines the state of the collection chrome. values allowed are 'replaced', 'enabled', 'disabled', 'collapsed' _fontSize: "number", _fontFamily: "string", + _sidebarWidthPercent: "string", // percent of text window width taken up by sidebar // appearance properties on the data document backgroundColor: "string", // background color of document -- cgit v1.2.3-70-g09d2 From c3e6acaff6efce9e973354c61b7250fa4046e113 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 6 May 2020 15:00:34 -0400 Subject: fixed label box overflow. fixed linking to items in a stacking panel. --- .../views/collections/CollectionStackingView.tsx | 22 +++++++++++++++++-- src/client/views/collections/CollectionSubView.tsx | 25 +++++++++++++++++++++- .../CollectionFreeFormLinksView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 4 +++- src/client/views/nodes/LabelBox.scss | 11 +++------- src/client/views/nodes/LabelBox.tsx | 7 ++---- 6 files changed, 53 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index b6faea845..4cc2e1a5f 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -12,7 +12,7 @@ import { listSpec, makeInterface } from "../../../new_fields/Schema"; import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField"; import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../new_fields/Types"; import { TraceMobx } from "../../../new_fields/util"; -import { emptyFunction, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils } from "../../../Utils"; +import { emptyFunction, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils, smoothScroll } from "../../../Utils"; import { DragManager, dropActionType } from "../../util/DragManager"; import { Transform } from "../../util/Transform"; import { undoBatch } from "../../util/UndoManager"; @@ -165,6 +165,24 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument) return this.props.addDocTab(doc, where); } + + focusDocument = (doc: Doc, willZoom: boolean, scale?: number, afterFocus?: () => boolean) => { + Doc.BrushDoc(this.props.Document); + this.props.focus(this.props.Document); + Doc.linkFollowHighlight(doc); + + const found = this._mainCont && Array.from(this._mainCont.getElementsByClassName("documentView-node")).find((node: any) => node.id === doc[Id]); + if (found) { + const top = found.getBoundingClientRect().top; + const localTop = this.props.ScreenToLocalTransform().transformPoint(0, top); + smoothScroll(500, this._mainCont!, localTop[1] + this._mainCont!.scrollTop); + } + afterFocus && setTimeout(() => { + if (afterFocus?.()) { + } + }, 500); + } + getDisplayDoc(doc: Doc, dataDoc: Doc | undefined, dxf: () => Transform, width: () => number) { const layoutDoc = Doc.Layout(doc, this.props.ChildLayoutTemplate?.()); const height = () => this.getDocHeight(doc); @@ -187,7 +205,7 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument) onClick={this.onChildClickHandler} onDoubleClick={this.onChildDoubleClickHandler} ScreenToLocalTransform={dxf} - focus={this.props.focus} + focus={this.focusDocument} ContainingCollectionDoc={this.props.CollectionView?.props.Document} ContainingCollectionView={this.props.CollectionView} addDocument={this.props.addDocument} diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index b4ca29b19..8c78e568c 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -231,7 +231,21 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: } return false; } + readUploadedFileAsText = (inputFile: File) => { + const temporaryFileReader = new FileReader(); + return new Promise((resolve, reject) => { + temporaryFileReader.onerror = () => { + temporaryFileReader.abort(); + reject(new DOMException("Problem parsing input file.")); + }; + + temporaryFileReader.onload = () => { + resolve(temporaryFileReader.result); + }; + temporaryFileReader.readAsText(inputFile); + }); + }; @undoBatch @action protected async onExternalDrop(e: React.DragEvent, options: DocumentOptions, completed?: () => void) { @@ -369,7 +383,16 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: } if (item.kind === "file") { const file = item.getAsFile(); - file && file.type && files.push(file); + file?.type && files.push(file); + + file?.type === "application/json" && this.readUploadedFileAsText(file).then(result => { + console.log(result); + const json = JSON.parse(result as string) as any; + addDocument(Docs.Create.TreeDocument( + json["rectangular-puzzle"].crossword.clues[0].clue.map((c: any) => + Docs.Create.LabelDocument({ title: c["#text"], _width: 120, _height: 20 }) + ), { _width: 150, _height: 600, title: "across", backgroundColor: "white", _singleLine: true })); + }); } } for (const { source: { name, type }, result } of await Networking.UploadFilesToServer(files)) { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index 5e5ad7db5..1208fb324 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -31,7 +31,7 @@ export class CollectionFreeFormLinksView extends React.Component { }, [] as { a: DocumentView, b: DocumentView, l: Doc[] }[]); return connections.filter(c => c.a.props.Document.type === DocumentType.LINK && - c.a.props.bringToFront !== emptyFunction && c.b.props.bringToFront !== emptyFunction // bcz: this prevents links to be drawn to anchors in CollectionTree views -- this is a hack that should be fixed + c.a.props.pinToPres !== emptyFunction && c.b.props.pinToPres !== emptyFunction // bcz: this prevents links to be drawn to anchors in CollectionTree views -- this is a hack that should be fixed ).map(c => ); } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 2d5d7d231..1724d39cc 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1143,7 +1143,9 @@ export class DocumentView extends DocComponent(Docu const highlightStyles = ["solid", "dashed", "solid", "solid", "solid", "solid", "solid"]; let highlighting = fullDegree && this.layoutDoc.type !== DocumentType.FONTICON && this.layoutDoc._viewType !== CollectionViewType.Linear; highlighting = highlighting && this.props.focus !== emptyFunction; // bcz: hack to turn off highlighting onsidebar panel documents. need to flag a document as not highlightable in a more direct way - return
Doc.BrushDoc(this.props.Document)} // onPointerLeave={e => Doc.BrushDoc(this.props.Document)} diff --git a/src/client/views/nodes/LabelBox.scss b/src/client/views/nodes/LabelBox.scss index 7c7e92379..5be23d2c2 100644 --- a/src/client/views/nodes/LabelBox.scss +++ b/src/client/views/nodes/LabelBox.scss @@ -8,19 +8,14 @@ .labelBox-mainButton { width: 100%; - height: 100%; + height: max-content; border-radius: inherit; letter-spacing: 2px; text-transform: uppercase; overflow: hidden; - display:flex; -} - -.labelBox-mainButtonCenter { - overflow: hidden; - display: inline; - align-items: center; + display: inline-block; margin: auto; + text-overflow: ellipsis; } .labelBox-params { diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx index 3cdec8acb..ac27640bd 100644 --- a/src/client/views/nodes/LabelBox.tsx +++ b/src/client/views/nodes/LabelBox.tsx @@ -80,12 +80,9 @@ export class LabelBox extends ViewBoxBaseComponent -
- {StrCast(this.rootDoc.text, StrCast(this.rootDoc.title))} -
+ {StrCast(this.rootDoc.text, StrCast(this.rootDoc.title))}
{!missingParams?.length ? (null) : missingParams.map(m =>
{m}
)} -- cgit v1.2.3-70-g09d2 From 7e2b162446a7f384ef2781fd786a97c21d1a172b Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 6 May 2020 18:33:21 -0400 Subject: fix for labelbox layout --- src/client/views/nodes/LabelBox.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/nodes/LabelBox.scss b/src/client/views/nodes/LabelBox.scss index 5be23d2c2..9e3ff96a7 100644 --- a/src/client/views/nodes/LabelBox.scss +++ b/src/client/views/nodes/LabelBox.scss @@ -7,7 +7,7 @@ } .labelBox-mainButton { - width: 100%; + width: fit-content; height: max-content; border-radius: inherit; letter-spacing: 2px; -- cgit v1.2.3-70-g09d2 From 51a1f88b4e975946eb5ac8cef75a122e197cd872 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 7 May 2020 01:35:11 -0400 Subject: added batch requesting of list items. fixed some performance issues with tree views. --- src/client/DocServer.ts | 64 +++++++++++------- src/client/util/Scripting.ts | 2 +- src/client/views/DocumentButtonBar.tsx | 32 ++++----- src/client/views/DocumentDecorations.tsx | 2 +- .../views/collections/CollectionDockingView.tsx | 8 +-- .../views/collections/CollectionStackingView.tsx | 10 ++- .../views/collections/CollectionTreeView.scss | 1 - .../views/collections/CollectionTreeView.tsx | 18 +++-- .../views/collections/ParentDocumentSelector.tsx | 4 +- src/new_fields/List.ts | 76 +++++++++++++++------- src/new_fields/Proxy.ts | 18 ++++- .../authentication/models/current_user_utils.ts | 13 ++-- src/server/database.ts | 2 +- 13 files changed, 161 insertions(+), 89 deletions(-) (limited to 'src') diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index 0c9d5f75c..bf9fd232c 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -7,6 +7,7 @@ import { RefField } from '../new_fields/RefField'; import { Id, HandleUpdate } from '../new_fields/FieldSymbols'; import GestureOverlay from './views/GestureOverlay'; import MobileInkOverlay from '../mobile/MobileInkOverlay'; +import { runInAction } from 'mobx'; /** * This class encapsulates the transfer and cross-client synchronization of @@ -109,6 +110,7 @@ export namespace DocServer { GUID = identifier; _socket = OpenSocket(`${protocol}//${hostname}:${port}`); + _GetCachedRefField = _GetCachedRefFieldImpl; _GetRefField = _GetRefFieldImpl; _GetRefFields = _GetRefFieldsImpl; _CreateField = _CreateFieldImpl; @@ -243,12 +245,22 @@ export namespace DocServer { return Promise.resolve(cached); } }; + const _GetCachedRefFieldImpl = (id: string): Opt => { + const cached = _cache[id]; + if (cached !== undefined && !(cached instanceof Promise)) { + return cached; + } + } let _GetRefField: (id: string) => Promise> = errorFunc; + let _GetCachedRefField: (id: string) => Opt = errorFunc; export function GetRefField(id: string): Promise> { return _GetRefField(id); } + export function GetCachedRefField(id: string): Opt { + return _GetCachedRefField(id); + } export async function getYoutubeChannels() { const apiKey = await Utils.EmitCallback(_socket, MessageStore.YoutubeApiQuery, { type: YoutubeQueryTypes.Channels }); @@ -308,32 +320,34 @@ export namespace DocServer { const deserializeFields = getSerializedFields.then(async fields => { const fieldMap: { [id: string]: RefField } = {}; const proms: Promise[] = []; - for (const field of fields) { - if (field !== undefined && field !== null) { - // deserialize - const prom = SerializationHelper.Deserialize(field).then(deserialized => { - fieldMap[field.id] = deserialized; - - //overwrite or delete any promises (that we inserted as flags - // to indicate that the field was in the process of being fetched). Now everything - // should be an actual value within or entirely absent from the cache. - if (deserialized !== undefined) { - _cache[field.id] = deserialized; - } else { - delete _cache[field.id]; - } - return deserialized; - }); - // 4) here, for each of the documents we've requested *ourselves* (i.e. weren't promises or found in the cache) - // we set the value at the field's id to a promise that will resolve to the field. - // When we find that promises exist at keys in the cache, THIS is where they were set, just by some other caller (method). - // The mapping in the .then call ensures that when other callers await these promises, they'll - // get the resolved field - _cache[field.id] = prom; - // adds to a list of promises that will be awaited asynchronously - proms.push(prom); + runInAction(() => { + for (const field of fields) { + if (field !== undefined && field !== null) { + // deserialize + const prom = SerializationHelper.Deserialize(field).then(deserialized => { + fieldMap[field.id] = deserialized; + + //overwrite or delete any promises (that we inserted as flags + // to indicate that the field was in the process of being fetched). Now everything + // should be an actual value within or entirely absent from the cache. + if (deserialized !== undefined) { + _cache[field.id] = deserialized; + } else { + delete _cache[field.id]; + } + return deserialized; + }); + // 4) here, for each of the documents we've requested *ourselves* (i.e. weren't promises or found in the cache) + // we set the value at the field's id to a promise that will resolve to the field. + // When we find that promises exist at keys in the cache, THIS is where they were set, just by some other caller (method). + // The mapping in the .then call ensures that when other callers await these promises, they'll + // get the resolved field + _cache[field.id] = prom; + // adds to a list of promises that will be awaited asynchronously + proms.push(prom); + } } - } + }); await Promise.all(proms); return fieldMap; }); diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts index 12628273b..8b7b9c9c7 100644 --- a/src/client/util/Scripting.ts +++ b/src/client/util/Scripting.ts @@ -136,7 +136,7 @@ function Run(script: string | undefined, customParams: string[], diagnostics: an if (batch) { batch.end(); } - onError && onError(error); + onError?.(error); return { success: false, error, result: errorVal }; } }; diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index cf57094b2..d58eb5875 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -50,11 +50,9 @@ enum UtilityButtonState { } @observer -export class DocumentButtonBar extends React.Component<{ views: (DocumentView | undefined)[], stack?: any }, {}> { +export class DocumentButtonBar extends React.Component<{ views: () => (DocumentView | undefined)[], stack?: any }, {}> { private _linkButton = React.createRef(); private _dragRef = React.createRef(); - private _downX = 0; - private _downY = 0; private _pullAnimating = false; private _pushAnimating = false; private _pullColorAnimating = false; @@ -71,7 +69,7 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView | public static hasPushedHack = false; public static hasPulledHack = false; - constructor(props: { views: (DocumentView | undefined)[] }) { + constructor(props: { views: () => (DocumentView | undefined)[] }) { super(props); runInAction(() => DocumentButtonBar.Instance = this); } @@ -113,7 +111,7 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView | this._pullColorAnimating = false; }); - get view0() { return this.props.views?.[0]; } + get view0() { return this.props.views()?.[0]; } @action onLinkButtonMoved = (e: PointerEvent) => { @@ -265,7 +263,7 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView | const view0 = this.view0; return !view0 ? (null) :
this.props.views.filter(dv => dv).map(dv => dv!.props.Document)} suggestWithFunction /> /* tfs: @bcz This might need to be the data document? */}> + content={ this.props.views().filter(dv => dv).map(dv => dv!.props.Document)} suggestWithFunction /> /* tfs: @bcz This might need to be the data document? */}>
e.stopPropagation()} > {}
@@ -289,7 +287,7 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView | } onAliasButtonMoved = () => { if (this._dragRef.current) { - const dragDocView = this.props.views[0]!; + const dragDocView = this.view0!; const dragData = new DragManager.DocumentDragData([dragDocView.props.Document]); const [left, top] = dragDocView.props.ScreenToLocalTransform().inverse().transformPoint(0, 0); dragData.embedDoc = true; @@ -308,16 +306,18 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView | get templateButton() { const view0 = this.view0; const templates: Map = new Map(); + const views = this.props.views(); Array.from(Object.values(Templates.TemplateList)).map(template => - templates.set(template, this.props.views.reduce((checked, doc) => checked || doc?.props.Document["_show" + template.Name] ? true : false, false as boolean))); - return !view0 ? (null) :
- this._aliasDown = true)} onClose={action(() => this._aliasDown = false)} - content={!this._aliasDown ? (null) : v).map(v => v as DocumentView)} templates={templates} />}> -
- {} -
-
-
; + templates.set(template, views.reduce((checked, doc) => checked || doc?.props.Document["_show" + template.Name] ? true : false, false as boolean))); + return !view0 ? (null) : +
+ this._aliasDown = true)} onClose={action(() => this._aliasDown = false)} + content={!this._aliasDown ? (null) : v).map(v => v as DocumentView)} templates={templates} />}> +
+ {} +
+
+
; } render() { diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index b89806656..9b6105811 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -499,7 +499,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
- +
); diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 6cd5d1b1b..6f5989052 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -517,14 +517,14 @@ export class CollectionDockingView extends React.Component ((view: Opt) => view ? [view] : [])(DocumentManager.Instance.getDocumentView(doc)), (views) => { - !rendered && ReactDOM.render( - + ReactDOM.render( + views} Stack={stack} /> , gearSpan); - rendered = true; + tab.buttonDisposer?.(); }); tab.reactComponents = [gearSpan]; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 4cc2e1a5f..c199988c0 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -57,6 +57,14 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument) } @computed get NodeWidth() { return this.props.PanelWidth() - this.gridGap; } + constructor(props: any) { + super(props); + + if (this.sectionHeaders === undefined) { + this.props.Document.sectionHeaders = new List(); + } + } + children(docs: Doc[], columns?: number) { TraceMobx(); this._docXfs.length = 0; @@ -85,7 +93,7 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument) setTimeout(() => this.props.Document.sectionHeaders = new List(), 0); return new Map(); } - const sectionHeaders: SchemaHeaderField[] = Array.from(this.sectionHeaders); + const sectionHeaders = Array.from(this.sectionHeaders); const fields = new Map(sectionHeaders.map(sh => [sh, []] as [SchemaHeaderField, []])); let changed = false; this.filteredChildren.map(d => { diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss index a00bb6bfb..2aac81146 100644 --- a/src/client/views/collections/CollectionTreeView.scss +++ b/src/client/views/collections/CollectionTreeView.scss @@ -81,7 +81,6 @@ position: relative; text-overflow: ellipsis; white-space: pre-wrap; - overflow: hidden; min-width: 10px; // width:100%;//width: max-content; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 297c11e35..4fb54cc07 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -34,6 +34,7 @@ import "./CollectionTreeView.scss"; import { CollectionViewType } from './CollectionView'; import React = require("react"); import { makeTemplate } from '../../util/DropConverter'; +import { TraceMobx } from '../../../new_fields/util'; export interface TreeViewProps { @@ -100,7 +101,7 @@ class TreeView extends React.Component { get defaultExpandedView() { return this.childDocs ? this.fieldKey : StrCast(this.props.document.defaultExpandedView, "fields"); } @observable _overrideTreeViewOpen = false; // override of the treeViewOpen field allowing the display state to be independent of the document's state set treeViewOpen(c: boolean) { if (this.props.treeViewPreventOpen) this._overrideTreeViewOpen = c; else this.props.document.treeViewOpen = this._overrideTreeViewOpen = c; } - @computed get treeViewOpen() { return (!this.props.treeViewPreventOpen && BoolCast(this.props.document.treeViewOpen)) || this._overrideTreeViewOpen; } + @computed get treeViewOpen() { return (!this.props.treeViewPreventOpen && !this.props.document.treeViewPreventOpen && BoolCast(this.props.document.treeViewOpen)) || this._overrideTreeViewOpen; } @computed get treeViewExpandedView() { return StrCast(this.props.document.treeViewExpandedView, this.defaultExpandedView); } @computed get MAX_EMBED_HEIGHT() { return NumCast(this.props.containingCollection.maxEmbedHeight, 200); } @computed get dataDoc() { return this.templateDataDoc ? this.templateDataDoc : this.props.document; } @@ -326,6 +327,7 @@ class TreeView extends React.Component { rtfHeight = () => this.rtfWidth() < Doc.Layout(this.props.document)?.[WidthSym]() ? Math.min(Doc.Layout(this.props.document)?.[HeightSym](), this.MAX_EMBED_HEIGHT) : this.MAX_EMBED_HEIGHT; @computed get renderContent() { + TraceMobx(); const expandKey = this.treeViewExpandedView === this.fieldKey ? this.fieldKey : this.treeViewExpandedView === "links" ? "links" : undefined; if (expandKey !== undefined) { const remDoc = (doc: Doc) => this.remove(doc, expandKey); @@ -419,13 +421,15 @@ class TreeView extends React.Component { return [{ script: focusScript!, label: "Focus" }]; } _docRef = React.createRef(); + _editTitleScript: ScriptField | undefined; /** * Renders the EditableView title element for placement into the tree. */ @computed get renderTitle() { + TraceMobx(); const onItemDown = SetupDrag(this._tref, () => this.dataDoc, this.move, this.props.dropAction, this.props.treeViewId[Id], true); - const editTitle = ScriptField.MakeFunction("setInPlace(this, 'editTitle', true)"); + //!this._editTitleScript && (this._editTitleScript = ScriptField.MakeFunction("setInPlace(this, 'editTitle', true)")); const headerElements = ( <> @@ -449,7 +453,6 @@ class TreeView extends React.Component { return <>
{ ref={this._docRef} Document={this.props.document} DataDoc={undefined} - LibraryPath={this.props.libraryPath || []} + LibraryPath={this.props.libraryPath || emptyPath} addDocument={undefined} addDocTab={this.props.addDocTab} rootSelected={returnTrue} pinToPres={emptyFunction} - onClick={this.props.onChildClick || editTitle} + onClick={this.props.onChildClick || this._editTitleScript} dropAction={this.props.dropAction} moveDocument={this.move} removeDocument={this.removeDoc} @@ -478,7 +481,7 @@ class TreeView extends React.Component { NativeWidth={returnZero} contextMenuItems={this.contextMenuItems} renderDepth={1} - focus={emptyFunction} + focus={returnTrue} parentActive={returnTrue} whenActiveChanged={emptyFunction} bringToFront={emptyFunction} @@ -493,8 +496,9 @@ class TreeView extends React.Component { } render() { + TraceMobx(); const sorting = this.props.document[`${this.fieldKey}-sortAscending`]; - setTimeout(() => runInAction(() => untracked(() => this._overrideTreeViewOpen = this.treeViewOpen)), 0); + //setTimeout(() => runInAction(() => untracked(() => this._overrideTreeViewOpen = this.treeViewOpen)), 0); return
  • { diff --git a/src/client/views/collections/ParentDocumentSelector.tsx b/src/client/views/collections/ParentDocumentSelector.tsx index 10c6ead1a..6e4f801c0 100644 --- a/src/client/views/collections/ParentDocumentSelector.tsx +++ b/src/client/views/collections/ParentDocumentSelector.tsx @@ -94,7 +94,7 @@ export class ParentDocSelector extends React.Component { } @observer -export class DockingViewButtonSelector extends React.Component<{ views: DocumentView[], Stack: any }> { +export class DockingViewButtonSelector extends React.Component<{ views: () => DocumentView[], Stack: any }> { customStylesheet(styles: any) { return { ...styles, @@ -120,7 +120,7 @@ export class DockingViewButtonSelector extends React.Component<{ views: Document if (getComputedStyle(this._ref.current!).width !== "100%") { e.stopPropagation(); e.preventDefault(); } - this.props.views[0]?.select(false); + this.props.views()[0]?.select(false); }} className="buttonSelector"> diff --git a/src/new_fields/List.ts b/src/new_fields/List.ts index a43f11e82..fdabea365 100644 --- a/src/new_fields/List.ts +++ b/src/new_fields/List.ts @@ -2,12 +2,13 @@ import { Deserializable, autoObject, afterDocDeserialize } from "../client/util/ import { Field } from "./Doc"; import { setter, getter, deleteProperty, updateFunction } from "./util"; import { serializable, alias, list } from "serializr"; -import { observable, action } from "mobx"; +import { observable, action, runInAction } from "mobx"; import { ObjectField } from "./ObjectField"; import { RefField } from "./RefField"; import { ProxyField } from "./Proxy"; -import { Self, Update, Parent, OnUpdate, SelfProxy, ToScriptString, ToString, Copy } from "./FieldSymbols"; +import { Self, Update, Parent, OnUpdate, SelfProxy, ToScriptString, ToString, Copy, Id } from "./FieldSymbols"; import { Scripting } from "../client/util/Scripting"; +import { DocServer } from "../client/DocServer"; const listHandlers: any = { /// Mutator methods @@ -54,11 +55,13 @@ const listHandlers: any = { return res; }, sort(cmpFunc: any) { + this[Self].__realFields(); // coerce retrieving entire array const res = this[Self].__fields.sort(cmpFunc ? (first: any, second: any) => cmpFunc(toRealField(first), toRealField(second)) : undefined); this[Update](); return res; }, splice: action(function (this: any, start: number, deleteCount: number, ...items: any[]) { + this[Self].__realFields(); // coerce retrieving entire array items = items.map(toObjectField); const list = this[Self]; for (let i = 0; i < items.length; i++) { @@ -94,102 +97,102 @@ const listHandlers: any = { }, /// Accessor methods concat: action(function (this: any, ...items: any[]) { + this[Self].__realFields(); return this[Self].__fields.map(toRealField).concat(...items); }), includes(valueToFind: any, fromIndex: number) { - const fields = this[Self].__fields; if (valueToFind instanceof RefField) { - return fields.map(toRealField).includes(valueToFind, fromIndex); + return this[Self].__realFields().includes(valueToFind, fromIndex); } else { - return fields.includes(valueToFind, fromIndex); + return this[Self].__fields.includes(valueToFind, fromIndex); } }, indexOf(valueToFind: any, fromIndex: number) { - const fields = this[Self].__fields; if (valueToFind instanceof RefField) { - return fields.map(toRealField).indexOf(valueToFind, fromIndex); + return this[Self].__realFields().indexOf(valueToFind, fromIndex); } else { - return fields.indexOf(valueToFind, fromIndex); + return this[Self].__fields.indexOf(valueToFind, fromIndex); } }, join(separator: any) { + this[Self].__realFields(); return this[Self].__fields.map(toRealField).join(separator); }, lastIndexOf(valueToFind: any, fromIndex: number) { - const fields = this[Self].__fields; if (valueToFind instanceof RefField) { - return fields.map(toRealField).lastIndexOf(valueToFind, fromIndex); + return this[Self].__realFields().lastIndexOf(valueToFind, fromIndex); } else { - return fields.lastIndexOf(valueToFind, fromIndex); + return this[Self].__fields.lastIndexOf(valueToFind, fromIndex); } }, slice(begin: number, end: number) { + this[Self].__realFields(); return this[Self].__fields.slice(begin, end).map(toRealField); }, /// Iteration methods entries() { - return this[Self].__fields.map(toRealField).entries(); + return this[Self].__realFields().entries(); }, every(callback: any, thisArg: any) { - return this[Self].__fields.map(toRealField).every(callback, thisArg); + return this[Self].__realFields().every(callback, thisArg); // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. // If we don't want to support the array parameter, we should use this version instead // return this[Self].__fields.every((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg); }, filter(callback: any, thisArg: any) { - return this[Self].__fields.map(toRealField).filter(callback, thisArg); + return this[Self].__realFields().filter(callback, thisArg); // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. // If we don't want to support the array parameter, we should use this version instead // return this[Self].__fields.filter((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg); }, find(callback: any, thisArg: any) { - return this[Self].__fields.map(toRealField).find(callback, thisArg); + return this[Self].__realFields().find(callback, thisArg); // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. // If we don't want to support the array parameter, we should use this version instead // return this[Self].__fields.find((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg); }, findIndex(callback: any, thisArg: any) { - return this[Self].__fields.map(toRealField).findIndex(callback, thisArg); + return this[Self].__realFields().findIndex(callback, thisArg); // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. // If we don't want to support the array parameter, we should use this version instead // return this[Self].__fields.findIndex((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg); }, forEach(callback: any, thisArg: any) { - return this[Self].__fields.map(toRealField).forEach(callback, thisArg); + return this[Self].__realFields().forEach(callback, thisArg); // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. // If we don't want to support the array parameter, we should use this version instead // return this[Self].__fields.forEach((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg); }, map(callback: any, thisArg: any) { - return this[Self].__fields.map(toRealField).map(callback, thisArg); + return this[Self].__realFields().map(callback, thisArg); // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. // If we don't want to support the array parameter, we should use this version instead // return this[Self].__fields.map((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg); }, reduce(callback: any, initialValue: any) { - return this[Self].__fields.map(toRealField).reduce(callback, initialValue); + return this[Self].__realFields().reduce(callback, initialValue); // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. // If we don't want to support the array parameter, we should use this version instead // return this[Self].__fields.reduce((acc:any, element:any, index:number, array:any) => callback(acc, toRealField(element), index, array), initialValue); }, reduceRight(callback: any, initialValue: any) { - return this[Self].__fields.map(toRealField).reduceRight(callback, initialValue); + return this[Self].__realFields().reduceRight(callback, initialValue); // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. // If we don't want to support the array parameter, we should use this version instead // return this[Self].__fields.reduceRight((acc:any, element:any, index:number, array:any) => callback(acc, toRealField(element), index, array), initialValue); }, some(callback: any, thisArg: any) { - return this[Self].__fields.map(toRealField).some(callback, thisArg); + return this[Self].__realFields().some(callback, thisArg); // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. // If we don't want to support the array parameter, we should use this version instead // return this[Self].__fields.some((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg); }, values() { - return this[Self].__fields.map(toRealField).values(); + return this[Self].__realFields().values(); }, [Symbol.iterator]() { - return this[Self].__fields.map(toRealField).values(); + return this[Self].__realFields().values(); } }; @@ -254,6 +257,31 @@ class ListImpl extends ObjectField { [key: number]: T | (T extends RefField ? Promise : never); + // this requests all ProxyFields at the same time to avoid the overhead + // of separate network requests and separate updates to the React dom. + private __realFields() { + const waiting = this.__fields.filter(f => f instanceof ProxyField && f.promisedValue()); + const promised = waiting.map(f => f instanceof ProxyField ? f.promisedValue() : ""); + // if we find any ProxyFields that don't have a current value, then + // start the server request for all of them + if (promised.length) { + const promise = DocServer.GetRefFields(promised); + // as soon as we get the fields from the server, set all the list values in one + // action to generate one React dom update. + promise.then(fields => runInAction(() => { + waiting.map((w, i) => w instanceof ProxyField && w.setValue(fields[promised[i]])); + })); + // we also have to mark all lists items with this promise so that any calls to them + // will await the batch request. + // This counts on the handler for 'promise' in the call above being invoked before the + // handler for 'promise' in the lines below. + waiting.map((w, i) => { + w instanceof ProxyField && w.setPromise(promise.then(fields => fields[promised[i]])); + }); + } + return this.__fields.map(toRealField); + } + @serializable(alias("fields", list(autoObject(), { afterDeserialize: afterDocDeserialize }))) private get __fields() { return this.___fields; @@ -283,7 +311,7 @@ class ListImpl extends ObjectField { // console.log(diff); const update = this[OnUpdate]; // update && update(diff); - update && update(); + update?.(); } private [Self] = this; diff --git a/src/new_fields/Proxy.ts b/src/new_fields/Proxy.ts index d50c0f14e..555faaad0 100644 --- a/src/new_fields/Proxy.ts +++ b/src/new_fields/Proxy.ts @@ -1,7 +1,7 @@ import { Deserializable } from "../client/util/SerializationHelper"; import { FieldWaiting } from "./Doc"; import { primitive, serializable } from "serializr"; -import { observable, action } from "mobx"; +import { observable, action, runInAction } from "mobx"; import { DocServer } from "../client/DocServer"; import { RefField } from "./RefField"; import { ObjectField } from "./ObjectField"; @@ -61,6 +61,11 @@ export class ProxyField extends ObjectField { return undefined; } if (!this.promise) { + const cached = DocServer.GetCachedRefField(this.fieldId); + if (cached !== undefined) { + runInAction(() => this.cache = cached as any); + return cached as any; + } this.promise = DocServer.GetRefField(this.fieldId).then(action((field: any) => { this.promise = undefined; this.cache = field; @@ -70,6 +75,17 @@ export class ProxyField extends ObjectField { } return this.promise as any; } + promisedValue(): string { return !this.cache && !this.failed && !this.promise ? this.fieldId : ""; } + setPromise(promise: any) { + this.promise = promise; + } + @action + setValue(field: any) { + this.promise = undefined; + this.cache = field; + if (field === undefined) this.failed = true; + return field; + } } export namespace ProxyField { diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index e7b448358..6e06fe931 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -21,8 +21,7 @@ import { FormattedTextBox } from "../../../client/views/nodes/formattedText/Form import { MainView } from "../../../client/views/MainView"; import { DocumentType } from "../../../client/documents/DocumentTypes"; import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField"; -import { faBoxOpen } from "@fortawesome/free-solid-svg-icons"; -import { CollectionMulticolumnView, DimUnit } from "../../../client/views/collections/collectionMulticolumn/CollectionMulticolumnView"; +import { DimUnit } from "../../../client/views/collections/collectionMulticolumn/CollectionMulticolumnView"; export class CurrentUserUtils { private static curr_id: string; @@ -282,8 +281,12 @@ export class CurrentUserUtils { doc["template-icon-view-col"] as Doc, doc["template-icon-view-rtf"] as Doc], { title: "icon templates", _height: 75 })); } else { const templateIconsDoc = Cast(doc["template-icons"], Doc, null); - DocListCastAsync(templateIconsDoc).then(list => templateIconsDoc.data = new List([doc["template-icon-view"] as Doc, doc["template-icon-view-img"] as Doc, - doc["template-icon-view-col"] as Doc, doc["template-icon-view-rtf"] as Doc])); + const requiredTypes = [doc["template-icon-view"] as Doc, doc["template-icon-view-img"] as Doc, + doc["template-icon-view-col"] as Doc, doc["template-icon-view-rtf"] as Doc]; + DocListCastAsync(templateIconsDoc.data).then(async curIcons => { + await Promise.all(curIcons!); + requiredTypes.map(ntype => Doc.AddDocToList(templateIconsDoc, "data", ntype)); + }); } return doc["template-icons"] as Doc; } @@ -501,7 +504,7 @@ export class CurrentUserUtils { static setupDocumentCollection(doc: Doc) { if (doc.myDocuments === undefined) { doc.myDocuments = new PrefetchProxy(Docs.Create.TreeDocument([], { - title: "DOCUMENTS", _height: 42, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: true, lockedPosition: true, + title: "DOCUMENTS", _height: 42, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: false, lockedPosition: true, })); } return doc.myDocuments as Doc; diff --git a/src/server/database.ts b/src/server/database.ts index cfd707825..580f7f919 100644 --- a/src/server/database.ts +++ b/src/server/database.ts @@ -291,7 +291,7 @@ export namespace Database { } } - export const Instance: IDatabase = getDatabase(); + export const Instance = getDatabase(); export namespace Auxiliary { -- cgit v1.2.3-70-g09d2 From 34db0a78d2dc8989313decf8993691f40847b231 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 7 May 2020 18:13:16 -0400 Subject: fixes for adding/remove documents -- needs to be extended for views other than freeform. --- .../apis/google_docs/GooglePhotosClientUtils.ts | 23 +++-- src/client/views/collections/CollectionSubView.tsx | 26 +++--- src/client/views/collections/CollectionView.scss | 2 +- src/client/views/collections/CollectionView.tsx | 54 ++++++----- .../collectionFreeForm/CollectionFreeFormView.tsx | 101 +++++++++++++-------- .../collections/collectionFreeForm/MarqueeView.tsx | 13 +-- 6 files changed, 123 insertions(+), 96 deletions(-) (limited to 'src') diff --git a/src/client/apis/google_docs/GooglePhotosClientUtils.ts b/src/client/apis/google_docs/GooglePhotosClientUtils.ts index ff471853a..1e4c120bc 100644 --- a/src/client/apis/google_docs/GooglePhotosClientUtils.ts +++ b/src/client/apis/google_docs/GooglePhotosClientUtils.ts @@ -153,21 +153,20 @@ export namespace GooglePhotos { } const tagMapping = new Map(); const images = (await DocListCastAsync(collection.data))!.map(Doc.GetProto); - images && images.forEach(image => tagMapping.set(image[Id], ContentCategories.NONE)); - const values = Object.values(ContentCategories); + images?.forEach(image => tagMapping.set(image[Id], ContentCategories.NONE)); + const values = Object.values(ContentCategories).filter(value => value !== ContentCategories.NONE); for (const value of values) { - if (value === ContentCategories.NONE) { - continue; - } - for (const id of (await ContentSearch({ included: [value] }))?.mediaItems?.map(({ id }) => id)) { + const searched = (await ContentSearch({ included: [value] }))?.mediaItems?.map(({ id }) => id); + console.log("Searching " + value); + console.log(searched); + searched?.forEach(async id => { const image = await Cast(idMapping[id], Doc); - if (!image) { - continue; + if (image) { + const key = image[Id]; + const tags = tagMapping.get(key); + !tags?.includes(value) && tagMapping.set(key, tags + delimiter + value); } - const key = image[Id]; - const tags = tagMapping.get(key); - !tags?.includes(value) && tagMapping.set(key, tags + delimiter + value); - } + }); } images?.forEach(image => { const concatenated = tagMapping.get(image[Id])!; diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 8c78e568c..250c9b3b0 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -6,7 +6,7 @@ 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 { Cast } from "../../../new_fields/Types"; +import { Cast, ScriptCast } from "../../../new_fields/Types"; import { GestureUtils } from "../../../pen-gestures/GestureUtils"; import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; import { Upload } from "../../../server/SharedMediaTypes"; @@ -208,19 +208,18 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: @action protected onInternalDrop(e: Event, de: DragManager.DropEvent): boolean { const docDragData = de.complete.docDragData; - (this.props.Document.dropConverter instanceof ScriptField) && - this.props.Document.dropConverter.script.run({ dragData: docDragData }); /// bcz: check this + ScriptCast(this.props.Document.dropConverter)?.script.run({ dragData: docDragData }); if (docDragData) { let added = false; if (docDragData.dropAction || docDragData.userDropAction) { - added = docDragData.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d) || added, false); + added = this.props.addDocument(docDragData.droppedDocuments as any as Doc); } else if (docDragData.moveDocument) { - const movedDocs = docDragData.draggedDocuments; - added = movedDocs.reduce((added: boolean, d, i) => - docDragData.droppedDocuments[i] !== d ? this.props.addDocument(docDragData.droppedDocuments[i]) : - docDragData.moveDocument?.(d, this.props.Document, this.props.addDocument) || added, false); + const movedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] === d); + const addedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] !== d); + const res = addedDocs.length ? this.props.addDocument(addedDocs as any as Doc) : true; + added = movedDocs.length ? docDragData.moveDocument(movedDocs as any as Doc, this.props.Document, this.props.addDocument) : res; } else { - added = docDragData.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d) || added, false); + added = this.props.addDocument(docDragData.droppedDocuments as any as Doc); } e.stopPropagation(); return added; @@ -389,8 +388,13 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: console.log(result); const json = JSON.parse(result as string) as any; addDocument(Docs.Create.TreeDocument( - json["rectangular-puzzle"].crossword.clues[0].clue.map((c: any) => - Docs.Create.LabelDocument({ title: c["#text"], _width: 120, _height: 20 }) + json["rectangular-puzzle"].crossword.clues[0].clue.map((c: any) => { + const label = Docs.Create.LabelDocument({ title: c["#text"], _width: 120, _height: 20 }); + const proto = Doc.GetProto(label) + proto._width = 120; + proto._height = 20; + return proto; + } ), { _width: 150, _height: 600, title: "across", backgroundColor: "white", _singleLine: true })); }); } diff --git a/src/client/views/collections/CollectionView.scss b/src/client/views/collections/CollectionView.scss index d43dd387a..7877fe155 100644 --- a/src/client/views/collections/CollectionView.scss +++ b/src/client/views/collections/CollectionView.scss @@ -70,7 +70,7 @@ height: 30px; position: absolute; bottom: 15px; - left: 15px; + right: 15px; border: 2px solid black; border-radius: 50%; padding: 3px; diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 43da1c44f..ccfc660cc 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -15,9 +15,7 @@ import { ImageField } from '../../../new_fields/URLField'; import { TraceMobx } from '../../../new_fields/util'; 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'; -import { SelectionManager } from '../../util/SelectionManager'; import { ContextMenu } from "../ContextMenu"; import { FieldView, FieldViewProps } from '../nodes/FieldView'; import { ScriptBox } from '../ScriptBox'; @@ -45,7 +43,6 @@ 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'; import { CollectionPileView } from './CollectionPileView'; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; @@ -119,35 +116,32 @@ export class CollectionView extends Touchable this.props.whenActiveChanged(this._isChildActive = isActive); @action.bound - addDocument(doc: Doc): boolean { - if (this.props.filterAddDocument?.(doc) === false) { - return false; + addDocument = (doc: Doc): boolean => { + if (doc instanceof Doc) { + if (this.props.filterAddDocument?.(doc) === false) { + return false; + } } - + const docs = doc instanceof Doc ? [doc] : doc as any as Doc[]; const targetDataDoc = this.props.Document[DataSym]; const docList = DocListCast(targetDataDoc[this.props.fieldKey]); - !docList.includes(doc) && (targetDataDoc[this.props.fieldKey] = new List([...docList, doc])); // DocAddToList may write to targetdataDoc's parent ... we don't want this. should really change GetProto to GetDataDoc and test for resolvedDataDoc there - // Doc.AddDocToList(targetDataDoc, this.props.fieldKey, doc); - targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now())); - doc.context = this.props.Document; - Doc.GetProto(doc).lastOpened = new DateField; + const added = docs.filter(d => !docList.includes(d)); + if (added.length) { + added.map(doc => doc.context = this.props.Document); + targetDataDoc[this.props.fieldKey] = new List([...docList, ...added]); + targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now())); + } return true; } @action.bound - removeDocument(doc: Doc): boolean { + removeDocument = (doc: any): boolean => { + const docs = doc instanceof Doc ? [doc] : doc as Doc[]; const targetDataDoc = this.props.Document[DataSym]; - const docView = DocumentManager.Instance.getDocumentView(doc, this.props.ContainingCollectionView); - docView && SelectionManager.DeselectDoc(docView); const value = DocListCast(targetDataDoc[this.props.fieldKey]); - let index = value.reduce((p, v, i) => (v instanceof Doc && v === doc) ? i : p, -1); - index = index !== -1 ? index : value.reduce((p, v, i) => (v instanceof Doc && Doc.AreProtosEqual(v, doc)) ? i : p, -1); - - doc.context = undefined; - ContextMenu.Instance?.clearItems(); - if (index !== -1) { - value.splice(index, 1); - targetDataDoc[this.props.fieldKey] = new List(value); + const result = value.filter(v => !docs.includes(v)); + if (result.length !== value.length) { + targetDataDoc[this.props.fieldKey] = new List(result); return true; } return false; @@ -158,7 +152,7 @@ export class CollectionView extends Touchable boolean): boolean { + moveDocument = (doc: Doc, targetCollection: Doc | undefined, addDocument: (doc: Doc) => boolean): boolean => { if (Doc.AreProtosEqual(this.props.Document, targetCollection)) { return true; } @@ -166,10 +160,14 @@ export class CollectionView extends Touchable { - const children = DocListCast(this.props.Document[this.props.fieldKey]); - const imageProtos = children.filter(doc => Cast(doc.data, ImageField)).map(Doc.GetProto); - const allTagged = imageProtos.length > 0 && imageProtos.every(image => image.googlePhotosTags); - return !allTagged ? (null) : ; + return (null); + // this section would display an icon in the bototm right of a collection to indicate that all + // photos had been processed through Google's content analysis API and Google's tags had been + // assigned to the documents googlePhotosTags field. + // const children = DocListCast(this.props.Document[this.props.fieldKey]); + // const imageProtos = children.filter(doc => Cast(doc.data, ImageField)).map(Doc.GetProto); + // const allTagged = imageProtos.length > 0 && imageProtos.every(image => image.googlePhotosTags); + // return !allTagged ? (null) : ; } private SubViewHelper = (type: CollectionViewType, renderProps: CollectionRenderProps) => { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 37957b0f6..6011d5f9c 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -124,10 +124,15 @@ export class CollectionFreeFormView extends CollectionSubView { - const added = this.props.addDocument(newBox); - added && this.bringToFront(newBox); - added && this.updateCluster(newBox); - return added; + if (newBox instanceof Doc) { + const added = this.props.addDocument(newBox); + added && this.bringToFront(newBox); + added && this.updateCluster(newBox); + return added; + } else { + return this.props.addDocument(newBox); + // bcz: deal with clusters + } } private selectDocuments = (docs: Doc[]) => { SelectionManager.DeselectAll(); @@ -153,6 +158,7 @@ export class CollectionFreeFormView extends CollectionSubView pair.layout).slice().sort((doc1, doc2) => NumCast(doc1.zIndex) - NumCast(doc2.zIndex)); if (super.onInternalDrop(e, de)) { if (de.complete.docDragData) { if (de.complete.docDragData.droppedDocuments.length) { @@ -162,20 +168,25 @@ export class CollectionFreeFormView extends CollectionSubView { - const layoutDoc = Doc.Layout(d); - d.x = x + NumCast(d.x) - dropX; - d.y = y + NumCast(d.y) - dropY; - if (!NumCast(layoutDoc._width)) { - layoutDoc._width = 300; - } - if (!NumCast(layoutDoc._height)) { - const nw = NumCast(layoutDoc._nativeWidth); - const nh = NumCast(layoutDoc._nativeHeight); - layoutDoc._height = nw && nh ? nh / nw * NumCast(layoutDoc._width) : 300; + const droppedDocs = de.complete.docDragData.droppedDocuments; + runInAction(() => { + zsorted.forEach((doc, index) => doc.zIndex = index + 1); + for (let i = 0; i < droppedDocs.length; i++) { + const d = droppedDocs[i]; + const layoutDoc = Doc.Layout(d); + d.x = x + NumCast(d.x) - dropX; + d.y = y + NumCast(d.y) - dropY; + if (!NumCast(layoutDoc._width)) { + layoutDoc._width = 300; + } + if (!NumCast(layoutDoc._height)) { + const nw = NumCast(layoutDoc._nativeWidth); + const nh = NumCast(layoutDoc._nativeHeight); + layoutDoc._height = nw && nh ? nh / nw * NumCast(layoutDoc._width) : 300; + } + d.isBackground === undefined && (d.zIndex = zsorted.length + 1 + i); } - d.isBackground === undefined && this.bringToFront(d); - })); + }); (de.complete.docDragData.droppedDocuments.length === 1 || de.shiftKey) && this.updateClusterDocs(de.complete.docDragData.droppedDocuments); } @@ -760,20 +771,21 @@ export class CollectionFreeFormView extends CollectionSubView { + bringToFront = action((doc: Doc, sendToBack?: boolean) => { if (sendToBack || doc.isBackground) { doc.zIndex = 0; } else { const docs = this.childLayoutPairs.map(pair => pair.layout); - docs.slice().sort((doc1, doc2) => { - if (doc1 === doc) return 1; - if (doc2 === doc) return -1; - return NumCast(doc1.zIndex) - NumCast(doc2.zIndex); - }).forEach((doc, index) => doc.zIndex = index + 1); - doc.zIndex = docs.length + 1; + docs.slice().sort((doc1, doc2) => NumCast(doc1.zIndex) - NumCast(doc2.zIndex)); + let zlast = docs.length ? NumCast(docs[docs.length - 1].zIndex) : 1; + if (zlast - docs.length > 100) { + for (let i = 0; i < docs.length; i++) doc.zIndex = i + 1; + zlast = docs.length + 1; + } + doc.zIndex = zlast + 1; } - } + }) scaleAtPt(docpt: number[], scale: number) { const screenXY = this.getTransform().inverse().transformPoint(docpt[0], docpt[1]); @@ -895,14 +907,22 @@ export class CollectionFreeFormView extends CollectionSubView { if (where === "inParent") { - const pt = this.getTransform().transformPoint(NumCast(doc.x), NumCast(doc.y)); - doc.x = pt[0]; - doc.y = pt[1]; - this.props.addDocument(doc); - return true; + if (doc instanceof Doc) { + const pt = this.getTransform().transformPoint(NumCast(doc.x), NumCast(doc.y)); + doc.x = pt[0]; + doc.y = pt[1]; + return this.props.addDocument(doc); + } else { + (doc as any as Doc[]).forEach(doc => { + const pt = this.getTransform().transformPoint(NumCast(doc.x), NumCast(doc.y)); + doc.x = pt[0]; + doc.y = pt[1]; + }); + return this.props.addDocument(doc); + } } if (where === "inPlace" && this.layoutDoc.isInPlaceContainer) { - this.dataDoc[this.props.fieldKey] = new List([doc]); + this.dataDoc[this.props.fieldKey] = doc instanceof Doc ? doc : new List(doc as any as Doc[]); return true; } return this.props.addDocTab(doc, where); @@ -1002,8 +1022,10 @@ export class CollectionFreeFormView extends CollectionSubView - Array.from(newPool.entries()).map(entry => { + const array = Array.from(newPool.entries()); + runInAction(() => { + for (let i = 0; i < array.length; i++) { + const entry = array[i]; const lastPos = this._cachedPool.get(entry[0]); // last computed pos const newPos = entry[1]; if (!lastPos || newPos.x !== lastPos.x || newPos.y !== lastPos.y || newPos.z !== lastPos.z || newPos.zIndex !== lastPos.zIndex) { @@ -1012,7 +1034,8 @@ export class CollectionFreeFormView extends CollectionSubView this._cachedPool.set(k[0], k[1])); const elements: ViewDefResult[] = computedElementData.slice(); @@ -1058,12 +1081,13 @@ export class CollectionFreeFormView extends CollectionSubView { - this.childDocs.forEach(doc => { + const childDocs = this.childDocs.slice(); + childDocs.forEach(doc => { const scr = this.getTransform().inverse().transformPoint(NumCast(doc.x), NumCast(doc.y)); doc.x = scr?.[0]; doc.y = scr?.[1]; - this.props.addDocTab(doc, "inParent") && this.props.removeDocument(doc); }); + this.props.addDocTab(childDocs as any as Doc, "inParent"); this.props.ContainingCollectionView?.removeDocument(this.props.Document); })); layoutDocsInGrid = () => { @@ -1148,6 +1172,11 @@ export class CollectionFreeFormView extends CollectionSubView { + const activeDocs = this.getActiveDocuments(); + if (activeDocs.length > 50) { + DragManager.SetSnapLines([], []); + return; + } const size = this.props.ScreenToLocalTransform().transformDirection(this.props.PanelWidth(), this.props.PanelHeight()); const selRect = { left: this.panX() - size[0] / 2, top: this.panY() - size[1] / 2, width: size[0], height: size[1] }; const docDims = (doc: Doc) => ({ left: NumCast(doc.x), top: NumCast(doc.y), width: NumCast(doc._width), height: NumCast(doc._height) }); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 5bac075b4..43d4203ad 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -198,7 +198,6 @@ export class MarqueeView extends React.Component { - if (!this.props.active(true)) this.props.selectDocuments([this.props.Document], []); if (this._visible) { const mselect = this.marqueeSelect(); if (!e.shiftKey) { @@ -300,10 +299,7 @@ export class MarqueeView extends React.Component { - this.marqueeSelect(false).map(d => this.props.removeDocument(d)); - if (this.ink) { - // this.marqueeInkDelete(this.ink.inkData); - } + this.props.removeDocument(this.marqueeSelect(false) as any as Doc); SelectionManager.DeselectAll(); this.cleanupInteractions(false); MarqueeOptionsMenu.Instance.fadeOut(true); @@ -349,13 +345,14 @@ export class MarqueeView extends React.Component { - this.props.removeDocument(d); + selected.map(action(d => { + //this.props.removeDocument(d); d.x = NumCast(d.x) - bounds.left - bounds.width / 2; d.y = NumCast(d.y) - bounds.top - bounds.height / 2; d.displayTimecode = undefined; // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection return d; - }); + })); + this.props.removeDocument(selected as any as Doc); } const newCollection = this.getCollection(selected, (e as KeyboardEvent)?.key === "t" ? Docs.Create.StackingDocument : undefined); this.props.addDocument(newCollection); -- cgit v1.2.3-70-g09d2 From fcd0895e5933270718b9c1a262e7e377eaabb024 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 7 May 2020 19:18:52 -0400 Subject: fixed most add/remove/move documents to support doc[]'s --- src/client/util/DragManager.ts | 4 +- src/client/views/DocComponent.tsx | 37 +++++++++---- src/client/views/MainView.tsx | 6 +- src/client/views/TemplateMenu.tsx | 6 +- src/client/views/collections/CollectionSubView.tsx | 14 ++--- .../views/collections/CollectionTreeView.tsx | 64 +++++++++++++--------- src/client/views/collections/CollectionView.tsx | 4 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 4 +- .../collections/collectionFreeForm/MarqueeView.tsx | 4 +- src/client/views/nodes/DocumentView.tsx | 12 ++-- src/client/views/nodes/FieldView.tsx | 6 +- src/client/views/nodes/PresBox.tsx | 9 ++- src/client/views/nodes/VideoBox.tsx | 9 ++- 13 files changed, 107 insertions(+), 72 deletions(-) (limited to 'src') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 0d208cf1b..cc8cc38dd 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -77,8 +77,8 @@ export namespace DragManager { return root; } export let AbortDrag: () => void = emptyFunction; - export type MoveFunction = (document: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean) => boolean; - export type RemoveFunction = (document: Doc) => boolean; + export type MoveFunction = (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean; + export type RemoveFunction = (document: Doc | Doc[]) => boolean; export interface DragDropDisposer { (): void; } export interface DragOptions { diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index 11866aebe..f602cbb15 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -1,4 +1,4 @@ -import { Doc, Opt, DataSym } from '../../new_fields/Doc'; +import { Doc, Opt, DataSym, DocListCast } from '../../new_fields/Doc'; import { Touchable } from './Touchable'; import { computed, action, observable } from 'mobx'; import { Cast, BoolCast, ScriptCast } from '../../new_fields/Types'; @@ -6,6 +6,8 @@ import { listSpec } from '../../new_fields/Schema'; import { InkingControl } from './InkingControl'; import { InkTool } from '../../new_fields/InkField'; import { InteractionUtils } from '../util/InteractionUtils'; +import { List } from '../../new_fields/List'; +import { DateField } from '../../new_fields/DateField'; /// DocComponent returns a generic React base class used by views that don't have 'fieldKey' props (e.g.,CollectionFreeFormDocumentView, DocumentView) @@ -99,22 +101,37 @@ export function ViewBoxAnnotatableComponent

    d as Doc), true) : -1; - return index !== -1 && value && value.splice(index, 1) ? true : false; + removeDocument(doc: Doc | Doc[]): boolean { + const docs = doc instanceof Doc ? [doc] : doc; + docs.map(doc => doc.annotationOn = undefined); + const targetDataDoc = this.dataDoc; + const value = DocListCast(targetDataDoc[this.props.fieldKey + "-" + this._annotationKey]); + const result = value.filter(v => !docs.includes(v)); + if (result.length !== value.length) { + targetDataDoc[this.props.fieldKey] = new List(result); + return true; + } + return false; } // if the moved document is already in this overlay collection nothing needs to be done. // otherwise, if the document can be removed from where it was, it will then be added to this document's overlay collection. @action.bound - moveDocument(doc: Doc, targetCollection: Doc | undefined, addDocument: (doc: Doc) => boolean): boolean { + moveDocument(doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean): boolean { return Doc.AreProtosEqual(this.props.Document, targetCollection) ? true : this.removeDocument(doc) ? addDocument(doc) : false; } @action.bound - addDocument(doc: Doc): boolean { - doc.context = Doc.GetProto(doc).annotationOn = this.props.Document; - return Doc.AddDocToList(this.dataDoc, this.props.fieldKey + "-" + this._annotationKey, doc) ? true : false; + addDocument(doc: Doc | Doc[]): boolean { + const docs = doc instanceof Doc ? [doc] : doc; + docs.map(doc => doc.context = Doc.GetProto(doc).annotationOn = this.props.Document); + const targetDataDoc = this.props.Document[DataSym]; + const docList = DocListCast(targetDataDoc[this.props.fieldKey + "-" + this._annotationKey]); + const added = docs.filter(d => !docList.includes(d)); + if (added.length) { + added.map(doc => doc.context = this.props.Document); + targetDataDoc[this.props.fieldKey + "-" + this._annotationKey] = new List([...docList, ...added]); + targetDataDoc[this.props.fieldKey + "-" + this._annotationKey + "-lastModified"] = new DateField(new Date(Date.now())); + } + return true; } whenActiveChanged = action((isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive)); diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index e67f2f3a2..5b838446d 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -520,9 +520,9 @@ export class MainView extends React.Component { return !this._flyoutTranslate ? (

    ) : (null); } - addButtonDoc = (doc: Doc) => Doc.AddDocToList(Doc.UserDoc().dockedBtns as Doc, "data", doc); - remButtonDoc = (doc: Doc) => Doc.RemoveDocFromList(Doc.UserDoc().dockedBtns as Doc, "data", doc); - moveButtonDoc = (doc: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean) => this.remButtonDoc(doc) && addDocument(doc); + addButtonDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg: boolean, doc) => flg && Doc.AddDocToList(Doc.UserDoc().dockedBtns as Doc, "data", doc), true); + remButtonDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg: boolean, doc) => flg && Doc.RemoveDocFromList(Doc.UserDoc().dockedBtns as Doc, "data", doc), true); + moveButtonDoc = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => this.remButtonDoc(doc) && addDocument(doc); buttonBarXf = () => { if (!this._docBtnRef.current) return Transform.Identity(); diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index 665ab4e41..5f300372f 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -158,9 +158,9 @@ export class TemplateMenu extends React.Component { annotationsKey={""} dontRegisterView={true} fieldKey={"data"} - moveDocument={(doc: Doc) => false} - removeDocument={(doc: Doc) => false} - addDocument={(doc: Doc) => false} /> + moveDocument={returnFalse} + removeDocument={returnFalse} + addDocument={returnFalse} /> ; } } diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 250c9b3b0..ae84b1923 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -27,9 +27,9 @@ import { CollectionView } from "./CollectionView"; import React = require("react"); export interface CollectionViewProps extends FieldViewProps { - addDocument: (document: Doc) => boolean; - removeDocument: (document: Doc) => boolean; - moveDocument: (document: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean) => boolean; + addDocument: (document: Doc | Doc[]) => boolean; + removeDocument: (document: Doc | Doc[]) => boolean; + moveDocument: (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean; PanelWidth: () => number; PanelHeight: () => number; VisibleHeight?: () => number; @@ -212,14 +212,14 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: if (docDragData) { let added = false; if (docDragData.dropAction || docDragData.userDropAction) { - added = this.props.addDocument(docDragData.droppedDocuments as any as Doc); + added = this.props.addDocument(docDragData.droppedDocuments); } else if (docDragData.moveDocument) { const movedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] === d); const addedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] !== d); - const res = addedDocs.length ? this.props.addDocument(addedDocs as any as Doc) : true; - added = movedDocs.length ? docDragData.moveDocument(movedDocs as any as Doc, this.props.Document, this.props.addDocument) : res; + const res = addedDocs.length ? this.props.addDocument(addedDocs) : true; + added = movedDocs.length ? docDragData.moveDocument(movedDocs, this.props.Document, this.props.addDocument) : res; } else { - added = this.props.addDocument(docDragData.droppedDocuments as any as Doc); + added = this.props.addDocument(docDragData.droppedDocuments); } e.stopPropagation(); return added; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 4fb54cc07..815202cfe 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -44,7 +44,7 @@ export interface TreeViewProps { containingCollection: Doc; prevSibling?: Doc; renderDepth: number; - deleteDoc: (doc: Doc) => boolean; + deleteDoc: (doc: Doc | Doc[]) => boolean; moveDocument: DragManager.MoveFunction; dropAction: dropActionType; addDocTab: (doc: Doc, where: string, libraryPath?: Doc[]) => boolean; @@ -52,7 +52,7 @@ export interface TreeViewProps { panelWidth: () => number; panelHeight: () => number; ChromeHeight: undefined | (() => number); - addDocument: (doc: Doc, relativeTo?: Doc, before?: boolean) => boolean; + addDocument: (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => boolean; indentDocument?: () => void; outdentDocument?: () => void; ScreenToLocalTransform: () => Transform; @@ -133,14 +133,16 @@ class TreeView extends React.Component { @undoBatch delete = () => this.props.deleteDoc(this.props.document); @undoBatch openRight = () => this.props.addDocTab(this.props.dropAction === "alias" ? Doc.MakeAlias(this.props.document) : this.props.document, "onRight", this.props.libraryPath); @undoBatch indent = () => this.props.addDocument(this.props.document) && this.delete(); - @undoBatch move = (doc: Doc, target: Doc | undefined, addDoc: (doc: Doc) => boolean) => { + @undoBatch move = (doc: Doc | Doc[], target: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => { return this.props.document !== target && this.props.deleteDoc(doc) && addDoc(doc); } - @undoBatch @action remove = (document: Document, key: string) => { - return Doc.RemoveDocFromList(this.dataDoc, key, document); + @undoBatch @action remove = (doc: Doc | Doc[], key: string) => { + return (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => + flg && Doc.RemoveDocFromList(this.dataDoc, key, doc), true); } - @undoBatch @action removeDoc = (document: Document) => { - return Doc.RemoveDocFromList(this.props.containingCollection, Doc.LayoutFieldKey(this.props.containingCollection), document); + @undoBatch @action removeDoc = (doc: Doc | Doc[]) => { + return (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => + flg && Doc.RemoveDocFromList(this.props.containingCollection, Doc.LayoutFieldKey(this.props.containingCollection), doc), true); } protected createTreeDropTarget = (ele: HTMLDivElement) => { @@ -224,9 +226,10 @@ class TreeView extends React.Component { if (de.complete.docDragData) { e.stopPropagation(); if (de.complete.docDragData.draggedDocuments[0] === this.props.document) return true; - let addDoc = (doc: Doc) => this.props.addDocument(doc, undefined, before); + let addDoc = (doc: Doc | Doc[]) => this.props.addDocument(doc, undefined, before); if (inside) { - addDoc = (doc: Doc) => Doc.AddDocToList(this.dataDoc, this.fieldKey, doc) || addDoc(doc); + addDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce( + ((flg: boolean, doc) => flg && Doc.AddDocToList(this.dataDoc, this.fieldKey, doc)), true) || addDoc(doc); } const movedDocs = (de.complete.docDragData.treeViewId === this.props.treeViewId[Id] ? de.complete.docDragData.draggedDocuments : de.complete.docDragData.droppedDocuments); const move = de.complete.docDragData.dropAction === "move" || de.complete.docDragData.dropAction; @@ -286,8 +289,9 @@ class TreeView extends React.Component { let contentElement: (JSX.Element | null)[] | JSX.Element = []; if (contents instanceof Doc || (Cast(contents, listSpec(Doc)) && (Cast(contents, listSpec(Doc))!.length && Cast(contents, listSpec(Doc))![0] instanceof Doc))) { - const remDoc = (doc: Doc) => this.remove(doc, key); - const addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, key, doc, addBefore, before, false, true); + const remDoc = (doc: Doc | Doc[]) => this.remove(doc, key); + const addDoc = (doc: Doc | Doc[], addBefore?: Doc, before?: boolean) => (doc instanceof Doc ? [doc] : doc).reduce( + (flg, doc) => flg && Doc.AddDocToList(this.dataDoc, key, doc, addBefore, before, false, true), true); contentElement = TreeView.GetChildElements(contents instanceof Doc ? [contents] : DocListCast(contents), this.props.treeViewId, doc, undefined, key, this.props.containingCollection, this.props.prevSibling, addDoc, remDoc, this.move, this.props.dropAction, this.props.addDocTab, this.props.pinToPres, this.props.backgroundColor, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active, @@ -330,8 +334,9 @@ class TreeView extends React.Component { TraceMobx(); const expandKey = this.treeViewExpandedView === this.fieldKey ? this.fieldKey : this.treeViewExpandedView === "links" ? "links" : undefined; if (expandKey !== undefined) { - const remDoc = (doc: Doc) => this.remove(doc, expandKey); - const addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, expandKey, doc, addBefore, before, false, true); + const remDoc = (doc: Doc | Doc[]) => this.remove(doc, expandKey); + const addDoc = (doc: Doc | Doc[], addBefore?: Doc, before?: boolean) => + (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && Doc.AddDocToList(this.dataDoc, expandKey, doc, addBefore, before, false, true), true); const docs = expandKey === "links" ? this.childLinks : this.childDocs; const sortKey = `${this.fieldKey}-sortAscending`; return
      { @@ -464,6 +469,7 @@ class TreeView extends React.Component { ref={this._docRef} Document={this.props.document} DataDoc={undefined} + treeViewId={this.props.treeViewId[Id]} LibraryPath={this.props.libraryPath || emptyPath} addDocument={undefined} addDocTab={this.props.addDocTab} @@ -529,8 +535,8 @@ class TreeView extends React.Component { key: string, parentCollectionDoc: Doc | undefined, parentPrevSibling: Doc | undefined, - add: (doc: Doc, relativeTo?: Doc, before?: boolean) => boolean, - remove: ((doc: Doc) => boolean), + add: (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => boolean, + remove: ((doc: Doc | Doc[]) => boolean), move: DragManager.MoveFunction, dropAction: dropActionType, addDocTab: (doc: Doc, where: string) => boolean, @@ -619,7 +625,7 @@ class TreeView extends React.Component { remove(child); } }; - const addDocument = (doc: Doc, relativeTo?: Doc, before?: boolean) => { + const addDocument = (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => { return add(doc, relativeTo ? relativeTo : docs[i], before !== undefined ? before : false); }; const childLayout = Doc.Layout(pair.layout); @@ -689,22 +695,26 @@ export class CollectionTreeView extends CollectionSubView { - const children = Cast(this.props.Document[DataSym][this.props.fieldKey], listSpec(Doc), []); - if (children.indexOf(document) !== -1) { - children.splice(children.indexOf(document), 1); + remove = (doc: Doc | Doc[]): boolean => { + const docs = doc instanceof Doc ? [doc] : doc as Doc[]; + const targetDataDoc = this.props.Document[DataSym]; + const value = DocListCast(targetDataDoc[this.props.fieldKey]); + const result = value.filter(v => !docs.includes(v)); + if (result.length !== value.length) { + targetDataDoc[this.props.fieldKey] = new List(result); return true; } return false; } @action - addDoc = (doc: Document, relativeTo: Opt, before?: boolean): boolean => { - const doAddDoc = () => - Doc.AddDocToList(this.props.Document[DataSym], this.props.fieldKey, doc, relativeTo, before, false, false, false); + addDoc = (doc: Doc | Doc[], relativeTo: Opt, before?: boolean): boolean => { + const doAddDoc = (doc: Doc | Doc[]) => + (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => + flg && Doc.AddDocToList(this.props.Document[DataSym], this.props.fieldKey, doc, relativeTo, before, false, false, false), true); if (this.props.Document.resolvedDataDoc instanceof Promise) { - this.props.Document.resolvedDataDoc.then((resolved: any) => doAddDoc()); + this.props.Document.resolvedDataDoc.then((resolved: any) => doAddDoc(doc)); } else { - doAddDoc(); + doAddDoc(doc); } return true; } @@ -788,8 +798,8 @@ export class CollectionTreeView extends CollectionSubView this.addDoc(doc, relativeTo, before); - const moveDoc = (d: Doc, target: Doc | undefined, addDoc: (doc: Doc) => boolean) => this.props.moveDocument(d, target, addDoc); + const addDoc = (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => this.addDoc(doc, relativeTo, before); + const moveDoc = (d: Doc | Doc[], target: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => this.props.moveDocument(d, target, addDoc); const childDocs = this.props.overrideDocuments ? this.props.overrideDocuments : this.childDocs; return !childDocs ? (null) : (
      this.props.whenActiveChanged(this._isChildActive = isActive); @action.bound - addDocument = (doc: Doc): boolean => { + addDocument = (doc: Doc | Doc[]): boolean => { if (doc instanceof Doc) { if (this.props.filterAddDocument?.(doc) === false) { return false; } } - const docs = doc instanceof Doc ? [doc] : doc as any as Doc[]; + const docs = doc instanceof Doc ? [doc] : doc; const targetDataDoc = this.props.Document[DataSym]; const docList = DocListCast(targetDataDoc[this.props.fieldKey]); const added = docs.filter(d => !docList.includes(d)); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 6011d5f9c..b32318d66 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -123,7 +123,7 @@ export class CollectionFreeFormView extends CollectionSubView { + private addDocument = (newBox: Doc | Doc[]) => { if (newBox instanceof Doc) { const added = this.props.addDocument(newBox); added && this.bringToFront(newBox); @@ -184,7 +184,7 @@ export class CollectionFreeFormView extends CollectionSubView { - this.props.removeDocument(this.marqueeSelect(false) as any as Doc); + this.props.removeDocument(this.marqueeSelect(false)); SelectionManager.DeselectAll(); this.cleanupInteractions(false); MarqueeOptionsMenu.Instance.fadeOut(true); @@ -352,7 +352,7 @@ export class MarqueeView extends React.Component void; - addDocument?: (doc: Doc) => boolean; - removeDocument?: (doc: Doc) => boolean; - moveDocument?: (doc: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean) => boolean; + addDocument?: (doc: Doc | Doc[]) => boolean; + removeDocument?: (doc: Doc | Doc[]) => boolean; + moveDocument?: (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean; ScreenToLocalTransform: () => Transform; setupDragLines?: () => void; renderDepth: number; @@ -243,6 +244,7 @@ export class DocumentView extends DocComponent(Docu dragData.removeDocument = this.props.removeDocument; dragData.moveDocument = this.props.moveDocument;// this.Document.onDragStart ? undefined : this.props.moveDocument; dragData.dragDivName = this.props.dragDivName; + dragData.treeViewId = this.props.treeViewId; DragManager.StartDocumentDrag([this._mainCont.current], dragData, x, y, { hideSource: !dropAction && !this.Document.onDragStart }); } } @@ -1043,7 +1045,7 @@ export class DocumentView extends DocComponent(Docu makeLink = () => this._link; // pass the link placeholde to child views so they can react to make a specialized anchor. This is essentially a function call to the descendants since the value of the _link variable will immediately get set back to undefined. @undoBatch - hideLinkAnchor = (doc: Doc) => doc.hidden = true + hideLinkAnchor = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg: boolean, doc) => flg && (doc.hidden = true), true) anchorPanelWidth = () => this.props.PanelWidth() || 1; anchorPanelHeight = () => this.props.PanelHeight() || 1; @computed get anchors() { @@ -1143,7 +1145,7 @@ export class DocumentView extends DocComponent(Docu const highlightStyles = ["solid", "dashed", "solid", "solid", "solid", "solid", "solid"]; let highlighting = fullDegree && this.layoutDoc.type !== DocumentType.FONTICON && this.layoutDoc._viewType !== CollectionViewType.Linear; highlighting = highlighting && this.props.focus !== emptyFunction; // bcz: hack to turn off highlighting onsidebar panel documents. need to flag a document as not highlightable in a more direct way - return
      void; rootSelected: (outsideReaction?: boolean) => boolean; renderDepth: number; - addDocument?: (document: Doc) => boolean; + addDocument?: (document: Doc | Doc[]) => boolean; addDocTab: (document: Doc, where: string) => boolean; pinToPres: (document: Doc) => void; - removeDocument?: (document: Doc) => boolean; - moveDocument?: (document: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean) => boolean; + removeDocument?: (document: Doc | Doc[]) => boolean; + moveDocument?: (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean; backgroundColor?: (document: Doc) => string | undefined; ScreenToLocalTransform: () => Transform; bringToFront: (doc: Doc, sendToBack?: boolean) => void; diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index 343e74c87..49862d39a 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -271,9 +271,12 @@ export class PresBox extends ViewBoxBaseComponent }); whenActiveChanged = action((isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive)); - addDocumentFilter = (doc: Doc) => { - doc.aliasOf instanceof Doc && (doc.presentationTargetDoc = doc.aliasOf); - !this.childDocs.includes(doc) && (doc.presZoomButton = true); + addDocumentFilter = (doc: Doc|Doc[]) => { + const docs = doc instanceof Doc ? [doc]: doc; + docs.forEach(doc => { + doc.aliasOf instanceof Doc && (doc.presentationTargetDoc = doc.aliasOf); + !this.childDocs.includes(doc) && (doc.presZoomButton = true); + }); return true; } childLayoutTemplate = () => this.rootDoc._viewType !== CollectionViewType.Stacking ? undefined : this.presElement; diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 266b7f43f..208b93ba6 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -337,9 +337,12 @@ export class VideoBox extends ViewBoxAnnotatableComponent { + const curTime = (this.layoutDoc.currentTimecode || -1); + curTime !== -1 && (doc.displayTimecode = curTime); + }) return this.addDocument(doc); } -- cgit v1.2.3-70-g09d2 From 78e0b57cab3a5fea7421ca4661d890b635bb4790 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 7 May 2020 20:36:31 -0400 Subject: fixed gear in tab panes showing up. fixed tree view titling. fixed some current_user_util templates to drag as render templates, not prototypes. --- src/client/views/MainView.tsx | 21 ++++++++- .../views/collections/CollectionDockingView.tsx | 12 ++--- .../views/collections/CollectionTreeView.tsx | 52 +++++++++------------- .../authentication/models/current_user_utils.ts | 14 ++++-- 4 files changed, 57 insertions(+), 42 deletions(-) (limited to 'src') diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 5b838446d..fad6bf295 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -1,5 +1,12 @@ import { library } from '@fortawesome/fontawesome-svg-core'; -import { faTerminal, faToggleOn, faFile as fileSolid, faExternalLinkAlt, faLocationArrow, faSearch, faFileDownload, faStop, faCalculator, faWindowMaximize, faAddressCard, faQuestionCircle, faArrowLeft, faArrowRight, faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt, faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter, faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote, faThumbtack, faTree, faTv, faUndoAlt, faVideo } from '@fortawesome/free-solid-svg-icons'; +import { + faTrashAlt, faAngleRight, faBell, faTrash, faCamera, faExpand, faCaretDown, faCaretRight, faCaretSquareDown, faCaretSquareRight, faArrowsAltH, faPlus, faMinus, + faTerminal, faToggleOn, faFile as fileSolid, faExternalLinkAlt, faLocationArrow, faSearch, faFileDownload, faStop, faCalculator, faWindowMaximize, faAddressCard, + faQuestionCircle, faArrowLeft, faArrowRight, faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt, + faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter, + faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote, + faThumbtack, faTree, faTv, faUndoAlt, faVideo +} from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, configure, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; @@ -105,6 +112,18 @@ export class MainView extends React.Component { } } + library.add(faTrashAlt); + library.add(faAngleRight); + library.add(faBell); + library.add(faTrash); + library.add(faCamera); + library.add(faExpand); + library.add(faCaretDown); + library.add(faCaretRight); + library.add(faCaretSquareDown); + library.add(faCaretSquareRight); + library.add(faArrowsAltH); + library.add(faPlus, faMinus); library.add(faTerminal); library.add(faToggleOn); library.add(faLocationArrow); diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 6f5989052..3c33d4481 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -520,11 +520,13 @@ export class CollectionDockingView extends React.Component ((view: Opt) => view ? [view] : [])(DocumentManager.Instance.getDocumentView(doc)), (views) => { - ReactDOM.render( - views} Stack={stack} /> - , - gearSpan); - tab.buttonDisposer?.(); + if (views.length) { + ReactDOM.render( + views} Stack={stack} /> + , + gearSpan); + tab.buttonDisposer?.(); + } }); tab.reactComponents = [gearSpan]; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 815202cfe..92018a5b8 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -1,7 +1,5 @@ -import { library } from '@fortawesome/fontawesome-svg-core'; -import { faAngleRight, faArrowsAltH, faBell, faCamera, faCaretDown, faCaretRight, faCaretSquareDown, faCaretSquareRight, faExpand, faMinus, faPlus, faTrash, faTrashAlt } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, observable, runInAction, untracked } from "mobx"; +import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; import { DataSym, Doc, DocListCast, Field, HeightSym, Opt, WidthSym } from '../../../new_fields/Doc'; import { Id } from '../../../new_fields/FieldSymbols'; @@ -36,7 +34,6 @@ import React = require("react"); import { makeTemplate } from '../../util/DropConverter'; import { TraceMobx } from '../../../new_fields/util'; - export interface TreeViewProps { document: Doc; dataDoc?: Doc; @@ -63,24 +60,12 @@ export interface TreeViewProps { active: (outsideReaction?: boolean) => boolean; treeViewHideHeaderFields: () => boolean; treeViewPreventOpen: boolean; - renderedIds: string[]; + renderedIds: string[]; // list of document ids rendered used to avoid unending expansion of items in a cycle onCheckedClick?: ScriptField; onChildClick?: ScriptField; ignoreFields?: string[]; } -library.add(faTrashAlt); -library.add(faAngleRight); -library.add(faBell); -library.add(faTrash); -library.add(faCamera); -library.add(faExpand); -library.add(faCaretDown); -library.add(faCaretRight); -library.add(faCaretSquareDown); -library.add(faCaretSquareRight); -library.add(faArrowsAltH); -library.add(faPlus, faMinus); @observer /** * Renders a treeView of a collection of documents @@ -91,13 +76,14 @@ library.add(faPlus, faMinus); * treeViewExpandedView : name of field whose contents are being displayed as the document's subtree */ class TreeView extends React.Component { + static _editTitleScript: ScriptField | undefined; private _header?: React.RefObject = React.createRef(); private _treedropDisposer?: DragManager.DragDropDisposer; private _dref = React.createRef(); private _tref = React.createRef(); + private _docRef = React.createRef(); get displayName() { return "TreeView(" + this.props.document.title + ")"; } // this makes mobx trace() statements more descriptive - get defaultExpandedView() { return this.childDocs ? this.fieldKey : StrCast(this.props.document.defaultExpandedView, "fields"); } @observable _overrideTreeViewOpen = false; // override of the treeViewOpen field allowing the display state to be independent of the document's state set treeViewOpen(c: boolean) { if (this.props.treeViewPreventOpen) this._overrideTreeViewOpen = c; else this.props.document.treeViewOpen = this._overrideTreeViewOpen = c; } @@ -111,7 +97,7 @@ class TreeView extends React.Component { } childDocList(field: string) { const layout = Doc.LayoutField(this.props.document) instanceof Doc ? Doc.LayoutField(this.props.document) as Doc : undefined; - return ((this.props.dataDoc ? Cast(this.props.dataDoc[field], listSpec(Doc)) : undefined) || + return ((this.props.dataDoc ? DocListCast(this.props.dataDoc[field]) : undefined) || (layout ? Cast(layout[field], listSpec(Doc)) : undefined) || Cast(this.props.document[field], listSpec(Doc))) as Doc[]; } @@ -411,7 +397,10 @@ class TreeView extends React.Component { @computed get renderBullet() { const checked = this.props.document.type === DocumentType.COL ? undefined : this.onCheckedClick ? (this.props.document.treeViewChecked ? this.props.document.treeViewChecked : "unchecked") : undefined; - return
      + return
      {}
      ; } @@ -425,8 +414,6 @@ class TreeView extends React.Component { const focusScript = ScriptField.MakeFunction(`DocFocus(self)`); return [{ script: focusScript!, label: "Focus" }]; } - _docRef = React.createRef(); - _editTitleScript: ScriptField | undefined; /** * Renders the EditableView title element for placement into the tree. */ @@ -434,8 +421,7 @@ class TreeView extends React.Component { get renderTitle() { TraceMobx(); const onItemDown = SetupDrag(this._tref, () => this.dataDoc, this.move, this.props.dropAction, this.props.treeViewId[Id], true); - //!this._editTitleScript && (this._editTitleScript = ScriptField.MakeFunction("setInPlace(this, 'editTitle', true)")); - + (!TreeView._editTitleScript) && (TreeView._editTitleScript = ScriptField.MakeFunction("setInPlace(this, 'editTitle', true)")); const headerElements = ( <> this.showContextMenu(e)}> @@ -475,7 +461,7 @@ class TreeView extends React.Component { addDocTab={this.props.addDocTab} rootSelected={returnTrue} pinToPres={emptyFunction} - onClick={this.props.onChildClick || this._editTitleScript} + onClick={this.props.onChildClick || TreeView._editTitleScript} dropAction={this.props.dropAction} moveDocument={this.move} removeDocument={this.removeDoc} @@ -512,12 +498,14 @@ class TreeView extends React.Component { e.stopPropagation(); e.preventDefault(); } - }} onPointerDown={e => { - if (this.props.active(true)) { - e.stopPropagation(); - e.preventDefault(); - } - }} onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave}> + }} + onPointerDown={e => { + if (this.props.active(true)) { + e.stopPropagation(); + e.preventDefault(); + } + }} + onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave}> {this.renderBullet} {this.renderTitle}
      @@ -790,7 +778,7 @@ export class CollectionTreeView extends CollectionSubView
      ; } diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 6e06fe931..8a0fbeabe 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -50,7 +50,7 @@ export class CurrentUserUtils { ); queryTemplate.isTemplateDoc = makeTemplate(queryTemplate); doc["template-button-query"] = CurrentUserUtils.ficon({ - onDragStart: ScriptField.MakeFunction('makeDelegate(this.dragFactory, true)'), + onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: new PrefetchProxy(queryTemplate) as any as Doc, removeDropProperties: new List(["dropAction"]), title: "query view", icon: "question-circle" }); @@ -66,7 +66,7 @@ export class CurrentUserUtils { ); slideTemplate.isTemplateDoc = makeTemplate(slideTemplate); doc["template-button-slides"] = CurrentUserUtils.ficon({ - onDragStart: ScriptField.MakeFunction('makeDelegate(this.dragFactory, true)'), + onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: new PrefetchProxy(slideTemplate) as any as Doc, removeDropProperties: new List(["dropAction"]), title: "presentation slide", icon: "address-card" }); @@ -162,7 +162,7 @@ export class CurrentUserUtils { long.title = "Long Description"; doc["template-button-detail"] = CurrentUserUtils.ficon({ - onDragStart: ScriptField.MakeFunction('makeDelegate(this.dragFactory, true)'), + onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: new PrefetchProxy(detailView) as any as Doc, removeDropProperties: new List(["dropAction"]), title: "detail view", icon: "window-maximize" }); @@ -176,7 +176,13 @@ export class CurrentUserUtils { dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), })); } else { - DocListCast(Cast(doc["template-buttons"], Doc, null)?.data); // prefetch templates + const curButnTypes = Cast(doc["template-buttons"], Doc, null); + const requiredTypes = [doc["template-button-slides"] as Doc, doc["template-button-description"] as Doc, + doc["template-button-query"] as Doc, doc["template-button-detail"] as Doc, doc["template-button-switch"] as Doc]; + DocListCastAsync(curButnTypes.data).then(async curBtns => { + await Promise.all(curBtns!); + requiredTypes.map(btype => Doc.AddDocToList(curButnTypes, "data", btype)); + }); } return doc["template-buttons"] as Doc; } -- cgit v1.2.3-70-g09d2 From 136165e9c960be255396830e3a9d44532ee0cda7 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 7 May 2020 23:41:08 -0400 Subject: fixed tree view title editing. cleaned up annotation keys in DocComponent --- src/client/views/DocComponent.tsx | 15 ++++++------- src/client/views/collections/CollectionSubView.tsx | 2 +- .../views/collections/CollectionTreeView.tsx | 26 +++++++--------------- src/client/views/nodes/DocumentView.tsx | 2 +- 4 files changed, 17 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index f602cbb15..4e7d4c5ed 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -97,18 +97,17 @@ export function ViewBoxAnnotatableComponent

      doc.annotationOn = undefined); - const targetDataDoc = this.dataDoc; - const value = DocListCast(targetDataDoc[this.props.fieldKey + "-" + this._annotationKey]); + const targetDataDoc = this.dataDoc; this + const value = DocListCast(targetDataDoc[this.annotationKey]); const result = value.filter(v => !docs.includes(v)); if (result.length !== value.length) { - targetDataDoc[this.props.fieldKey] = new List(result); + targetDataDoc[this.annotationKey] = new List(result); return true; } return false; @@ -124,12 +123,12 @@ export function ViewBoxAnnotatableComponent

      doc.context = Doc.GetProto(doc).annotationOn = this.props.Document); const targetDataDoc = this.props.Document[DataSym]; - const docList = DocListCast(targetDataDoc[this.props.fieldKey + "-" + this._annotationKey]); + const docList = DocListCast(targetDataDoc[this.annotationKey]); const added = docs.filter(d => !docList.includes(d)); if (added.length) { added.map(doc => doc.context = this.props.Document); - targetDataDoc[this.props.fieldKey + "-" + this._annotationKey] = new List([...docList, ...added]); - targetDataDoc[this.props.fieldKey + "-" + this._annotationKey + "-lastModified"] = new DateField(new Date(Date.now())); + targetDataDoc[this.annotationKey] = new List([...docList, ...added]); + targetDataDoc[this.annotationKey + "-lastModified"] = new DateField(new Date(Date.now())); } return true; } diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index ae84b1923..d1c2d9a76 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -95,7 +95,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: // to its children which may be templates. // If 'annotationField' is specified, then all children exist on that field of the extension document, otherwise, they exist directly on the data document under 'fieldKey' @computed get dataField() { - return this.dataDoc[this.props.fieldKey + (this.props.annotationsKey ? "-" + this.props.annotationsKey : "")]; + return this.dataDoc[this.props.annotationsKey || this.props.fieldKey]; } get childLayoutPairs(): { layout: Doc; data: Doc; }[] { diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 92018a5b8..52ffd74c9 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -90,35 +90,25 @@ class TreeView extends React.Component { @computed get treeViewOpen() { return (!this.props.treeViewPreventOpen && !this.props.document.treeViewPreventOpen && BoolCast(this.props.document.treeViewOpen)) || this._overrideTreeViewOpen; } @computed get treeViewExpandedView() { return StrCast(this.props.document.treeViewExpandedView, this.defaultExpandedView); } @computed get MAX_EMBED_HEIGHT() { return NumCast(this.props.containingCollection.maxEmbedHeight, 200); } - @computed get dataDoc() { return this.templateDataDoc ? this.templateDataDoc : this.props.document; } + @computed get dataDoc() { return this.props.document[DataSym]; } @computed get fieldKey() { const splits = StrCast(Doc.LayoutField(this.props.document)).split("fieldKey={\'"); return splits.length > 1 ? splits[1].split("\'")[0] : "data"; } childDocList(field: string) { const layout = Doc.LayoutField(this.props.document) instanceof Doc ? Doc.LayoutField(this.props.document) as Doc : undefined; - return ((this.props.dataDoc ? DocListCast(this.props.dataDoc[field]) : undefined) || - (layout ? Cast(layout[field], listSpec(Doc)) : undefined) || - Cast(this.props.document[field], listSpec(Doc))) as Doc[]; + return ((this.props.dataDoc ? DocListCast(this.props.dataDoc[field]) : undefined) || // if there's a data doc for an expanded template, use it's data field + (layout ? Cast(layout[field], listSpec(Doc)) : undefined) || // else if there's a layout doc, display it's fields + Cast(this.props.document[field], listSpec(Doc))) as Doc[]; // otherwise use the document's data field } @computed get childDocs() { return this.childDocList(this.fieldKey); } @computed get childLinks() { return this.childDocList("links"); } - @computed get templateDataDoc() { - if (this.props.dataDoc === undefined && Doc.LayoutField(this.props.document) !== "string") { - // if there is no dataDoc (ie, we're not rendering a template layout), but this document has a layout document (not a layout string), - // then we render the layout document as a template and use this document as the data context for the template layout. - return this.props.document; - } - return this.props.dataDoc; - } @computed get boundsOfCollectionDocument() { return StrCast(this.props.document.type).indexOf(DocumentType.COL) === -1 || !DocListCast(this.props.document[this.fieldKey]).length ? undefined : Doc.ComputeContentBounds(DocListCast(this.props.document[this.fieldKey])); } - @undoBatch delete = () => this.props.deleteDoc(this.props.document); @undoBatch openRight = () => this.props.addDocTab(this.props.dropAction === "alias" ? Doc.MakeAlias(this.props.document) : this.props.document, "onRight", this.props.libraryPath); - @undoBatch indent = () => this.props.addDocument(this.props.document) && this.delete(); @undoBatch move = (doc: Doc | Doc[], target: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => { return this.props.document !== target && this.props.deleteDoc(doc) && addDoc(doc); } @@ -132,7 +122,7 @@ class TreeView extends React.Component { } protected createTreeDropTarget = (ele: HTMLDivElement) => { - this._treedropDisposer && this._treedropDisposer(); + this._treedropDisposer?.(); ele && (this._treedropDisposer = DragManager.MakeDropTarget(ele, this.treeDrop.bind(this)), this.props.document); } @@ -331,7 +321,7 @@ class TreeView extends React.Component { }}> {!docs ? (null) : TreeView.GetChildElements(docs, this.props.treeViewId, Doc.Layout(this.props.document), - this.templateDataDoc, expandKey, this.props.containingCollection, this.props.prevSibling, addDoc, remDoc, this.move, + this.dataDoc, expandKey, this.props.containingCollection, this.props.prevSibling, addDoc, remDoc, this.move, StrCast(this.props.document.childDropAction, this.props.dropAction) as dropActionType, this.props.addDocTab, this.props.pinToPres, this.props.backgroundColor, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active, this.props.panelWidth, this.props.ChromeHeight, this.props.renderDepth, this.props.treeViewHideHeaderFields, this.props.treeViewPreventOpen, [...this.props.renderedIds, this.props.document[Id]], this.props.libraryPath, this.props.onCheckedClick, this.props.onChildClick, this.props.ignoreFields)} @@ -347,7 +337,7 @@ class TreeView extends React.Component { return

      { get renderTitle() { TraceMobx(); const onItemDown = SetupDrag(this._tref, () => this.dataDoc, this.move, this.props.dropAction, this.props.treeViewId[Id], true); - (!TreeView._editTitleScript) && (TreeView._editTitleScript = ScriptField.MakeFunction("setInPlace(this, 'editTitle', true)")); + (!TreeView._editTitleScript) && (TreeView._editTitleScript = ScriptField.MakeFunction("setInPlace(self, 'editTitle', true)")); const headerElements = ( <> this.showContextMenu(e)}> diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 042869004..b97b607b9 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1081,7 +1081,7 @@ export class DocumentView extends DocComponent(Docu
      `} + LayoutTemplateString={``} ContentScaling={this.childScaling} ChromeHeight={this.chromeHeight} isSelected={this.isSelected} -- cgit v1.2.3-70-g09d2 From 2043fc6d4bf74397e4ccf378137e0ff1704167ca Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 8 May 2020 01:48:55 -0400 Subject: fixed webbox exception. fixed marquee div not to userSelect. fixed snap lines when zoomed out. --- .../collections/collectionFreeForm/CollectionFreeFormView.tsx | 2 +- .../views/collections/collectionFreeForm/MarqueeView.scss | 1 + src/client/views/nodes/DocumentView.tsx | 2 -- src/client/views/nodes/WebBox.tsx | 10 ++++++---- 4 files changed, 8 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index b32318d66..17c1dd44a 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1177,7 +1177,7 @@ export class CollectionFreeFormView extends CollectionSubView ({ left: NumCast(doc.x), top: NumCast(doc.y), width: NumCast(doc._width), height: NumCast(doc._height) }); const isDocInView = (doc: Doc, rect: { left: number, top: number, width: number, height: number }) => { diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.scss b/src/client/views/collections/collectionFreeForm/MarqueeView.scss index 1291e7dc1..a811dd15a 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.scss +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.scss @@ -7,6 +7,7 @@ height:100%; overflow: hidden; border-radius: inherit; + user-select: none; } .marqueeView:focus-within { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index b97b607b9..e3b69b8f3 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1149,8 +1149,6 @@ export class DocumentView extends DocComponent(Docu id={this.props.Document[Id]} ref={this._mainCont} onKeyDown={this.onKeyDown} onContextMenu={this.onContextMenu} onPointerDown={this.onPointerDown} onClick={this.onClick} - // onPointerEnter={e => Doc.BrushDoc(this.props.Document)} - // onPointerLeave={e => Doc.BrushDoc(this.props.Document)} onPointerEnter={action(() => Doc.BrushDoc(this.props.Document))} onPointerLeave={action((e: React.PointerEvent) => { let entered = false; diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 80e15fd5f..8239d6fdf 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -48,10 +48,12 @@ export class WebBox extends ViewBoxAnnotatableComponent 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 && (this._iframeRef.current!.contentDocument.children[0].scrollTop = NumCast(this.layoutDoc.scrollTop)); + if (this._iframeRef.current?.contentDocument) { + 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); + } this._reactionDisposer?.(); this._reactionDisposer = reaction(() => this.layoutDoc.scrollY, (scrollY) => { -- cgit v1.2.3-70-g09d2 From e627a85430345db08c03027a6b816141fb4f4a2c Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 8 May 2020 10:24:06 -0400 Subject: changed ink color swatches. reuse last background color & font size for text boxes. --- src/client/views/InkingControl.tsx | 7 ++++--- src/client/views/collections/collectionFreeForm/MarqueeView.tsx | 6 +++++- src/client/views/nodes/ColorBox.tsx | 2 +- src/client/views/nodes/formattedText/FormattedTextBox.tsx | 1 + src/client/views/nodes/formattedText/RichTextMenu.tsx | 7 ++++--- src/server/authentication/models/current_user_utils.ts | 2 ++ 6 files changed, 17 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx index 70ea955e1..81d99e009 100644 --- a/src/client/views/InkingControl.tsx +++ b/src/client/views/InkingControl.tsx @@ -34,7 +34,8 @@ export class InkingControl { @undoBatch switchColor = action((color: ColorState): void => { - Doc.UserDoc().inkColor = color.hex + (color.rgb.a !== undefined ? this.decimalToHexString(Math.round(color.rgb.a * 255)) : "ff"); + Doc.UserDoc().backgroundColor = color.hex.startsWith("#") ? + color.hex + (color.rgb.a !== undefined ? this.decimalToHexString(Math.round(color.rgb.a * 255)) : "ff") : color.hex; if (InkingControl.Instance.selectedTool === InkTool.None) { const selected = SelectionManager.SelectedDocuments(); @@ -44,9 +45,9 @@ export class InkingControl { view.props.Document.isTemplateForField ? view.props.Document : Doc.GetProto(view.props.Document); if (targetDoc) { if (StrCast(Doc.Layout(view.props.Document).layout).indexOf("FormattedTextBox") !== -1 && FormattedTextBox.HadSelection) { - Doc.Layout(view.props.Document).color = Doc.UserDoc().inkColor; + Doc.Layout(view.props.Document).color = Doc.UserDoc().bacgroundColor; } else { - Doc.Layout(view.props.Document)._backgroundColor = Doc.UserDoc().inkColor; // '_backgroundColor' is template specific. 'backgroundColor' would apply to all templates, but has no UI at the moment + Doc.Layout(view.props.Document)._backgroundColor = Doc.UserDoc().backgroundColor; // '_backgroundColor' is template specific. 'backgroundColor' would apply to all templates, but has no UI at the moment } } }); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 2230c391c..a777f6fe5 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -108,7 +108,11 @@ export class MarqueeView extends React.Component e.button === 0 && !e.ctrlKey && e.stopPropagation()} style={{ transform: `scale(${this.props.ContentScaling()})`, width: `${100 / this.props.ContentScaling()}%`, height: `${100 / this.props.ContentScaling()}%` }} > -
      ; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index bccf569f8..63552321b 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -205,6 +205,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp this.dataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now())); if ((!curTemp && !curProto) || curText || curLayout?.Data.includes("dash")) { // if no template, or there's text that didn't come from the layout template, write it to the document. (if this is driven by a template, then this overwrites the template text which is intended) if (json !== curLayout?.Data) { + !curText && tx.storedMarks?.map(m => m.type.name === "pFontSize" && (Doc.UserDoc().fontSize = this.layoutDoc._fontSize = m.attrs.fontSize)); this.dataDoc[this.props.fieldKey] = new RichTextField(json, curText); this.dataDoc[this.props.fieldKey + "-noTemplate"] = (curTemp?.Text || "") !== curText; // mark the data field as being split from the template if it has been edited } diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index cc04e0d6d..170a39801 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -197,9 +197,10 @@ export default class RichTextMenu extends AntimodeMenu { } else { toggleMark(mark.type, mark.attrs)(state, (tx: any) => { const { from, $from, to, empty } = tx.selection; - if (!tx.doc.rangeHasMark(from, to, mark.type)) { - toggleMark(mark.type, mark.attrs)({ tr: tx, doc: tx.doc, selection: tx.selection, storedMarks: tx.storedMarks }, dispatch); - } else dispatch(tx); + // if (!tx.doc.rangeHasMark(from, to, mark.type)) { + // toggleMark(mark.type, mark.attrs)({ tr: tx, doc: tx.doc, selection: tx.selection, storedMarks: tx.storedMarks }, dispatch); + // } else + dispatch(tx); }); } } diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 8a0fbeabe..a776b6f10 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -688,6 +688,8 @@ export class CurrentUserUtils { new InkingControl(); doc.title = Doc.CurrentUserEmail; doc.activePen = doc; + doc.inkColor = StrCast(doc.backgroundColor, ""); + doc.fontSize = NumCast(doc.fontSize, 12); doc["constants-snapThreshold"] = NumCast(doc["constants-snapThreshold"], 10); // doc["constants-dragThreshold"] = NumCast(doc["constants-dragThreshold"], 4); // Utils.DRAG_THRESHOLD = NumCast(doc["constants-dragThreshold"]); -- cgit v1.2.3-70-g09d2 From c1f49a0974982b803c565b6ac3c8931be7c8972f Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 8 May 2020 16:57:30 -0400 Subject: added " " for switching between pan/zoom & marquee. --- src/client/views/DocumentButtonBar.tsx | 11 +---------- src/client/views/GlobalKeyHandler.ts | 5 +++++ src/client/views/PreviewCursor.tsx | 2 +- .../views/collections/CollectionDockingView.tsx | 23 ++++++++++++---------- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- .../collections/collectionFreeForm/MarqueeView.tsx | 14 ++++++------- 6 files changed, 27 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index d58eb5875..48685302a 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -229,16 +229,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV return !targetDoc ? (null) :
      { - if (isPinned) { - DockedFrameRenderer.UnpinDoc(targetDoc); - } - else { - targetDoc.sourceContext = this.view0?.props.ContainingCollectionDoc; // bcz: !! Shouldn't need this ... use search to lookup contexts dynamically - DockedFrameRenderer.PinDoc(targetDoc); - } - }}> + onClick={e => DockedFrameRenderer.PinDoc(targetDoc, isPinned)}>
      ; diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index 6cca4d69f..e6dd014c0 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -13,6 +13,8 @@ import { InkingControl } from "./InkingControl"; import { InkTool } from "../../new_fields/InkField"; import { DocumentView } from "./nodes/DocumentView"; import GoogleAuthenticationManager from "../apis/GoogleAuthenticationManager"; +import { CollectionFreeFormView } from "./collections/collectionFreeForm/CollectionFreeFormView"; +import { MarqueeView } from "./collections/collectionFreeForm/MarqueeView"; const modifiers = ["control", "meta", "shift", "alt"]; type KeyHandler = (keycode: string, e: KeyboardEvent) => KeyControlInfo | Promise; @@ -65,6 +67,9 @@ export default class KeyManager { private unmodified = action((keyname: string, e: KeyboardEvent) => { switch (keyname) { + case " ": + MarqueeView.DragState = !MarqueeView.DragState; + break; case "escape": const main = MainView.Instance; InkingControl.Instance.switchTool(InkTool.None); diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx index df30c1215..80c7f3d25 100644 --- a/src/client/views/PreviewCursor.tsx +++ b/src/client/views/PreviewCursor.tsx @@ -81,7 +81,7 @@ export class PreviewCursor extends React.Component<{}> { if (e.key !== "Escape" && e.key !== "Backspace" && e.key !== "Delete" && e.key !== "CapsLock" && e.key !== "Alt" && e.key !== "Shift" && e.key !== "Meta" && e.key !== "Control" && e.key !== "Insert" && e.key !== "Home" && e.key !== "End" && e.key !== "PageUp" && e.key !== "PageDown" && - e.key !== "NumLock" && + e.key !== "NumLock" && e.key !== " " && (e.keyCode < 112 || e.keyCode > 123) && // F1 thru F12 keys !e.key.startsWith("Arrow") && !e.defaultPrevented) { diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 3c33d4481..c1edc0fe7 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -683,16 +683,19 @@ export class DockedFrameRenderer extends React.Component { **/ @undoBatch @action - public static PinDoc(doc: Doc) { - //add this new doc to props.Document - const curPres = Cast(Doc.UserDoc().activePresentation, Doc) as Doc; - if (curPres) { - const pinDoc = Doc.MakeAlias(doc); - pinDoc.presentationTargetDoc = doc; - pinDoc.presZoomButton = true; - Doc.AddDocToList(curPres, "data", pinDoc); - if (!DocumentManager.Instance.getDocumentView(curPres)) { - CollectionDockingView.AddRightSplit(curPres); + public static PinDoc(doc: Doc, unpin = false) { + if (unpin) DockedFrameRenderer.UnpinDoc(doc); + else { + //add this new doc to props.Document + const curPres = Cast(Doc.UserDoc().activePresentation, Doc) as Doc; + if (curPres) { + const pinDoc = Doc.MakeAlias(doc); + pinDoc.presentationTargetDoc = doc; + pinDoc.presZoomButton = true; + Doc.AddDocToList(curPres, "data", pinDoc); + if (!DocumentManager.Instance.getDocumentView(curPres)) { + CollectionDockingView.AddRightSplit(curPres); + } } } } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 17c1dd44a..5d3d8eb4f 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -563,7 +563,7 @@ export class CollectionFreeFormView extends CollectionSubView Transform; @@ -39,7 +37,7 @@ interface MarqueeViewProps { @observer export class MarqueeView extends React.Component { - private _mainCont = React.createRef(); + @observable public static DragState = true; @observable _lastX: number = 0; @observable _lastY: number = 0; @observable _downX: number = 0; @@ -168,9 +166,9 @@ export class MarqueeView extends React.Component { this._downX = this._lastX = e.clientX; this._downY = this._lastY = e.clientY; - if (e.button === 2 || (e.button === 0 && e.altKey)) { + if (e.button === 2 || (e.button === 0 && (e.altKey || !MarqueeView.DragState))) { this.setPreviewCursor(e.clientX, e.clientY, true); - if (e.altKey) { + if (e.altKey || !MarqueeView.DragState) { //e.stopPropagation(); // bcz: removed so that you can alt-click on button in a collection to switch link following behaviors. e.preventDefault(); } @@ -195,7 +193,7 @@ export class MarqueeView extends React.Component e.currentTarget.scrollTop = e.currentTarget.scrollLeft = 0} onClick={this.onClick} onPointerDown={this.onPointerDown}> {this._visible ? this.marqueeDiv : null} {this.props.children} -- cgit v1.2.3-70-g09d2 From e50914de0657d1f0d48297e9fbdbed3d0731d9ee Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 8 May 2020 19:01:39 -0400 Subject: enabled two-finger pan, pinch zoom and marquee drag without a modifier key --- src/client/views/GlobalKeyHandler.ts | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 7 ++++--- .../views/collections/collectionFreeForm/MarqueeView.tsx | 12 ++++++------ 3 files changed, 11 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index e6dd014c0..c73e1a66a 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -68,7 +68,7 @@ export default class KeyManager { private unmodified = action((keyname: string, e: KeyboardEvent) => { switch (keyname) { case " ": - MarqueeView.DragState = !MarqueeView.DragState; + MarqueeView.DragMarquee = !MarqueeView.DragMarquee; break; case "escape": const main = MainView.Instance; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 5d3d8eb4f..d4da87568 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -563,7 +563,7 @@ export class CollectionFreeFormView extends CollectionSubView { - let deltaScale = deltaY > 0 ? (1 / 1.1) : 1.1; + let deltaScale = deltaY > 0 ? (1 / 1.05) : 1.05; if (deltaScale * this.zoomScaling() < 1 && this.isAnnotationOverlay) { deltaScale = 1 / this.zoomScaling(); } @@ -732,7 +732,8 @@ export class CollectionFreeFormView extends CollectionSubView { - @observable public static DragState = true; + @observable public static DragMarquee = false; @observable _lastX: number = 0; @observable _lastY: number = 0; @observable _downX: number = 0; @@ -166,9 +166,9 @@ export class MarqueeView extends React.Component { this._downX = this._lastX = e.clientX; this._downY = this._lastY = e.clientY; - if (e.button === 2 || (e.button === 0 && (e.altKey || !MarqueeView.DragState))) { + if (e.button === 2 || (e.button === 0 && (e.altKey || MarqueeView.DragMarquee))) { this.setPreviewCursor(e.clientX, e.clientY, true); - if (e.altKey || !MarqueeView.DragState) { + if (e.altKey || MarqueeView.DragMarquee) { //e.stopPropagation(); // bcz: removed so that you can alt-click on button in a collection to switch link following behaviors. e.preventDefault(); } @@ -193,7 +193,7 @@ export class MarqueeView extends React.Component e.currentTarget.scrollTop = e.currentTarget.scrollLeft = 0} onClick={this.onClick} onPointerDown={this.onPointerDown}> {this._visible ? this.marqueeDiv : null} {this.props.children} -- cgit v1.2.3-70-g09d2 From fe98b0a9c436f498fcc16d05c24cdf6c684e7ab8 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 8 May 2020 19:31:41 -0400 Subject: from last --- .../collections/collectionFreeForm/MarqueeView.tsx | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index a4e474e96..a85739af9 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -1,24 +1,25 @@ import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; -import { Doc, DocListCast, DataSym, WidthSym, HeightSym, Opt } from "../../../../new_fields/Doc"; -import { InkField, InkData } from "../../../../new_fields/InkField"; +import { Doc, Opt } from "../../../../new_fields/Doc"; +import { InkData, InkField } from "../../../../new_fields/InkField"; import { List } from "../../../../new_fields/List"; +import { RichTextField } from "../../../../new_fields/RichTextField"; import { SchemaHeaderField } from "../../../../new_fields/SchemaHeaderField"; -import { Cast, NumCast, FieldValue, StrCast } from "../../../../new_fields/Types"; +import { Cast, FieldValue, NumCast, StrCast } from "../../../../new_fields/Types"; import { Utils } from "../../../../Utils"; -import { Docs, DocUtils, DocumentOptions } from "../../../documents/Documents"; +import { CognitiveServices } from "../../../cognitive_services/CognitiveServices"; +import { Docs, DocumentOptions, DocUtils } from "../../../documents/Documents"; import { SelectionManager } from "../../../util/SelectionManager"; import { Transform } from "../../../util/Transform"; import { undoBatch } from "../../../util/UndoManager"; import { ContextMenu } from "../../ContextMenu"; +import { FormattedTextBox } from "../../nodes/formattedText/FormattedTextBox"; import { PreviewCursor } from "../../PreviewCursor"; import { SubCollectionViewProps } from "../CollectionSubView"; +import { CollectionView } from "../CollectionView"; import MarqueeOptionsMenu from "./MarqueeOptionsMenu"; import "./MarqueeView.scss"; import React = require("react"); -import { CognitiveServices } from "../../../cognitive_services/CognitiveServices"; -import { RichTextField } from "../../../../new_fields/RichTextField"; -import { CollectionView } from "../CollectionView"; interface MarqueeViewProps { getContainerTransform: () => Transform; @@ -550,7 +551,7 @@ export class MarqueeView extends React.Component !doc.isBackground && doc.z === undefined).map(doc => { + this.props.activeDocuments().filter(doc => !doc.isBackground && !doc.z).map(doc => { const layoutDoc = Doc.Layout(doc); const x = NumCast(doc.x); const y = NumCast(doc.y); -- cgit v1.2.3-70-g09d2 From b8a376d01560dee12eaa17a0ac6668dee4470725 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 8 May 2020 19:51:07 -0400 Subject: fixed marquee when over a media item to allow dragging, too. --- src/client/views/collections/CollectionTreeView.tsx | 4 ++-- src/client/views/collections/collectionFreeForm/MarqueeView.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 52ffd74c9..58d021b5c 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -166,7 +166,7 @@ class TreeView extends React.Component { })} OnFillDown={undoBatch((value: string) => { Doc.SetInPlace(this.props.document, key, value, false); - const doc = Docs.Create.FreeformDocument([], { title: "-", x: 0, y: 0, _width: 100, _height: 25, templates: new List([Templates.Title.Layout]) }); + const doc = Docs.Create.FreeformDocument([], { title: "-", x: 0, y: 0, _width: 100, _height: 25, _LODdisable: true, templates: new List([Templates.Title.Layout]) }); Doc.SetInPlace(this.props.document, "editTitle", undefined, false); Doc.SetInPlace(doc, "editTitle", true, false); return this.props.addDocument(doc); @@ -801,7 +801,7 @@ export class CollectionTreeView extends CollectionSubView Doc.SetInPlace(this.dataDoc, "title", value, false) || true)} OnFillDown={undoBatch((value: string) => { Doc.SetInPlace(this.dataDoc, "title", value, false); - const doc = Docs.Create.FreeformDocument([], { title: "", x: 0, y: 0, _width: 100, _height: 25, templates: new List([Templates.Title.Layout]) }); + const doc = Docs.Create.FreeformDocument([], { title: "", x: 0, y: 0, _width: 100, _height: 25, _LODdisable: true, templates: new List([Templates.Title.Layout]) }); EditableView.loadId = doc[Id]; Doc.SetInPlace(doc, "editTitle", true, false); this.addDoc(doc, childDocs.length ? childDocs[0] : undefined, true); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index a85739af9..6c023b291 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -169,7 +169,7 @@ export class MarqueeView extends React.Component e.currentTarget.scrollTop = e.currentTarget.scrollLeft = 0} onClick={this.onClick} onPointerDown={this.onPointerDown}> {this._visible ? this.marqueeDiv : null} {this.props.children} -- cgit v1.2.3-70-g09d2 From fd65d1ceb46226281a346ecd8221afea91dfe5db Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 8 May 2020 20:49:56 -0400 Subject: another fix to marquee selection without a modifier key --- src/client/views/collections/collectionFreeForm/MarqueeView.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 6c023b291..285907776 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -168,9 +168,9 @@ export class MarqueeView extends React.Component Date: Fri, 8 May 2020 20:58:57 -0400 Subject: from last --- .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index d4da87568..dfcb30588 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -732,7 +732,7 @@ export class CollectionFreeFormView extends CollectionSubView Date: Fri, 8 May 2020 21:27:13 -0400 Subject: yet another change to marqueeing without modifier --- .../collections/collectionFreeForm/MarqueeView.tsx | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 285907776..1addea6a1 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -170,7 +170,7 @@ export class MarqueeView extends React.Component { + this.hideMarquee(); + MarqueeOptionsMenu.Instance.fadeOut(true); + document.removeEventListener("pointerdown", hideMarquee); + }; if (!this._commandExecuted && (Math.abs(this.Bounds.height * this.Bounds.width) > 100)) { MarqueeOptionsMenu.Instance.createCollection = this.collection; MarqueeOptionsMenu.Instance.delete = this.delete; @@ -219,16 +224,12 @@ export class MarqueeView extends React.Component { - this.hideMarquee(); - MarqueeOptionsMenu.Instance.fadeOut(true); - document.removeEventListener("pointerdown", hideMarquee); - }; - document.addEventListener("pointerdown", hideMarquee); - if (e.altKey || MarqueeView.DragMarquee) { e.preventDefault(); } -- cgit v1.2.3-70-g09d2 From 4914965affb984e04e847460ce1b5750807b316f Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 9 May 2020 15:56:11 -0400 Subject: fixed missing gear in golden layout. fixed double dragging events. changed dragging to give prefernce to modifier keys over dropactions. changed names of Documents to Catalog. added document copy past with ctrl c/ctrl v --- src/client/util/DragManager.ts | 7 ++----- src/client/views/GlobalKeyHandler.ts | 10 ++++++++++ src/client/views/MainView.tsx | 3 +-- src/client/views/PreviewCursor.tsx | 13 +++++++++++++ src/client/views/collections/CollectionDockingView.tsx | 2 +- src/client/views/collections/CollectionSubView.tsx | 10 ++++++---- src/client/views/collections/CollectionTreeView.tsx | 3 +-- src/client/views/collections/CollectionView.tsx | 10 +++++----- src/client/views/nodes/DocumentView.tsx | 15 ++++++++++----- src/server/authentication/models/current_user_utils.ts | 14 +++++++------- 10 files changed, 56 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index cc8cc38dd..4f547e2f7 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -176,7 +176,7 @@ export namespace DragManager { element: HTMLElement, dropFunc: (e: Event, de: DropEvent) => void, doc?: Doc, - preDropFunc?: (e: Event, de: DropEvent) => void, + preDropFunc?: (e: Event, de: DropEvent, targetAction: dropActionType) => void, ): DragDropDisposer { if ("canDrop" in element.dataset) { throw new Error( @@ -187,10 +187,7 @@ export namespace DragManager { const handler = (e: Event) => dropFunc(e, (e as CustomEvent).detail); const preDropHandler = (e: Event) => { const de = (e as CustomEvent).detail; - if (de.complete.docDragData && doc?.targetDropAction) { - de.complete.docDragData.dropAction = StrCast(doc.targetDropAction) as dropActionType; - } - preDropFunc?.(e, de); + preDropFunc?.(e, de, StrCast(doc?.targetDropAction) as dropActionType); }; element.addEventListener("dashOnDrop", handler); doc && element.addEventListener("dashPreDrop", preDropHandler); diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index c73e1a66a..d9281ac24 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -15,6 +15,7 @@ import { DocumentView } from "./nodes/DocumentView"; import GoogleAuthenticationManager from "../apis/GoogleAuthenticationManager"; import { CollectionFreeFormView } from "./collections/collectionFreeForm/CollectionFreeFormView"; import { MarqueeView } from "./collections/collectionFreeForm/MarqueeView"; +import { Id } from "../../new_fields/FieldSymbols"; const modifiers = ["control", "meta", "shift", "alt"]; type KeyHandler = (keycode: string, e: KeyboardEvent) => KeyControlInfo | Promise; @@ -240,8 +241,17 @@ export default class KeyManager { break; case "a": case "v": + stopPropagation = false; + preventDefault = false; + break; case "x": case "c": + SelectionManager.SelectedDocuments().length && navigator.clipboard.writeText("__DashDocId:" + SelectionManager.SelectedDocuments()[0].Document[Id]); + // window.getSelection()?.removeAllRanges(); + // let range = document.createRange(); + // range.selectNode(SelectionManager.SelectedDocuments()[0].ContentDiv!); + // window.getSelection()?.addRange(range); + // document.execCommand('copy'); stopPropagation = false; preventDefault = false; break; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index fad6bf295..b6dfe60e5 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -249,8 +249,7 @@ export class MainView extends React.Component { title: "Collection " + workspaceCount, }; const freeformDoc = CurrentUserUtils.GuestTarget || Docs.Create.FreeformDocument([], freeformOptions); - Doc.AddDocToList(Doc.GetProto(Doc.UserDoc().myDocuments as Doc), "data", freeformDoc); - const mainDoc = Docs.Create.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600, path: [Doc.UserDoc().myDocuments as Doc] }], { title: `Workspace ${workspaceCount}` }, id, "row"); + const mainDoc = Docs.Create.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600, path: [Doc.UserDoc().myCatalog as Doc] }], { title: `Workspace ${workspaceCount}` }, id, "row"); const toggleTheme = ScriptField.MakeScript(`self.darkScheme = !self.darkScheme`); mainDoc.contextMenuScripts = new List([toggleTheme!]); diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx index 80c7f3d25..b9036bf1e 100644 --- a/src/client/views/PreviewCursor.tsx +++ b/src/client/views/PreviewCursor.tsx @@ -6,6 +6,7 @@ import "./PreviewCursor.scss"; import { Docs } from '../documents/Documents'; import { Doc } from '../../new_fields/Doc'; import { Transform } from "../util/Transform"; +import { DocServer } from '../DocServer'; @observer export class PreviewCursor extends React.Component<{}> { @@ -49,6 +50,18 @@ export class PreviewCursor extends React.Component<{}> { })); } + if (e.clipboardData.getData("text/plain").includes("__DashDocId:")) { + const docid = e.clipboardData.getData("text/plain").split("__DashDocId:")[1]; + return DocServer.GetRefField(docid).then(doc => { + if (doc instanceof Doc) { + const alias = Doc.MakeAlias(doc); + alias.x = newPoint[0]; + alias.y = newPoint[1]; + PreviewCursor._addDocument(alias); + } + }); + } + // creates text document return PreviewCursor._addLiveTextDoc(Docs.Create.TextDocument("", { _width: 500, diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index c1edc0fe7..6fdb96f0d 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -527,7 +527,7 @@ export class CollectionDockingView extends React.Component(schemaCtor: (doc: Doc) => T, moreProps?: protected onGesture(e: Event, ge: GestureUtils.GestureEvent) { } - protected onInternalPreDrop(e: Event, de: DragManager.DropEvent) { + protected onInternalPreDrop(e: Event, de: DragManager.DropEvent, targetAction: dropActionType) { if (de.complete.docDragData) { - if (de.complete.docDragData.draggedDocuments.some(d => this.childDocs.includes(d))) { - de.complete.docDragData.dropAction = "move"; + // if targetDropAction is, say 'alias', but we're just dragging within a collection, we want to ignore the targetAction. + // otherwise, the targetAction should become the actual action (which can still be overridden by the userDropAction -eg, shift/ctrl keys) + if (targetAction && !de.complete.docDragData.draggedDocuments.some(d => d.context === this.props.Document && this.childDocs.includes(d))) { + de.complete.docDragData.dropAction = targetAction; } e.stopPropagation(); } diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 58d021b5c..7086ba380 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -410,7 +410,6 @@ class TreeView extends React.Component { @computed get renderTitle() { TraceMobx(); - const onItemDown = SetupDrag(this._tref, () => this.dataDoc, this.move, this.props.dropAction, this.props.treeViewId[Id], true); (!TreeView._editTitleScript) && (TreeView._editTitleScript = ScriptField.MakeFunction("setInPlace(self, 'editTitle', true)")); const headerElements = ( <> @@ -432,7 +431,7 @@ class TreeView extends React.Component {
      ); return <> -
      boolean; // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example) + filterAddDocument: (doc: Doc | Doc[]) => boolean; // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example) childLayoutTemplate?: () => Opt; // specify a layout Doc template to use for children of the collection childLayoutString?: string; // specify a layout string to use for children of the collection } export interface CollectionRenderProps { - addDocument: (document: Doc) => boolean; - removeDocument: (document: Doc) => boolean; - moveDocument: (document: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean) => boolean; + addDocument: (document: Doc | Doc[]) => boolean; + removeDocument: (document: Doc | Doc[]) => boolean; + moveDocument: (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean; active: () => boolean; whenActiveChanged: (isActive: boolean) => void; PanelWidth: () => number; @@ -152,7 +152,7 @@ export class CollectionView extends Touchable boolean): boolean => { + moveDocument = (doc: Doc, targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean): boolean => { if (Doc.AreProtosEqual(this.props.Document, targetCollection)) { return true; } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index e3b69b8f3..ebfc38a54 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -4,7 +4,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; import * as rp from "request-promise"; -import { Doc, DocListCast, HeightSym, Opt, WidthSym } from "../../../new_fields/Doc"; +import { Doc, DocListCast, HeightSym, Opt, WidthSym, DataSym } from "../../../new_fields/Doc"; import { Document } from '../../../new_fields/documentSchemas'; import { Id } from '../../../new_fields/FieldSymbols'; import { InkTool } from '../../../new_fields/InkField'; @@ -15,7 +15,7 @@ import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types"; import { ImageField } from '../../../new_fields/URLField'; import { TraceMobx } from '../../../new_fields/util'; import { GestureUtils } from '../../../pen-gestures/GestureUtils'; -import { emptyFunction, OmitKeys, returnOne, returnTransparent, Utils } from "../../../Utils"; +import { emptyFunction, OmitKeys, returnOne, returnTransparent, Utils, emptyPath } from "../../../Utils"; import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils'; import { ClientRecommender } from '../../ClientRecommender'; import { DocServer } from "../../DocServer"; @@ -549,7 +549,7 @@ export class DocumentView extends DocComponent(Docu if (!e.altKey && (!this.topMost || this.Document.onDragStart || this.onClickHandler) && (e.buttons === 1 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE))) { document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); - this.startDragging(this._downX, this._downY, this.props.dropAction ? this.props.dropAction : this.Document.dropAction ? this.Document.dropAction as any : e.ctrlKey || e.altKey ? "alias" : undefined); + this.startDragging(this._downX, this._downY, ((e.ctrlKey || e.altKey) && "alias") || (this.props.dropAction || this.Document.dropAction || undefined) as dropActionType); } } e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document' however it does mark the event as cancelBubble=true which we test for in the move event handlers @@ -721,6 +721,7 @@ export class DocumentView extends DocComponent(Docu let open = cm.findByDescription("Add a Perspective..."); const openItems: ContextMenuProps[] = open && "subitems" in open ? open.subitems : []; + openItems.push({ description: "New Echo ", event: () => this.props.addDocTab(Doc.MakeAlias(this.props.Document), "onRight"), icon: "layer-group" }); openItems.push({ description: "Open Fields ", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "onRight"), icon: "layer-group" }); templateDoc && openItems.push({ description: "Open Template ", event: () => this.props.addDocTab(templateDoc, "onRight"), icon: "eye" }); if (!open) { @@ -864,8 +865,12 @@ export class DocumentView extends DocComponent(Docu const path = this.props.LibraryPath.reduce((p: string, d: Doc) => p + "/" + (Doc.AreProtosEqual(d, (Doc.UserDoc()["tabs-button-library"] as Doc).sourcePanel as Doc) ? "" : d.title), ""); cm.addItem({ description: `path: ${path}`, event: () => { - this.props.LibraryPath.map(lp => Doc.GetProto(lp).treeViewOpen = lp.treeViewOpen = true); - Doc.linkFollowHighlight(this.props.Document); + if (this.props.LibraryPath !== emptyPath) { + this.props.LibraryPath.map(lp => Doc.GetProto(lp).treeViewOpen = lp.treeViewOpen = true); + Doc.linkFollowHighlight(this.props.Document); + } else { + Doc.AddDocToList(Doc.GetProto(Doc.UserDoc().myCatalog as Doc), "data", this.props.Document[DataSym]); + } }, icon: "check" }); } diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index a776b6f10..bebf77a8c 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -507,13 +507,13 @@ export class CurrentUserUtils { return doc.myWorkspaces as Doc; } - static setupDocumentCollection(doc: Doc) { - if (doc.myDocuments === undefined) { - doc.myDocuments = new PrefetchProxy(Docs.Create.TreeDocument([], { - title: "DOCUMENTS", _height: 42, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: false, lockedPosition: true, + static setupCatalog(doc: Doc) { + if (doc.myCatalog === undefined) { + doc.myCatalog = new PrefetchProxy(Docs.Create.TreeDocument([], { + title: "CATALOG", _height: 42, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: false, lockedPosition: true, })); } - return doc.myDocuments as Doc; + return doc.myCatalog as Doc; } static setupRecentlyClosed(doc: Doc) { // setup Recently Closed library item @@ -533,7 +533,7 @@ export class CurrentUserUtils { // setup the Library button which will display the library panel. This panel includes a collection of workspaces, documents, and recently closed views static setupLibraryPanel(doc: Doc, sidebarContainer: Doc) { const workspaces = CurrentUserUtils.setupWorkspaces(doc); - const documents = CurrentUserUtils.setupDocumentCollection(doc); + const documents = CurrentUserUtils.setupCatalog(doc); const recentlyClosed = CurrentUserUtils.setupRecentlyClosed(doc); if (doc["tabs-button-library"] === undefined) { @@ -541,7 +541,7 @@ export class CurrentUserUtils { _width: 50, _height: 25, title: "Library", _fontSize: 10, letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)", sourcePanel: new PrefetchProxy(Docs.Create.TreeDocument([workspaces, documents, recentlyClosed, doc], { - title: "Library", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "move", lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true + title: "Library", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias", lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true })) as any as Doc, targetContainer: new PrefetchProxy(sidebarContainer) as any as Doc, onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel;") -- cgit v1.2.3-70-g09d2 From 99028f27788740d377fec3504f9370412cd2947d Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 9 May 2020 16:57:23 -0400 Subject: fixed google docs prompt problem. --- src/client/apis/GoogleAuthenticationManager.tsx | 1 - .../views/nodes/formattedText/FormattedTextBox.tsx | 16 +++++++--------- 2 files changed, 7 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/client/apis/GoogleAuthenticationManager.tsx b/src/client/apis/GoogleAuthenticationManager.tsx index 018c980d8..22d6fb582 100644 --- a/src/client/apis/GoogleAuthenticationManager.tsx +++ b/src/client/apis/GoogleAuthenticationManager.tsx @@ -36,7 +36,6 @@ export default class GoogleAuthenticationManager extends React.Component<{}> { public fetchOrGenerateAccessToken = async (displayIfFound = false) => { let response: any = await Networking.FetchFromServer("/readGoogleAccessToken"); - // if this is an authentication url, activate the UI to register the new access token if (new RegExp(AuthenticationUrl).test(response)) { this.isOpen = true; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 63552321b..f3c277e20 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -790,15 +790,13 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } checkState = (exportState: Opt, dataDoc: Doc) => { - GoogleAuthenticationManager.Instance.fetchOrGenerateAccessToken().then(() => { - if (exportState && this._editorView) { - const equalContent = isEqual(this._editorView.state.doc, exportState.state.doc); - const equalTitles = dataDoc.title === exportState.title; - const unchanged = equalContent && equalTitles; - dataDoc.unchanged = unchanged; - DocumentButtonBar.Instance.setPullState(unchanged); - } - }); + if (exportState && this._editorView) { + const equalContent = isEqual(this._editorView.state.doc, exportState.state.doc); + const equalTitles = dataDoc.title === exportState.title; + const unchanged = equalContent && equalTitles; + dataDoc.unchanged = unchanged; + DocumentButtonBar.Instance.setPullState(unchanged); + } } clipboardTextSerializer = (slice: Slice): string => { -- cgit v1.2.3-70-g09d2 From 5c876f2f456f75e9886946f738f07a730688f38a Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 9 May 2020 17:44:14 -0400 Subject: lint fixes --- src/Utils.ts | 2 +- src/client/DocServer.ts | 2 +- src/client/views/DocComponent.tsx | 2 +- src/client/views/collections/CollectionSchemaCells.tsx | 6 +++--- .../views/collections/CollectionSchemaMovableTableHOC.tsx | 8 ++++---- src/client/views/collections/CollectionSchemaView.tsx | 6 +++--- src/client/views/collections/CollectionSubView.tsx | 6 +++--- src/client/views/collections/CollectionTreeView.tsx | 2 +- src/client/views/collections/CollectionView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/linking/LinkMenuItem.tsx | 2 +- src/client/views/nodes/VideoBox.tsx | 2 +- src/client/views/nodes/formattedText/DashFieldView.tsx | 5 +++-- src/new_fields/Doc.ts | 12 ++++++------ 14 files changed, 30 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/Utils.ts b/src/Utils.ts index 732f74bfc..bcb215804 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -323,7 +323,7 @@ export function OmitKeys(obj: any, keys: string[], pattern?: string, addKeyFunc? pattern && Array.from(Object.keys(omit)).filter(key => key.match(pattern)).forEach(key => { extract[key] = omit[key]; delete omit[key]; - }) + }); addKeyFunc?.(omit); return { omit, extract }; } diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index bf9fd232c..34ef502ad 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -250,7 +250,7 @@ export namespace DocServer { if (cached !== undefined && !(cached instanceof Promise)) { return cached; } - } + }; let _GetRefField: (id: string) => Promise> = errorFunc; let _GetCachedRefField: (id: string) => Opt = errorFunc; diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index 4e7d4c5ed..881e352a6 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -103,7 +103,7 @@ export function ViewBoxAnnotatableComponent

      doc.annotationOn = undefined); - const targetDataDoc = this.dataDoc; this + const targetDataDoc = this.dataDoc; const value = DocListCast(targetDataDoc[this.annotationKey]); const result = value.filter(v => !docs.includes(v)); if (result.length !== value.length) { diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx index 5253ee0b9..8a5450b0c 100644 --- a/src/client/views/collections/CollectionSchemaCells.tsx +++ b/src/client/views/collections/CollectionSchemaCells.tsx @@ -37,8 +37,8 @@ export interface CellProps { renderDepth: number; addDocTab: (document: Doc, where: string) => boolean; pinToPres: (document: Doc) => void; - moveDocument: (document: Doc, targetCollection: Doc | undefined, - addDocument: (document: Doc) => boolean) => boolean; + moveDocument: (document: Doc | Doc[], targetCollection: Doc | undefined, + addDocument: (document: Doc | Doc[]) => boolean) => boolean; isFocused: boolean; changeFocusedCellByIndex: (row: number, col: number) => void; setIsEditing: (isEditing: boolean) => void; @@ -185,7 +185,7 @@ export class CollectionSchemaCell extends React.Component { const onItemDown = (e: React.PointerEvent) => { fieldIsDoc && SetupDrag(this._focusRef, () => this._document[props.fieldKey] instanceof Doc ? this._document[props.fieldKey] : this._document, - this._document[props.fieldKey] instanceof Doc ? (doc: Doc, target: Doc | undefined, addDoc: (newDoc: Doc) => any) => addDoc(doc) : this.props.moveDocument, + this._document[props.fieldKey] instanceof Doc ? (doc: Doc | Doc[], target: Doc | undefined, addDoc: (newDoc: Doc | Doc[]) => any) => addDoc(doc) : this.props.moveDocument, this._document[props.fieldKey] instanceof Doc ? "alias" : this.props.Document.schemaDoc ? "copy" : undefined)(e); }; const onPointerEnter = (e: React.PointerEvent): void => { diff --git a/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx b/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx index 8636e3eb5..5aec46a83 100644 --- a/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx +++ b/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx @@ -130,8 +130,8 @@ export class MovableColumn extends React.Component { export interface MovableRowProps { rowInfo: RowInfo; ScreenToLocalTransform: () => Transform; - addDoc: (doc: Doc, relativeTo?: Doc, before?: boolean) => boolean; - removeDoc: (doc: Doc) => boolean; + addDoc: (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => boolean; + removeDoc: (doc: Doc | Doc[]) => boolean; rowFocused: boolean; textWrapRow: (doc: Doc) => void; rowWrapped: boolean; @@ -183,7 +183,7 @@ export class MovableRow extends React.Component { if (docDragData) { e.stopPropagation(); if (docDragData.draggedDocuments[0] === rowDoc) return true; - const addDocument = (doc: Doc) => this.props.addDoc(doc, rowDoc, before); + const addDocument = (doc: Doc | Doc[]) => this.props.addDoc(doc, rowDoc, before); const movedDocs = docDragData.draggedDocuments; return (docDragData.dropAction || docDragData.userDropAction) ? docDragData.droppedDocuments.reduce((added: boolean, d) => this.props.addDoc(d, rowDoc, before) || added, false) @@ -201,7 +201,7 @@ export class MovableRow extends React.Component { @undoBatch @action - move: DragManager.MoveFunction = (doc: Doc, targetCollection: Doc | undefined, addDoc) => { + move: DragManager.MoveFunction = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDoc) => { const targetView = targetCollection && DocumentManager.Instance.getDocumentView(targetCollection); if (targetView && targetView.props.ContainingCollectionDoc) { return doc !== targetCollection && doc !== targetView.props.ContainingCollectionDoc && this.props.removeDoc(doc) && addDoc(doc); diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index c0024293f..51ad6c81b 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -207,9 +207,9 @@ export interface SchemaTableProps { ContainingCollectionDoc: Opt; fieldKey: string; renderDepth: number; - deleteDocument: (document: Doc) => boolean; - addDocument: (document: Doc) => boolean; - moveDocument: (document: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean) => boolean; + deleteDocument: (document: Doc | Doc[]) => boolean; + addDocument: (document: Doc | Doc[]) => boolean; + moveDocument: (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean; ScreenToLocalTransform: () => Transform; active: (outsideReaction: boolean) => boolean; onDrop: (e: React.DragEvent, options: DocumentOptions, completed?: (() => void) | undefined) => void; diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 4fef16315..8b50bd8fc 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -246,7 +246,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: }; temporaryFileReader.readAsText(inputFile); }); - }; + } @undoBatch @action protected async onExternalDrop(e: React.DragEvent, options: DocumentOptions, completed?: () => void) { @@ -388,11 +388,11 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: file?.type === "application/json" && this.readUploadedFileAsText(file).then(result => { console.log(result); - const json = JSON.parse(result as string) as any; + const json = JSON.parse(result as string); addDocument(Docs.Create.TreeDocument( json["rectangular-puzzle"].crossword.clues[0].clue.map((c: any) => { const label = Docs.Create.LabelDocument({ title: c["#text"], _width: 120, _height: 20 }); - const proto = Doc.GetProto(label) + const proto = Doc.GetProto(label); proto._width = 120; proto._height = 20; return proto; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 7086ba380..f6fcc1ac4 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -673,7 +673,7 @@ export class CollectionTreeView extends CollectionSubView { - const docs = doc instanceof Doc ? [doc] : doc as Doc[]; + const docs = doc instanceof Doc ? [doc] : doc; const targetDataDoc = this.props.Document[DataSym]; const value = DocListCast(targetDataDoc[this.props.fieldKey]); const result = value.filter(v => !docs.includes(v)); diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 6c96baede..0841d9680 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -152,7 +152,7 @@ export class CollectionView extends Touchable boolean): boolean => { + moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean): boolean => { if (Doc.AreProtosEqual(this.props.Document, targetCollection)) { return true; } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index dfcb30588..6cc0cfcd2 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -786,7 +786,7 @@ export class CollectionFreeFormView extends CollectionSubView boolean): boolean => { + dragData.moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean): boolean => { docView.props.removeDocument?.(doc); addDocument(doc); return true; diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 208b93ba6..9602eac52 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -342,7 +342,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent { const curTime = (this.layoutDoc.currentTimecode || -1); curTime !== -1 && (doc.displayTimecode = curTime); - }) + }); return this.addDocument(doc); } diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx index f28057fd7..d5a28fd14 100644 --- a/src/client/views/nodes/formattedText/DashFieldView.tsx +++ b/src/client/views/nodes/formattedText/DashFieldView.tsx @@ -82,7 +82,7 @@ export class DashFieldViewInternal extends React.Component(); - let rtfMap: { copy: Doc, key: string, field: RichTextField }[] = []; + const cloneMap = new Map(); + const rtfMap: { copy: Doc, key: string, field: RichTextField }[] = []; const copy = Doc.makeClone(doc, cloneMap, rtfMap); rtfMap.map(({ copy, key, field }) => { const replacer = (match: any, attr: string, id: string, offset: any, string: any) => { @@ -605,7 +605,7 @@ export namespace Doc { return href + (mapped ? mapped[Id] : id); }; const regex = `(${Utils.prepend("/doc/")})([^"]*)`; - var re = new RegExp(regex, "g"); + const re = new RegExp(regex, "g"); copy[key] = new RichTextField(field.Data.replace(/("docid":|"targetId":|"linkId":)"([^"]+)"/g, replacer).replace(re, replacer2), field.Text); }); return copy; @@ -626,9 +626,9 @@ export namespace Doc { const list = Cast(doc[key], listSpec(Doc)); if (list !== undefined && !(list instanceof Promise)) { copy[key] = new List(list.filter(d => d instanceof Doc).map(d => Doc.makeClone(d as Doc, cloneMap, rtfs))); - } else if (doc[key] instanceof Doc) + } else if (doc[key] instanceof Doc) { copy[key] = key.includes("layout[") ? undefined : Doc.makeClone(doc[key] as Doc, cloneMap, rtfs); // reference documents except copy documents that are expanded teplate fields - else { + } else { copy[key] = ObjectField.MakeCopy(field); if (field instanceof RichTextField) { if (field.Data.includes('"docid":') || field.Data.includes('"targetId":') || field.Data.includes('"linkId":')) { @@ -636,7 +636,7 @@ export namespace Doc { } } } - } + }; if (key === "proto") { if (doc[key] instanceof Doc) { copy[key] = Doc.makeClone(doc[key]!, cloneMap, rtfs); -- cgit v1.2.3-70-g09d2 From 638fb6b16c4d69090e3806cca0a1a1909ec612c9 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 9 May 2020 21:43:04 -0400 Subject: added document clone and paste for all collections --- src/client/views/DocumentDecorations.tsx | 4 +- src/client/views/GlobalKeyHandler.ts | 65 +++++++++++++--- src/client/views/MainView.tsx | 2 + src/client/views/PreviewCursor.tsx | 91 ++++++++++++---------- .../views/collections/CollectionTreeView.tsx | 6 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 12 ++- .../collections/collectionFreeForm/MarqueeView.tsx | 5 +- 7 files changed, 127 insertions(+), 58 deletions(-) (limited to 'src') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 9b6105811..1054822c7 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -174,8 +174,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> } @undoBatch @action - onCloseClick = async (e: PointerEvent) => { - if (e.button === 0) { + onCloseClick = async (e: PointerEvent | undefined) => { + if (!e?.button) { const recent = Cast(Doc.UserDoc().myRecentlyClosed, Doc) as Doc; const selected = SelectionManager.SelectedDocuments().slice(); SelectionManager.DeselectAll(); diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index d9281ac24..3fd14735b 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -1,10 +1,10 @@ -import { UndoManager } from "../util/UndoManager"; +import { UndoManager, undoBatch } from "../util/UndoManager"; import { SelectionManager } from "../util/SelectionManager"; import { CollectionDockingView } from "./collections/CollectionDockingView"; import { MainView } from "./MainView"; import { DragManager } from "../util/DragManager"; import { action, runInAction } from "mobx"; -import { Doc } from "../../new_fields/Doc"; +import { Doc, DocListCast } from "../../new_fields/Doc"; import { DictationManager } from "../util/DictationManager"; import SharingManager from "../util/SharingManager"; import { Cast, PromiseValue, NumCast } from "../../new_fields/Types"; @@ -16,6 +16,11 @@ import GoogleAuthenticationManager from "../apis/GoogleAuthenticationManager"; import { CollectionFreeFormView } from "./collections/collectionFreeForm/CollectionFreeFormView"; import { MarqueeView } from "./collections/collectionFreeForm/MarqueeView"; import { Id } from "../../new_fields/FieldSymbols"; +import { DocumentDecorations } from "./DocumentDecorations"; +import { DocumentType } from "../documents/DocumentTypes"; +import { DocServer } from "../DocServer"; +import { List } from "../../new_fields/List"; +import { DateField } from "../../new_fields/DateField"; const modifiers = ["control", "meta", "shift", "alt"]; type KeyHandler = (keycode: string, e: KeyboardEvent) => KeyControlInfo | Promise; @@ -245,15 +250,25 @@ export default class KeyManager { preventDefault = false; break; case "x": + if (SelectionManager.SelectedDocuments().length) { + const bds = DocumentDecorations.Instance.Bounds; + const pt = [bds.x + (bds.r - bds.x) / 2, bds.y + (bds.b - bds.y) / 2]; + const text = `__DashDocId(${pt[0]},${pt[1]}):` + SelectionManager.SelectedDocuments().map(dv => dv.Document[Id]).join(":"); + SelectionManager.SelectedDocuments().length && navigator.clipboard.writeText(text); + DocumentDecorations.Instance.onCloseClick(undefined); + stopPropagation = false; + preventDefault = false; + } + break; case "c": - SelectionManager.SelectedDocuments().length && navigator.clipboard.writeText("__DashDocId:" + SelectionManager.SelectedDocuments()[0].Document[Id]); - // window.getSelection()?.removeAllRanges(); - // let range = document.createRange(); - // range.selectNode(SelectionManager.SelectedDocuments()[0].ContentDiv!); - // window.getSelection()?.addRange(range); - // document.execCommand('copy'); - stopPropagation = false; - preventDefault = false; + if (SelectionManager.SelectedDocuments().length) { + const bds = DocumentDecorations.Instance.Bounds; + const pt = [bds.x + (bds.r - bds.x) / 2, bds.y + (bds.b - bds.y) / 2]; + const text = `__DashDocId(${pt[0]},${pt[1]}):` + SelectionManager.SelectedDocuments().map(dv => dv.Document[Id]).join(":"); + SelectionManager.SelectedDocuments().length && navigator.clipboard.writeText(text);; + stopPropagation = false; + preventDefault = false; + } break; } @@ -263,6 +278,36 @@ export default class KeyManager { }; }); + public paste(e: ClipboardEvent) { + if (e.clipboardData?.getData("text/plain") !== "" && e.clipboardData?.getData("text/plain").startsWith("__DashDocId(")) { + const first = SelectionManager.SelectedDocuments().length ? SelectionManager.SelectedDocuments()[0] : undefined; + if (first?.props.Document.type === DocumentType.COL) { + const docids = e.clipboardData.getData("text/plain").split(":"); + let count = 1; + const list: Doc[] = []; + const targetDataDoc = Doc.GetProto(first.props.Document); + const fieldKey = Doc.LayoutFieldKey(first.props.Document); + const docList = DocListCast(targetDataDoc[fieldKey]); + docids.map((did, i) => i && DocServer.GetRefField(did).then(doc => { + count++; + if (doc instanceof Doc) { + list.push(doc); + } + if (count === docids.length) { + const added = list.filter(d => !docList.includes(d)); + if (added.length) { + added.map(doc => doc.context = targetDataDoc); + undoBatch(() => { + targetDataDoc[fieldKey] = new List([...docList, ...added]); + targetDataDoc[fieldKey + "-lastModified"] = new DateField(new Date(Date.now())); + })(); + } + } + })); + } + } + } + async printClipboard() { const text: string = await navigator.clipboard.readText(); } diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index b6dfe60e5..cbaae63bc 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -83,12 +83,14 @@ export class MainView extends React.Component { firstScriptTag.parentNode!.insertBefore(tag, firstScriptTag); window.removeEventListener("keydown", KeyManager.Instance.handle); window.addEventListener("keydown", KeyManager.Instance.handle); + window.addEventListener("paste", KeyManager.Instance.paste); } componentWillUnMount() { window.removeEventListener("keydown", KeyManager.Instance.handle); window.removeEventListener("pointerdown", this.globalPointerDown); window.removeEventListener("pointerup", this.globalPointerUp); + window.removeEventListener("paste", KeyManager.Instance.paste); } constructor(props: Readonly<{}>) { diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx index b9036bf1e..14b5b3fce 100644 --- a/src/client/views/PreviewCursor.tsx +++ b/src/client/views/PreviewCursor.tsx @@ -7,13 +7,15 @@ import { Docs } from '../documents/Documents'; import { Doc } from '../../new_fields/Doc'; import { Transform } from "../util/Transform"; import { DocServer } from '../DocServer'; +import { NumCast } from '../../new_fields/Types'; +import { undoBatch } from '../util/UndoManager'; @observer export class PreviewCursor extends React.Component<{}> { static _onKeyPress?: (e: KeyboardEvent) => void; static _getTransform: () => Transform; + static _addDocument: (doc: Doc | Doc[]) => void; static _addLiveTextDoc: (doc: Doc) => void; - static _addDocument: (doc: Doc) => boolean; static _nudge: (x: number, y: number) => boolean; @observable static _clickPoint = [0, 0]; @observable public static Visible = false; @@ -28,62 +30,73 @@ export class PreviewCursor extends React.Component<{}> { const newPoint = PreviewCursor._getTransform().transformPoint(PreviewCursor._clickPoint[0], PreviewCursor._clickPoint[1]); runInAction(() => PreviewCursor.Visible = false); + // tests for URL and makes web document + const re: any = /^https?:\/\//g; if (e.clipboardData.getData("text/plain") !== "") { // tests for youtube and makes video document if (e.clipboardData.getData("text/plain").indexOf("www.youtube.com/watch") !== -1) { const url = e.clipboardData.getData("text/plain").replace("youtube.com/watch?v=", "youtube.com/embed/"); - return PreviewCursor._addDocument(Docs.Create.VideoDocument(url, { + undoBatch(() => PreviewCursor._addDocument(Docs.Create.VideoDocument(url, { title: url, _width: 400, _height: 315, _nativeWidth: 600, _nativeHeight: 472.5, x: newPoint[0], y: newPoint[1] - })); + })))(); } - // tests for URL and makes web document - const re: any = /^https?:\/\//g; - if (re.test(e.clipboardData.getData("text/plain"))) { + else if (re.test(e.clipboardData.getData("text/plain"))) { const url = e.clipboardData.getData("text/plain"); - return PreviewCursor._addDocument(Docs.Create.WebDocument(url, { + undoBatch(() => PreviewCursor._addDocument(Docs.Create.WebDocument(url, { title: url, _width: 500, _height: 300, // nativeWidth: 300, nativeHeight: 472.5, x: newPoint[0], y: newPoint[1] - })); + })))(); } - if (e.clipboardData.getData("text/plain").includes("__DashDocId:")) { - const docid = e.clipboardData.getData("text/plain").split("__DashDocId:")[1]; - return DocServer.GetRefField(docid).then(doc => { + else if (e.clipboardData.getData("text/plain").startsWith("__DashDocId(")) { + const docids = e.clipboardData.getData("text/plain").split(":"); + const strs = docids[0].split(","); + const ptx = Number(strs[0].substring("__DashDocId(".length)); + const pty = Number(strs[1].substring(0, strs[1].length - 1)); + const center = PreviewCursor._getTransform().transformPoint(ptx, pty); + let count = 1; + const list: Doc[] = []; + docids.map((did, i) => i && DocServer.GetRefField(did).then(doc => { + count++; if (doc instanceof Doc) { - const alias = Doc.MakeAlias(doc); - alias.x = newPoint[0]; - alias.y = newPoint[1]; - PreviewCursor._addDocument(alias); + const alias = Doc.MakeClone(doc); + alias.x = newPoint[0] + NumCast(doc.x) - center[0]; + alias.y = newPoint[1] + NumCast(doc.y) - center[1]; + list.push(alias); } - }); - } + if (count === docids.length) { + undoBatch(() => PreviewCursor._addDocument(list))(); + } + })); - // creates text document - return PreviewCursor._addLiveTextDoc(Docs.Create.TextDocument("", { - _width: 500, - limitHeight: 400, - _autoHeight: true, - x: newPoint[0], - y: newPoint[1], - title: "-pasted text-" - })); - } - //pasting in images - if (e.clipboardData.getData("text/html") !== "" && e.clipboardData.getData("text/html").includes(" PreviewCursor._addLiveTextDoc(Docs.Create.TextDocument("", { + _width: 500, + limitHeight: 400, + _autoHeight: true, + x: newPoint[0], + y: newPoint[1], + title: "-pasted text-" + })))(); + } + } else + //pasting in images + if (e.clipboardData.getData("text/html") !== "" && e.clipboardData.getData("text/html").includes(" PreviewCursor._addDocument(Docs.Create.ImageDocument( + arr[1], { + _width: 300, title: arr[1], + x: newPoint[0], + y: newPoint[1], + })))(); + } } } @@ -125,7 +138,7 @@ export class PreviewCursor extends React.Component<{}> { onKeyPress: (e: KeyboardEvent) => void, addLiveText: (doc: Doc) => void, getTransform: () => Transform, - addDocument: (doc: Doc) => boolean, + addDocument: (doc: Doc | Doc[]) => boolean, nudge: (nudgeX: number, nudgeY: number) => boolean) { this._clickPoint = [x, y]; this._onKeyPress = onKeyPress; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index f6fcc1ac4..8cd34e7ed 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -396,7 +396,7 @@ class TreeView extends React.Component { } showContextMenu = (e: React.MouseEvent) => { - simulateMouseClick(this._docRef.current!.ContentDiv!, e.clientX, e.clientY + 30, e.screenX, e.screenY + 30); + this._docRef.current?.ContentDiv && simulateMouseClick(this._docRef.current.ContentDiv, e.clientX, e.clientY + 30, e.screenX, e.screenY + 30); e.stopPropagation(); } focusOnDoc = (doc: Doc) => DocumentManager.Instance.getFirstDocumentView(doc)?.props.focus(doc, true); @@ -772,6 +772,9 @@ export class CollectionTreeView extends CollectionSubView; } + onKeyPress = (e: React.KeyboardEvent) => { + console.log(e); + } render() { if (!(this.props.Document instanceof Doc)) return (null); const dropAction = StrCast(this.props.Document.childDropAction) as dropActionType; @@ -786,6 +789,7 @@ export class CollectionTreeView extends CollectionSubView this._mainEle && this._mainEle.scrollHeight > this._mainEle.clientHeight && e.stopPropagation()} onDrop={this.onTreeDrop} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 6cc0cfcd2..1bc59c727 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1246,8 +1246,16 @@ export class CollectionFreeFormView extends CollectionSubView + return {this.children} diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 1addea6a1..35d925bca 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -24,13 +24,10 @@ import React = require("react"); interface MarqueeViewProps { getContainerTransform: () => Transform; getTransform: () => Transform; - addDocument: (doc: Doc) => boolean; activeDocuments: () => Doc[]; selectDocuments: (docs: Doc[], ink: { Document: Doc, Ink: Map }[]) => void; - removeDocument: (doc: Doc) => boolean; addLiveTextDocument: (doc: Doc) => void; isSelected: () => boolean; - isAnnotationOverlay?: boolean; nudge: (x: number, y: number) => boolean; setPreviewCursor?: (func: (x: number, y: number, drag: boolean) => void) => void; } @@ -248,7 +245,7 @@ export class MarqueeView extends React.Component Date: Sun, 10 May 2020 10:31:07 -0400 Subject: fixed scaling of overlay collections --- .../collectionFreeForm/CollectionFreeFormView.tsx | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 1bc59c727..ed3e50f45 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,7 +1,7 @@ import { library } from "@fortawesome/fontawesome-svg-core"; import { faEye, faEyeSlash } from "@fortawesome/free-regular-svg-icons"; import { faBraille, faChalkboard, faCompass, faCompressArrowsAlt, faExpandArrowsAlt, faFileUpload, faPaintBrush, faTable, faUpload } from "@fortawesome/free-solid-svg-icons"; -import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from "mobx"; +import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction, _allowStateChangesInsideComputed } from "mobx"; import { observer } from "mobx-react"; import { computedFn } from "mobx-utils"; import { Doc, HeightSym, Opt, WidthSym, DocListCast } from "../../../../new_fields/Doc"; @@ -1061,9 +1061,19 @@ export class CollectionFreeFormView extends CollectionSubView this.doLayoutComputation, -- cgit v1.2.3-70-g09d2 From 5726d19a615385b0bcdf1e3a944056d31074edbb Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 10 May 2020 17:02:04 -0400 Subject: made opening docs on right not create aliases. made clicking on an original document trigger replacing it with an alias. --- .../views/collections/CollectionDockingView.tsx | 38 +++++++++++++++++----- .../views/collections/CollectionTreeView.tsx | 2 +- src/client/views/collections/CollectionView.tsx | 1 + .../collectionFreeForm/CollectionFreeFormView.tsx | 7 ++++ src/client/views/nodes/DocumentView.tsx | 13 +++++--- 5 files changed, 47 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 6fdb96f0d..6e9b2386d 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -71,8 +71,6 @@ export class CollectionDockingView extends React.Component { let config: any; if (dragDocs.length === 1) { @@ -192,6 +190,29 @@ export class CollectionDockingView extends React.Component { + if (!CollectionDockingView.Instance) return undefined; + const instance = CollectionDockingView.Instance; + const replaceTab = (doc: Doc, child: any): Opt => { + for (let i = 0; i < child.contentItems.length; i++) { + if (child.contentItems[i].isRow || child.contentItems[i].isColumn || child.contentItems[i].isStack) { + const val = replaceTab(doc, child.contentItems[i]); + if (val) return val; + } else if (child.contentItems[i].config.component === "DocumentFrameRenderer" && + child.contentItems[i].config.props.documentId === doc[Id]) { + const alias = Doc.MakeAlias(doc); + child.contentItems[i].config.props.documentId = alias[Id]; + child.contentItems[i].config.title = alias.title; + instance.stateChanged(); + return alias; + } + } + return undefined; + } + return replaceTab(document, instance._goldenLayout.root); + } // // Creates a vertical split on the right side of the docking view, and then adds the Document to the right of that split @@ -455,12 +476,6 @@ export class CollectionDockingView extends React.Component { @@ -789,6 +804,13 @@ export class DockedFrameRenderer extends React.Component { return CollectionDockingView.AddRightSplit(doc, libraryPath); } else if (location === "close") { return CollectionDockingView.CloseRightSplit(doc); + } else if (location === "replace") { + const alias = CollectionDockingView.ReplaceTab(doc, this._stack); + if (alias) { + runInAction(() => this._document = alias); + return true; + } + return false; } else {// if (location === "inPlace") { return CollectionDockingView.Instance.AddTab(this._stack, doc, libraryPath); } diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 8cd34e7ed..2f332e77d 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -108,7 +108,7 @@ class TreeView extends React.Component { Doc.ComputeContentBounds(DocListCast(this.props.document[this.fieldKey])); } - @undoBatch openRight = () => this.props.addDocTab(this.props.dropAction === "alias" ? Doc.MakeAlias(this.props.document) : this.props.document, "onRight", this.props.libraryPath); + @undoBatch openRight = () => this.props.addDocTab(this.props.document, "onRight", this.props.libraryPath); @undoBatch move = (doc: Doc | Doc[], target: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => { return this.props.document !== target && this.props.deleteDoc(doc) && addDoc(doc); } diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 0841d9680..ac9f64d94 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -128,6 +128,7 @@ export class CollectionView extends Touchable !docList.includes(d)); if (added.length) { added.map(doc => doc.context = this.props.Document); + added.map(add => Doc.AddDocToList(Cast(Doc.UserDoc().myCatalog, Doc, null), "data", add)); targetDataDoc[this.props.fieldKey] = new List([...docList, ...added]); targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now())); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index ed3e50f45..61081618a 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -339,6 +339,13 @@ export class CollectionFreeFormView extends CollectionSubView(Docu }, console.log); func(); } else { - const fullScreenAlias = Doc.MakeAlias(this.props.Document); - if (StrCast(fullScreenAlias.layoutKey) !== "layout_fullScreen" && fullScreenAlias.layout_fullScreen) { - fullScreenAlias.layoutKey = "layout_fullScreen"; - } - UndoManager.RunInBatch(() => this.props.addDocTab(fullScreenAlias, "inTab"), "double tap"); + UndoManager.RunInBatch(() => { + if (StrCast(this.props.Document.layoutKey) !== "layout_fullScreen" && this.props.Document.layout_fullScreen) { + const fullScreenAlias = Doc.MakeAlias(this.props.Document); + fullScreenAlias.layoutKey = "layout_fullScreen"; + this.props.addDocTab(fullScreenAlias, "inTab"); + this.props.addDocTab(this.props.Document, "inTab"); + } + }, "double tap"); SelectionManager.DeselectAll(); Doc.UnBrushDoc(this.props.Document); } -- cgit v1.2.3-70-g09d2 From 56161b9541a8232fca11e69ffb1bf22864a941a1 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 11 May 2020 01:51:12 -0400 Subject: compile error fixes. fix to freeform view zooming when zoomed way out. --- src/client/views/GlobalKeyHandler.ts | 2 +- src/client/views/TemplateMenu.tsx | 4 ++-- src/client/views/collections/CollectionDockingView.tsx | 2 +- .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/collections/collectionFreeForm/MarqueeView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 1 + 6 files changed, 7 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index 3fd14735b..1b16b15bb 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -265,7 +265,7 @@ export default class KeyManager { const bds = DocumentDecorations.Instance.Bounds; const pt = [bds.x + (bds.r - bds.x) / 2, bds.y + (bds.b - bds.y) / 2]; const text = `__DashDocId(${pt[0]},${pt[1]}):` + SelectionManager.SelectedDocuments().map(dv => dv.Document[Id]).join(":"); - SelectionManager.SelectedDocuments().length && navigator.clipboard.writeText(text);; + SelectionManager.SelectedDocuments().length && navigator.clipboard.writeText(text); stopPropagation = false; preventDefault = false; } diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index 5f300372f..43debfe99 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -113,8 +113,8 @@ export class TemplateMenu extends React.Component { render() { const firstDoc = this.props.docViews[0].props.Document; const templateName = StrCast(firstDoc.layoutKey, "layout").replace("layout_", ""); - const noteTypes = DocListCast(Cast(Doc.UserDoc()["template-notes"], Doc, null)); - const addedTypes = DocListCast(Cast(Doc.UserDoc().templateButtons, Doc, null)?.data); + const noteTypes = DocListCast(Cast(Doc.UserDoc()["template-notes"], Doc, null)?.data); + const addedTypes = DocListCast(Cast(Doc.UserDoc()["template-buttons"], Doc, null)?.data); const layout = Doc.Layout(firstDoc); const templateMenu: Array = []; this.props.templates.forEach((checked, template) => diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 6e9b2386d..296b2453b 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -210,7 +210,7 @@ export class CollectionDockingView extends React.Component= 0.15) { + if (localTransform.Scale >= 0.15 || localTransform.Scale > this.zoomScaling()) { const safeScale = Math.min(Math.max(0.15, localTransform.Scale), 40); this.props.Document.scale = Math.abs(safeScale); this.setPan(-localTransform.TranslateX / safeScale, -localTransform.TranslateY / safeScale); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 35d925bca..8e20b39d2 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -245,7 +245,7 @@ export class MarqueeView extends React.Component(Docu const fullScreenAlias = Doc.MakeAlias(this.props.Document); fullScreenAlias.layoutKey = "layout_fullScreen"; this.props.addDocTab(fullScreenAlias, "inTab"); + } else { this.props.addDocTab(this.props.Document, "inTab"); } }, "double tap"); -- cgit v1.2.3-70-g09d2 From a3839d4b5a2180e2e80fa79f6eb4459e2976f380 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 11 May 2020 14:59:54 -0400 Subject: changed Cors behavior for WebBox(On for everything except GoogldDocs). Update Freeze to work for ctrl-resizing text, and showing full screen. reorged context menus. --- src/client/views/DocumentButtonBar.tsx | 2 +- src/client/views/DocumentDecorations.scss | 1 + src/client/views/DocumentDecorations.tsx | 1 + src/client/views/MainView.tsx | 1 + src/client/views/PreviewCursor.tsx | 2 +- .../views/collections/CollectionDockingView.tsx | 12 ++++---- .../views/collections/CollectionStackingView.tsx | 1 + .../collectionFreeForm/CollectionFreeFormView.tsx | 27 +++++++++--------- src/client/views/nodes/DocumentView.tsx | 25 ++++++---------- src/client/views/nodes/ImageBox.tsx | 33 +++++++++++++--------- src/client/views/nodes/WebBox.tsx | 8 ++---- .../views/nodes/formattedText/FormattedTextBox.tsx | 18 +++++++++++- .../formattedText/FormattedTextBoxComment.tsx | 2 +- src/new_fields/Doc.ts | 26 +++++++++++------ .../authentication/models/current_user_utils.ts | 2 +- 15 files changed, 94 insertions(+), 67 deletions(-) (limited to 'src') diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 48685302a..10d9ec401 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -194,7 +194,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV e.preventDefault(); let googleDoc = await Cast(dataDoc.googleDoc, Doc); if (!googleDoc) { - const options = { _width: 600, _nativeWidth: 960, _nativeHeight: 800, isAnnotating: false }; + const options = { _width: 600, _nativeWidth: 960, _nativeHeight: 800, isAnnotating: false, UseCors: false }; googleDoc = Docs.Create.WebDocument(googleDocUrl, options); dataDoc.googleDoc = googleDoc; } diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss index 4f34eb9e3..15eb537da 100644 --- a/src/client/views/DocumentDecorations.scss +++ b/src/client/views/DocumentDecorations.scss @@ -72,6 +72,7 @@ $linkGap : 3px; grid-column-start: 5; grid-column-end: 7; border-radius: 100%; + background: dimgray; .borderRadiusTooltip { width: 10px; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 1054822c7..9669c21a9 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -301,6 +301,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> } SelectionManager.SelectedDocuments().forEach(action((element: DocumentView) => { + if (e.ctrlKey && !element.props.Document._nativeHeight) element.toggleNativeDimensions(); if (dX !== 0 || dY !== 0 || dW !== 0 || dH !== 0) { const doc = Document(element.rootDoc); let nwidth = doc._nativeWidth || 0; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index cbaae63bc..560dd5d11 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -249,6 +249,7 @@ export class MainView extends React.Component { _width: this._panelWidth * .7, _height: this._panelHeight, title: "Collection " + workspaceCount, + _LODdisable: true }; const freeformDoc = CurrentUserUtils.GuestTarget || Docs.Create.FreeformDocument([], freeformOptions); const mainDoc = Docs.Create.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600, path: [Doc.UserDoc().myCatalog as Doc] }], { title: `Workspace ${workspaceCount}` }, id, "row"); diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx index 14b5b3fce..2ddca369a 100644 --- a/src/client/views/PreviewCursor.tsx +++ b/src/client/views/PreviewCursor.tsx @@ -46,7 +46,7 @@ export class PreviewCursor extends React.Component<{}> { else if (re.test(e.clipboardData.getData("text/plain"))) { const url = e.clipboardData.getData("text/plain"); undoBatch(() => PreviewCursor._addDocument(Docs.Create.WebDocument(url, { - title: url, _width: 500, _height: 300, + title: url, _width: 500, _height: 300, UseCors: true, // nativeWidth: 300, nativeHeight: 472.5, x: newPoint[0], y: newPoint[1] })))(); diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 296b2453b..50e3b73eb 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -755,8 +755,10 @@ export class DockedFrameRenderer extends React.Component { } get layoutDoc() { return this._document && Doc.Layout(this._document); } - panelWidth = () => this.layoutDoc && this.layoutDoc.maxWidth ? Math.min(Math.max(NumCast(this.layoutDoc._width), NumCast(this.layoutDoc._nativeWidth)), this._panelWidth) : this._panelWidth; - panelHeight = () => this._panelHeight; + nativeAspect = () => this.nativeWidth() ? this.nativeWidth() / this.nativeHeight() : 0; + panelWidth = () => this.layoutDoc?.maxWidth ? Math.min(Math.max(NumCast(this.layoutDoc._width), NumCast(this.layoutDoc._nativeWidth)), this._panelWidth) : + (this.nativeAspect() && this.nativeAspect() < this._panelWidth / this._panelHeight ? this._panelHeight * this.nativeAspect() : this._panelWidth); + panelHeight = () => this.nativeAspect() && this.nativeAspect() > this._panelWidth / this._panelHeight ? this._panelWidth / this.nativeAspect() : this._panelHeight; nativeWidth = () => !this.layoutDoc!._fitWidth ? NumCast(this.layoutDoc!._nativeWidth) || this._panelWidth : 0; nativeHeight = () => !this.layoutDoc!._fitWidth ? NumCast(this.layoutDoc!._nativeHeight) || this._panelHeight : 0; @@ -794,7 +796,7 @@ export class DockedFrameRenderer extends React.Component { return Transform.Identity(); } get previewPanelCenteringOffset() { return this.nativeWidth() ? (this._panelWidth - this.nativeWidth() * this.contentScaling()) / 2 : 0; } - get widthpercent() { return this.nativeWidth() ? `${(this.nativeWidth() * this.contentScaling()) / this.panelWidth() * 100}%` : undefined; } + get widthpercent() { return this.nativeWidth() ? `${(this.nativeWidth() * this.contentScaling()) / this._panelWidth * 100}%` : undefined; } addDocTab = (doc: Doc, location: string, libraryPath?: Doc[]) => { SelectionManager.DeselectAll(); @@ -832,8 +834,8 @@ export class DockedFrameRenderer extends React.Component { ContentScaling={this.contentScaling} PanelWidth={this.panelWidth} PanelHeight={this.panelHeight} - NativeHeight={returnZero} - NativeWidth={returnZero} + NativeHeight={this.nativeHeight} + NativeWidth={this.nativeWidth} ScreenToLocalTransform={this.ScreenToLocalTransform} renderDepth={0} parentActive={returnTrue} diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index c199988c0..979e9e3f8 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -432,6 +432,7 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument) if (!e.isPropagationStopped()) { const subItems: ContextMenuProps[] = []; subItems.push({ description: `${this.props.Document.fillColumn ? "Variable Size" : "Autosize"} Column`, event: () => this.props.Document.fillColumn = !this.props.Document.fillColumn, icon: "plus" }); + subItems.push({ description: `${this.Document._autoHeight ? "Variable Height" : "Auto Height"}`, event: () => this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight, icon: "plus" }); ContextMenu.Instance.addItem({ description: "Options...", subitems: subItems, icon: "eye" }); } } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index d24ba6bb0..129b245b8 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -113,8 +113,8 @@ export class CollectionFreeFormView extends CollectionSubView !this.nativeWidth && !this.isAnnotationOverlay ? this.props.PanelWidth() / 2 / this.parentScaling : 0; // shift so pan position is at center of window for non-overlay collections - private centeringShiftY = () => !this.nativeHeight && !this.isAnnotationOverlay ? this.props.PanelHeight() / 2 / this.parentScaling : 0;// shift so pan position is at center of window for non-overlay collections + private centeringShiftX = () => !this.isAnnotationOverlay ? this.props.PanelWidth() / 2 / this.parentScaling / this.contentScaling : 0; // shift so pan position is at center of window for non-overlay collections + private centeringShiftY = () => !this.isAnnotationOverlay ? this.props.PanelHeight() / 2 / this.parentScaling / this.contentScaling : 0;// shift so pan position is at center of window for non-overlay collections private getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth + 1, -this.borderWidth + 1).translate(-this.centeringShiftX(), -this.centeringShiftY()).transform(this.getLocalTransform()); private getTransformOverlay = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth + 1, -this.borderWidth + 1); private getContainerTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth, -this.borderWidth); @@ -340,12 +340,12 @@ export class CollectionFreeFormView extends CollectionSubView { + Doc.toggleNativeDimensions(this.layoutDoc, this.props.ContentScaling(), this.props.NativeWidth(), this.props.NativeHeight()); + } private thumbIdentifier?: number; @@ -1138,6 +1138,7 @@ export class CollectionFreeFormView extends CollectionSubView { this.props.Document._panX = this.props.Document._panY = 0; this.props.Document.scale = 1; }, icon: "compress-arrows-alt" }); + optionItems.push({ description: !this.layoutDoc._nativeWidth || !this.layoutDoc._nativeHeight ? "Freeze" : "Unfreeze", event: this.toggleNativeDimensions, icon: "snowflake" }); optionItems.push({ description: `${this.Document._LODdisable ? "Enable LOD" : "Disable LOD"}`, event: () => this.Document._LODdisable = !this.Document._LODdisable, icon: "table" }); optionItems.push({ description: `${this.fitToContent ? "Unset" : "Set"} Fit To Container`, event: () => this.Document._fitToBox = !this.fitToContent, icon: !this.fitToContent ? "expand-arrows-alt" : "compress-arrows-alt" }); optionItems.push({ description: `${this.Document.useClusters ? "Uncluster" : "Use Clusters"}`, event: () => this.updateClusters(!this.Document.useClusters), icon: "braille" }); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index aca0433bb..6c9ade83f 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -648,18 +648,8 @@ export class DocumentView extends DocComponent(Docu @undoBatch @action - public static unfreezeNativeDimensions(layoutDoc: Doc) { - layoutDoc._nativeWidth = undefined; - layoutDoc._nativeHeight = undefined; - } - toggleNativeDimensions = () => { - if (this.Document._nativeWidth || this.Document._nativeHeight) { - DocumentView.unfreezeNativeDimensions(this.layoutDoc); - } - else { - Doc.freezeNativeDimensions(this.layoutDoc, this.props.PanelWidth(), this.props.PanelHeight()); - } + Doc.toggleNativeDimensions(this.layoutDoc, this.props.ContentScaling(), this.props.PanelWidth(), this.props.PanelHeight()); } @undoBatch @@ -735,10 +725,6 @@ export class DocumentView extends DocComponent(Docu let options = cm.findByDescription("Options..."); const optionItems: ContextMenuProps[] = options && "subitems" in options ? options.subitems : []; - optionItems.push({ description: `${this.Document._chromeStatus !== "disabled" ? "Hide" : "Show"} Chrome`, event: () => this.Document._chromeStatus = (this.Document._chromeStatus !== "disabled" ? "disabled" : "enabled"), icon: "project-diagram" }); - optionItems.push({ description: `${this.Document._autoHeight ? "Variable Height" : "Auto Height"}`, event: () => this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight, icon: "plus" }); - optionItems.push({ description: this.Document.lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.Document.lockedPosition) ? "unlock" : "lock" }); - optionItems.push({ description: this.Document.lockedTransform ? "Unlock Transform" : "Lock Transform", event: this.toggleLockTransform, icon: BoolCast(this.Document.lockedTransform) ? "unlock" : "lock" }); if (!options) { options = { description: "Options...", subitems: optionItems, icon: "compass" }; cm.addItem(options); @@ -757,6 +743,7 @@ export class DocumentView extends DocComponent(Docu onClicks.push({ description: "Edit onClick Script", event: () => UndoManager.RunInBatch(() => Doc.makeCustomViewClicked(this.props.Document, undefined, "onClick"), "edit onClick"), icon: "edit" }); !existingOnClick && cm.addItem({ description: "OnClick...", subitems: onClicks, icon: "hand-point-right" }); + const funcs: ContextMenuProps[] = []; if (this.Document.onDragStart) { funcs.push({ description: "Drag an Alias", icon: "edit", event: () => this.Document.dragFactory && (this.Document.onDragStart = ScriptField.MakeFunction('getAlias(this.dragFactory)')) }); @@ -768,7 +755,9 @@ export class DocumentView extends DocComponent(Docu const more = cm.findByDescription("More..."); const moreItems: ContextMenuProps[] = more && "subitems" in more ? more.subitems : []; moreItems.push({ description: "Make View of Metadata Field", event: () => Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.DataDoc), icon: "concierge-bell" }); - moreItems.push({ description: !this.Document._nativeWidth || !this.Document._nativeHeight ? "Freeze" : "Unfreeze", event: this.toggleNativeDimensions, icon: "snowflake" }); + moreItems.push({ description: `${this.Document._chromeStatus !== "disabled" ? "Hide" : "Show"} Chrome`, event: () => this.Document._chromeStatus = (this.Document._chromeStatus !== "disabled" ? "disabled" : "enabled"), icon: "project-diagram" }); + moreItems.push({ description: this.Document.lockedTransform ? "Unlock Transform" : "Lock Transform", event: this.toggleLockTransform, icon: BoolCast(this.Document.lockedTransform) ? "unlock" : "lock" }); + moreItems.push({ description: this.Document.lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.Document.lockedPosition) ? "unlock" : "lock" }); if (!ClientUtils.RELEASE) { // let copies: ContextMenuProps[] = []; @@ -794,6 +783,7 @@ export class DocumentView extends DocComponent(Docu // a.download = `DocExport-${this.props.Document[Id]}.zip`; // a.click(); }); + const recommender_subitems: ContextMenuProps[] = []; recommender_subitems.push({ @@ -826,6 +816,9 @@ export class DocumentView extends DocComponent(Docu moreItems.push({ description: "Publish", event: () => DocUtils.Publish(this.props.Document, this.Document.title || "", this.props.addDocument, this.props.removeDocument), icon: "file" }); moreItems.push({ description: "Undo Debug Test", event: () => UndoManager.TraceOpenBatches(), icon: "exclamation" }); !more && cm.addItem({ description: "More...", subitems: moreItems, icon: "hand-point-right" }); + + cm.moveAfter(cm.findByDescription("More...")!, cm.findByDescription("OnClick...")!); + runInAction(() => { if (!ClientUtils.RELEASE) { const setWriteMode = (mode: DocServer.WriteMode) => { diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 4153c184e..d85373e98 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -157,21 +157,20 @@ export class ImageBox extends ViewBoxAnnotatableComponent Utils.CopyText(field.url.href), icon: "expand-arrows-alt" }); funcs.push({ description: "Rotate", event: this.rotate, icon: "expand-arrows-alt" }); - funcs.push({ - description: "Reset Native Dimensions", event: action(async () => { - const curNW = NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"]); - const curNH = NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"]); - if (this.props.PanelWidth() / this.props.PanelHeight() > curNW / curNH) { - this.dataDoc[this.fieldKey + "-nativeWidth"] = this.props.PanelHeight() * curNW / curNH; - this.dataDoc[this.fieldKey + "-nativeHeight"] = this.props.PanelHeight(); - } else { - this.dataDoc[this.fieldKey + "-nativeWidth"] = this.props.PanelWidth(); - this.dataDoc[this.fieldKey + "-nativeHeight"] = this.props.PanelWidth() * curNH / curNW; - } - }), icon: "expand-arrows-alt" - }); + // funcs.push({ + // description: "Reset Native Dimensions", event: action(async () => { + // const curNW = NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"]); + // const curNH = NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"]); + // if (this.props.PanelWidth() / this.props.PanelHeight() > curNW / curNH) { + // this.dataDoc[this.fieldKey + "-nativeWidth"] = this.props.PanelHeight() * curNW / curNH; + // this.dataDoc[this.fieldKey + "-nativeHeight"] = this.props.PanelHeight(); + // } else { + // this.dataDoc[this.fieldKey + "-nativeWidth"] = this.props.PanelWidth(); + // this.dataDoc[this.fieldKey + "-nativeHeight"] = this.props.PanelWidth() * curNH / curNW; + // } + // }), icon: "expand-arrows-alt" + // }); const existingAnalyze = ContextMenu.Instance.findByDescription("Analyzers..."); const modes: ContextMenuProps[] = existingAnalyze && "subitems" in existingAnalyze ? existingAnalyze.subitems : []; @@ -181,6 +180,12 @@ export class ImageBox extends ViewBoxAnnotatableComponent Utils.CopyText(field.url.href), icon: "expand-arrows-alt" }); + !existingMore && ContextMenu.Instance.addItem({ description: "More...", subitems: mores, icon: "hand-point-right" }); } } diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 8239d6fdf..384a6e8a5 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -129,14 +129,12 @@ export class WebBox extends ViewBoxAnnotatableComponent { + toggleAnnotationMode = () => { if (!this.layoutDoc.isAnnotating) { - //DocumentView.unfreezeNativeDimensions(this.layoutDoc); this.layoutDoc.lockedTransform = false; this.layoutDoc.isAnnotating = true; } else { - //Doc.freezeNativeDimensions(this.layoutDoc, this.props.PanelWidth(), this.props.PanelHeight()); this.layoutDoc.lockedTransform = true; this.layoutDoc.isAnnotating = false; } @@ -158,10 +156,10 @@ export class WebBox extends ViewBoxAnnotatableComponent

      -
      +
      -
      +
      { + Doc.toggleNativeDimensions(this.layoutDoc, this.props.ContentScaling(), this.props.NativeWidth(), this.props.NativeHeight()); + } public static get DefaultLayout(): Doc | string | undefined { return Cast(Doc.UserDoc().defaultTextLayout, Doc, null) || StrCast(Doc.UserDoc().defaultTextLayout, null); @@ -438,6 +443,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp Doc.AddDocToList(Cast(Doc.UserDoc()["template-notes"], Doc, null), "data", this.rootDoc); }, icon: "eye" }); + //funcs.push({ description: `${this.Document._autoHeight ? "Variable Height" : "Auto Height"}`, event: () => this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight, icon: "plus" }); + funcs.push({ description: !this.layoutDoc._nativeWidth || !this.layoutDoc._nativeHeight ? "Freeze" : "Unfreeze", event: this.toggleNativeDimensions, icon: "snowflake" }); funcs.push({ description: "Toggle Single Line", event: () => this.layoutDoc._singleLine = !this.layoutDoc._singleLine, icon: "expand-arrows-alt" }); funcs.push({ description: "Toggle Sidebar", event: () => this.layoutDoc._showSidebar = !this.layoutDoc._showSidebar, icon: "expand-arrows-alt" }); funcs.push({ description: "Toggle Dictation Icon", event: () => this.layoutDoc._showAudio = !this.layoutDoc._showAudio, icon: "expand-arrows-alt" }); @@ -649,10 +656,14 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } } ); - this._disposers.height = reaction( + this._disposers.autoHeight = reaction( () => [this.layoutDoc[WidthSym](), this.layoutDoc._autoHeight], () => this.tryUpdateHeight() ); + this._disposers.height = reaction( + () => this.layoutDoc[HeightSym](), + height => height <= 20 && (this.layoutDoc._autoHeight = true) + ); this.setupEditor(this.config, this.props.fieldKey); @@ -1206,6 +1217,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp render() { TraceMobx(); const style: { [key: string]: any } = {}; + const scale = this.props.ContentScaling() * NumCast(this.layoutDoc.scale, 1); const divKeys = ["width", "height", "background"]; const replacer = (match: any, expr: string, offset: any, string: any) => { // bcz: this executes a script to convert a propery expression string: { script } into a value return ScriptField.MakeFunction(expr, { self: Doc.name, this: Doc.name })?.script.run({ self: this.rootDoc, this: this.layoutDoc }).result as string || ""; @@ -1258,6 +1270,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
      diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx index 9ad5aafb8..a33717855 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx @@ -91,7 +91,7 @@ export class FormattedTextBoxComment { (doc: Doc, followLinkLocation: string) => textBox.props.addDocTab(doc, e.ctrlKey ? "inTab" : followLinkLocation)); } } else if (textBox && (FormattedTextBoxComment.tooltipText as any).href) { - textBox.props.addDocTab(Docs.Create.WebDocument((FormattedTextBoxComment.tooltipText as any).href, { title: (FormattedTextBoxComment.tooltipText as any).href, _width: 200, _height: 400 }), "onRight"); + textBox.props.addDocTab(Docs.Create.WebDocument((FormattedTextBoxComment.tooltipText as any).href, { title: (FormattedTextBoxComment.tooltipText as any).href, _width: 200, _height: 400, UseCors: true }), "onRight"); } keep && textBox && FormattedTextBoxComment.start !== undefined && textBox.adoptAnnotation( FormattedTextBoxComment.start, FormattedTextBoxComment.end, FormattedTextBoxComment.mark); diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index e0627fb37..a1e1e11b1 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -20,7 +20,6 @@ import { deleteProperty, getField, getter, makeEditable, makeReadOnly, setter, u import { Docs, DocumentOptions } from "../client/documents/Documents"; import { PdfField, VideoField, AudioField, ImageField } from "./URLField"; import { LinkManager } from "../client/util/LinkManager"; -import { string32 } from "../../deploy/assets/pdf.worker"; export namespace Field { export function toKeyValueString(doc: Doc, key: string): string { @@ -936,19 +935,28 @@ export namespace Doc { } } } - - export function freezeNativeDimensions(layoutDoc: Doc, width: number, height: number): void { - layoutDoc._autoHeight = false; - if (!layoutDoc._nativeWidth) { - layoutDoc._nativeWidth = NumCast(layoutDoc._width, width); - layoutDoc._nativeHeight = NumCast(layoutDoc._height, height); - } - } export function assignDocToField(doc: Doc, field: string, id: string) { DocServer.GetRefField(id).then(layout => layout instanceof Doc && (doc[field] = layout)); return id; } + export function toggleNativeDimensions(layoutDoc: Doc, contentScale: number, panelWidth: number, panelHeight: number) { + runInAction(() => { + if (layoutDoc._nativeWidth || layoutDoc._nativeHeight) { + layoutDoc.scale = NumCast(layoutDoc.scale, 1) * contentScale; + layoutDoc._nativeWidth = undefined; + layoutDoc._nativeHeight = undefined; + } + else { + layoutDoc._autoHeight = false; + if (!layoutDoc._nativeWidth) { + layoutDoc._nativeWidth = NumCast(layoutDoc._width, panelWidth); + layoutDoc._nativeHeight = NumCast(layoutDoc._height, panelHeight); + } + } + }); + } + export function isDocPinned(doc: Doc) { //add this new doc to props.Document const curPres = Cast(Doc.UserDoc().activePresentation, Doc) as Doc; diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index bebf77a8c..b6ff10bab 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -315,7 +315,7 @@ export class CurrentUserUtils { { _width: 250, _height: 250, title: "container" }); } if (doc.emptyWebpage === undefined) { - doc.emptyWebpage = Docs.Create.WebDocument("", { title: "New Webpage", _width: 600 }); + doc.emptyWebpage = Docs.Create.WebDocument("", { title: "New Webpage", _width: 600, UseCors: true }); } return [ { title: "Drag a collection", label: "Col", icon: "folder", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyCollection as Doc }, -- cgit v1.2.3-70-g09d2 From 7e1f89f48d1c4e49dea78dff1c1983e75a11a6a6 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 11 May 2020 17:13:53 -0400 Subject: fixed issues with text auto height and scaled documents. allowed #tagging in text notes to support muliple values with ';'. DashFieldviews can have multiple values, too. logout is moved to settings. --- src/client/util/SettingsManager.tsx | 5 + src/client/views/DocumentDecorations.tsx | 8 +- src/client/views/MainView.scss | 4 +- src/client/views/MainView.tsx | 5 +- src/client/views/nodes/DocumentView.tsx | 2 +- .../views/nodes/formattedText/DashFieldView.tsx | 7 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 176 +++++++++++---------- .../views/nodes/formattedText/RichTextRules.ts | 6 +- 8 files changed, 119 insertions(+), 94 deletions(-) (limited to 'src') diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx index ff0b22381..e20434461 100644 --- a/src/client/util/SettingsManager.tsx +++ b/src/client/util/SettingsManager.tsx @@ -8,6 +8,8 @@ import { SelectionManager } from "./SelectionManager"; import "./SettingsManager.scss"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { Networking } from "../Network"; +import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils"; +import { Utils } from "../../Utils"; library.add(fa.faWindowClose); @@ -90,6 +92,9 @@ export default class SettingsManager extends React.Component<{}> {
      +
      {this.settingsContent === "password" ?
      diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 9669c21a9..a3c476125 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -237,6 +237,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> return false; } + _initialAutoHeight = false; @action onPointerDown = (e: React.PointerEvent): void => { setupMoveUpEvents(this, e, this.onPointerMove, this.onPointerUp, (e) => { }); @@ -251,6 +252,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> } this._snapX = e.pageX; this._snapY = e.pageY; + this._initialAutoHeight = true; } onPointerMove = (e: PointerEvent, down: number[], move: number[]): boolean => { @@ -353,7 +355,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> } else { dW && (doc._width = actualdW); dH && (doc._height = actualdH); - dH && doc._autoHeight && (doc._autoHeight = false); + dH && this._initialAutoHeight && (doc._autoHeight = this._initialAutoHeight = false); } } })); @@ -362,6 +364,10 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> @action onPointerUp = (e: PointerEvent): void => { + SelectionManager.SelectedDocuments().map(dv => { + dv.layoutDoc._delayAutoHeight && (dv.layoutDoc._autoHeight = true); + dv.layoutDoc._delayAutoHeight = undefined; + }); this._resizeHdlId = ""; this.Interacting = false; (e.button === 0) && this._resizeUndo?.end(); diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss index 753ba700c..dca2a1e3e 100644 --- a/src/client/views/MainView.scss +++ b/src/client/views/MainView.scss @@ -107,7 +107,9 @@ position: absolute; left: 0; bottom: 0; - font-size: 8px; + border-radius: 25%; + margin-left: -5px; + background: darkblue; } .mainView-settings:hover { diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 560dd5d11..62496b01f 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -493,10 +493,7 @@ export class MainView extends React.Component { ContainingCollectionView={undefined} ContainingCollectionDoc={undefined} /> -
      {this.docButtons} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 6c9ade83f..5cccec776 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1084,7 +1084,7 @@ export class DocumentView extends DocComponent(Docu `} - ContentScaling={this.childScaling} + ContentScaling={returnOne} ChromeHeight={this.chromeHeight} isSelected={this.isSelected} select={this.select} diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx index d5a28fd14..3c6841f08 100644 --- a/src/client/views/nodes/formattedText/DashFieldView.tsx +++ b/src/client/views/nodes/formattedText/DashFieldView.tsx @@ -79,11 +79,13 @@ export class DashFieldViewInternal extends React.Component 1 ? new List(splits) : newText; } } }); diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 2c51397eb..3a586ff66 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -658,11 +658,18 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp ); this._disposers.autoHeight = reaction( () => [this.layoutDoc[WidthSym](), this.layoutDoc._autoHeight], - () => this.tryUpdateHeight() + () => setTimeout(() => this.tryUpdateHeight(), 0) ); this._disposers.height = reaction( () => this.layoutDoc[HeightSym](), - height => height <= 20 && (this.layoutDoc._autoHeight = true) + action(height => { + if (height <= 20) { + if (this.layoutDoc._nativeWidth || this.layoutDoc._nativeHeight) { + Doc.toggleNativeDimensions(this.layoutDoc, this.props.ContentScaling(), this.props.PanelWidth(), this.props.PanelHeight()); + } + this.layoutDoc._delayAutoHeight = true; + } + }) ); this.setupEditor(this.config, this.props.fieldKey); @@ -1184,8 +1191,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp @action tryUpdateHeight(limitHeight?: number) { let scrollHeight = this._ref.current?.scrollHeight; - if (this.layoutDoc._autoHeight && !this.props.ignoreAutoHeight && scrollHeight && - getComputedStyle(this._ref.current!.parentElement!).top === "0px") { // if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation + if (this.layoutDoc._autoHeight && !this.props.ignoreAutoHeight && scrollHeight) { // if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation + scrollHeight = scrollHeight * NumCast(this.layoutDoc.scale, 1); if (limitHeight && scrollHeight > limitHeight) { scrollHeight = limitHeight; this.layoutDoc.limitHeight = undefined; @@ -1234,87 +1241,90 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp FormattedTextBoxComment.Hide(); } return ( - -
      this.hitBulletTargets(e.clientX, e.clientY, e.shiftKey, true)} - onBlur={this.onBlur} - onPointerUp={this.onPointerUp} - onPointerDown={this.onPointerDown} - onMouseUp={this.onMouseUp} - onWheel={this.onPointerWheel} - onPointerEnter={action(() => this._entered = true)} - onPointerLeave={action((e: React.PointerEvent) => { - this._entered = false; - const target = document.elementFromPoint(e.nativeEvent.x, e.nativeEvent.y); - for (let child: any = target; child; child = child?.parentElement) { - if (child === this._ref.current!) { - this._entered = true; +
      +
      this.hitBulletTargets(e.clientX, e.clientY, e.shiftKey, true)} + onBlur={this.onBlur} + onPointerUp={this.onPointerUp} + onPointerDown={this.onPointerDown} + onMouseUp={this.onMouseUp} + onWheel={this.onPointerWheel} + onPointerEnter={action(() => this._entered = true)} + onPointerLeave={action((e: React.PointerEvent) => { + this._entered = false; + const target = document.elementFromPoint(e.nativeEvent.x, e.nativeEvent.y); + for (let child: any = target; child; child = child?.parentElement) { + if (child === this._ref.current!) { + this._entered = true; + } } - } - })} - > -
      -
      + })} + > +
      +
      +
      + {!this.layoutDoc._showSidebar ? (null) : this.sidebarWidthPercent === "0%" ? +
      : +
      + + +
      +
      } + {!this.layoutDoc._showAudio ? (null) : +
      { + runInAction(() => this._recording = !this._recording); + setTimeout(() => this._editorView!.focus(), 500); + e.stopPropagation(); + }} > + +
      }
      - {!this.layoutDoc._showSidebar ? (null) : this.sidebarWidthPercent === "0%" ? -
      : -
      - - -
      -
      } - {!this.layoutDoc._showAudio ? (null) : -
      { - runInAction(() => this._recording = !this._recording); - setTimeout(() => this._editorView!.focus(), 500); - e.stopPropagation(); - }} > - -
      }
      ); } diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts index d619bc4a0..0ba591fec 100644 --- a/src/client/views/nodes/formattedText/RichTextRules.ts +++ b/src/client/views/nodes/formattedText/RichTextRules.ts @@ -11,6 +11,7 @@ import { FormattedTextBox } from "./FormattedTextBox"; import { wrappingInputRule } from "./prosemirrorPatches"; import RichTextMenu from "./RichTextMenu"; import { schema } from "./schema_rts"; +import { List } from "../../../../new_fields/List"; export class RichTextRules { public Document: Doc; @@ -64,11 +65,12 @@ export class RichTextRules { // create an inline view of a tag stored under the '#' field new InputRule( - new RegExp(/#([a-zA-Z_\-]+[a-zA-Z_\-0-9]*)\s$/), + new RegExp(/#([a-zA-Z_\-]+[a-zA-Z_;\-0-9]*)\s$/), (state, match, start, end) => { const tag = match[1]; if (!tag) return state.tr; - this.Document[DataSym]["#"] = tag; + const multiple = tag.split(";"); + this.Document[DataSym]["#"] = multiple.length > 1 ? new List(multiple) : tag; const fieldView = state.schema.nodes.dashField.create({ fieldKey: "#" }); return state.tr.deleteRange(start, end).insert(start, fieldView); }), -- cgit v1.2.3-70-g09d2 From f1473fc5bf7f2b3109be358ae14d28725240284c Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 11 May 2020 22:30:33 -0400 Subject: cleaned up menu items. improved snapping with fixed aspect items, but not perfect. --- src/client/documents/Documents.ts | 1 + src/client/util/DragManager.ts | 14 ++-- src/client/views/DocumentDecorations.tsx | 41 ++++++++++-- src/client/views/MainView.tsx | 4 +- .../views/collections/CollectionDockingView.tsx | 2 +- src/client/views/collections/CollectionView.tsx | 1 - .../collectionFreeForm/CollectionFreeFormView.tsx | 21 +++--- src/client/views/nodes/DocumentView.tsx | 75 ++++++++-------------- src/client/views/nodes/ImageBox.tsx | 4 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 37 ++++------- 10 files changed, 101 insertions(+), 99 deletions(-) (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index a87a77e1d..95b8daafc 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -150,6 +150,7 @@ export interface DocumentOptions { dragFactory?: Doc; // document to create when dragging with a suitable onDragStart script onDragStart?: ScriptField; //script to execute at start of drag operation -- e.g., when a "creator" button is dragged this script generates a different document to drop clipboard?: Doc; + UseCors?: boolean; icon?: string; sourcePanel?: Doc; // panel to display in 'targetContainer' as the result of a button onClick script targetContainer?: Doc; // document whose proto will be set to 'panel' as the result of a onClick click script diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 4f547e2f7..1ee4c57a2 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -256,7 +256,8 @@ export namespace DragManager { SnappingManager.setSnapLines(horizLines, vertLines); } - export function snapDrag(e: PointerEvent, xFromLeft: number, yFromTop: number, xFromRight: number, yFromBottom: number) { + // snap to the active snap lines - if oneAxis is set (eg, for maintaining aspect ratios), then it only snaps to the nearest horizontal/vertical line + export function snapDrag(e: PointerEvent, xFromLeft: number, yFromTop: number, xFromRight: number, yFromBottom: number, oneAxis: boolean = false) { const snapThreshold = NumCast(Doc.UserDoc()["constants-snapThreshold"], 10); const snapVal = (pts: number[], drag: number, snapLines: number[]) => { if (snapLines.length) { @@ -265,14 +266,15 @@ export namespace DragManager { const closestPts = rangePts.map(pt => snapLines.reduce((nearest, curr) => Math.abs(nearest - pt) > Math.abs(curr - pt) ? curr : nearest)); const closestDists = rangePts.map((pt, i) => Math.abs(pt - closestPts[i])); const minIndex = closestDists[0] < closestDists[1] && closestDists[0] < closestDists[2] ? 0 : closestDists[1] < closestDists[2] ? 1 : 2; - return closestDists[minIndex] < snapThreshold ? closestPts[minIndex] + offs[minIndex] : drag; + return closestDists[minIndex] < snapThreshold ? [closestDists[minIndex], closestPts[minIndex] + offs[minIndex]] : [Number.MAX_VALUE, drag]; } - return drag; + return [Number.MAX_VALUE, drag]; }; - + const xsnap = snapVal([xFromLeft, xFromRight], e.pageX, SnappingManager.vertSnapLines()); + const ysnap = snapVal([yFromTop, yFromBottom], e.pageY, SnappingManager.horizSnapLines()); return { - thisX: snapVal([xFromLeft, xFromRight], e.pageX, SnappingManager.vertSnapLines()), - thisY: snapVal([yFromTop, yFromBottom], e.pageY, SnappingManager.horizSnapLines()) + thisX: !oneAxis || xsnap[0] < ysnap[0] ? xsnap[1] : e.pageX, + thisY: !oneAxis || xsnap[0] > ysnap[0] ? ysnap[1] : e.pageY }; } export let docsBeingDragged: Doc[] = []; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index a3c476125..b939d96b6 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -20,7 +20,6 @@ import React = require("react"); import { Id } from '../../new_fields/FieldSymbols'; import e = require('express'); import { CollectionDockingView } from './collections/CollectionDockingView'; -import { MainView } from './MainView'; import { SnappingManager } from '../util/SnappingManager'; library.add(faCaretUp); @@ -238,6 +237,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> } _initialAutoHeight = false; + _dragHeights = new Map(); @action onPointerDown = (e: React.PointerEvent): void => { setupMoveUpEvents(this, e, this.onPointerMove, this.onPointerUp, (e) => { }); @@ -253,17 +253,38 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> this._snapX = e.pageX; this._snapY = e.pageY; this._initialAutoHeight = true; + DragManager.docsBeingDragged = SelectionManager.SelectedDocuments().map(dv => dv.rootDoc); + SelectionManager.SelectedDocuments().map(dv => { + this._dragHeights.set(dv.layoutDoc, NumCast(dv.layoutDoc._height)); + dv.layoutDoc._delayAutoHeight = dv.layoutDoc._height; + }); } onPointerMove = (e: PointerEvent, down: number[], move: number[]): boolean => { - const { thisX, thisY } = DragManager.snapDrag(e, -this._offX, -this._offY, this._offX, this._offY); + const first = SelectionManager.SelectedDocuments()[0]; + const fixedAspect = NumCast(first.layoutDoc._nativeWidth) !== 0; + let { thisX, thisY } = DragManager.snapDrag(e, -this._offX, -this._offY, this._offX, this._offY, fixedAspect); + if (fixedAspect) { // if aspect is set, then any snapped movement must be coerced to match the aspect ratio + const aspect = NumCast(first.layoutDoc._nativeWidth) / NumCast(first.layoutDoc._nativeHeight); + const deltaX = thisX - this._snapX; + const deltaY = thisY - this._snapY; + if (thisX !== e.pageX) { + const snapY = deltaX / aspect + this._snapY; + thisY = Math.abs(deltaX / aspect) < 10 ? snapY : thisY; + } else { + const snapX = deltaY * aspect + this._snapX; + thisX = Math.abs(deltaY * aspect) < 10 ? snapX : thisX; + } + } move[0] = thisX - this._snapX; move[1] = thisY - this._snapY; this._snapX = thisX; this._snapY = thisY; let dX = 0, dY = 0, dW = 0, dH = 0; - + const unfreeze = () => + SelectionManager.SelectedDocuments().forEach(action((element: DocumentView) => + (element.rootDoc.type === DocumentType.RTF && element.layoutDoc._nativeHeight) && element.toggleNativeDimensions())); switch (this._resizeHdlId) { case "": break; case "documentDecorations-topLeftResizer": @@ -278,6 +299,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> dH = -move[1]; break; case "documentDecorations-topResizer": + unfreeze(); dY = -1; dH = -move[1]; break; @@ -291,13 +313,16 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> dH = move[1]; break; case "documentDecorations-bottomResizer": + unfreeze(); dH = move[1]; break; case "documentDecorations-leftResizer": + unfreeze(); dX = -1; dW = -move[0]; break; case "documentDecorations-rightResizer": + unfreeze(); dW = move[0]; break; } @@ -309,9 +334,12 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> let nwidth = doc._nativeWidth || 0; let nheight = doc._nativeHeight || 0; const width = (doc._width || 0); - const height = (doc._height || (nheight / nwidth * width)); + let height = (doc._height || (nheight / nwidth * width)); const scale = element.props.ScreenToLocalTransform().Scale * element.props.ContentScaling(); if (nwidth && nheight) { + if (nwidth / nheight !== width / height) { + height = nheight / nwidth * width; + } if (Math.abs(dW) > Math.abs(dH)) dH = dW * nheight / nwidth; else dW = dH * nwidth / nheight; } @@ -365,7 +393,10 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> @action onPointerUp = (e: PointerEvent): void => { SelectionManager.SelectedDocuments().map(dv => { - dv.layoutDoc._delayAutoHeight && (dv.layoutDoc._autoHeight = true); + if (NumCast(dv.layoutDoc._delayAutoHeight) < this._dragHeights.get(dv.layoutDoc)!) { + dv.nativeWidth > 0 && Doc.toggleNativeDimensions(dv.layoutDoc, dv.props.ContentScaling(), dv.panelWidth(), dv.panelHeight()); + dv.layoutDoc._autoHeight = true; + } dv.layoutDoc._delayAutoHeight = undefined; }); this._resizeHdlId = ""; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 62496b01f..9bfef06b4 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -83,14 +83,14 @@ export class MainView extends React.Component { firstScriptTag.parentNode!.insertBefore(tag, firstScriptTag); window.removeEventListener("keydown", KeyManager.Instance.handle); window.addEventListener("keydown", KeyManager.Instance.handle); - window.addEventListener("paste", KeyManager.Instance.paste); + window.addEventListener("paste", KeyManager.Instance.paste as any); } componentWillUnMount() { window.removeEventListener("keydown", KeyManager.Instance.handle); window.removeEventListener("pointerdown", this.globalPointerDown); window.removeEventListener("pointerup", this.globalPointerUp); - window.removeEventListener("paste", KeyManager.Instance.paste); + window.removeEventListener("paste", KeyManager.Instance.paste as any); } constructor(props: Readonly<{}>) { diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 50e3b73eb..2e24cbb12 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -757,7 +757,7 @@ export class DockedFrameRenderer extends React.Component { get layoutDoc() { return this._document && Doc.Layout(this._document); } nativeAspect = () => this.nativeWidth() ? this.nativeWidth() / this.nativeHeight() : 0; panelWidth = () => this.layoutDoc?.maxWidth ? Math.min(Math.max(NumCast(this.layoutDoc._width), NumCast(this.layoutDoc._nativeWidth)), this._panelWidth) : - (this.nativeAspect() && this.nativeAspect() < this._panelWidth / this._panelHeight ? this._panelHeight * this.nativeAspect() : this._panelWidth); + (this.nativeAspect() && this.nativeAspect() < this._panelWidth / this._panelHeight ? this._panelHeight * this.nativeAspect() : this._panelWidth) panelHeight = () => this.nativeAspect() && this.nativeAspect() > this._panelWidth / this._panelHeight ? this._panelWidth / this.nativeAspect() : this._panelHeight; nativeWidth = () => !this.layoutDoc!._fitWidth ? NumCast(this.layoutDoc!._nativeWidth) || this._panelWidth : 0; diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index ac9f64d94..0f239d385 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -234,7 +234,6 @@ export class CollectionView extends Touchable { if (!e.isPropagationStopped() && this.props.Document[Id] !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 - this.setupViewTypes("Change Perspective...", (vtype => { this.props.Document._viewType = vtype; return this.props.Document; }), true); this.setupViewTypes("Add a Perspective...", vtype => { const newRendition = Doc.MakeAlias(this.props.Document); newRendition._viewType = vtype; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 129b245b8..6caee960d 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1133,19 +1133,25 @@ export class CollectionFreeFormView extends CollectionSubView { - if (this.props.children && this.props.annotationsKey) return; + if (this.props.annotationsKey) return; + + ContextMenu.Instance.addItem({ + description: (this._timelineVisible ? "Close" : "Open") + " Animation Timeline", event: action(() => { + this._timelineVisible = !this._timelineVisible; + }), icon: this._timelineVisible ? faEyeSlash : faEye + }); + const options = ContextMenu.Instance.findByDescription("Options..."); const optionItems: ContextMenuProps[] = options && "subitems" in options ? options.subitems : []; optionItems.push({ description: "reset view", event: () => { this.props.Document._panX = this.props.Document._panY = 0; this.props.Document.scale = 1; }, icon: "compress-arrows-alt" }); - optionItems.push({ description: !this.layoutDoc._nativeWidth || !this.layoutDoc._nativeHeight ? "Freeze" : "Unfreeze", event: this.toggleNativeDimensions, icon: "snowflake" }); - optionItems.push({ description: `${this.Document._LODdisable ? "Enable LOD" : "Disable LOD"}`, event: () => this.Document._LODdisable = !this.Document._LODdisable, icon: "table" }); + optionItems.push({ description: "Reset default note style", event: () => Doc.UserDoc().defaultTextLayout = undefined, icon: "eye" }); + optionItems.push({ description: (!this.layoutDoc._nativeWidth || !this.layoutDoc._nativeHeight ? "Freeze" : "Unfreeze") + " Aspect", event: this.toggleNativeDimensions, icon: "snowflake" }); optionItems.push({ description: `${this.fitToContent ? "Unset" : "Set"} Fit To Container`, event: () => this.Document._fitToBox = !this.fitToContent, icon: !this.fitToContent ? "expand-arrows-alt" : "compress-arrows-alt" }); optionItems.push({ description: `${this.Document.useClusters ? "Uncluster" : "Use Clusters"}`, event: () => this.updateClusters(!this.Document.useClusters), icon: "braille" }); this.props.ContainingCollectionView && optionItems.push({ description: "Promote Collection", event: this.promoteCollection, icon: "table" }); optionItems.push({ description: "Arrange contents in grid", event: this.layoutDocsInGrid, icon: "table" }); // layoutItems.push({ description: "Analyze Strokes", event: this.analyzeStrokes, icon: "paint-brush" }); - optionItems.push({ description: "Jitter Rotation", event: action(() => this.props.Document._jitterRotation = (this.props.Document._jitterRotation ? 0 : 10)), icon: "paint-brush" }); optionItems.push({ description: "Import document", icon: "upload", event: ({ x, y }) => { const input = document.createElement("input"); @@ -1173,14 +1179,9 @@ export class CollectionFreeFormView extends CollectionSubView this.Document._LODdisable = !this.Document._LODdisable, icon: "table" }); ContextMenu.Instance.addItem({ description: "Options...", subitems: optionItems, icon: "eye" }); - - ContextMenu.Instance.addItem({ - description: (this._timelineVisible ? "Close" : "Open") + " Animation Timeline", event: action(() => { - this._timelineVisible = !this._timelineVisible; - }), icon: this._timelineVisible ? faEyeSlash : faEye - }); } @observable _timelineVisible = false; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 5cccec776..1bf297796 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -704,7 +704,6 @@ export class DocumentView extends DocComponent(Docu } const cm = ContextMenu.Instance; - const templateDoc = Cast(this.props.Document[StrCast(this.props.Document.layoutKey)], Doc, null); const customScripts = Cast(this.props.Document.contextMenuScripts, listSpec(ScriptField), []); Cast(this.props.Document.contextMenuLabels, listSpec("string"), []).forEach((label, i) => @@ -713,25 +712,16 @@ export class DocumentView extends DocComponent(Docu cm.addItem({ description: item.label, event: () => item.script.script.run({ this: this.layoutDoc, self: this.rootDoc }), icon: "sticky-note" })); - let open = cm.findByDescription("Add a Perspective..."); - const openItems: ContextMenuProps[] = open && "subitems" in open ? open.subitems : []; - openItems.push({ description: "New Echo ", event: () => this.props.addDocTab(Doc.MakeAlias(this.props.Document), "onRight"), icon: "layer-group" }); - openItems.push({ description: "Open Fields ", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "onRight"), icon: "layer-group" }); - templateDoc && openItems.push({ description: "Open Template ", event: () => this.props.addDocTab(templateDoc, "onRight"), icon: "eye" }); - if (!open) { - open = { description: "Add a Perspective....", subitems: openItems, icon: "external-link-alt" }; - cm.addItem(open); - } - let options = cm.findByDescription("Options..."); const optionItems: ContextMenuProps[] = options && "subitems" in options ? options.subitems : []; + const templateDoc = Cast(this.props.Document[StrCast(this.props.Document.layoutKey)], Doc, null); + optionItems.push({ description: "Open Fields ", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "onRight"), icon: "layer-group" }); + templateDoc && optionItems.push({ description: "Open Template ", event: () => this.props.addDocTab(templateDoc, "onRight"), icon: "eye" }); if (!options) { options = { description: "Options...", subitems: optionItems, icon: "compass" }; cm.addItem(options); } - cm.moveAfter(options, open); - const existingOnClick = cm.findByDescription("OnClick..."); const onClicks: ContextMenuProps[] = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : []; onClicks.push({ description: "Enter Portal", event: this.makeIntoPortal, icon: "window-restore" }); @@ -764,9 +754,6 @@ export class DocumentView extends DocComponent(Docu moreItems.push({ description: "Copy ID", event: () => Utils.CopyText(this.props.Document[Id]), icon: "fingerprint" }); // cm.addItem({ description: "Copy...", subitems: copies, icon: "copy" }); } - if (Cast(this.props.Document.data, ImageField)) { - moreItems.push({ description: "Export to Google Photos", event: () => GooglePhotos.Transactions.UploadImages([this.props.Document]), icon: "caret-square-right" }); - } if (Cast(Doc.GetProto(this.props.Document).data, listSpec(Doc))) { moreItems.push({ description: "Export to Google Photos Album", event: () => GooglePhotos.Export.CollectionToAlbum({ collection: this.props.Document }).then(console.log), icon: "caret-square-right" }); moreItems.push({ description: "Tag Child Images via Google Photos", event: () => GooglePhotos.Query.TagChildImages(this.props.Document), icon: "caret-square-right" }); @@ -820,47 +807,38 @@ export class DocumentView extends DocComponent(Docu cm.moveAfter(cm.findByDescription("More...")!, cm.findByDescription("OnClick...")!); runInAction(() => { - if (!ClientUtils.RELEASE) { - const setWriteMode = (mode: DocServer.WriteMode) => { - DocServer.AclsMode = mode; - const mode1 = mode; - const mode2 = mode === DocServer.WriteMode.Default ? mode : DocServer.WriteMode.Playground; - DocServer.setFieldWriteMode("x", mode1); - DocServer.setFieldWriteMode("y", mode1); - DocServer.setFieldWriteMode("_width", mode1); - DocServer.setFieldWriteMode("_height", mode1); - - DocServer.setFieldWriteMode("_panX", mode2); - DocServer.setFieldWriteMode("_panY", mode2); - DocServer.setFieldWriteMode("scale", mode2); - DocServer.setFieldWriteMode("_viewType", mode2); - }; - const aclsMenu: ContextMenuProps[] = []; - aclsMenu.push({ description: "Default (write/read all)", event: () => setWriteMode(DocServer.WriteMode.Default), icon: DocServer.AclsMode === DocServer.WriteMode.Default ? "check" : "exclamation" }); - aclsMenu.push({ description: "Playground (write own/no read)", event: () => setWriteMode(DocServer.WriteMode.Playground), icon: DocServer.AclsMode === DocServer.WriteMode.Playground ? "check" : "exclamation" }); - aclsMenu.push({ description: "Live Playground (write own/read others)", event: () => setWriteMode(DocServer.WriteMode.LivePlayground), icon: DocServer.AclsMode === DocServer.WriteMode.LivePlayground ? "check" : "exclamation" }); - aclsMenu.push({ description: "Live Readonly (no write/read others)", event: () => setWriteMode(DocServer.WriteMode.LiveReadonly), icon: DocServer.AclsMode === DocServer.WriteMode.LiveReadonly ? "check" : "exclamation" }); - cm.addItem({ description: "Collaboration ACLs...", subitems: aclsMenu, icon: "share" }); - } + const setWriteMode = (mode: DocServer.WriteMode) => { + DocServer.AclsMode = mode; + const mode1 = mode; + const mode2 = mode === DocServer.WriteMode.Default ? mode : DocServer.WriteMode.Playground; + DocServer.setFieldWriteMode("x", mode1); + DocServer.setFieldWriteMode("y", mode1); + DocServer.setFieldWriteMode("_width", mode1); + DocServer.setFieldWriteMode("_height", mode1); + + DocServer.setFieldWriteMode("_panX", mode2); + DocServer.setFieldWriteMode("_panY", mode2); + DocServer.setFieldWriteMode("scale", mode2); + DocServer.setFieldWriteMode("_viewType", mode2); + }; + const aclsMenu: ContextMenuProps[] = []; + aclsMenu.push({ description: "Share", event: () => SharingManager.Instance.open(this), icon: "external-link-alt" }); + aclsMenu.push({ description: "Default (write/read all)", event: () => setWriteMode(DocServer.WriteMode.Default), icon: DocServer.AclsMode === DocServer.WriteMode.Default ? "check" : "exclamation" }); + aclsMenu.push({ description: "Playground (write own/no read)", event: () => setWriteMode(DocServer.WriteMode.Playground), icon: DocServer.AclsMode === DocServer.WriteMode.Playground ? "check" : "exclamation" }); + aclsMenu.push({ description: "Live Playground (write own/read others)", event: () => setWriteMode(DocServer.WriteMode.LivePlayground), icon: DocServer.AclsMode === DocServer.WriteMode.LivePlayground ? "check" : "exclamation" }); + aclsMenu.push({ description: "Live Readonly (no write/read others)", event: () => setWriteMode(DocServer.WriteMode.LiveReadonly), icon: DocServer.AclsMode === DocServer.WriteMode.LiveReadonly ? "check" : "exclamation" }); + cm.addItem({ description: "Collaboration ...", subitems: aclsMenu, icon: "share" }); }); runInAction(() => { - cm.addItem({ - description: "Share", - event: () => SharingManager.Instance.open(this), - icon: "external-link-alt" - }); - if (!this.topMost && !(e instanceof Touch)) { // DocumentViews should stop propagation of this event e.stopPropagation(); } ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15); - if (!SelectionManager.IsSelected(this, true)) { - SelectionManager.SelectDoc(this, false); - } + !SelectionManager.IsSelected(this, true) && SelectionManager.SelectDoc(this, false); }); const path = this.props.LibraryPath.reduce((p: string, d: Doc) => p + "/" + (Doc.AreProtosEqual(d, (Doc.UserDoc()["tabs-button-library"] as Doc).sourcePanel as Doc) ? "" : d.title), ""); - cm.addItem({ + const item = ({ description: `path: ${path}`, event: () => { if (this.props.LibraryPath !== emptyPath) { this.props.LibraryPath.map(lp => Doc.GetProto(lp).treeViewOpen = lp.treeViewOpen = true); @@ -870,6 +848,7 @@ export class DocumentView extends DocComponent(Docu } }, icon: "check" }); + //cm.addItem(item); } recommender = async () => { diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index d85373e98..aaebceaa2 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -29,6 +29,7 @@ import FaceRectangles from './FaceRectangles'; import { FieldView, FieldViewProps } from './FieldView'; import "./ImageBox.scss"; import React = require("react"); +import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils'; const requestImageSize = require('../../util/request-image-size'); const path = require('path'); const { Howl } = require('howler'); @@ -158,6 +159,8 @@ export class ImageBox extends ViewBoxAnnotatableComponent GooglePhotos.Transactions.UploadImages([this.props.Document]), icon: "caret-square-right" }); + funcs.push({ description: "Copy path", event: () => Utils.CopyText(field.url.href), icon: "expand-arrows-alt" }); // funcs.push({ // description: "Reset Native Dimensions", event: action(async () => { // const curNW = NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"]); @@ -184,7 +187,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent Utils.CopyText(field.url.href), icon: "expand-arrows-alt" }); !existingMore && ContextMenu.Instance.addItem({ description: "More...", subitems: mores, icon: "hand-point-right" }); } } diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 3a586ff66..23bf86a32 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -419,9 +419,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp const funcs: ContextMenuProps[] = []; this.rootDoc.isTemplateDoc && funcs.push({ description: "Make Default Layout", event: async () => Doc.UserDoc().defaultTextLayout = new PrefetchProxy(this.rootDoc), icon: "eye" }); - funcs.push({ description: "Reset Default Layout", event: () => Doc.UserDoc().defaultTextLayout = undefined, icon: "eye" }); !this.layoutDoc.isTemplateDoc && funcs.push({ - description: "Make Template", event: () => { + description: "Convert to use as a style", event: () => { this.rootDoc.isTemplateDoc = makeTemplate(this.rootDoc); Doc.AddDocToList(Cast(Doc.UserDoc()["template-notes"], Doc, null), "data", this.rootDoc); }, icon: "eye" @@ -444,11 +443,15 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp }, icon: "eye" }); //funcs.push({ description: `${this.Document._autoHeight ? "Variable Height" : "Auto Height"}`, event: () => this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight, icon: "plus" }); - funcs.push({ description: !this.layoutDoc._nativeWidth || !this.layoutDoc._nativeHeight ? "Freeze" : "Unfreeze", event: this.toggleNativeDimensions, icon: "snowflake" }); + funcs.push({ description: (!this.layoutDoc._nativeWidth || !this.layoutDoc._nativeHeight ? "Freeze" : "Unfreeze") + " Aspect", event: this.toggleNativeDimensions, icon: "snowflake" }); funcs.push({ description: "Toggle Single Line", event: () => this.layoutDoc._singleLine = !this.layoutDoc._singleLine, icon: "expand-arrows-alt" }); - funcs.push({ description: "Toggle Sidebar", event: () => this.layoutDoc._showSidebar = !this.layoutDoc._showSidebar, icon: "expand-arrows-alt" }); - funcs.push({ description: "Toggle Dictation Icon", event: () => this.layoutDoc._showAudio = !this.layoutDoc._showAudio, icon: "expand-arrows-alt" }); - funcs.push({ description: "Toggle Menubar", event: () => this.toggleMenubar(), icon: "expand-arrows-alt" }); + + const uicontrols: ContextMenuProps[] = []; + uicontrols.push({ description: "Toggle Sidebar", event: () => this.layoutDoc._showSidebar = !this.layoutDoc._showSidebar, icon: "expand-arrows-alt" }); + uicontrols.push({ description: "Toggle Dictation Icon", event: () => this.layoutDoc._showAudio = !this.layoutDoc._showAudio, icon: "expand-arrows-alt" }); + uicontrols.push({ description: "Toggle Menubar", event: () => this.toggleMenubar(), icon: "expand-arrows-alt" }); + + funcs.push({ description: "UI Controls...", subitems: uicontrols, icon: "asterisk" }); const highlighting: ContextMenuProps[] = []; ["My Text", "Text from Others", "Todo Items", "Important Items", "Ignore Items", "Disagree Items", "By Recent Minute", "By Recent Hour"].forEach(option => @@ -481,19 +484,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp }); changeItems.push({ description: "FreeForm", event: undoBatch(() => Doc.makeCustomViewClicked(this.rootDoc, Docs.Create.FreeformDocument, "freeform"), "change view"), icon: "eye" }); !change && cm.addItem({ description: "Change Perspective...", subitems: changeItems, icon: "external-link-alt" }); - - const open = cm.findByDescription("Add a Perspective..."); - const openItems: ContextMenuProps[] = open && "subitems" in open ? open.subitems : []; - - openItems.push({ - description: "FreeForm", event: undoBatch(() => { - const alias = Doc.MakeAlias(this.rootDoc); - Doc.makeCustomViewClicked(alias, Docs.Create.FreeformDocument, "freeform"); - this.props.addDocTab(alias, "onRight"); - }), icon: "eye" - }); - !open && cm.addItem({ description: "Add a Perspective...", subitems: openItems, icon: "external-link-alt" }); - } recordDictation = () => { @@ -663,11 +653,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp this._disposers.height = reaction( () => this.layoutDoc[HeightSym](), action(height => { - if (height <= 20) { - if (this.layoutDoc._nativeWidth || this.layoutDoc._nativeHeight) { - Doc.toggleNativeDimensions(this.layoutDoc, this.props.ContentScaling(), this.props.PanelWidth(), this.props.PanelHeight()); - } - this.layoutDoc._delayAutoHeight = true; + if (height <= 20 && height < NumCast(this.layoutDoc._delayAutoHeight, 20)) { + this.layoutDoc._delayAutoHeight = height; } }) ); @@ -1202,7 +1189,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp const dh = NumCast(this.rootDoc._height, 0); const newHeight = Math.max(10, (nh ? dh / nh * scrollHeight : scrollHeight) + (this.props.ChromeHeight ? this.props.ChromeHeight() : 0)); if (Math.abs(newHeight - dh) > 1) { // bcz: Argh! without this, we get into a React crash if the same document is opened in a freeform view and in the treeview. no idea why, but after dragging the freeform document, selecting it, and selecting text, it will compute to 1 pixel higher than the treeview which causes a cycle - if (this.rootDoc !== this.layoutDoc && !this.layoutDoc.resolvedDataDoc) { + if (this.rootDoc !== this.layoutDoc.doc && !this.layoutDoc.resolvedDataDoc) { // if we have a template that hasn't been resolved yet, we can't set the height or we'd be setting it on the unresolved template. So set a timeout and hope its arrived... console.log("Delayed height adjustment..."); setTimeout(() => { -- cgit v1.2.3-70-g09d2 From 5c4865247b4aca883d39950a15c172ae0431a74e Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 12 May 2020 02:59:48 -0400 Subject: added snapping for fixedAspect br/tl drag handles. --- src/client/util/DragManager.ts | 45 +++++++++++++++++++++++++++----- src/client/views/DocumentDecorations.tsx | 39 +++++++++++++++------------ 2 files changed, 60 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 1ee4c57a2..d1d7f2a8a 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -255,9 +255,42 @@ export namespace DragManager { export function SetSnapLines(horizLines: number[], vertLines: number[]) { SnappingManager.setSnapLines(horizLines, vertLines); } + export function snapDragAspect(dragPt: number[], snapAspect: number) { + let closest = NumCast(Doc.UserDoc()["constants-snapThreshold"], 10); + let near = dragPt; + const intersect = (x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number, dragx: number, dragy: number) => { + if ((x1 === x2 && y1 === y2) || (x3 === x4 && y3 === y4)) return undefined; // Check if none of the lines are of length 0 + const denominator = ((y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1)); + if (denominator === 0) return undefined; // Lines are parallel + let ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denominator; + // let ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denominator; + //if (ua < 0 || ua > 1 || ub < 0 || ub > 1) return undefined; // is the intersection along the segments + + // Return a object with the x and y coordinates of the intersection + let x = x1 + ua * (x2 - x1) + let y = y1 + ua * (y2 - y1) + const dist = Math.sqrt((dragx - x) * (dragx - x) + (dragy - y) * (dragy - y)); + return { pt: [x, y], dist } + } + SnappingManager.vertSnapLines().forEach((xCoord, i) => { + const pt = intersect(dragPt[0], dragPt[1], dragPt[0] + snapAspect, dragPt[1] + 1, xCoord, -1, xCoord, 1, dragPt[0], dragPt[1]); + if (pt && pt.dist < closest) { + closest = pt.dist; + near = pt.pt; + } + }); + SnappingManager.horizSnapLines().forEach((yCoord, i) => { + const pt = intersect(dragPt[0], dragPt[1], dragPt[0] + snapAspect, dragPt[1] + 1, -1, yCoord, 1, yCoord, dragPt[0], dragPt[1]); + if (pt && pt.dist < closest) { + closest = pt.dist; + near = pt.pt; + } + }); + return { thisX: near[0], thisY: near[1] }; + } // snap to the active snap lines - if oneAxis is set (eg, for maintaining aspect ratios), then it only snaps to the nearest horizontal/vertical line - export function snapDrag(e: PointerEvent, xFromLeft: number, yFromTop: number, xFromRight: number, yFromBottom: number, oneAxis: boolean = false) { + export function snapDrag(e: PointerEvent, xFromLeft: number, yFromTop: number, xFromRight: number, yFromBottom: number) { const snapThreshold = NumCast(Doc.UserDoc()["constants-snapThreshold"], 10); const snapVal = (pts: number[], drag: number, snapLines: number[]) => { if (snapLines.length) { @@ -266,15 +299,13 @@ export namespace DragManager { const closestPts = rangePts.map(pt => snapLines.reduce((nearest, curr) => Math.abs(nearest - pt) > Math.abs(curr - pt) ? curr : nearest)); const closestDists = rangePts.map((pt, i) => Math.abs(pt - closestPts[i])); const minIndex = closestDists[0] < closestDists[1] && closestDists[0] < closestDists[2] ? 0 : closestDists[1] < closestDists[2] ? 1 : 2; - return closestDists[minIndex] < snapThreshold ? [closestDists[minIndex], closestPts[minIndex] + offs[minIndex]] : [Number.MAX_VALUE, drag]; + return closestDists[minIndex] < snapThreshold ? closestPts[minIndex] + offs[minIndex] : drag; } - return [Number.MAX_VALUE, drag]; + return drag; }; - const xsnap = snapVal([xFromLeft, xFromRight], e.pageX, SnappingManager.vertSnapLines()); - const ysnap = snapVal([yFromTop, yFromBottom], e.pageY, SnappingManager.horizSnapLines()); return { - thisX: !oneAxis || xsnap[0] < ysnap[0] ? xsnap[1] : e.pageX, - thisY: !oneAxis || xsnap[0] > ysnap[0] ? ysnap[1] : e.pageY + thisX: snapVal([xFromLeft, xFromRight], e.pageX, SnappingManager.vertSnapLines()), + thisY: snapVal([yFromTop, yFromBottom], e.pageY, SnappingManager.horizSnapLines()) }; } export let docsBeingDragged: Doc[] = []; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index b939d96b6..3cd7f8da3 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -3,7 +3,7 @@ import { faCaretUp, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote, faT import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; -import { Doc, DataSym, Field } from "../../new_fields/Doc"; +import { Doc, DataSym, Field, WidthSym, HeightSym } from "../../new_fields/Doc"; import { Document } from '../../new_fields/documentSchemas'; import { ScriptField } from '../../new_fields/ScriptField'; import { Cast, StrCast, NumCast } from "../../new_fields/Types"; @@ -262,24 +262,29 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> onPointerMove = (e: PointerEvent, down: number[], move: number[]): boolean => { const first = SelectionManager.SelectedDocuments()[0]; - const fixedAspect = NumCast(first.layoutDoc._nativeWidth) !== 0; - let { thisX, thisY } = DragManager.snapDrag(e, -this._offX, -this._offY, this._offX, this._offY, fixedAspect); - if (fixedAspect) { // if aspect is set, then any snapped movement must be coerced to match the aspect ratio - const aspect = NumCast(first.layoutDoc._nativeWidth) / NumCast(first.layoutDoc._nativeHeight); - const deltaX = thisX - this._snapX; - const deltaY = thisY - this._snapY; - if (thisX !== e.pageX) { - const snapY = deltaX / aspect + this._snapY; - thisY = Math.abs(deltaX / aspect) < 10 ? snapY : thisY; - } else { - const snapX = deltaY * aspect + this._snapX; - thisX = Math.abs(deltaY * aspect) < 10 ? snapX : thisX; + let thisPt = { thisX: e.clientX - this._offX, thisY: e.clientY - this._offY }; + const fixedAspect = first.layoutDoc._nativeWidth ? NumCast(first.layoutDoc._nativeWidth) / NumCast(first.layoutDoc._nativeHeight) : 0; + if (fixedAspect) { // need to generalize for bl and tr drag handles + const project = (p: number[], a: number[], b: number[]) => { + var atob = [b[0] - a[0], b[1] - a[1]]; + var atop = [p[0] - a[0], p[1] - a[1]]; + var len = atob[0] * atob[0] + atob[1] * atob[1]; + var dot = atop[0] * atob[0] + atop[1] * atob[1]; + var t = dot / len; + dot = (b[0] - a[0]) * (p[1] - a[1]) - (b[1] - a[1]) * (p[0] - a[0]); + return [a[0] + atob[0] * t, a[1] + atob[1] * t]; } + const tl = first.props.ScreenToLocalTransform().inverse().transformPoint(0, 0); + const drag = project([e.clientX + this._offX, e.clientY + this._offY], tl, [tl[0] + fixedAspect, tl[1] + 1]) + thisPt = DragManager.snapDragAspect(drag, fixedAspect); + } else { + thisPt = DragManager.snapDrag(e, -this._offX, -this._offY, this._offX, this._offY); } - move[0] = thisX - this._snapX; - move[1] = thisY - this._snapY; - this._snapX = thisX; - this._snapY = thisY; + + move[0] = thisPt.thisX - this._snapX; + move[1] = thisPt.thisY - this._snapY; + this._snapX = thisPt.thisX; + this._snapY = thisPt.thisY; let dX = 0, dY = 0, dW = 0, dH = 0; const unfreeze = () => -- cgit v1.2.3-70-g09d2 From 3911cf85eaf57c133166a6bd08732193ac74d885 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 12 May 2020 12:10:21 -0400 Subject: changed isBackground setting to reset nativeW/H to W/H. fixed presBox reordering. fixed resizing of fixedAspect suff from sides. --- src/client/views/DocumentDecorations.tsx | 2 +- src/client/views/collections/CollectionDockingView.tsx | 1 + src/client/views/collections/CollectionStackingView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 6 +++++- src/client/views/nodes/PresBox.tsx | 6 +++--- 5 files changed, 11 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 3cd7f8da3..313d8be23 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -264,7 +264,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> const first = SelectionManager.SelectedDocuments()[0]; let thisPt = { thisX: e.clientX - this._offX, thisY: e.clientY - this._offY }; const fixedAspect = first.layoutDoc._nativeWidth ? NumCast(first.layoutDoc._nativeWidth) / NumCast(first.layoutDoc._nativeHeight) : 0; - if (fixedAspect) { // need to generalize for bl and tr drag handles + if (fixedAspect && (this._resizeHdlId === "documentDecorations-bottomRightResizer" || this._resizeHdlId === "documentDecorations-topLeftResizer")) { // need to generalize for bl and tr drag handles const project = (p: number[], a: number[], b: number[]) => { var atob = [b[0] - a[0], b[1] - a[1]]; var atop = [p[0] - a[0], p[1] - a[1]]; diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 2e24cbb12..581625222 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -707,6 +707,7 @@ export class DockedFrameRenderer extends React.Component { const pinDoc = Doc.MakeAlias(doc); pinDoc.presentationTargetDoc = doc; pinDoc.presZoomButton = true; + pinDoc.context = curPres; Doc.AddDocToList(curPres, "data", pinDoc); if (!DocumentManager.Instance.getDocumentView(curPres)) { CollectionDockingView.AddRightSplit(curPres); diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 979e9e3f8..97459d910 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -73,7 +73,7 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument) const width = () => this.getDocWidth(d); const dref = React.createRef(); const dxf = () => this.getDocTransform(d, dref.current!); - this._docXfs.push({ dxf: dxf, width: width, height: height }); + this._docXfs.push({ dxf, width, height }); const rowSpan = Math.ceil((height() + this.gridGap) / this.gridGap); const style = this.isStackingView ? { width: width(), marginTop: i ? this.gridGap : 0, height: height() } : { gridRowEnd: `span ${rowSpan}` }; return
      diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 1bf297796..91275d89b 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -669,7 +669,11 @@ export class DocumentView extends DocComponent(Docu toggleBackground = (temporary: boolean): void => { this.Document._overflow = temporary ? "visible" : "hidden"; this.Document.isBackground = !temporary ? !this.Document.isBackground : (this.Document.isBackground ? undefined : true); - this.Document.isBackground && this.props.bringToFront(this.Document, true); + if (this.Document.isBackground) { + this.props.bringToFront(this.props.Document, true); + this.props.Document[DataSym][Doc.LayoutFieldKey(this.Document) + "-nativeWidth"] = this.Document[WidthSym](); + this.props.Document[DataSym][Doc.LayoutFieldKey(this.Document) + "-nativeHeight"] = this.Document[HeightSym](); + } } @undoBatch diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index 49862d39a..5ff71e922 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -44,7 +44,7 @@ export class PresBox extends ViewBoxBaseComponent // stored on each pres element. (this.presElement as Doc).lookupField = ScriptField.MakeScript( `if (field === 'indexInPres') return docList(container[container.presentationFieldKey]).indexOf(data);` + - "if (field === 'presCollapsedHeight') return container._viewType === CollectionViewType.Stacking ? 50 : 46;" + + `if (field === 'presCollapsedHeight') return container._viewType === '${CollectionViewType.Stacking}' ? 50 : 46;` + "return undefined;", { field: "string", data: Doc.name, container: Doc.name }); } this.props.Document.presentationFieldKey = this.fieldKey; // provide info to the presElement script so that it can look up rendering information about the presBox @@ -271,8 +271,8 @@ export class PresBox extends ViewBoxBaseComponent }); whenActiveChanged = action((isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive)); - addDocumentFilter = (doc: Doc|Doc[]) => { - const docs = doc instanceof Doc ? [doc]: doc; + addDocumentFilter = (doc: Doc | Doc[]) => { + const docs = doc instanceof Doc ? [doc] : doc; docs.forEach(doc => { doc.aliasOf instanceof Doc && (doc.presentationTargetDoc = doc.aliasOf); !this.childDocs.includes(doc) && (doc.presZoomButton = true); -- cgit v1.2.3-70-g09d2 From 54e8450ea88a03bee23cbad3321b5f6bac465e33 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 12 May 2020 13:56:14 -0400 Subject: fixed issues with preselements not updating. fixed focus issues with stacking view for Presentations --- src/client/documents/Documents.ts | 1 + .../views/collections/CollectionStackingView.tsx | 7 ++-- src/client/views/nodes/LabelBox.scss | 1 + src/client/views/nodes/PresBox.tsx | 45 ++++++++++++---------- .../views/presentationview/PresElementBox.tsx | 22 +++++------ 5 files changed, 40 insertions(+), 36 deletions(-) (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 95b8daafc..125a531f4 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -127,6 +127,7 @@ export interface DocumentOptions { borderRounding?: string; boxShadow?: string; dontRegisterChildViews?: boolean; + lookupField?: ScriptField; // script that returns the value of a field. This script is passed the rootDoc, layoutDoc, field, and container of the document. see PresBox. "onDoubleClick-rawScript"?: string; // onDoubleClick script in raw text form "onClick-rawScript"?: string; // onClick script in raw text form "onCheckedClick-rawScript"?: string; // onChecked script in raw text form diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 97459d910..821a6d476 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -175,8 +175,8 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument) focusDocument = (doc: Doc, willZoom: boolean, scale?: number, afterFocus?: () => boolean) => { - Doc.BrushDoc(this.props.Document); - this.props.focus(this.props.Document); + Doc.BrushDoc(doc); + this.props.focus(doc); Doc.linkFollowHighlight(doc); const found = this._mainCont && Array.from(this._mainCont.getElementsByClassName("documentView-node")).find((node: any) => node.id === doc[Id]); @@ -186,8 +186,7 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument) smoothScroll(500, this._mainCont!, localTop[1] + this._mainCont!.scrollTop); } afterFocus && setTimeout(() => { - if (afterFocus?.()) { - } + if (afterFocus?.()) { } }, 500); } diff --git a/src/client/views/nodes/LabelBox.scss b/src/client/views/nodes/LabelBox.scss index 9e3ff96a7..b605df262 100644 --- a/src/client/views/nodes/LabelBox.scss +++ b/src/client/views/nodes/LabelBox.scss @@ -4,6 +4,7 @@ border-radius: inherit; display: flex; flex-direction: column; + position: absolute; } .labelBox-mainButton { diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index 5ff71e922..e203c7efa 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -30,7 +30,7 @@ export class PresBox extends ViewBoxBaseComponent public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PresBox, fieldKey); } @observable _isChildActive = false; @computed get childDocs() { return DocListCast(this.dataDoc[this.fieldKey]); } - @computed get currentIndex() { return NumCast(this.presElement?.currentIndex); } + @computed get itemIndex() { return NumCast(this.rootDoc._itemIndex); } @computed get presElement() { return Cast(Doc.UserDoc().presElement, Doc, null); } constructor(props: any) { super(props); @@ -42,10 +42,8 @@ export class PresBox extends ViewBoxBaseComponent // this is a design choice -- we could write this data to the presElements which would require a reaction to keep it up to date, and it would prevent // the preselement docs from being part of multiple presentations since they would all have the same field, or we'd have to keep per-presentation data // stored on each pres element. - (this.presElement as Doc).lookupField = ScriptField.MakeScript( - `if (field === 'indexInPres') return docList(container[container.presentationFieldKey]).indexOf(data);` + - `if (field === 'presCollapsedHeight') return container._viewType === '${CollectionViewType.Stacking}' ? 50 : 46;` + - "return undefined;", { field: "string", data: Doc.name, container: Doc.name }); + (this.presElement as Doc).lookupField = ScriptField.MakeFunction("lookupPresBoxField(container, field, data)", + { field: "string", data: Doc.name, container: Doc.name }); } this.props.Document.presentationFieldKey = this.fieldKey; // provide info to the presElement script so that it can look up rendering information about the presBox } @@ -61,15 +59,15 @@ export class PresBox extends ViewBoxBaseComponent @action next = () => { this.updateCurrentPresentation(); - if (this.childDocs[this.currentIndex + 1] !== undefined) { - let nextSelected = this.currentIndex + 1; - this.gotoDocument(nextSelected, this.currentIndex); + if (this.childDocs[this.itemIndex + 1] !== undefined) { + let nextSelected = this.itemIndex + 1; + this.gotoDocument(nextSelected, this.itemIndex); for (nextSelected = nextSelected + 1; nextSelected < this.childDocs.length; nextSelected++) { if (!this.childDocs[nextSelected].groupButton) { break; } else { - this.gotoDocument(nextSelected, this.currentIndex); + this.gotoDocument(nextSelected, this.itemIndex); } } } @@ -79,18 +77,18 @@ export class PresBox extends ViewBoxBaseComponent @action back = () => { this.updateCurrentPresentation(); - const docAtCurrent = this.childDocs[this.currentIndex]; + const docAtCurrent = this.childDocs[this.itemIndex]; if (docAtCurrent) { //check if any of the group members had used zooming in including the current document //If so making sure to zoom out, which goes back to state before zooming action - let prevSelected = this.currentIndex; + let prevSelected = this.itemIndex; let didZoom = docAtCurrent.zoomButton; for (; !didZoom && prevSelected > 0 && this.childDocs[prevSelected].groupButton; prevSelected--) { didZoom = this.childDocs[prevSelected].zoomButton; } prevSelected = Math.max(0, prevSelected - 1); - this.gotoDocument(prevSelected, this.currentIndex); + this.gotoDocument(prevSelected, this.itemIndex); } } @@ -194,10 +192,10 @@ export class PresBox extends ViewBoxBaseComponent this.updateCurrentPresentation(); Doc.UnBrushAllDocs(); if (index >= 0 && index < this.childDocs.length) { - this.presElement.currentIndex = index; + this.rootDoc._itemIndex = index; - if (!this.presElement.presStatus) { - this.presElement.presStatus = true; + if (!this.layoutDoc.presStatus) { + this.layoutDoc.presStatus = true; this.startPresentation(index); } @@ -210,12 +208,12 @@ export class PresBox extends ViewBoxBaseComponent //The function that starts or resets presentaton functionally, depending on status flag. startOrResetPres = () => { this.updateCurrentPresentation(); - if (this.presElement.presStatus) { + if (this.layoutDoc.presStatus) { this.resetPresentation(); } else { - this.presElement.presStatus = true; + this.layoutDoc.presStatus = true; this.startPresentation(0); - this.gotoDocument(0, this.currentIndex); + this.gotoDocument(0, this.itemIndex); } } @@ -225,7 +223,7 @@ export class PresBox extends ViewBoxBaseComponent this.updateCurrentPresentation(); this.childDocs.forEach(doc => (doc.presentationTargetDoc as Doc).opacity = 1); this.rootDoc._itemIndex = 0; - this.presElement.presStatus = false; + this.layoutDoc.presStatus = false; } //The function that starts the presentation, also checking if actions should be applied @@ -281,7 +279,7 @@ export class PresBox extends ViewBoxBaseComponent } childLayoutTemplate = () => this.rootDoc._viewType !== CollectionViewType.Stacking ? undefined : this.presElement; removeDocument = (doc: Doc) => Doc.RemoveDocFromList(this.dataDoc, this.fieldKey, doc); - selectElement = (doc: Doc) => this.gotoDocument(this.childDocs.indexOf(doc), NumCast(this.rootDoc._itemIndex)); + selectElement = (doc: Doc) => this.gotoDocument(this.childDocs.indexOf(doc), NumCast(this.itemIndex)); getTransform = () => this.props.ScreenToLocalTransform().translate(-5, -65);// listBox padding-left and pres-box-cont minHeight panelHeight = () => this.props.PanelHeight() - 20; active = (outsideReaction?: boolean) => ((InkingControl.Instance.selectedTool === InkTool.None && !this.layoutDoc.isBackground) && @@ -329,5 +327,10 @@ export class PresBox extends ViewBoxBaseComponent
      ; } } -Scripting.addGlobal(function lookupPresBoxField(presLayout: Doc, data: Doc, fieldKey: string) { +Scripting.addGlobal(function lookupPresBoxField(container: Doc, field: string, data: Doc) { + if (field === 'indexInPres') return DocListCast(container[StrCast(container.presentationFieldKey)]).indexOf(data); + if (field === 'presCollapsedHeight') return container._viewType === CollectionViewType.Stacking ? 50 : 46; + if (field === 'presStatus') return container.presStatus; + if (field === '_itemIndex') return container._itemIndex; + return undefined; }); diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx index 6d7602268..e13a5f2f7 100644 --- a/src/client/views/presentationview/PresElementBox.tsx +++ b/src/client/views/presentationview/PresElementBox.tsx @@ -41,8 +41,8 @@ export class PresElementBox extends ViewBoxBaseComponent= this.currentIndex && this.targetDoc) { + if (this.indexInPres >= this.itemIndex && this.targetDoc) { this.targetDoc.opacity = 1; } } else { - if (this.presStatus && this.indexInPres > this.currentIndex && this.targetDoc) { + if (this.presStatus && this.indexInPres > this.itemIndex && this.targetDoc) { this.targetDoc.opacity = 0; } } @@ -82,12 +82,12 @@ export class PresElementBox extends ViewBoxBaseComponent Date: Tue, 12 May 2020 17:21:48 -0400 Subject: fixed copy paste of documents in freeform collections. --- src/client/views/GlobalKeyHandler.ts | 4 ++-- src/client/views/PreviewCursor.tsx | 11 ++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index 1b16b15bb..b52a0063b 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -263,8 +263,8 @@ export default class KeyManager { case "c": if (SelectionManager.SelectedDocuments().length) { const bds = DocumentDecorations.Instance.Bounds; - const pt = [bds.x + (bds.r - bds.x) / 2, bds.y + (bds.b - bds.y) / 2]; - const text = `__DashDocId(${pt[0]},${pt[1]}):` + SelectionManager.SelectedDocuments().map(dv => dv.Document[Id]).join(":"); + const pt = SelectionManager.SelectedDocuments()[0].props.ScreenToLocalTransform().transformPoint(bds.x + (bds.r - bds.x) / 2, bds.y + (bds.b - bds.y) / 2); + const text = `__DashDocId(${pt?.[0] || 0},${pt?.[1] || 0}):` + SelectionManager.SelectedDocuments().map(dv => dv.Document[Id]).join(":"); SelectionManager.SelectedDocuments().length && navigator.clipboard.writeText(text); stopPropagation = false; preventDefault = false; diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx index 2ddca369a..f7a7944c9 100644 --- a/src/client/views/PreviewCursor.tsx +++ b/src/client/views/PreviewCursor.tsx @@ -7,8 +7,8 @@ import { Docs } from '../documents/Documents'; import { Doc } from '../../new_fields/Doc'; import { Transform } from "../util/Transform"; import { DocServer } from '../DocServer'; -import { NumCast } from '../../new_fields/Types'; import { undoBatch } from '../util/UndoManager'; +import { NumCast } from '../../new_fields/Types'; @observer export class PreviewCursor extends React.Component<{}> { @@ -57,22 +57,23 @@ export class PreviewCursor extends React.Component<{}> { const strs = docids[0].split(","); const ptx = Number(strs[0].substring("__DashDocId(".length)); const pty = Number(strs[1].substring(0, strs[1].length - 1)); - const center = PreviewCursor._getTransform().transformPoint(ptx, pty); let count = 1; const list: Doc[] = []; docids.map((did, i) => i && DocServer.GetRefField(did).then(doc => { count++; if (doc instanceof Doc) { const alias = Doc.MakeClone(doc); - alias.x = newPoint[0] + NumCast(doc.x) - center[0]; - alias.y = newPoint[1] + NumCast(doc.y) - center[1]; + const deltaX = NumCast(doc.x) - ptx; + const deltaY = NumCast(doc.y) - pty; + alias.x = newPoint[0] + deltaX; + alias.y = newPoint[1] + deltaY; list.push(alias); } if (count === docids.length) { undoBatch(() => PreviewCursor._addDocument(list))(); } })); - + e.stopPropagation(); } else { // creates text document undoBatch(() => PreviewCursor._addLiveTextDoc(Docs.Create.TextDocument("", { -- cgit v1.2.3-70-g09d2 From 7b5b04560ba24b049d77d36562fed1f7dc190d43 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Wed, 13 May 2020 01:22:16 -0700 Subject: improved buxton heuristic, but still seems intractable --- src/scraping/buxton/final/BuxtonImporter.ts | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/scraping/buxton/final/BuxtonImporter.ts b/src/scraping/buxton/final/BuxtonImporter.ts index 94302c7b3..e55850b29 100644 --- a/src/scraping/buxton/final/BuxtonImporter.ts +++ b/src/scraping/buxton/final/BuxtonImporter.ts @@ -451,11 +451,23 @@ async function writeImages(zip: any): Promise { }); // if it's not an icon, by this rough heuristic, i.e. is it not square - if (Math.abs(width - height) > 10) { - valid.push({ width, height, type, mediaPath }); + const number = Number(/image(\d+)/.exec(mediaPath)![1]); + if (number > 5 || width - height > 10) { + valid.push({ width, height, type, mediaPath, number }); } } + valid.sort((a, b) => a.number - b.number); + + const [{ width: first_w, height: first_h }, { width: second_w, height: second_h }] = valid; + if (Math.abs(first_w / second_w - first_h / second_h) < 0.01) { + const first_size = first_w * first_h; + const second_size = second_w * second_h; + const target = first_size >= second_size ? 1 : 0; + valid.splice(target, 1); + console.log(`Heuristically removed image with size ${target ? second_size : first_size}`); + } + // for each valid image, output the _o, _l, _m, and _s files // THIS IS WHERE THE SCRIPT SPENDS MOST OF ITS TIME for (const { type, width, height, mediaPath } of valid) { -- cgit v1.2.3-70-g09d2 From 408c8beb55e774f466abe455bb1296c89fe0c256 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 13 May 2020 11:40:58 -0400 Subject: fixed presentations to not find items in the presentation list. cleaned up webbox css --- src/client/util/DocumentManager.ts | 40 +++++++---------- .../views/collections/CollectionStackingView.tsx | 1 + .../collectionFreeForm/CollectionFreeFormView.tsx | 1 + src/client/views/nodes/PresBox.tsx | 1 + src/client/views/nodes/WebBox.scss | 52 +++++++++++++--------- src/client/views/nodes/WebBox.tsx | 7 +-- 6 files changed, 53 insertions(+), 49 deletions(-) (limited to 'src') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 1ba6f0248..99d85125a 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -94,37 +94,29 @@ export class DocumentManager { // heuristic to return the "best" documents first: // choose an exact match over an alias match // choose documents that have a PanelWidth() over those that don't (the treeview documents have no panelWidth) - docViews.map(view => !view.props.Document.presBox && view.props.PanelWidth() > 1 && view.props.Document === toFind && toReturn.push(view)); - docViews.map(view => !view.props.Document.presBox && view.props.PanelWidth() <= 1 && view.props.Document === toFind && toReturn.push(view)); - docViews.map(view => !view.props.Document.presBox && view.props.PanelWidth() > 1 && view.props.Document !== toFind && Doc.AreProtosEqual(view.props.Document, toFind) && toReturn.push(view)); - docViews.map(view => !view.props.Document.presBox && view.props.PanelWidth() <= 1 && view.props.Document !== toFind && Doc.AreProtosEqual(view.props.Document, toFind) && toReturn.push(view)); + docViews.map(view => view.props.PanelWidth() > 1 && view.props.Document === toFind && toReturn.push(view)); + docViews.map(view => view.props.PanelWidth() <= 1 && view.props.Document === toFind && toReturn.push(view)); + docViews.map(view => view.props.PanelWidth() > 1 && view.props.Document !== toFind && Doc.AreProtosEqual(view.props.Document, toFind) && toReturn.push(view)); + docViews.map(view => view.props.PanelWidth() <= 1 && view.props.Document !== toFind && Doc.AreProtosEqual(view.props.Document, toFind) && toReturn.push(view)); return toReturn; } @computed public get LinkedDocumentViews() { - const pairs = DocumentManager.Instance.DocumentViews - //.filter(dv => (dv.isSelected() || Doc.IsBrushed(dv.props.Document))) // draw links from DocumentViews that are selected or brushed OR - // || DocumentManager.Instance.DocumentViews.some(dv2 => { // Documentviews which - // const rest = DocListCast(dv2.props.Document.links).some(l => Doc.AreProtosEqual(l, dv.props.Document));// are link doc anchors - // const init = (dv2.isSelected() || Doc.IsBrushed(dv2.props.Document)) && dv2.Document.type !== DocumentType.AUDIO; // on a view that is selected or brushed - // return init && rest; - // } - // ) - .reduce((pairs, dv) => { - const linksList = LinkManager.Instance.getAllRelatedLinks(dv.props.Document); - pairs.push(...linksList.reduce((pairs, link) => { - const linkToDoc = link && LinkManager.Instance.getOppositeAnchor(link, dv.props.Document); - linkToDoc && DocumentManager.Instance.getDocumentViews(linkToDoc).map(docView1 => { - if (dv.props.Document.type !== DocumentType.LINK || dv.props.LayoutTemplateString !== docView1.props.LayoutTemplateString) { - pairs.push({ a: dv, b: docView1, l: link }); - } - }); - return pairs; - }, [] as { a: DocumentView, b: DocumentView, l: Doc }[])); + const pairs = DocumentManager.Instance.DocumentViews.reduce((pairs, dv) => { + const linksList = LinkManager.Instance.getAllRelatedLinks(dv.props.Document); + pairs.push(...linksList.reduce((pairs, link) => { + const linkToDoc = link && LinkManager.Instance.getOppositeAnchor(link, dv.props.Document); + linkToDoc && DocumentManager.Instance.getDocumentViews(linkToDoc).map(docView1 => { + if (dv.props.Document.type !== DocumentType.LINK || dv.props.LayoutTemplateString !== docView1.props.LayoutTemplateString) { + pairs.push({ a: dv, b: docView1, l: link }); + } + }); return pairs; - }, [] as { a: DocumentView, b: DocumentView, l: Doc }[]); + }, [] as { a: DocumentView, b: DocumentView, l: Doc }[])); + return pairs; + }, [] as { a: DocumentView, b: DocumentView, l: Doc }[]); return pairs; } diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 821a6d476..d97f26daf 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -207,6 +207,7 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument) NativeHeight={returnZero} NativeWidth={returnZero} fitToBox={false} + dontRegisterView={this.props.dontRegisterView} rootSelected={this.rootSelected} dropAction={StrCast(this.props.Document.childDropAction) as dropActionType} onClick={this.onChildClickHandler} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 6caee960d..cfa1a046f 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -893,6 +893,7 @@ export class CollectionFreeFormView extends CollectionSubView childLayoutTemplate={this.childLayoutTemplate} filterAddDocument={this.addDocumentFilter} removeDocument={returnFalse} + dontRegisterView={true} focus={this.selectElement} ScreenToLocalTransform={this.getTransform} /> : (null) diff --git a/src/client/views/nodes/WebBox.scss b/src/client/views/nodes/WebBox.scss index 4c05d4627..4623444b9 100644 --- a/src/client/views/nodes/WebBox.scss +++ b/src/client/views/nodes/WebBox.scss @@ -5,6 +5,36 @@ transform-origin: top left; width: 100%; height: 100%; + + .webBox-htmlSpan { + position: absolute; + top: 0; + left: 0; + } + .webBox-cont { + pointer-events: none; + } + .webBox-cont, .webBox-cont-interactive { + padding: 0vw; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + transform-origin: top left; + overflow: auto; + .webBox-iframe { + width: 100%; + height: 100%; + position: absolute; + top:0; + } + } + .webBox-cont-interactive { + span { + user-select: text !important; + } + } .webBox-outerContent { width: 100%; height: 100%; @@ -20,29 +50,7 @@ display:none; } } -.webBox-cont { - padding: 0vw; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - transform-origin: top left; - overflow: auto; - pointer-events: none; -} - -.webBox-cont-interactive { - span { - user-select: text !important; - } -} -#webBox-htmlSpan { - position: absolute; - top: 0; - left: 0; -} .webBox-overlay { width: 100%; diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 384a6e8a5..b0abb2479 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -308,18 +308,19 @@ export class WebBox extends ViewBoxAnnotatableComponent; + view = ; } else if (field instanceof WebField) { const url = this.layoutDoc.UseCors ? Utils.CorsProxy(field.url.href) : field.url.href; - view =