From e0316c21838613df0fbf43df6a9ca5d696c52f47 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Tue, 30 Jul 2019 20:19:58 -0400 Subject: more interesting speech commands and command manager pattern for DictationManager --- .../collectionFreeForm/CollectionFreeFormView.tsx | 92 +++++++++++++--------- 1 file changed, 56 insertions(+), 36 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 8dac785e1..7856f3718 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -20,7 +20,7 @@ import { DocumentContentsView } from "../../nodes/DocumentContentsView"; import { DocumentViewProps, positionSchema } from "../../nodes/DocumentView"; import { pageSchema } from "../../nodes/ImageBox"; import PDFMenu from "../../pdf/PDFMenu"; -import { CollectionSubView } from "../CollectionSubView"; +import { CollectionSubView, SubCollectionViewProps } from "../CollectionSubView"; import { CollectionFreeFormLinksView } from "./CollectionFreeFormLinksView"; import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCursors"; import "./CollectionFreeFormView.scss"; @@ -38,6 +38,7 @@ import { faTable, faPaintBrush, faAsterisk, faExpandArrowsAlt, faCompressArrowsA import { undo } from "prosemirror-history"; import { number } from "prop-types"; import { ContextMenu } from "../../ContextMenu"; +import DictationManager from "../../../util/DictationManager"; library.add(faEye, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt, faCompass); @@ -121,11 +122,18 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { }); } + constructor(props: SubCollectionViewProps) { + super(props); + let fixed = DictationManager.Instance.registerStatic; + fixed(["Unset Fit To Container", "Set Fit To Container"], this.fitToContainer); + fixed(["Arrange contents in grid"], this.arrangeContents); + fixed(["Analyze Strokes"], this.analyzeStrokes); + } + @computed get fieldExtensionDoc() { return Doc.resolvedFieldDataDoc(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey, "true"); } - @undoBatch @action drop = (e: Event, de: DragManager.DropEvent) => { @@ -516,50 +524,62 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { super.setCursorPosition(this.getTransform().transformPoint(e.clientX, e.clientY)); } + fitToContainer = async () => this.props.Document.fitToBox = !this.fitToBox; + + arrangeContents = async () => { + const docs = await DocListCastAsync(this.Document[this.props.fieldKey]); + UndoManager.RunInBatch(() => { + if (docs) { + let startX = this.Document.panX || 0; + let x = startX; + let y = this.Document.panY || 0; + let i = 0; + const width = Math.max(...docs.map(doc => NumCast(doc.width))); + const height = Math.max(...docs.map(doc => NumCast(doc.height))); + for (const doc of docs) { + doc.x = x; + doc.y = y; + x += width + 20; + if (++i === 6) { + i = 0; + x = startX; + y += height + 20; + } + } + } + }, "arrange contents"); + } + + analyzeStrokes = async () => { + let data = Cast(this.fieldExtensionDoc[this.inkKey], InkField); + if (!data) { + return; + } + let relevantKeys = ["inkAnalysis", "handwriting"]; + CognitiveServices.Inking.Manager.analyzer(this.fieldExtensionDoc, relevantKeys, data.inkData); + } + onContextMenu = () => { let layoutItems: ContextMenuProps[] = []; layoutItems.push({ description: `${this.fitToBox ? "Unset" : "Set"} Fit To Container`, - event: async () => this.props.Document.fitToBox = !this.fitToBox, + event: this.fitToContainer, icon: !this.fitToBox ? "expand-arrows-alt" : "compress-arrows-alt" }); layoutItems.push({ description: "Arrange contents in grid", - icon: "table", - event: async () => { - const docs = await DocListCastAsync(this.Document[this.props.fieldKey]); - UndoManager.RunInBatch(() => { - if (docs) { - let startX = this.Document.panX || 0; - let x = startX; - let y = this.Document.panY || 0; - let i = 0; - const width = Math.max(...docs.map(doc => NumCast(doc.width))); - const height = Math.max(...docs.map(doc => NumCast(doc.height))); - for (const doc of docs) { - doc.x = x; - doc.y = y; - x += width + 20; - if (++i === 6) { - i = 0; - x = startX; - y += height + 20; - } - } - } - }, "arrange contents"); - } + event: this.arrangeContents, + icon: "table" }); - ContextMenu.Instance.addItem({ description: "Layout...", subitems: layoutItems, icon: "compass" }); ContextMenu.Instance.addItem({ - description: "Analyze Strokes", event: async () => { - let data = Cast(this.fieldExtensionDoc[this.inkKey], InkField); - if (!data) { - return; - } - let relevantKeys = ["inkAnalysis", "handwriting"]; - CognitiveServices.Inking.Manager.analyzer(this.fieldExtensionDoc, relevantKeys, data.inkData); - }, icon: "paint-brush" + description: "Layout...", + subitems: layoutItems, + icon: "compass" + }); + ContextMenu.Instance.addItem({ + description: "Analyze Strokes", + event: this.analyzeStrokes, + icon: "paint-brush" }); } -- cgit v1.2.3-70-g09d2 From 49faa4e76f91fed04bb1923d81dd23d57a157a63 Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 31 Jul 2019 07:35:41 -0400 Subject: grouping experiment --- .../collectionFreeForm/CollectionFreeFormView.tsx | 49 +++++++++++++++++++++- src/client/views/nodes/DocumentView.tsx | 1 + 2 files changed, 49 insertions(+), 1 deletion(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 8dac785e1..c4c3ba084 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -38,6 +38,7 @@ import { faTable, faPaintBrush, faAsterisk, faExpandArrowsAlt, faCompressArrowsA import { undo } from "prosemirror-history"; import { number } from "prop-types"; import { ContextMenu } from "../../ContextMenu"; +import { SwatchesPicker } from "react-color"; library.add(faEye, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt, faCompass); @@ -125,7 +126,24 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { return Doc.resolvedFieldDataDoc(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey, "true"); } - + 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); + } + bounsdSelect(doc: Doc, doc2: Doc) { + var x2 = NumCast(doc2.x) - 25; + var y2 = NumCast(doc2.y) - 25; + var w2 = NumCast(doc2.width) + 25; + var h2 = NumCast(doc2.height) + 25; + var x = NumCast(doc.x) - 25; + var y = NumCast(doc.y) - 25; + var w = NumCast(doc.width) + 25; + var h = NumCast(doc.height) + 25; + if (this.intersectRect({ left: x, top: y, width: w, height: h }, { left: x2, top: y2, width: w2, height: h2 })) { + return true; + } + return false; + } @undoBatch @action drop = (e: Event, de: DragManager.DropEvent) => { @@ -151,6 +169,35 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } this.bringToFront(d); }); + + let sets: (Doc[])[] = [] + this.childDocs.map(c => { + let included = [] + for (let i = 0; i < sets.length; i++) { + for (let j = 0; j < sets[i].length; j++) { + if (this.bounsdSelect(c, sets[i][j])) { + included.push(i); + break; + } + } + } + if (included.length === 0) + sets.push([c]); + else if (included.length === 1) + sets[included[0]].push(c); + else { + sets[included[0]].push(c); + for (let s = 1; s < included.length; s++) { + sets[included[0]].push(...sets[included[s]]); + sets[included[s]].length = 0; + } + } + }); + for (let s = 0; s < sets.length; s++) { + for (let i = 0; i < sets[s].length; i++) { + Doc.GetProto(sets[s][i]).cluster = s; + } + } } } else if (de.data instanceof DragManager.AnnotationDragData) { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 4b5cf3a43..2dc2c18a3 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -694,6 +694,7 @@ export class DocumentView extends DocComponent(Docu color: foregroundColor, outlineColor: "maroon", outlineStyle: "dashed", + boxShadow: `#9c9396 ${StrCast(this.props.Document.boxShadow, "0vw 0vw 11vw")}`, outlineWidth: BoolCast(this.layoutDoc.libraryBrush) && !StrCast(Doc.GetProto(this.props.Document).borderRounding) ? `${this.props.ScreenToLocalTransform().Scale}px` : "0px", marginLeft: BoolCast(this.layoutDoc.libraryBrush) && StrCast(Doc.GetProto(this.props.Document).borderRounding) ? -- cgit v1.2.3-70-g09d2 From ec224416fc454c7fdbb62943408226c973d8c751 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Thu, 1 Aug 2019 02:30:47 -0400 Subject: fixed import ordering issue, allow for multiple targets and valid document types --- src/client/documents/Documents.ts | 45 ++++++++------- src/client/util/DictationManager.ts | 66 ++++++++-------------- .../collectionFreeForm/CollectionFreeFormView.tsx | 8 --- src/client/views/nodes/DocumentView.tsx | 1 - src/client/views/search/FilterBox.tsx | 2 +- src/client/views/search/SearchItem.tsx | 2 +- src/client/views/search/ToggleBar.tsx | 2 +- 7 files changed, 49 insertions(+), 77 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 2a1f63d59..3c7de17c8 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -1,3 +1,24 @@ +export enum DocumentType { + NONE = "none", + TEXT = "text", + HIST = "histogram", + IMG = "image", + WEB = "web", + COL = "collection", + KVP = "kvp", + VID = "video", + AUDIO = "audio", + PDF = "pdf", + ICON = "icon", + IMPORT = "import", + LINK = "link", + LINKDOC = "linkdoc", + BUTTON = "button", + TEMPLATE = "template", + EXTENSION = "extension", + YOUTUBE = "youtube", +} + import { HistogramField } from "../northstar/dash-fields/HistogramField"; import { HistogramBox } from "../northstar/dash-nodes/HistogramBox"; import { HistogramOperation } from "../northstar/operations/HistogramOperation"; @@ -25,14 +46,13 @@ import { OmitKeys, JSONUtils } from "../../Utils"; import { ImageField, VideoField, AudioField, PdfField, WebField, YoutubeField } from "../../new_fields/URLField"; import { HtmlField } from "../../new_fields/HtmlField"; import { List } from "../../new_fields/List"; -import { Cast, NumCast, StrCast, ToConstructor, InterfaceValue, FieldValue } from "../../new_fields/Types"; +import { Cast, NumCast } from "../../new_fields/Types"; import { IconField } from "../../new_fields/IconField"; import { listSpec } from "../../new_fields/Schema"; import { DocServer } from "../DocServer"; import { dropActionType } from "../util/DragManager"; import { DateField } from "../../new_fields/DateField"; import { UndoManager } from "../util/UndoManager"; -import { RouteStore } from "../../server/RouteStore"; import { YoutubeBox } from "../apis/youtube/YoutubeBox"; import { CollectionDockingView } from "../views/collections/CollectionDockingView"; import { LinkManager } from "../util/LinkManager"; @@ -44,27 +64,6 @@ import { SchemaHeaderField, RandomPastel } from "../../new_fields/SchemaHeaderFi var requestImageSize = require('../util/request-image-size'); var path = require('path'); -export enum DocumentType { - NONE = "none", - TEXT = "text", - HIST = "histogram", - IMG = "image", - WEB = "web", - COL = "collection", - KVP = "kvp", - VID = "video", - AUDIO = "audio", - PDF = "pdf", - ICON = "icon", - IMPORT = "import", - LINK = "link", - LINKDOC = "linkdoc", - BUTTON = "button", - TEMPLATE = "template", - EXTENSION = "extension", - YOUTUBE = "youtube", -} - export interface DocumentOptions { x?: number; y?: number; diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts index 49afe5371..b0866a826 100644 --- a/src/client/util/DictationManager.ts +++ b/src/client/util/DictationManager.ts @@ -6,9 +6,9 @@ import { Doc } from "../../new_fields/Doc"; import { List } from "../../new_fields/List"; import { Docs, DocumentType } from "../documents/Documents"; import { CollectionViewType } from "../views/collections/CollectionBaseView"; -import { listSpec } from "../../new_fields/Schema"; import { Cast, CastCtor } from "../../new_fields/Types"; -import { ImageField, AudioField } from "../../new_fields/URLField"; +import { listSpec } from "../../new_fields/Schema"; +import { AudioField, ImageField } from "../../new_fields/URLField"; import { HistogramField } from "../northstar/dash-fields/HistogramField"; namespace CORE { @@ -17,7 +17,7 @@ namespace CORE { } } -const Mapping = new Map([ +const ConstructorMap = new Map([ [DocumentType.COL, listSpec(Doc)], [DocumentType.AUDIO, AudioField], [DocumentType.IMG, ImageField], @@ -26,7 +26,7 @@ const Mapping = new Map([ ]); const tryCast = (view: DocumentView, type: DocumentType) => { - let ctor = Mapping.get(type); + let ctor = ConstructorMap.get(type); if (!ctor) { return false; } @@ -82,28 +82,6 @@ export default class DictationManager { }); } - private sanitize = (title: string) => { - return title.replace("...", "").toLowerCase().trim(); - } - - public registerStatic = (keys: Array, action: IndependentAction, filter?: ActionPredicate) => { - let success = true; - keys.forEach(key => { - key = this.sanitize(key); - let existing = RegisteredCommands.Independent.get(key); - if (!existing) { - let unit = { - action: action, - filter: filter - }; - RegisteredCommands.Independent.set(key, unit); - } else { - success = false; - } - }); - return success; - } - public interpretNumber = (number: string) => { let initial = parseInt(number); if (!isNaN(initial)) { @@ -116,34 +94,38 @@ export default class DictationManager { return typeof converted === "string" ? parseInt(converted) : converted; } - public registerDynamic = (dynamicKey: RegExp, action: DependentAction) => { - RegisteredCommands.Dependent.push({ - expression: dynamicKey, - action: action - }); - } - @undoBatch public execute = async (phrase: string) => { - let target = SelectionManager.SelectedDocuments()[0]; - if (!target) { + let targets = SelectionManager.SelectedDocuments(); + if (!targets || !targets.length) { return; } - phrase = this.sanitize(phrase); let entry = RegisteredCommands.Independent.get(phrase); - if (entry && (!entry.restrictTo || validate(target, entry.restrictTo))) { - await entry.action(target); - return true; + if (entry) { + let success = false; + for (let target of targets) { + if (!entry.restrictTo || validate(target, entry.restrictTo)) { + await entry.action(target); + success = true; + } + } + return success; } for (let entry of RegisteredCommands.Dependent) { let regex = entry.expression; let matches = regex.exec(phrase); regex.lastIndex = 0; - if (matches !== null && (!entry.restrictTo || validate(target, entry.restrictTo))) { - await entry.action(target, matches); - return true; + if (matches !== null) { + let success = false; + for (let target of targets) { + if (!entry.restrictTo || validate(target, entry.restrictTo)) { + await entry.action(target, matches); + success = true; + } + } + return success; } } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 59c77f1c9..fa49e7175 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -123,14 +123,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { }); } - constructor(props: SubCollectionViewProps) { - super(props); - let fixed = DictationManager.Instance.registerStatic; - fixed(["Unset Fit To Container", "Set Fit To Container"], this.fitToContainer); - fixed(["Arrange contents in grid"], this.arrangeContents); - fixed(["Analyze Strokes"], this.analyzeStrokes); - } - @computed get fieldExtensionDoc() { return Doc.resolvedFieldDataDoc(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey, "true"); } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 39574db0f..51661d1ae 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -41,7 +41,6 @@ import { ClientUtils } from '../../util/ClientUtils'; import { EditableView } from '../EditableView'; import { faHandPointer, faHandPointRight } from '@fortawesome/free-regular-svg-icons'; import { DocumentDecorations } from '../DocumentDecorations'; -import { CognitiveServices } from '../../cognitive_services/CognitiveServices'; import DictationManager from '../../util/DictationManager'; import { CollectionViewType } from '../collections/CollectionBaseView'; const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? diff --git a/src/client/views/search/FilterBox.tsx b/src/client/views/search/FilterBox.tsx index 995ddd5c3..3e8582d61 100644 --- a/src/client/views/search/FilterBox.tsx +++ b/src/client/views/search/FilterBox.tsx @@ -384,7 +384,7 @@ export class FilterBox extends React.Component {
Collection Filters Active
: undefined} - ) + ); } // Useful queries: diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx index 0390359b3..6fbc92007 100644 --- a/src/client/views/search/SearchItem.tsx +++ b/src/client/views/search/SearchItem.tsx @@ -134,7 +134,7 @@ export class LinkContextMenu extends React.Component { - ) + ); } } diff --git a/src/client/views/search/ToggleBar.tsx b/src/client/views/search/ToggleBar.tsx index a30104089..ed5ecd3ba 100644 --- a/src/client/views/search/ToggleBar.tsx +++ b/src/client/views/search/ToggleBar.tsx @@ -59,7 +59,7 @@ export class ToggleBar extends React.Component{ this._forwardTimeline.play(); this._forwardTimeline.reverse(); this.props.handleChange(); - console.log(this.props.getStatus()) + console.log(this.props.getStatus()); } @action.bound -- cgit v1.2.3-70-g09d2 From 6f3d4a7015e15e0523fc194f7f911f6d45259165 Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 1 Aug 2019 13:57:59 -0400 Subject: added floating docs --- src/client/util/DragManager.ts | 7 +++- src/client/views/TemplateMenu.tsx | 44 ++++++++++++++++++++- .../collectionFreeForm/CollectionFreeFormView.scss | 1 + .../collectionFreeForm/CollectionFreeFormView.tsx | 46 +++++++++++++++------- .../views/nodes/CollectionFreeFormDocumentView.tsx | 1 + src/client/views/nodes/DocumentView.tsx | 42 +++++++++----------- 6 files changed, 100 insertions(+), 41 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index abcc3a4e1..0b5c785a4 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -10,6 +10,7 @@ import { LinkManager } from "./LinkManager"; import { SelectionManager } from "./SelectionManager"; import { SchemaHeaderField } from "../../new_fields/SchemaHeaderField"; import { DocumentDecorations } from "../views/DocumentDecorations"; +import { NumberLiteralType } from "typescript"; export type dropActionType = "alias" | "copy" | undefined; export function SetupDrag( @@ -140,6 +141,10 @@ export namespace DragManager { dragHasStarted?: () => void; withoutShiftDrag?: boolean; + + offsetX?: number; + + offsetY?: number; } export interface DragDropDisposer { @@ -423,7 +428,7 @@ export namespace DragManager { lastX = e.pageX; lastY = e.pageY; dragElements.map((dragElement, i) => (dragElement.style.transform = - `translate(${(xs[i] += moveX)}px, ${(ys[i] += moveY)}px) scale(${scaleXs[i]}, ${scaleYs[i]})`) + `translate(${(xs[i] += moveX) + (options ? (options.offsetX || 0) : 0)}px, ${(ys[i] += moveY) + (options ? (options.offsetY || 0) : 0)}px) scale(${scaleXs[i]}, ${scaleYs[i]})`) ); }; diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index 1b32f0ddd..c413650f0 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -7,6 +7,10 @@ import { DocumentView } from "./nodes/DocumentView"; import { Template } from "./Templates"; import React = require("react"); import { undoBatch } from "../util/UndoManager"; +import { DocumentManager } from "../util/DocumentManager"; +import { NumCast } from "../../new_fields/Types"; +import { DragManager } from "../util/DragManager"; +import { SelectionManager } from "../util/SelectionManager"; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -35,11 +39,46 @@ export interface TemplateMenuProps { @observer export class TemplateMenu extends React.Component { @observable private _hidden: boolean = true; + dragRef = React.createRef(); constructor(props: TemplateMenuProps) { super(props); } + toggleFloat = (e: React.MouseEvent): void => { + SelectionManager.DeselectAll(); + let topDocView = this.props.docs[0]; + let topDoc = topDocView.props.Document; + let xf = topDocView.props.ScreenToLocalTransform(); + let ex = e.clientX; + let ey = e.clientY; + undoBatch(action(() => topDoc.z = topDoc.z ? 0 : 1))(); + if (!topDoc.z) { + setTimeout(() => { + let newDocView = DocumentManager.Instance.getDocumentView(topDoc); + if (newDocView) { + let de = new DragManager.DocumentDragData([topDoc], [undefined]); + de.moveDocument = topDocView.props.moveDocument; + let xf = newDocView.ContentDiv!.getBoundingClientRect(); + console.log("ex = " + ex + " " + xf.left + " " + (ex - xf.left)); + DragManager.StartDocumentDrag([newDocView.ContentDiv!], de, ex, ey, { + offsetX: (ex - xf.left), offsetY: (ey - xf.top), + handlers: { + dragComplete: () => { }, + }, + hideSource: false + }); + } + }, 10); + } else if (topDocView.props.ContainingCollectionView) { + let collView = topDocView.props.ContainingCollectionView!; + let [sx, sy] = xf.inverse().transformPoint(0, 0); + let [x, y] = collView.props.ScreenToLocalTransform().transformPoint(sx, sy); + topDoc.x = x; + topDoc.y = y; + } + } + @undoBatch @action toggleTemplate = (event: React.ChangeEvent, template: Template): void => { @@ -89,9 +128,10 @@ export class TemplateMenu extends React.Component { return (
this.toggleTemplateActivity()}>+
-
    +
      {templateMenu} - + +
); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss index cca199afa..c4311fa52 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss @@ -46,6 +46,7 @@ border-radius: inherit; box-sizing: border-box; position: absolute; + overflow: hidden; .marqueeView { overflow: hidden; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 29f9b1429..9cbc652b9 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -77,7 +77,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } @computed get contentBounds() { - let bounds = this.fitToBox && !this.isAnnotationOverlay ? this.ComputeContentBounds(this.elements.filter(e => e.bounds).map(e => e.bounds!)) : undefined; + let bounds = this.fitToBox && !this.isAnnotationOverlay ? this.ComputeContentBounds(this.elements.filter(e => e.bounds && !e.bounds.z).map(e => e.bounds!)) : undefined; let res = { panX: bounds ? (bounds.x + bounds.r) / 2 : this.Document.panX || 0, panY: bounds ? (bounds.y + bounds.b) / 2 : this.Document.panY || 0, @@ -98,6 +98,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { private centeringShiftX = () => !this.nativeWidth && !this.isAnnotationOverlay ? this._pwidth / 2 / this.parentScaling : 0; // shift so pan position is at center of window for non-overlay collections private centeringShiftY = () => !this.nativeHeight && !this.isAnnotationOverlay ? this._pheight / 2 / this.parentScaling : 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); private getLocalTransform = (): Transform => Transform.Identity().scale(1 / this.zoomScaling()).translate(this.panX(), this.panY()); private addLiveTextBox = (newBox: Doc) => { @@ -131,12 +132,15 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @action drop = (e: Event, de: DragManager.DropEvent) => { let xf = this.getTransform(); + let xfo = this.getTransformOverlay(); let [xp, yp] = xf.transformPoint(de.x, de.y); + let [xpo, ypo] = xfo.transformPoint(de.x, de.y); if (super.drop(e, de)) { if (de.data instanceof DragManager.DocumentDragData) { if (de.data.droppedDocuments.length) { - let x = xp - de.data.xOffset; - let y = yp - de.data.yOffset; + let z = NumCast(de.data.draggedDocuments[0].z); + let x = (z ? xpo : xp) - de.data.xOffset; + let y = (z ? ypo : yp) - de.data.yOffset; let dropX = NumCast(de.data.droppedDocuments[0].x); let dropY = NumCast(de.data.droppedDocuments[0].y); de.data.droppedDocuments.forEach(d => { @@ -292,8 +296,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { const newPanY = Math.min((1 - 1 / scale) * this.nativeHeight, Math.max(0, panY)); this.props.Document.panX = this.isAnnotationOverlay ? newPanX : panX; this.props.Document.panY = this.isAnnotationOverlay && StrCast(this.props.Document.backgroundLayout).indexOf("PDFBox") === -1 ? newPanY : panY; - // this.props.Document.panX = panX; - // this.props.Document.panY = panY; if (this.props.Document.scrollY) { this.props.Document.scrollY = panY - scale * this.props.Document[HeightSym](); } @@ -396,7 +398,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { addDocument: this.props.addDocument, removeDocument: this.props.removeDocument, moveDocument: this.props.moveDocument, - ScreenToLocalTransform: this.getTransform, + ScreenToLocalTransform: pair.layout.z ? this.getTransformOverlay : this.getTransform, renderDepth: this.props.renderDepth + 1, selectOnLoad: pair.layout[Id] === this._selectOnLoaded, PanelWidth: pair.layout[WidthSym], @@ -436,23 +438,25 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { }; } - getCalculatedPositions(script: ScriptField, params: { doc: Doc, index: number, collection: Doc, docs: Doc[], state: any }): { x?: number, y?: number, width?: number, height?: number, state?: any } { + getCalculatedPositions(script: ScriptField, params: { doc: Doc, index: number, collection: Doc, docs: Doc[], state: any }): { x?: number, y?: number, z?: number, width?: number, height?: number, state?: any } { const result = script.script.run(params); if (!result.success) { return {}; } - return result.result === undefined ? {} : result.result; + let doc = params.doc; + return result.result === undefined ? { x: Cast(doc.x, "number"), y: Cast(doc.y, "number"), z: Cast(doc.z, "number"), width: Cast(doc.width, "number"), height: Cast(doc.height, "number") } : result.result; } - private viewDefToJSX(viewDef: any): { ele: JSX.Element, bounds?: { x: number, y: number, width: number, height: number } } | undefined { + private viewDefToJSX(viewDef: any): { ele: JSX.Element, bounds?: { x: number, y: number, z?: number, width: number, height: number } } | undefined { if (viewDef.type === "text") { const text = Cast(viewDef.text, "string"); const x = Cast(viewDef.x, "number"); const y = Cast(viewDef.y, "number"); + const z = Cast(viewDef.z, "number"); const width = Cast(viewDef.width, "number"); const height = Cast(viewDef.height, "number"); const fontSize = Cast(viewDef.fontSize, "number"); - if ([text, x, y, width, height].some(val => val === undefined)) { + if ([text, x, y, z, width, height].some(val => val === undefined)) { return undefined; } @@ -460,7 +464,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { ele:
{text}
, bounds: { x: x!, y: y!, width: width!, height: height! } + }}>{text}, bounds: { x: x!, y: y!, z: z, width: width!, height: height! } }; } } @@ -472,7 +476,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { const script = this.Document.arrangeScript; let state: any = undefined; const docs = this.childDocs; - let elements: { ele: JSX.Element, bounds?: { x: number, y: number, width: number, height: number } }[] = []; + let elements: { ele: JSX.Element, bounds?: { x: number, y: number, z?: number, width: number, height: number } }[] = []; if (initScript) { const initResult = initScript.script.run({ docs, collection: this.Document }); if (initResult.success) { @@ -494,13 +498,13 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { let minim = BoolCast(doc.isMinimized); if (minim === undefined || !minim) { const pos = script ? this.getCalculatedPositions(script, { doc, index: prev.length, collection: this.Document, docs, state }) : - { x: Cast(doc.x, "number"), y: Cast(doc.y, "number"), width: Cast(doc.width, "number"), height: Cast(doc.height, "number") }; + { x: Cast(doc.x, "number"), y: Cast(doc.y, "number"), z: Cast(doc.z, "number"), width: Cast(doc.width, "number"), height: Cast(doc.height, "number") }; state = pos.state === undefined ? state : pos.state; prev.push({ ele: , - bounds: (pos.x !== undefined && pos.y !== undefined && pos.width !== undefined && pos.height !== undefined) ? { x: pos.x, y: pos.y, width: pos.width, height: pos.height } : undefined + bounds: (pos.x !== undefined && pos.y !== undefined && pos.width !== undefined && pos.height !== undefined) ? { x: pos.x, y: pos.y, z: pos.z, width: pos.width, height: pos.height } : undefined }); } } @@ -514,8 +518,13 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @computed.struct get views() { - return this.elements.map(ele => ele.ele); + return this.elements.filter(ele => ele.bounds && !ele.bounds.z).map(ele => ele.ele); } + @computed.struct + get overlayViews() { + return this.elements.filter(ele => ele.bounds && ele.bounds.z).map(ele => ele.ele); + } + @action onCursorMove = (e: React.PointerEvent) => { @@ -603,6 +612,12 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { , ...this.views ] + private overlayChildViews = () => { + console.log(this.overlayViews.length); + return [ + ...this.overlayViews + ]; + } public static AddCustomLayout(doc: Doc, dataKey: string): () => void { return () => { @@ -651,6 +666,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { + {this.overlayChildViews()} ); diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 7ffd760e0..3b6c443c2 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -77,6 +77,7 @@ export class CollectionFreeFormDocumentView extends DocComponent; -- cgit v1.2.3-70-g09d2 From 65f23d993c091ee7fa61becea85b5f60ec2e9104 Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 1 Aug 2019 15:44:22 -0400 Subject: added dragging of clusters. --- .../collectionFreeForm/CollectionFreeFormView.tsx | 37 +++++++++++++++++----- src/client/views/nodes/DocumentView.tsx | 3 +- 2 files changed, 31 insertions(+), 9 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 8cac60edb..12e5924b4 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -131,15 +131,16 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { 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); } + _groupingBorder = 150; bounsdSelect(doc: Doc, doc2: Doc) { - var x2 = NumCast(doc2.x) - 25; - var y2 = NumCast(doc2.y) - 25; - var w2 = NumCast(doc2.width) + 25; - var h2 = NumCast(doc2.height) + 25; - var x = NumCast(doc.x) - 25; - var y = NumCast(doc.y) - 25; - var w = NumCast(doc.width) + 25; - var h = NumCast(doc.height) + 25; + var x2 = NumCast(doc2.x) - this._groupingBorder; + var y2 = NumCast(doc2.y) - this._groupingBorder; + var w2 = NumCast(doc2.width) + this._groupingBorder; + var h2 = NumCast(doc2.height) + this._groupingBorder; + var x = NumCast(doc.x) - this._groupingBorder; + var y = NumCast(doc.y) - this._groupingBorder; + var w = NumCast(doc.width) + this._groupingBorder; + var h = NumCast(doc.height) + this._groupingBorder; if (this.intersectRect({ left: x, top: y, width: w, height: h }, { left: x2, top: y2, width: w2, height: h2 })) { return true; } @@ -242,6 +243,26 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @action onPointerMove = (e: PointerEvent): void => { if (!e.cancelBubble) { + let probe = this.getTransform().transformPoint(e.clientX, e.clientY); + let cluster = this.childDocs.reduce((cluster, cd) => { + let cx = NumCast(cd.x) - this._groupingBorder; + let cy = NumCast(cd.y) - this._groupingBorder; + let cw = NumCast(cd.width) + this._groupingBorder; + let ch = NumCast(cd.height) + this._groupingBorder; + if (this.intersectRect({ left: cx, top: cy, width: cw, height: ch }, { left: probe[0], top: probe[1], width: 1, height: 1 })) + return NumCast(cd.cluster); + return cluster; + }, -1); + if (cluster !== -1) { + let eles = this.childDocs.filter(cd => NumCast(cd.cluster) === cluster); + this.selectDocuments(eles); + DragManager.StartDocumentDrag(SelectionManager.SelectedDocuments().map(v => v.ContentDiv!), new DragManager.DocumentDragData(eles, eles.map(d => undefined)), e.clientX, e.clientY); + 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 + e.preventDefault(); + document.removeEventListener("pointermove", this.onPointerMove); + document.removeEventListener("pointerup", this.onPointerUp); + return; + } let x = this.Document.panX || 0; let y = this.Document.panY || 0; let docs = this.childDocs || []; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index c5cf2e23a..fa1e824f8 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -695,6 +695,7 @@ export class DocumentView extends DocComponent(Docu }); } let showTextTitle = showTitle && StrCast(this.layoutDoc.layout).startsWith("(Docu color: foregroundColor, outlineColor: "maroon", outlineStyle: "dashed", - boxShadow: `#9c9396 ${StrCast(this.props.Document.boxShadow, "0vw 0vw 11vw")}`, + boxShadow: `${colors[NumCast(this.props.Document.cluster) % colors.length]} ${StrCast(this.props.Document.boxShadow, "0vw 0vw 11vw")}`, outlineWidth: BoolCast(this.layoutDoc.libraryBrush) && !StrCast(Doc.GetProto(this.props.Document).borderRounding) ? `${this.props.ScreenToLocalTransform().Scale}px` : "0px", marginLeft: BoolCast(this.layoutDoc.libraryBrush) && StrCast(Doc.GetProto(this.props.Document).borderRounding) ? -- cgit v1.2.3-70-g09d2 From c48345b74fadc558062ced96591f041eb4f2729d Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Thu, 1 Aug 2019 15:55:07 -0400 Subject: cognitive services --- src/client/cognitive_services/CognitiveServices.ts | 32 ++++++++++++++-------- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/nodes/ImageBox.tsx | 8 ++++-- 3 files changed, 27 insertions(+), 15 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/cognitive_services/CognitiveServices.ts b/src/client/cognitive_services/CognitiveServices.ts index c118d91d3..08fcb4883 100644 --- a/src/client/cognitive_services/CognitiveServices.ts +++ b/src/client/cognitive_services/CognitiveServices.ts @@ -7,9 +7,9 @@ import { Utils } from "../../Utils"; import { InkData } from "../../new_fields/InkField"; import { UndoManager } from "../util/UndoManager"; -type APIManager = { converter: BodyConverter, requester: RequestExecutor, analyzer: AnalysisApplier }; +type APIManager = { converter: BodyConverter, requester: RequestExecutor }; type RequestExecutor = (apiKey: string, body: string, service: Service) => Promise; -type AnalysisApplier = (target: Doc, relevantKeys: string[], ...args: any) => any; +type AnalysisApplier = (target: Doc, relevantKeys: string[], data: D, ...args: any) => any; type BodyConverter = (data: D) => string; type Converter = (results: any) => Field; @@ -38,7 +38,7 @@ export enum Confidence { */ export namespace CognitiveServices { - const ExecuteQuery = async (service: Service, manager: APIManager, data: D): Promise> => { + const ExecuteQuery = async (service: Service, manager: APIManager, data: D): Promise => { return fetch(Utils.prepend(`${RouteStore.cognitiveServices}/${service}`)).then(async response => { let apiKey = await response.text(); if (!apiKey) { @@ -46,7 +46,7 @@ export namespace CognitiveServices { return undefined; } - let results: Opt; + let results: any; try { results = await manager.requester(apiKey, manager.converter(data), service).then(json => JSON.parse(json)); } catch { @@ -99,7 +99,11 @@ export namespace CognitiveServices { return request.post(options); }, - analyzer: async (target: Doc, keys: string[], url: string, service: Service, converter: Converter) => { + }; + + export namespace Appliers { + + export const ProcessImage: AnalysisApplier = async (target: Doc, keys: string[], url: string, service: Service, converter: Converter) => { let batch = UndoManager.StartBatch("Image Analysis"); let storageKey = keys[0]; @@ -107,7 +111,7 @@ export namespace CognitiveServices { return; } let toStore: any; - let results = await ExecuteQuery(service, Manager, url); + let results = await ExecuteQuery(service, Manager, url); if (!results) { toStore = "Cognitive Services could not process the given image URL."; } else { @@ -120,9 +124,9 @@ export namespace CognitiveServices { target[storageKey] = toStore; batch.end(); - } + }; - }; + } export type Face = { faceAttributes: any, faceId: string, faceRectangle: Rectangle }; @@ -179,10 +183,14 @@ export namespace CognitiveServices { return new Promise(promisified); }, - analyzer: async (target: Doc, keys: string[], inkData: InkData) => { + }; + + export namespace Appliers { + + export const ConcatenateHandwriting: AnalysisApplier = async (target: Doc, keys: string[], inkData: InkData) => { let batch = UndoManager.StartBatch("Ink Analysis"); - let results = await ExecuteQuery(Service.Handwriting, Manager, inkData); + let results = await ExecuteQuery(Service.Handwriting, Manager, inkData); if (results) { results.recognitionUnits && (results = results.recognitionUnits); target[keys[0]] = Docs.Get.DocumentHierarchyFromJson(results, "Ink Analysis"); @@ -192,9 +200,9 @@ export namespace CognitiveServices { } batch.end(); - } + }; - }; + } export interface AzureStrokeData { id: number; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index fa49e7175..9535a6f78 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -555,7 +555,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { return; } let relevantKeys = ["inkAnalysis", "handwriting"]; - CognitiveServices.Inking.Manager.analyzer(this.fieldExtensionDoc, relevantKeys, data.inkData); + CognitiveServices.Inking.Appliers.ConcatenateHandwriting(this.fieldExtensionDoc, relevantKeys, data.inkData); } onContextMenu = (e: React.MouseEvent) => { diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 9a0615d68..879a91fa1 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -237,7 +237,9 @@ export class ImageBox extends DocComponent(ImageD results.map((face: CognitiveServices.Image.Face) => faceDocs.push(Docs.Get.DocumentHierarchyFromJson(face, `Face: ${face.faceId}`)!)); return faceDocs; }; - CognitiveServices.Image.Manager.analyzer(this.extensionDoc, ["faces"], this.url, Service.Face, converter); + if (this.url) { + CognitiveServices.Image.Appliers.ProcessImage(this.extensionDoc, ["faces"], this.url, Service.Face, converter); + } } generateMetadata = (threshold: Confidence = Confidence.Excellent) => { @@ -256,7 +258,9 @@ export class ImageBox extends DocComponent(ImageD tagDoc.confidence = threshold; return tagDoc; }; - CognitiveServices.Image.Manager.analyzer(this.extensionDoc, ["generatedTagsDoc"], this.url, Service.ComputerVision, converter); + if (this.url) { + CognitiveServices.Image.Appliers.ProcessImage(this.extensionDoc, ["generatedTagsDoc"], this.url, Service.ComputerVision, converter); + } } @action -- cgit v1.2.3-70-g09d2 From 64d25bd7a92daa4a8b9ee69f0eabd88e5cbeeca5 Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 1 Aug 2019 16:04:43 -0400 Subject: cleaned up detaillayout for pivot viewer. --- .../collections/collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/new_fields/Doc.ts | 9 ++------- 2 files changed, 3 insertions(+), 8 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 9cbc652b9..90f67c54e 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -456,7 +456,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { const width = Cast(viewDef.width, "number"); const height = Cast(viewDef.height, "number"); const fontSize = Cast(viewDef.fontSize, "number"); - if ([text, x, y, z, width, height].some(val => val === undefined)) { + if ([text, x, y, width, height].some(val => val === undefined)) { return undefined; } diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 6e2c5e697..b70951040 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -525,19 +525,14 @@ export namespace Doc { } export function UseDetailLayout(d: Doc) { runInAction(async () => { - const dl1 = d.detailedLayout; - let detailLayout1 = await PromiseValue(dl1); - const dl2 = d.detailedLayout; - let detailLayout = await PromiseValue(dl2); + let detailLayout = await d.detailedLayout; if (detailLayout) { d.layout = detailLayout; d.nativeWidth = d.nativeHeight = undefined; if (detailLayout instanceof Doc) { let delegDetailLayout = Doc.MakeDelegate(detailLayout) as Doc; d.layout = delegDetailLayout; - let subDetailLayout1 = await PromiseValue(delegDetailLayout.detailedLayout); - let subDetailLayout = await PromiseValue(delegDetailLayout.detailedLayout); - delegDetailLayout.layout = subDetailLayout; + delegDetailLayout.layout = await delegDetailLayout.detailedLayout; } } }); -- cgit v1.2.3-70-g09d2 From 8cd098ab0e348c614640bc0971f3859161b8c2b4 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 2 Aug 2019 16:39:03 -0400 Subject: fixed drag interactions with groups. --- .../collectionFreeForm/CollectionFreeFormView.tsx | 18 ++++++++++++++++-- src/client/views/nodes/DocumentView.tsx | 4 ++-- 2 files changed, 18 insertions(+), 4 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 12e5924b4..3ff816c46 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -131,7 +131,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { 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); } - _groupingBorder = 150; + _groupingBorder = 100; bounsdSelect(doc: Doc, doc2: Doc) { var x2 = NumCast(doc2.x) - this._groupingBorder; var y2 = NumCast(doc2.y) - this._groupingBorder; @@ -256,7 +256,21 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { if (cluster !== -1) { let eles = this.childDocs.filter(cd => NumCast(cd.cluster) === cluster); this.selectDocuments(eles); - DragManager.StartDocumentDrag(SelectionManager.SelectedDocuments().map(v => v.ContentDiv!), new DragManager.DocumentDragData(eles, eles.map(d => undefined)), e.clientX, e.clientY); + let clusterDocs = SelectionManager.SelectedDocuments(); + SelectionManager.DeselectAll(); + let de = new DragManager.DocumentDragData(eles, eles.map(d => undefined)); + de.moveDocument = this.props.moveDocument; + const [left, top] = clusterDocs[0].props.ScreenToLocalTransform().scale(clusterDocs[0].props.ContentScaling()).inverse().transformPoint(0, 0); + const [xoff, yoff] = this.getTransform().transformDirection(e.x - left, e.y - top); + de.dropAction = e.ctrlKey || e.altKey ? "alias" : undefined; + de.xOffset = xoff; + de.yOffset = yoff; + DragManager.StartDocumentDrag(clusterDocs.map(v => v.ContentDiv!), de, e.clientX, e.clientY, { + handlers: { + dragComplete: action(emptyFunction) + }, + hideSource: !de.dropAction + }); 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 e.preventDefault(); document.removeEventListener("pointermove", this.onPointerMove); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index fa1e824f8..d79b58a7b 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -695,7 +695,7 @@ export class DocumentView extends DocComponent(Docu }); } let showTextTitle = showTitle && StrCast(this.layoutDoc.layout).startsWith("(Docu color: foregroundColor, outlineColor: "maroon", outlineStyle: "dashed", - boxShadow: `${colors[NumCast(this.props.Document.cluster) % colors.length]} ${StrCast(this.props.Document.boxShadow, "0vw 0vw 11vw")}`, + boxShadow: `${colors[NumCast(this.props.Document.cluster) % colors.length]} ${StrCast(this.props.Document.boxShadow, `0vw 0vw ${50 / this.props.ContentScaling()}px`)}`, outlineWidth: BoolCast(this.layoutDoc.libraryBrush) && !StrCast(Doc.GetProto(this.props.Document).borderRounding) ? `${this.props.ScreenToLocalTransform().Scale}px` : "0px", marginLeft: BoolCast(this.layoutDoc.libraryBrush) && StrCast(Doc.GetProto(this.props.Document).borderRounding) ? -- cgit v1.2.3-70-g09d2 From fe9017c3cdc2481f4bcce40dcc1514a6f7af37dc Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 2 Aug 2019 18:21:23 -0400 Subject: improvements to grouping with backgrounds --- .../views/collections/CollectionBaseView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 68 ++++++++++++---------- src/client/views/nodes/DocumentView.tsx | 9 ++- 3 files changed, 44 insertions(+), 35 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index c595a4c56..6801b94fd 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -147,7 +147,7 @@ export class CollectionBaseView extends React.Component {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 232ac22c9..bc1aee159 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -108,6 +108,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { private addDocument = (newBox: Doc, allowDuplicates: boolean) => { this.props.addDocument(newBox, false); this.bringToFront(newBox); + this.updateClusters(); return true; } private selectDocuments = (docs: Doc[]) => { @@ -175,34 +176,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { this.bringToFront(d); }); - let sets: (Doc[])[] = [] - this.childDocs.map(c => { - let included = [] - for (let i = 0; i < sets.length; i++) { - for (let j = 0; j < sets[i].length; j++) { - if (this.bounsdSelect(c, sets[i][j])) { - included.push(i); - break; - } - } - } - if (included.length === 0) - sets.push([c]); - else if (included.length === 1) - sets[included[0]].push(c); - else { - sets[included[0]].push(c); - for (let s = 1; s < included.length; s++) { - sets[included[0]].push(...sets[included[s]]); - sets[included[s]].length = 0; - } - } - }); - for (let s = 0; s < sets.length; s++) { - for (let i = 0; i < sets[s].length; i++) { - Doc.GetProto(sets[s][i]).cluster = s; - } - } + this.updateClusters(); } } else if (de.data instanceof DragManager.AnnotationDragData) { @@ -223,6 +197,38 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { return false; } + @action + updateClusters() { + let sets: (Doc[])[] = [] + this.childDocs.map(c => { + let included = [] + for (let i = 0; i < sets.length; i++) { + for (let j = 0; j < sets[i].length; j++) { + if (this.bounsdSelect(c, sets[i][j])) { + included.push(i); + break; + } + } + } + if (included.length === 0) + sets.push([c]); + else if (included.length === 1) + sets[included[0]].push(c); + else { + sets[included[0]].push(c); + for (let s = 1; s < included.length; s++) { + sets[included[0]].push(...sets[included[s]]); + sets[included[s]].length = 0; + } + } + }); + for (let s = 0; s < sets.length; s++) { + for (let i = 0; i < sets[s].length; i++) { + Doc.GetProto(sets[s][i]).cluster = s; + } + } + } + @action onPointerDown = (e: React.PointerEvent): void => { if (e.button === 0 && !e.shiftKey && !e.altKey && (!this.isAnnotationOverlay || this.zoomScaling() !== 1) && this.props.active()) { @@ -247,8 +253,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { let cluster = this.childDocs.reduce((cluster, cd) => { let cx = NumCast(cd.x) - this._groupingBorder; let cy = NumCast(cd.y) - this._groupingBorder; - let cw = NumCast(cd.width) + this._groupingBorder; - let ch = NumCast(cd.height) + this._groupingBorder; + let cw = NumCast(cd.width) + 2 * this._groupingBorder; + let ch = NumCast(cd.height) + 2 * this._groupingBorder; if (this.intersectRect({ left: cx, top: cy, width: cw, height: ch }, { left: probe[0], top: probe[1], width: 1, height: 1 })) return NumCast(cd.cluster); return cluster; @@ -392,7 +398,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } bringToFront = (doc: Doc, sendToBack?: boolean) => { - if (sendToBack) { + if (sendToBack || doc.isBackground) { doc.zIndex = 0; return; } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index d79b58a7b..16ae5471d 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -695,7 +695,8 @@ export class DocumentView extends DocComponent(Docu }); } let showTextTitle = showTitle && StrCast(this.layoutDoc.layout).startsWith("(Docu color: foregroundColor, outlineColor: "maroon", outlineStyle: "dashed", - boxShadow: `${colors[NumCast(this.props.Document.cluster) % colors.length]} ${StrCast(this.props.Document.boxShadow, `0vw 0vw ${50 / this.props.ContentScaling()}px`)}`, + boxShadow: this.layoutDoc.isBackground ? + `0px 0px 50px 50px ${groupCol}` : + `${groupCol} ${StrCast(this.props.Document.boxShadow, `0vw 0vw ${50 / this.props.ContentScaling()}px`)}`, outlineWidth: BoolCast(this.layoutDoc.libraryBrush) && !StrCast(Doc.GetProto(this.props.Document).borderRounding) ? `${this.props.ScreenToLocalTransform().Scale}px` : "0px", marginLeft: BoolCast(this.layoutDoc.libraryBrush) && StrCast(Doc.GetProto(this.props.Document).borderRounding) ? @@ -714,7 +717,7 @@ export class DocumentView extends DocComponent(Docu border: BoolCast(this.layoutDoc.libraryBrush) && StrCast(Doc.GetProto(this.props.Document).borderRounding) ? `dashed maroon ${this.props.ScreenToLocalTransform().Scale}px` : undefined, borderRadius: "inherit", - background: backgroundColor, + background: this.layoutDoc.isBackground ? groupCol : backgroundColor, width: nativeWidth, height: nativeHeight, transform: `scale(${this.props.ContentScaling()})`, -- cgit v1.2.3-70-g09d2 From 753615c80d4cf08605ebaaeeaf0a44a0fd88d898 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 3 Aug 2019 15:21:10 -0400 Subject: working version of clustering --- src/Utils.ts | 2 + src/client/documents/Documents.ts | 3 +- src/client/util/DragManager.ts | 8 +- src/client/views/MainView.tsx | 4 +- src/client/views/TemplateMenu.tsx | 5 +- .../views/collections/CollectionDockingView.tsx | 3 +- .../views/collections/CollectionSchemaView.tsx | 3 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 142 +++++++++++++-------- .../collections/collectionFreeForm/MarqueeView.tsx | 1 + .../views/nodes/CollectionFreeFormDocumentView.tsx | 12 +- src/client/views/nodes/DocumentView.tsx | 17 +-- .../views/presentationview/PresentationElement.tsx | 3 +- src/client/views/search/SearchItem.tsx | 3 +- 13 files changed, 125 insertions(+), 81 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/Utils.ts b/src/Utils.ts index 8df67df5d..502540eb0 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -140,6 +140,8 @@ export function returnOne() { return 1; } export function returnZero() { return 0; } +export function returnEmptyString() { return ""; } + export function emptyFunction() { } export type Without = Pick>; diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 09bafcf43..07e38a4c0 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -84,6 +84,7 @@ export interface DocumentOptions { templates?: List; viewType?: number; backgroundColor?: string; + defaultBackgroundColor?: string; dropAction?: dropActionType; backgroundLayout?: string; chromeStatus?: string; @@ -124,7 +125,7 @@ export namespace Docs { const TemplateMap: TemplateMap = new Map([ [DocumentType.TEXT, { layout: { view: FormattedTextBox }, - options: { height: 150, backgroundColor: "#f1efeb" } + options: { height: 150, backgroundColor: "#f1efeb", defaultBackgroundColor: "#f1efeb" } }], [DocumentType.HIST, { layout: { view: HistogramBox, collectionView: [CollectionView, data] as CollectionViewType }, diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 0b5c785a4..a7aaaed7c 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -404,7 +404,8 @@ export namespace DragManager { hideSource = options.hideSource(); } } - eles.map(ele => (ele.hidden = hideSource)); + eles.map(ele => (ele.hidden = hideSource) && + (ele.parentElement && ele.parentElement.className.indexOf("collectionFreeFormDocumentView") !== -1 && (ele.parentElement.hidden = hideSource))); let lastX = downX; let lastY = downY; @@ -434,7 +435,10 @@ export namespace DragManager { let hideDragElements = () => { dragElements.map(dragElement => dragElement.parentNode === dragDiv && dragDiv.removeChild(dragElement)); - eles.map(ele => (ele.hidden = false)); + eles.map(ele => { + ele.hidden = false; + (ele.parentElement && ele.parentElement.className.indexOf("collectionFreeFormDocumentView") !== -1 && (ele.parentElement.hidden = false)); + }); }; let endDrag = () => { document.removeEventListener("pointermove", moveHandler, true); diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 2ecf5fd85..53f589684 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -15,7 +15,7 @@ import { listSpec } from '../../new_fields/Schema'; import { Cast, FieldValue, NumCast, BoolCast, StrCast } from '../../new_fields/Types'; import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils'; import { RouteStore } from '../../server/RouteStore'; -import { emptyFunction, returnOne, returnTrue, Utils } from '../../Utils'; +import { emptyFunction, returnOne, returnTrue, Utils, returnEmptyString } from '../../Utils'; import { DocServer } from '../DocServer'; import { Docs } from '../documents/Documents'; import { SetupDrag } from '../util/DragManager'; @@ -270,6 +270,7 @@ export class MainView extends React.Component { PanelWidth={this.getPWidth} PanelHeight={this.getPHeight} renderDepth={0} + backgroundColor={returnEmptyString} selectOnLoad={false} focus={emptyFunction} parentActive={returnTrue} @@ -334,6 +335,7 @@ export class MainView extends React.Component { renderDepth={0} selectOnLoad={false} focus={emptyFunction} + backgroundColor={returnEmptyString} parentActive={returnTrue} whenActiveChanged={emptyFunction} bringToFront={emptyFunction} diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index e654a0644..6dd908445 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -60,12 +60,9 @@ export class TemplateMenu extends React.Component { let de = new DragManager.DocumentDragData([topDoc], [undefined]); de.moveDocument = topDocView.props.moveDocument; let xf = newDocView.ContentDiv!.getBoundingClientRect(); - console.log("ex = " + ex + " " + xf.left + " " + (ex - xf.left)); DragManager.StartDocumentDrag([newDocView.ContentDiv!], de, ex, ey, { offsetX: (ex - xf.left), offsetY: (ey - xf.top), - handlers: { - dragComplete: () => { }, - }, + handlers: { dragComplete: () => { }, }, hideSource: false }); } diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 588102f01..f559480ed 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -10,7 +10,7 @@ import { Id } from '../../../new_fields/FieldSymbols'; import { FieldId } from "../../../new_fields/RefField"; import { listSpec } from "../../../new_fields/Schema"; import { Cast, NumCast, StrCast, BoolCast } from "../../../new_fields/Types"; -import { emptyFunction, returnTrue, Utils, returnOne } from "../../../Utils"; +import { emptyFunction, returnTrue, Utils, returnOne, returnEmptyString } from "../../../Utils"; import { DocServer } from "../../DocServer"; import { DocumentManager } from '../../util/DocumentManager'; import { DragLinksAsDocuments, DragManager } from "../../util/DragManager"; @@ -607,6 +607,7 @@ export class DockedFrameRenderer extends React.Component { parentActive={returnTrue} whenActiveChanged={emptyFunction} focus={emptyFunction} + backgroundColor={returnEmptyString} addDocTab={this.addDocTab} ContainingCollectionView={undefined} zoomToScale={emptyFunction} diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 9efd0d3ec..8218877ba 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -6,7 +6,7 @@ import { action, computed, observable, trace, untracked } from "mobx"; import { observer } from "mobx-react"; import ReactTable, { CellInfo, ComponentPropsGetterR, Column, RowInfo, ResizedChangeFunction, Resize } from "react-table"; import "react-table/react-table.css"; -import { emptyFunction, returnOne } from "../../../Utils"; +import { emptyFunction, returnOne, returnEmptyString } from "../../../Utils"; import { Doc, DocListCast, Field, Opt } from "../../../new_fields/Doc"; import { Id } from "../../../new_fields/FieldSymbols"; import { List } from "../../../new_fields/List"; @@ -999,6 +999,7 @@ export class CollectionSchemaPreview extends React.Component r1.left + r1.width || r2.left + r2.width < r1.left || r2.top > r1.top + r1.height || r2.top + r2.height < r1.top); } - _groupingBorder = 100; + _clusterDistance = 75; bounsdSelect(doc: Doc, doc2: Doc) { - var x2 = NumCast(doc2.x) - this._groupingBorder; - var y2 = NumCast(doc2.y) - this._groupingBorder; - var w2 = NumCast(doc2.width) + this._groupingBorder; - var h2 = NumCast(doc2.height) + this._groupingBorder; - var x = NumCast(doc.x) - this._groupingBorder; - var y = NumCast(doc.y) - this._groupingBorder; - var w = NumCast(doc.width) + this._groupingBorder; - var h = NumCast(doc.height) + this._groupingBorder; - if (this.intersectRect({ left: x, top: y, width: w, height: h }, { left: x2, top: y2, width: w2, height: h2 })) { + var x2 = NumCast(doc2.x) - this._clusterDistance; + var y2 = NumCast(doc2.y) - this._clusterDistance; + var w2 = NumCast(doc2.width) + this._clusterDistance; + var h2 = NumCast(doc2.height) + this._clusterDistance; + var x = NumCast(doc.x) - this._clusterDistance; + var y = NumCast(doc.y) - this._clusterDistance; + var w = NumCast(doc.width) + this._clusterDistance; + var h = NumCast(doc.height) + this._clusterDistance; + if (doc.z === doc2.z && this.intersectRect({ left: x, top: y, width: w, height: h }, { left: x2, top: y2, width: w2, height: h2 })) { return true; } return false; @@ -197,36 +199,83 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { return false; } + tryDragCluster(e: PointerEvent) { + let probe = this.getTransform().transformPoint(e.clientX, e.clientY); + let cluster = this.childDocs.reduce((cluster, cd) => { + let cx = NumCast(cd.x) - this._clusterDistance; + let cy = NumCast(cd.y) - this._clusterDistance; + let cw = NumCast(cd.width) + 2 * this._clusterDistance; + let ch = NumCast(cd.height) + 2 * this._clusterDistance; + if (!cd.z && this.intersectRect({ left: cx, top: cy, width: cw, height: ch }, { left: probe[0], top: probe[1], width: 1, height: 1 })) + return NumCast(cd.cluster); + return cluster; + }, -1); + if (cluster !== -1) { + let eles = this.childDocs.filter(cd => NumCast(cd.cluster) === cluster); + this.selectDocuments(eles); + let clusterDocs = SelectionManager.SelectedDocuments(); + SelectionManager.DeselectAll(); + let de = new DragManager.DocumentDragData(eles, eles.map(d => undefined)); + de.moveDocument = this.props.moveDocument; + const [left, top] = clusterDocs[0].props.ScreenToLocalTransform().scale(clusterDocs[0].props.ContentScaling()).inverse().transformPoint(0, 0); + const [xoff, yoff] = this.getTransform().transformDirection(e.x - left, e.y - top); + de.dropAction = e.ctrlKey || e.altKey ? "alias" : undefined; + de.xOffset = xoff; + de.yOffset = yoff; + DragManager.StartDocumentDrag(clusterDocs.map(v => v.ContentDiv!), de, e.clientX, e.clientY, { + handlers: { dragComplete: action(emptyFunction) }, + hideSource: !de.dropAction + }); + return true; + } + + return false; + } + @observable sets: (Doc[])[] = []; @action updateClusters() { - let sets: (Doc[])[] = [] + this.sets.length = 0; this.childDocs.map(c => { let included = [] - for (let i = 0; i < sets.length; i++) { - for (let j = 0; j < sets[i].length; j++) { - if (this.bounsdSelect(c, sets[i][j])) { + for (let i = 0; i < this.sets.length; i++) { + for (let j = 0; j < this.sets[i].length; j++) { + if (this.bounsdSelect(c, this.sets[i][j])) { included.push(i); break; } } } if (included.length === 0) - sets.push([c]); + this.sets.push([c]); else if (included.length === 1) - sets[included[0]].push(c); + this.sets[included[0]].push(c); else { - sets[included[0]].push(c); + this.sets[included[0]].push(c); for (let s = 1; s < included.length; s++) { - sets[included[0]].push(...sets[included[s]]); - sets[included[s]].length = 0; + this.sets[included[0]].push(...this.sets[included[s]]); + this.sets[included[s]].length = 0; } } }); - for (let s = 0; s < sets.length; s++) { - for (let i = 0; i < sets[s].length; i++) { - Doc.GetProto(sets[s][i]).cluster = s; + for (let s = 0; s < this.sets.length; s++) { + for (let i = 0; i < this.sets[s].length; i++) { + this.sets[s][i].cluster = s; + } + } + } + + getClusterColor = (doc: Doc) => { + if (this.props.Document.useClusters) { + let cluster = NumCast(doc.cluster); + let set = this.sets.length > cluster ? this.sets[NumCast(doc.cluster)] : undefined; + let colors = ["#da42429e", "#31ea318c", "#8c4000", "#4a7ae2c4", "#d809ff", "#ff7601", "#1dffff", "yellow", "#1b8231f2", "#000000ad"]; + let clusterColor = colors[cluster % colors.length]; + for (let i = 0; set && i < set.length; i++) { + if (set[i].backgroundColor && set[i].backgroundColor !== set[i].defaultBackgroundColor) clusterColor = StrCast(set[i].backgroundColor); } + return clusterColor; } + return ""; } @action @@ -249,34 +298,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @action onPointerMove = (e: PointerEvent): void => { if (!e.cancelBubble) { - let probe = this.getTransform().transformPoint(e.clientX, e.clientY); - let cluster = this.childDocs.reduce((cluster, cd) => { - let cx = NumCast(cd.x) - this._groupingBorder; - let cy = NumCast(cd.y) - this._groupingBorder; - let cw = NumCast(cd.width) + 2 * this._groupingBorder; - let ch = NumCast(cd.height) + 2 * this._groupingBorder; - if (this.intersectRect({ left: cx, top: cy, width: cw, height: ch }, { left: probe[0], top: probe[1], width: 1, height: 1 })) - return NumCast(cd.cluster); - return cluster; - }, -1); - if (cluster !== -1) { - let eles = this.childDocs.filter(cd => NumCast(cd.cluster) === cluster); - this.selectDocuments(eles); - let clusterDocs = SelectionManager.SelectedDocuments(); - SelectionManager.DeselectAll(); - let de = new DragManager.DocumentDragData(eles, eles.map(d => undefined)); - de.moveDocument = this.props.moveDocument; - const [left, top] = clusterDocs[0].props.ScreenToLocalTransform().scale(clusterDocs[0].props.ContentScaling()).inverse().transformPoint(0, 0); - const [xoff, yoff] = this.getTransform().transformDirection(e.x - left, e.y - top); - de.dropAction = e.ctrlKey || e.altKey ? "alias" : undefined; - de.xOffset = xoff; - de.yOffset = yoff; - DragManager.StartDocumentDrag(clusterDocs.map(v => v.ContentDiv!), de, e.clientX, e.clientY, { - handlers: { - dragComplete: action(emptyFunction) - }, - hideSource: !de.dropAction - }); + if (this.props.Document.useClusters && this.tryDragCluster(e)) { 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 e.preventDefault(); document.removeEventListener("pointermove", this.onPointerMove); @@ -493,6 +515,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { ContentScaling: returnOne, ContainingCollectionView: this.props.CollectionView, focus: this.focusDocument, + backgroundColor: this.getClusterColor, parentActive: this.props.active, whenActiveChanged: this.props.whenActiveChanged, bringToFront: this.bringToFront, @@ -516,6 +539,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { ContentScaling: returnOne, ContainingCollectionView: this.props.CollectionView, focus: this.focusDocument, + backgroundColor: returnEmptyString, parentActive: this.props.active, whenActiveChanged: this.props.whenActiveChanged, bringToFront: this.bringToFront, @@ -625,6 +649,15 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { event: async () => this.props.Document.fitToBox = !this.fitToBox, icon: !this.fitToBox ? "expand-arrows-alt" : "compress-arrows-alt" }); + layoutItems.push({ + description: `${this.props.Document.useClusters ? "Uncluster" : "Use Clusters"}`, + event: async () => { + Docs.Prototypes.get(DocumentType.TEXT).defaultBackgroundColor = "#f1efeb"; + Docs.Prototypes.get(DocumentType.COL).defaultBackgroundColor = "white"; + this.props.Document.useClusters = !this.props.Document.useClusters; + }, + icon: !this.props.Document.useClusters ? "expand-arrows-alt" : "compress-arrows-alt" + }); layoutItems.push({ description: "Arrange contents in grid", icon: "table", @@ -700,10 +733,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { ...this.views ] private overlayChildViews = () => { - console.log(this.overlayViews.length); - return [ - ...this.overlayViews - ]; + return [...this.overlayViews]; } public static AddCustomLayout(doc: Doc, dataKey: string): () => void { diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index b9ee588dd..ff96bd993 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -278,6 +278,7 @@ export class MarqueeView extends React.Component panX: 0, panY: 0, backgroundColor: this.props.container.isAnnotationOverlay ? undefined : "white", + defaultBackgroundColor: this.props.container.isAnnotationOverlay ? undefined : "white", width: bounds.width, height: bounds.height, title: e.key === "s" || e.key === "S" ? "-summary-" : "a nested collection", diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 3b6c443c2..ee596c841 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -8,6 +8,7 @@ import { DocumentView, DocumentViewProps, positionSchema } from "./DocumentView" import "./DocumentView.scss"; import React = require("react"); import { Doc } from "../../../new_fields/Doc"; +import { returnEmptyString } from "../../../Utils"; export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { x?: number; @@ -69,6 +70,11 @@ export class CollectionFreeFormDocumentView extends DocComponent this.clusterColor; + render() { const hasPosition = this.props.x !== undefined || this.props.y !== undefined; return ( @@ -77,7 +83,10 @@ export class CollectionFreeFormDocumentView extends DocComponent void; collapseToPoint?: (scrpt: number[], expandedDocs: Doc[] | undefined) => void; zoomToScale: (scale: number) => void; + backgroundColor: (doc: Doc) => string; getScale: () => number; animateBetweenIcon?: (iconPos: number[], startTime: number, maximizing: boolean) => void; ChromeHeight?: () => number; @@ -675,12 +676,9 @@ export class DocumentView extends DocComponent(Docu // to determine the render JSX string, otherwise the layout field should directly contain a JSX layout string. return this.props.Document.layout instanceof Doc ? this.props.Document.layout : this.props.Document; } + render() { - if (this.Document.hidden) { - return null; - } - let self = this; - let backgroundColor = StrCast(this.layoutDoc.backgroundColor); + let backgroundColor = this.props.backgroundColor(this.props.Document) || StrCast(this.layoutDoc.backgroundColor); let foregroundColor = StrCast(this.layoutDoc.color); var nativeWidth = this.nativeWidth > 0 && !BoolCast(this.props.Document.ignoreAspect) ? `${this.nativeWidth}px` : "100%"; var nativeHeight = BoolCast(this.props.Document.ignoreAspect) ? this.props.PanelHeight() / this.props.ContentScaling() : this.nativeHeight > 0 ? `${this.nativeHeight}px` : "100%"; @@ -695,8 +693,6 @@ export class DocumentView extends DocComponent(Docu }); } let showTextTitle = showTitle && StrCast(this.layoutDoc.layout).startsWith("(Docu color: foregroundColor, outlineColor: "maroon", outlineStyle: "dashed", - boxShadow: this.layoutDoc.isBackground ? - `0px 0px 50px 50px ${groupCol}` : - `${groupCol} ${StrCast(this.props.Document.boxShadow, `0vw 0vw ${50 / this.props.ContentScaling()}px`)}`, outlineWidth: BoolCast(this.layoutDoc.libraryBrush) && !StrCast(Doc.GetProto(this.props.Document).borderRounding) ? `${this.props.ScreenToLocalTransform().Scale}px` : "0px", marginLeft: BoolCast(this.layoutDoc.libraryBrush) && StrCast(Doc.GetProto(this.props.Document).borderRounding) ? @@ -717,7 +710,7 @@ export class DocumentView extends DocComponent(Docu border: BoolCast(this.layoutDoc.libraryBrush) && StrCast(Doc.GetProto(this.props.Document).borderRounding) ? `dashed maroon ${this.props.ScreenToLocalTransform().Scale}px` : undefined, borderRadius: "inherit", - background: this.layoutDoc.isBackground ? groupCol : backgroundColor, + background: backgroundColor, width: nativeWidth, height: nativeHeight, transform: `scale(${this.props.ContentScaling()})`, diff --git a/src/client/views/presentationview/PresentationElement.tsx b/src/client/views/presentationview/PresentationElement.tsx index 11f3eb846..e2d8daea9 100644 --- a/src/client/views/presentationview/PresentationElement.tsx +++ b/src/client/views/presentationview/PresentationElement.tsx @@ -9,7 +9,7 @@ import { Id } from "../../../new_fields/FieldSymbols"; import { List } from "../../../new_fields/List"; import { listSpec } from "../../../new_fields/Schema"; import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types"; -import { Utils, returnFalse, emptyFunction, returnOne } from "../../../Utils"; +import { Utils, returnFalse, emptyFunction, returnOne, returnEmptyString } from "../../../Utils"; import { DragManager, dropActionType, SetupDrag } from "../../util/DragManager"; import { SelectionManager } from "../../util/SelectionManager"; import { ContextMenu } from "../ContextMenu"; @@ -843,6 +843,7 @@ export default class PresentationElement extends React.Component 350} PanelHeight={() => 90} focus={emptyFunction} + backgroundColor={returnEmptyString} selectOnLoad={false} parentActive={returnFalse} whenActiveChanged={returnFalse} diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx index 0390359b3..1b9bba5c6 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, DocListCast, HeightSym, WidthSym } from "../../../new_fields/Doc"; import { Id } from "../../../new_fields/FieldSymbols"; import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; -import { emptyFunction, returnFalse, returnOne, Utils } from "../../../Utils"; +import { emptyFunction, returnFalse, returnOne, Utils, returnEmptyString } from "../../../Utils"; import { DocumentType } from "../../documents/Documents"; import { DocumentManager } from "../../util/DocumentManager"; import { SetupDrag, DragManager } from "../../util/DragManager"; @@ -223,6 +223,7 @@ export class SearchItem extends React.Component { PanelWidth={returnXDimension} PanelHeight={returnYDimension} focus={emptyFunction} + backgroundColor={returnEmptyString} selectOnLoad={false} parentActive={returnFalse} whenActiveChanged={returnFalse} -- cgit v1.2.3-70-g09d2 From 098e3780c9d16738070a92dbfcdf68372a9d18a9 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 3 Aug 2019 15:35:51 -0400 Subject: from last --- .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index ee21c5a4d..24439ef4c 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -135,7 +135,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { 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); } _clusterDistance = 75; - bounsdSelect(doc: Doc, doc2: Doc) { + boundsOverlap(doc: Doc, doc2: Doc) { var x2 = NumCast(doc2.x) - this._clusterDistance; var y2 = NumCast(doc2.y) - this._clusterDistance; var w2 = NumCast(doc2.width) + this._clusterDistance; @@ -239,7 +239,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { let included = [] for (let i = 0; i < this.sets.length; i++) { for (let j = 0; j < this.sets[i].length; j++) { - if (this.bounsdSelect(c, this.sets[i][j])) { + if (this.boundsOverlap(c, this.sets[i][j])) { included.push(i); break; } -- cgit v1.2.3-70-g09d2 From b7c70cf115ea3d23e06fc7a3837e983b62993334 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 3 Aug 2019 17:30:58 -0400 Subject: a few updates and an option to switch between default backgrounds and cluster backgrounds. --- .../collectionFreeForm/CollectionFreeFormView.tsx | 20 +++++++++++++++----- src/client/views/nodes/DocumentView.tsx | 4 +++- 2 files changed, 18 insertions(+), 6 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 24439ef4c..b4d065d26 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -267,12 +267,17 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { getClusterColor = (doc: Doc) => { if (this.props.Document.useClusters) { let cluster = NumCast(doc.cluster); - let set = this.sets.length > cluster ? this.sets[NumCast(doc.cluster)] : undefined; + if (this.sets.length <= cluster) { + setTimeout(() => this.updateClusters(), 0); + return; + } + let set = this.sets.length > cluster ? this.sets[cluster] : undefined; let colors = ["#da42429e", "#31ea318c", "#8c4000", "#4a7ae2c4", "#d809ff", "#ff7601", "#1dffff", "yellow", "#1b8231f2", "#000000ad"]; let clusterColor = colors[cluster % colors.length]; - for (let i = 0; set && i < set.length; i++) { - if (set[i].backgroundColor && set[i].backgroundColor !== set[i].defaultBackgroundColor) clusterColor = StrCast(set[i].backgroundColor); - } + set && set.filter(s => !s.isBackground).map(s => + s.backgroundColor && s.backgroundColor !== s.defaultBackgroundColor && (clusterColor = StrCast(s.backgroundColor))); + set && set.filter(s => s.isBackground).map(s => + s.backgroundColor && s.backgroundColor !== s.defaultBackgroundColor && (clusterColor = StrCast(s.backgroundColor))); return clusterColor; } return ""; @@ -652,12 +657,17 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { layoutItems.push({ description: `${this.props.Document.useClusters ? "Uncluster" : "Use Clusters"}`, event: async () => { - Docs.Prototypes.get(DocumentType.TEXT).defaultBackgroundColor = "#f1efeb"; + Docs.Prototypes.get(DocumentType.TEXT).defaultBackgroundColor = "#f1efeb"; // backward compatibility with databases that didn't have a default background color on prototypes Docs.Prototypes.get(DocumentType.COL).defaultBackgroundColor = "white"; this.props.Document.useClusters = !this.props.Document.useClusters; }, icon: !this.props.Document.useClusters ? "expand-arrows-alt" : "compress-arrows-alt" }); + layoutItems.push({ + description: `${this.props.Document.clusterOverridesDefaultBackground ? "Use Default Backgrounds" : "Clusters Override Defaults"}`, + event: async () => this.props.Document.clusterOverridesDefaultBackground = !this.props.Document.clusterOverridesDefaultBackground, + icon: !this.props.Document.useClusters ? "expand-arrows-alt" : "compress-arrows-alt" + }); layoutItems.push({ description: "Arrange contents in grid", icon: "table", diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index ae6a01ab4..0347fc9b2 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -678,7 +678,9 @@ export class DocumentView extends DocComponent(Docu } render() { - let backgroundColor = this.props.backgroundColor(this.props.Document) || StrCast(this.layoutDoc.backgroundColor); + let backgroundColor = this.layoutDoc.isBackground || (this.props.ContainingCollectionView && this.props.ContainingCollectionView.props.Document.clusterOverridesDefaultBackground && this.layoutDoc.backgroundColor === this.layoutDoc.defaultBackgroundColor) ? + this.props.backgroundColor(this.layoutDoc) || StrCast(this.layoutDoc.backgroundColor) : + StrCast(this.layoutDoc.backgroundColor) || this.props.backgroundColor(this.layoutDoc); let foregroundColor = StrCast(this.layoutDoc.color); var nativeWidth = this.nativeWidth > 0 && !BoolCast(this.props.Document.ignoreAspect) ? `${this.nativeWidth}px` : "100%"; var nativeHeight = BoolCast(this.props.Document.ignoreAspect) ? this.props.PanelHeight() / this.props.ContentScaling() : this.nativeHeight > 0 ? `${this.nativeHeight}px` : "100%"; -- cgit v1.2.3-70-g09d2 From e65a75245617e2161ad5a75dd2b91461144dfdf7 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 3 Aug 2019 18:47:48 -0400 Subject: fixed marquee collection'ing with backgrounds. fixed rotating images. fixed marqueeing ink. --- src/client/views/InkingCanvas.tsx | 2 +- .../collections/collectionFreeForm/MarqueeView.tsx | 21 +++++++++++--------- src/client/views/nodes/FormattedTextBox.tsx | 8 ++++---- src/client/views/nodes/ImageBox.tsx | 10 +++++----- src/new_fields/Doc.ts | 23 +++++++++++++--------- 5 files changed, 36 insertions(+), 28 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx index c4cd863d1..1c221e3df 100644 --- a/src/client/views/InkingCanvas.tsx +++ b/src/client/views/InkingCanvas.tsx @@ -176,7 +176,7 @@ export class InkingCanvas extends React.Component { } render() { - let svgCanvasStyle = InkingControl.Instance.selectedTool !== InkTool.None ? "canSelect" : "noSelect"; + let svgCanvasStyle = InkingControl.Instance.selectedTool !== InkTool.None && !this.props.Document.isBackground ? "canSelect" : "noSelect"; return (
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index ff96bd993..aad26efa0 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -226,15 +226,17 @@ export class MarqueeView extends React.Component } get ink() { - let container = this.props.container.Document; + let container = this.props.container.props.Document; let containerKey = this.props.container.props.fieldKey; - return Cast(container[containerKey + "_ink"], InkField); + let extensionDoc = Doc.resolvedFieldDataDoc(container, containerKey, "true"); + return Cast(extensionDoc.ink, InkField); } set ink(value: InkField | undefined) { - let container = Doc.GetProto(this.props.container.Document); + let container = Doc.GetProto(this.props.container.props.Document); let containerKey = this.props.container.props.fieldKey; - container[containerKey + "_ink"] = value; + let extensionDoc = Doc.resolvedFieldDataDoc(container, containerKey, "true"); + extensionDoc.ink = value; } @undoBatch @@ -247,7 +249,7 @@ export class MarqueeView extends React.Component this._commandExecuted = true; e.stopPropagation(); (e as any).propagationIsStopped = true; - this.marqueeSelect().map(d => this.props.removeDocument(d)); + this.marqueeSelect(false).map(d => this.props.removeDocument(d)); if (this.ink) { this.marqueeInkDelete(this.ink.inkData); } @@ -261,7 +263,7 @@ export class MarqueeView extends React.Component e.preventDefault(); (e as any).propagationIsStopped = true; let bounds = this.Bounds; - let selected = this.marqueeSelect(); + let selected = this.marqueeSelect(false); if (e.key === "c") { selected.map(d => { this.props.removeDocument(d); @@ -283,7 +285,8 @@ export class MarqueeView extends React.Component height: bounds.height, title: e.key === "s" || e.key === "S" ? "-summary-" : "a nested collection", }); - newCollection.data_ink = inkData ? new InkField(this.marqueeInkSelect(inkData)) : undefined; + let dataExtensionField = Doc.CreateDocumentExtensionForField(newCollection, "data"); + dataExtensionField.ink = inkData ? new InkField(this.marqueeInkSelect(inkData)) : undefined; this.marqueeInkDelete(inkData); if (e.key === "s") { @@ -367,7 +370,7 @@ export class MarqueeView extends React.Component } } - marqueeSelect() { + marqueeSelect(selectBackgrounds: boolean = true) { let selRect = this.Bounds; let selection: Doc[] = []; this.props.activeDocuments().filter(doc => !doc.isBackground).map(doc => { @@ -379,7 +382,7 @@ export class MarqueeView extends React.Component selection.push(doc); } }); - if (!selection.length) { + if (!selection.length && selectBackgrounds) { this.props.activeDocuments().map(doc => { var x = NumCast(doc.x); var y = NumCast(doc.y); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index e076efe18..6c97add76 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -674,7 +674,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe let self = this; let style = this.props.isOverlay ? "scroll" : "hidden"; let rounded = StrCast(this.props.Document.borderRounding) === "100%" ? "-rounded" : ""; - let interactive = InkingControl.Instance.selectedTool ? "" : "interactive"; + let interactive: "all" | "none" = InkingControl.Instance.selectedTool || this.props.Document.isBackground || + (this.props.Document.isButton && !this.props.isSelected()) ? "none" : "all"; Doc.UpdateDocumentExtensionForField(this.dataDoc, this.props.fieldKey); return (
-
+
); } diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 17dc4184a..0d9c2bb8a 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -314,14 +314,14 @@ export class ImageBox extends DocComponent(ImageD resize(srcpath: string, layoutdoc: Doc) { requestImageSize(srcpath) .then((size: any) => { - let aspect = size.height / size.width; let rotation = NumCast(this.dataDoc.rotation) % 180; - if (rotation === 90 || rotation === 270) aspect = 1 / aspect; - if (Math.abs(NumCast(layoutdoc.height) - size.height) > 1 || Math.abs(NumCast(layoutdoc.width) - size.width) > 1) { + let realsize = rotation === 90 || rotation === 270 ? { height: size.width, width: size.height } : size; + let aspect = realsize.height / realsize.width; + if (Math.abs(NumCast(layoutdoc.height) - realsize.height) > 1 || Math.abs(NumCast(layoutdoc.width) - realsize.width) > 1) { setTimeout(action(() => { layoutdoc.height = layoutdoc[WidthSym]() * aspect; - layoutdoc.nativeHeight = size.height; - layoutdoc.nativeWidth = size.width; + layoutdoc.nativeHeight = realsize.height; + layoutdoc.nativeWidth = realsize.width; }), 0); } }) diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index b70951040..b081588a3 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -341,19 +341,24 @@ export namespace Doc { return fieldExt && doc[fieldKey + "_ext"] instanceof Doc ? doc[fieldKey + "_ext"] as Doc : doc; } + export function CreateDocumentExtensionForField(doc: Doc, fieldKey: string) { + let docExtensionForField = new Doc(doc[Id] + fieldKey, true); + docExtensionForField.title = fieldKey + ".ext"; + docExtensionForField.extendsDoc = doc; // this is used by search to map field matches on the extension doc back to the document it extends. + docExtensionForField.type = DocumentType.EXTENSION; + let proto: Doc | undefined = doc; + while (proto && !Doc.IsPrototype(proto)) { + proto = proto.proto; + } + (proto ? proto : doc)[fieldKey + "_ext"] = new PrefetchProxy(docExtensionForField); + return docExtensionForField; + } + export function UpdateDocumentExtensionForField(doc: Doc, fieldKey: string) { let docExtensionForField = doc[fieldKey + "_ext"] as Doc; if (docExtensionForField === undefined) { setTimeout(() => { - docExtensionForField = new Doc(doc[Id] + fieldKey, true); - docExtensionForField.title = fieldKey + ".ext"; - docExtensionForField.extendsDoc = doc; // this is used by search to map field matches on the extension doc back to the document it extends. - docExtensionForField.type = DocumentType.EXTENSION; - let proto: Doc | undefined = doc; - while (proto && !Doc.IsPrototype(proto)) { - proto = proto.proto; - } - (proto ? proto : doc)[fieldKey + "_ext"] = new PrefetchProxy(docExtensionForField); + CreateDocumentExtensionForField(doc, field); }, 0); } else if (doc instanceof Doc) { // backward compatibility -- add fields for docs that don't have them already docExtensionForField.extendsDoc === undefined && setTimeout(() => docExtensionForField.extendsDoc = doc, 0); -- cgit v1.2.3-70-g09d2 From 02346eabdefd428ca23d6a3fbefdcd51ef62b738 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 4 Aug 2019 01:17:29 -0400 Subject: fixed errors/warnings --- src/client/apis/youtube/YoutubeBox.tsx | 8 +- src/client/views/InkingControl.tsx | 4 +- src/client/views/TemplateMenu.tsx | 2 +- .../views/collections/CollectionSchemaCells.tsx | 4 +- .../views/collections/CollectionSchemaHeaders.tsx | 2 +- .../views/collections/CollectionSchemaView.tsx | 5 +- .../views/collections/CollectionStackingView.tsx | 116 +++++++++------------ src/client/views/collections/CollectionView.tsx | 11 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 23 ++-- src/client/views/nodes/ButtonBox.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 2 +- src/client/views/nodes/PDFBox.tsx | 4 +- src/client/views/search/FilterBox.tsx | 2 +- src/client/views/search/SearchItem.tsx | 2 +- src/client/views/search/ToggleBar.tsx | 2 +- src/new_fields/Doc.ts | 4 +- 16 files changed, 82 insertions(+), 111 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/apis/youtube/YoutubeBox.tsx b/src/client/apis/youtube/YoutubeBox.tsx index dc142802c..d73988bb8 100644 --- a/src/client/apis/youtube/YoutubeBox.tsx +++ b/src/client/apis/youtube/YoutubeBox.tsx @@ -57,7 +57,7 @@ export class YoutubeBox extends React.Component { if (awaitedBackUp) { - let jsonList = await DocListCastAsync(awaitedBackUp!.json); + let jsonList = await DocListCastAsync(awaitedBackUp.json); let jsonDetailList = await DocListCastAsync(awaitedDetails!.json); if (jsonList!.length !== 0) { @@ -76,8 +76,8 @@ export class YoutubeBox extends React.Component { let videoDescription = StrCast(snippet!.description); let pusblishDate = (this.roundPublishTime(StrCast(snippet!.publishedAt)))!; let channelTitle = StrCast(snippet!.channelTitle); - let duration: string; - let viewCount: string; + let duration: string = ""; + let viewCount: string = ""; if (jsonDetailList!.length !== 0) { let contentDetails = await Cast(jsonDetailList![index].contentDetails, Doc); let statistics = await Cast(jsonDetailList![index].statistics, Doc); @@ -85,7 +85,7 @@ export class YoutubeBox extends React.Component { viewCount = this.abbreviateViewCount(parseInt(StrCast(statistics!.viewCount)))!; } index = index + 1; - let newTemplate: VideoTemplate = { videoId: id, videoTitle: videoTitle, thumbnailUrl: thumbnailUrl, publishDate: pusblishDate, channelTitle: channelTitle, videoDescription: videoDescription, duration: duration!, viewCount: viewCount! }; + let newTemplate: VideoTemplate = { videoId: id, videoTitle: videoTitle, thumbnailUrl: thumbnailUrl, publishDate: pusblishDate, channelTitle: channelTitle, videoDescription: videoDescription, duration: duration, viewCount: viewCount }; runInAction(() => this.curVideoTemplates.push(newTemplate)); } } diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx index 58c83915b..3f40642b5 100644 --- a/src/client/views/InkingControl.tsx +++ b/src/client/views/InkingControl.tsx @@ -1,5 +1,5 @@ import { observable, action, computed, runInAction } from "mobx"; -import { ColorState } from 'react-color'; +import { ColorResult } from 'react-color'; import React = require("react"); import { observer } from "mobx-react"; import "./InkingControl.scss"; @@ -41,7 +41,7 @@ export class InkingControl extends React.Component { } @undoBatch - switchColor = action((color: ColorState): void => { + switchColor = action((color: ColorResult): void => { this._selectedColor = color.hex + (color.rgb.a !== undefined ? this.decimalToHexString(Math.round(color.rgb.a * 255)) : "ff"); if (InkingControl.Instance.selectedTool === InkTool.None) { if (MainOverlayTextBox.Instance.SetColor(color.hex)) return; diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index 6dd908445..393e97a7e 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -68,7 +68,7 @@ export class TemplateMenu extends React.Component { } }, 10); } else if (topDocView.props.ContainingCollectionView) { - let collView = topDocView.props.ContainingCollectionView!; + let collView = topDocView.props.ContainingCollectionView; let [sx, sy] = xf.inverse().transformPoint(0, 0); let [x, y] = collView.props.ScreenToLocalTransform().transformPoint(sx, sy); topDoc.x = x; diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx index 4ff65b277..7e3061354 100644 --- a/src/client/views/collections/CollectionSchemaCells.tsx +++ b/src/client/views/collections/CollectionSchemaCells.tsx @@ -175,11 +175,11 @@ export class CollectionSchemaCell extends React.Component { }; let onPointerEnter = (e: React.PointerEvent): void => { if (e.buttons === 1 && SelectionManager.GetIsDragging() && (type === "document" || type === undefined)) { - dragRef!.current!.className = "collectionSchemaView-cellContainer doc-drag-over"; + dragRef.current!.className = "collectionSchemaView-cellContainer doc-drag-over"; } }; let onPointerLeave = (e: React.PointerEvent): void => { - dragRef!.current!.className = "collectionSchemaView-cellContainer"; + dragRef.current!.className = "collectionSchemaView-cellContainer"; }; let contents: any = "incorrect type"; diff --git a/src/client/views/collections/CollectionSchemaHeaders.tsx b/src/client/views/collections/CollectionSchemaHeaders.tsx index dfd65770e..d24f63fbb 100644 --- a/src/client/views/collections/CollectionSchemaHeaders.tsx +++ b/src/client/views/collections/CollectionSchemaHeaders.tsx @@ -13,7 +13,7 @@ import { faFile } from "@fortawesome/free-regular-svg-icons"; import { SchemaHeaderField, RandomPastel, PastelSchemaPalette } from "../../../new_fields/SchemaHeaderField"; import { undoBatch } from "../../util/UndoManager"; -library.add(faPlus, faFont, faHashtag, faAlignJustify, faCheckSquare, faToggleOn, faFile, faSortAmountDown, faSortAmountUp, faTimes); +library.add(faPlus, faFont, faHashtag, faAlignJustify, faCheckSquare, faToggleOn, faFile as any, faSortAmountDown, faSortAmountUp, faTimes); export interface HeaderProps { keyValue: SchemaHeaderField; diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 2d4c88b94..75787c0a8 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -303,14 +303,13 @@ export class SchemaTable extends React.Component { return resized; }, [] as { "id": string, "value": number }[]); } - - @computed get sorted(): { "id": string, "desc": boolean }[] { + @computed get sorted(): { "id": string, "desc"?: true }[] { return this.columns.reduce((sorted, shf) => { if (shf.desc) { sorted.push({ "id": shf.heading, "desc": shf.desc }); } return sorted; - }, [] as { "id": string, "desc": boolean }[]); + }, [] as { "id": string, "desc"?: true }[]); } @computed get borderWidth() { return Number(COLLECTION_BORDER_WIDTH); } diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index d7c3ac3b8..4a751c84c 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -1,26 +1,25 @@ import React = require("react"); import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { action, computed, IReactionDisposer, reaction, untracked, observable, runInAction } from "mobx"; +import { CursorProperty } from "csstype"; +import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; -import { Doc, HeightSym, WidthSym, DocListCast } from "../../../new_fields/Doc"; +import Switch from 'rc-switch'; +import { Doc, HeightSym, WidthSym } from "../../../new_fields/Doc"; import { Id } from "../../../new_fields/FieldSymbols"; -import { BoolCast, NumCast, Cast, StrCast } from "../../../new_fields/Types"; -import { emptyFunction, Utils, returnTrue } from "../../../Utils"; -import { CollectionSchemaPreview } from "./CollectionSchemaView"; -import "./CollectionStackingView.scss"; -import { CollectionSubView, SubCollectionViewProps } from "./CollectionSubView"; -import { undoBatch } from "../../util/UndoManager"; -import { DragManager } from "../../util/DragManager"; +import { List } from "../../../new_fields/List"; +import { listSpec } from "../../../new_fields/Schema"; +import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField"; +import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types"; +import { emptyFunction } from "../../../Utils"; import { DocumentType } from "../../documents/Documents"; +import { DragManager } from "../../util/DragManager"; import { Transform } from "../../util/Transform"; -import { CursorProperty } from "csstype"; -import { CollectionStackingViewFieldColumn } from "./CollectionStackingViewFieldColumn"; -import { listSpec } from "../../../new_fields/Schema"; -import { SchemaHeaderField, RandomPastel } from "../../../new_fields/SchemaHeaderField"; -import { List } from "../../../new_fields/List"; +import { undoBatch } from "../../util/UndoManager"; import { EditableView } from "../EditableView"; -import { CollectionViewProps } from "./CollectionBaseView"; -import Switch from 'rc-switch'; +import { CollectionSchemaPreview } from "./CollectionSchemaView"; +import "./CollectionStackingView.scss"; +import { CollectionStackingViewFieldColumn } from "./CollectionStackingViewFieldColumn"; +import { CollectionSubView } from "./CollectionSubView"; @observer export class CollectionStackingView extends CollectionSubView(doc => doc) { @@ -32,13 +31,13 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { _columnStart: number = 0; @observable private cursor: CursorProperty = "grab"; get sectionHeaders() { return Cast(this.props.Document.sectionHeaders, listSpec(SchemaHeaderField)); } - @computed get chromeCollapsed() { return this.props.chromeCollapsed; } @computed get xMargin() { return NumCast(this.props.Document.xMargin, 2 * this.gridGap); } @computed get yMargin() { return NumCast(this.props.Document.yMargin, 2 * this.gridGap); } @computed get gridGap() { return NumCast(this.props.Document.gridGap, 10); } @computed get singleColumn() { return BoolCast(this.props.Document.singleColumn, true); } @computed get columnWidth() { return this.singleColumn ? (this.props.PanelWidth() / (this.props as any).ContentScaling() - 2 * this.xMargin) : Math.min(this.props.PanelWidth() - 2 * this.xMargin, NumCast(this.props.Document.columnWidth, 250)); } @computed get filteredChildren() { return this.childDocs.filter(d => !d.isMinimized); } + @computed get sectionFilter() { return this.singleColumn ? StrCast(this.props.Document.sectionFilter) : ""; } get layoutDoc() { // if this document's layout field contains a document (ie, a rendering template), then we will use that @@ -46,37 +45,32 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { return this.props.Document.layout instanceof Doc ? this.props.Document.layout : this.props.Document; } - @computed - get SectionFilter() { return this.singleColumn ? StrCast(this.props.Document.sectionFilter) : "" } get Sections() { - let sectionHeaders = this.sectionHeaders; - if (!sectionHeaders) { - this.props.Document.sectionHeaders = sectionHeaders = new List(); + if (!this.sectionFilter) return new Map(); + + if (this.sectionHeaders === undefined) { + this.props.Document.sectionHeaders = new List(); } - let fields = new Map(sectionHeaders.map(sh => [sh, []])); - if (this.SectionFilter) { - this.filteredChildren.map(d => { - let sectionValue = (d[this.SectionFilter] ? d[this.SectionFilter] : `NO ${this.SectionFilter.toUpperCase()} VALUE`) as object; - // the next five lines ensures that floating point rounding errors don't create more than one section -syip - let parsed = parseInt(sectionValue.toString()); - let castedSectionValue: any = sectionValue; - if (!isNaN(parsed)) { - castedSectionValue = parsed; - } + const sectionHeaders = this.sectionHeaders!; + let fields = new Map(sectionHeaders.map(sh => [sh, []] as [SchemaHeaderField, []])); + this.filteredChildren.map(d => { + let sectionValue = (d[this.sectionFilter] ? d[this.sectionFilter] : `NO ${this.sectionFilter.toUpperCase()} VALUE`) as object; + // the next five lines ensures that floating point rounding errors don't create more than one section -syip + let parsed = parseInt(sectionValue.toString()); + let castedSectionValue = !isNaN(parsed) ? parsed : sectionValue; - // look for if header exists already - let existingHeader = sectionHeaders!.find(sh => sh.heading === (castedSectionValue ? castedSectionValue.toString() : `NO ${this.SectionFilter.toUpperCase()} VALUE`)); - if (existingHeader) { - fields.get(existingHeader)!.push(d); - } - else { - let newSchemaHeader = new SchemaHeaderField(castedSectionValue ? castedSectionValue.toString() : `NO ${this.SectionFilter.toUpperCase()} VALUE`); - fields.set(newSchemaHeader, [d]); - sectionHeaders!.push(newSchemaHeader); - } - }); - } else fields.clear(); + // look for if header exists already + let existingHeader = sectionHeaders.find(sh => sh.heading === (castedSectionValue ? castedSectionValue.toString() : `NO ${this.sectionFilter.toUpperCase()} VALUE`)); + if (existingHeader) { + fields.get(existingHeader)!.push(d); + } + else { + let newSchemaHeader = new SchemaHeaderField(castedSectionValue ? castedSectionValue.toString() : `NO ${this.sectionFilter.toUpperCase()} VALUE`); + fields.set(newSchemaHeader, [d]); + sectionHeaders.push(newSchemaHeader); + } + }); return fields; } @@ -96,10 +90,8 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { // reset section headers when a new filter is inputted this._sectionFilterDisposer = reaction( - () => this.SectionFilter, - () => { - this.props.Document.sectionHeaders = new List(); - } + () => this.sectionFilter, + () => this.props.Document.sectionHeaders = new List() ); } componentWillUnmount() { @@ -186,8 +178,8 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { @undoBatch @action drop = (e: Event, de: DragManager.DropEvent) => { - let targInd = -1; let where = [de.x, de.y]; + let targInd = -1; if (de.data instanceof DragManager.DocumentDragData) { this._docXfs.map((cd, i) => { let pos = cd.dxf().inverse().transformPoint(-2 * this.gridGap, -2 * this.gridGap); @@ -233,8 +225,9 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { } }); } + headings = () => Array.from(this.Sections.keys()); section = (heading: SchemaHeaderField | undefined, docList: Doc[]) => { - let key = this.SectionFilter; + let key = this.sectionFilter; let type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | undefined = undefined; let types = docList.length ? docList.map(d => typeof d[key]) : this.childDocs.map(d => typeof d[key]); if (types.map((i, idx) => types.indexOf(i) === idx).length === 1) { @@ -245,7 +238,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { return Array.from(this.Sections.keys())} + headings={this.headings} heading={heading ? heading.heading : ""} headingObject={heading} docList={docList} @@ -254,16 +247,13 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { createDropTarget={this.createDropTarget} screenToLocalTransform={this.props.ScreenToLocalTransform} />; - } @action addGroup = (value: string) => { - if (value) { - if (this.sectionHeaders) { - this.sectionHeaders.push(new SchemaHeaderField(value)); - return true; - } + if (value && this.sectionHeaders) { + this.sectionHeaders.push(new SchemaHeaderField(value)); + return true; } return false; } @@ -276,11 +266,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { } onToggle = (checked: Boolean) => { - if (checked) { - this.props.CollectionView.props.Document.chromeStatus = 'collapsed'; - } else { - this.props.CollectionView.props.Document.chromeStatus = 'view-mode'; - } + this.props.CollectionView.props.Document.chromeSatus = checked ? "collapsed" : "view-mode"; } render() { @@ -296,10 +282,10 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { return (
e.stopPropagation()} > - {this.SectionFilter ? Array.from(this.Sections.entries()).sort(this.sortFunc). - map(section => this.section(section[0], section[1])) : + {this.sectionFilter ? Array.from(this.Sections.entries()).sort(this.sortFunc). + map((section: [SchemaHeaderField, Doc[]]) => this.section(section[0], section[1])) : this.section(undefined, this.filteredChildren)} - {(this.SectionFilter && (this.props.CollectionView.props.Document.chromeStatus !== 'view-mode' && this.props.CollectionView.props.Document.chromeStatus !== 'disabled')) ? + {(this.sectionFilter && (this.props.CollectionView.props.Document.chromeStatus !== 'view-mode' && this.props.CollectionView.props.Document.chromeStatus !== 'disabled')) ?
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 57dc5879b..f59fee985 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -20,16 +20,7 @@ import { CollectionTreeView } from "./CollectionTreeView"; import { CollectionViewBaseChrome } from './CollectionViewChromes'; export const COLLECTION_BORDER_WIDTH = 2; -library.add(faTh); -library.add(faTree); -library.add(faSquare); -library.add(faProjectDiagram); -library.add(faSignature); -library.add(faThList); -library.add(faFingerprint); -library.add(faColumns); -library.add(faEllipsisV); -library.add(faImage, faEye); +library.add(faTh, faTree, faSquare, faProjectDiagram, faSignature, faThList, faFingerprint, faColumns, faEllipsisV, faImage, faEye as any); @observer export class CollectionView extends React.Component { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index b4d065d26..c943fac74 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -40,7 +40,7 @@ import v5 = require("uuid/v5"); import { setScheduler } from "bluebird"; import { DocumentType, Docs } from "../../../documents/Documents"; -library.add(faEye, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt, faCompass, faUpload); +library.add(faEye as any, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt, faCompass, faUpload); export const panZoomSchema = createSchema({ panX: "number", @@ -206,8 +206,9 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { let cy = NumCast(cd.y) - this._clusterDistance; let cw = NumCast(cd.width) + 2 * this._clusterDistance; let ch = NumCast(cd.height) + 2 * this._clusterDistance; - if (!cd.z && this.intersectRect({ left: cx, top: cy, width: cw, height: ch }, { left: probe[0], top: probe[1], width: 1, height: 1 })) + if (!cd.z && this.intersectRect({ left: cx, top: cy, width: cw, height: ch }, { left: probe[0], top: probe[1], width: 1, height: 1 })) { return NumCast(cd.cluster); + } return cluster; }, -1); if (cluster !== -1) { @@ -236,20 +237,20 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { updateClusters() { this.sets.length = 0; this.childDocs.map(c => { - let included = [] + let included = []; for (let i = 0; i < this.sets.length; i++) { - for (let j = 0; j < this.sets[i].length; j++) { - if (this.boundsOverlap(c, this.sets[i][j])) { + for (let member of this.sets[i]) { + if (this.boundsOverlap(c, member)) { included.push(i); break; } } } - if (included.length === 0) + if (included.length === 0) { this.sets.push([c]); - else if (included.length === 1) + } else if (included.length === 1) { this.sets[included[0]].push(c); - else { + } else { this.sets[included[0]].push(c); for (let s = 1; s < included.length; s++) { this.sets[included[0]].push(...this.sets[included[s]]); @@ -257,11 +258,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } } }); - for (let s = 0; s < this.sets.length; s++) { - for (let i = 0; i < this.sets[s].length; i++) { - this.sets[s][i].cluster = s; - } - } + this.sets.map((set, i) => set.map(member => member.cluster = i)); } getClusterColor = (doc: Doc) => { diff --git a/src/client/views/nodes/ButtonBox.tsx b/src/client/views/nodes/ButtonBox.tsx index e2c559c9a..640795789 100644 --- a/src/client/views/nodes/ButtonBox.tsx +++ b/src/client/views/nodes/ButtonBox.tsx @@ -16,7 +16,7 @@ import './ButtonBox.scss'; import { observer } from 'mobx-react'; import { DocumentIconContainer } from './DocumentIcon'; -library.add(faEdit); +library.add(faEdit as any); const ButtonSchema = createSchema({ onClick: ScriptField, diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 0347fc9b2..4528cf94d 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -95,7 +95,7 @@ export interface DocumentViewProps { addDocTab: (doc: Doc, dataDoc: Doc | undefined, where: string) => void; collapseToPoint?: (scrpt: number[], expandedDocs: Doc[] | undefined) => void; zoomToScale: (scale: number) => void; - backgroundColor: (doc: Doc) => string; + backgroundColor: (doc: Doc) => string | undefined; getScale: () => number; animateBetweenIcon?: (iconPos: number[], startTime: number, maximizing: boolean) => void; ChromeHeight?: () => number; diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index fa072aecf..a49709e83 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -152,9 +152,7 @@ export class PDFBox extends DocComponent(PdfDocumen } scrollTo(y: number) { - if (this._mainCont.current) { - this._mainCont.current.scrollTo({ top: Math.max(y - (this._mainCont.current!.offsetHeight / 2), 0), behavior: "auto" }); - } + this._mainCont.current && this._mainCont.current.scrollTo({ top: Math.max(y - (this._mainCont.current.offsetHeight / 2), 0), behavior: "auto" }); } settingsPanel() { diff --git a/src/client/views/search/FilterBox.tsx b/src/client/views/search/FilterBox.tsx index 995ddd5c3..3e8582d61 100644 --- a/src/client/views/search/FilterBox.tsx +++ b/src/client/views/search/FilterBox.tsx @@ -384,7 +384,7 @@ export class FilterBox extends React.Component {
Collection Filters Active
: undefined}
- ) + ); } // Useful queries: diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx index 1b9bba5c6..48eb87251 100644 --- a/src/client/views/search/SearchItem.tsx +++ b/src/client/views/search/SearchItem.tsx @@ -134,7 +134,7 @@ export class LinkContextMenu extends React.Component {
- ) + ); } } diff --git a/src/client/views/search/ToggleBar.tsx b/src/client/views/search/ToggleBar.tsx index a30104089..ed5ecd3ba 100644 --- a/src/client/views/search/ToggleBar.tsx +++ b/src/client/views/search/ToggleBar.tsx @@ -59,7 +59,7 @@ export class ToggleBar extends React.Component{ this._forwardTimeline.play(); this._forwardTimeline.reverse(); this.props.handleChange(); - console.log(this.props.getStatus()) + console.log(this.props.getStatus()); } @action.bound diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index b081588a3..c01f4e8cf 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -358,7 +358,7 @@ export namespace Doc { let docExtensionForField = doc[fieldKey + "_ext"] as Doc; if (docExtensionForField === undefined) { setTimeout(() => { - CreateDocumentExtensionForField(doc, field); + CreateDocumentExtensionForField(doc, fieldKey); }, 0); } else if (doc instanceof Doc) { // backward compatibility -- add fields for docs that don't have them already docExtensionForField.extendsDoc === undefined && setTimeout(() => docExtensionForField.extendsDoc = doc, 0); @@ -535,7 +535,7 @@ export namespace Doc { d.layout = detailLayout; d.nativeWidth = d.nativeHeight = undefined; if (detailLayout instanceof Doc) { - let delegDetailLayout = Doc.MakeDelegate(detailLayout) as Doc; + let delegDetailLayout = Doc.MakeDelegate(detailLayout); d.layout = delegDetailLayout; delegDetailLayout.layout = await delegDetailLayout.detailedLayout; } -- cgit v1.2.3-70-g09d2 From a8aa834d8e08bddde705ce90ef4dee8be3791862 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 4 Aug 2019 21:56:11 -0400 Subject: fixed dropping of PDFs (or anything that doesn't have a height). --- .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index c943fac74..2bdbb6749 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -69,7 +69,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { ComputeContentBounds(boundsList: { x: number, y: number, width: number, height: number }[]) { let bounds = boundsList.reduce((bounds, b) => { var [sptX, sptY] = [b.x, b.y]; - let [bptX, bptY] = [sptX + b.width, sptY + b.height]; + let [bptX, bptY] = [sptX + NumCast(b.width, 1), sptY + NumCast(b.height, 1)]; return { x: Math.min(sptX, bounds.x), y: Math.min(sptY, bounds.y), r: Math.max(bptX, bounds.r), b: Math.max(bptY, bounds.b) @@ -617,7 +617,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { ele: , - bounds: (pos.x !== undefined && pos.y !== undefined && pos.width !== undefined && pos.height !== undefined) ? { x: pos.x, y: pos.y, z: pos.z, width: pos.width, height: pos.height } : undefined + bounds: (pos.x !== undefined && pos.y !== undefined) ? { x: pos.x, y: pos.y, z: pos.z, width: NumCast(pos.width), height: NumCast(pos.height) } : undefined }); } } -- cgit v1.2.3-70-g09d2 From 298d1c9b29d6ce2171fd9ac8274b64583b73f6f5 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 5 Aug 2019 18:32:53 -0400 Subject: added reset view menu option --- .../collectionFreeForm/CollectionFreeFormView.tsx | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 2bdbb6749..a08a12426 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,6 +1,6 @@ import { library } from "@fortawesome/fontawesome-svg-core"; import { faEye } from "@fortawesome/free-regular-svg-icons"; -import { faCompass, faCompressArrowsAlt, faExpandArrowsAlt, faPaintBrush, faTable, faUpload } from "@fortawesome/free-solid-svg-icons"; +import { faCompass, faCompressArrowsAlt, faExpandArrowsAlt, faPaintBrush, faTable, faUpload, faChalkboard, faBraille } from "@fortawesome/free-solid-svg-icons"; import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; import { Doc, DocListCastAsync, HeightSym, WidthSym } from "../../../../new_fields/Doc"; @@ -36,11 +36,9 @@ import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCurso import "./CollectionFreeFormView.scss"; import { MarqueeView } from "./MarqueeView"; import React = require("react"); -import v5 = require("uuid/v5"); -import { setScheduler } from "bluebird"; import { DocumentType, Docs } from "../../../documents/Documents"; -library.add(faEye as any, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt, faCompass, faUpload); +library.add(faEye as any, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt, faCompass, faUpload, faBraille, faChalkboard); export const panZoomSchema = createSchema({ panX: "number", @@ -651,6 +649,12 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { event: async () => this.props.Document.fitToBox = !this.fitToBox, icon: !this.fitToBox ? "expand-arrows-alt" : "compress-arrows-alt" }); + layoutItems.push({ + description: "reset view", event: () => { + this.props.Document.panX = this.props.Document.panY = 0; + this.props.Document.scale = 1; + }, icon: "compress-arrows-alt" + }); layoutItems.push({ description: `${this.props.Document.useClusters ? "Uncluster" : "Use Clusters"}`, event: async () => { @@ -658,12 +662,12 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { Docs.Prototypes.get(DocumentType.COL).defaultBackgroundColor = "white"; this.props.Document.useClusters = !this.props.Document.useClusters; }, - icon: !this.props.Document.useClusters ? "expand-arrows-alt" : "compress-arrows-alt" + icon: !this.props.Document.useClusters ? "braille" : "braille" }); layoutItems.push({ description: `${this.props.Document.clusterOverridesDefaultBackground ? "Use Default Backgrounds" : "Clusters Override Defaults"}`, event: async () => this.props.Document.clusterOverridesDefaultBackground = !this.props.Document.clusterOverridesDefaultBackground, - icon: !this.props.Document.useClusters ? "expand-arrows-alt" : "compress-arrows-alt" + icon: !this.props.Document.useClusters ? "chalkboard" : "chalkboard" }); layoutItems.push({ description: "Arrange contents in grid", -- cgit v1.2.3-70-g09d2 From d8c065935a0cb5a89b6d76407b7729f8584424eb Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Tue, 6 Aug 2019 22:03:59 -0400 Subject: pivot view --- src/client/views/Main.tsx | 2 + src/client/views/collections/CollectionView.tsx | 1 + .../collectionFreeForm/CollectionFreeFormView.tsx | 32 +++++++++++++++ src/scraping/buxton/scraper.py | 15 +++---- src/scraping/buxton/scripts/initialization.txt | 46 ++++++++++++++++++++++ src/scraping/buxton/scripts/layout.txt | 1 + src/server/index.ts | 29 +++++++++----- src/server/remapUrl.ts | 2 + 8 files changed, 111 insertions(+), 17 deletions(-) create mode 100644 src/scraping/buxton/scripts/initialization.txt create mode 100644 src/scraping/buxton/scripts/layout.txt (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 1cf13aa74..daa778ed3 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -7,6 +7,7 @@ import { Cast } from "../../new_fields/Types"; import { Doc, DocListCastAsync } from "../../new_fields/Doc"; import { List } from "../../new_fields/List"; import { DocServer } from "../DocServer"; +import { PivotView } from "./collections/collectionFreeForm/CollectionFreeFormView"; let swapDocs = async () => { let oldDoc = await Cast(CurrentUserUtils.UserDocument.linkManagerDoc, Doc); @@ -33,6 +34,7 @@ let swapDocs = async () => { DocServer.init(window.location.protocol, window.location.hostname, 4321, info.email); await Docs.Prototypes.initialize(); await CurrentUserUtils.loadUserDocument(info); + await PivotView.loadLayouts(); // updates old user documents to prevent chrome on tree view. (await Cast(CurrentUserUtils.UserDocument.workspaces, Doc))!.chromeStatus = "disabled"; (await Cast(CurrentUserUtils.UserDocument.recentlyClosed, Doc))!.chromeStatus = "disabled"; diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index f59fee985..59572b7e7 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -97,6 +97,7 @@ export class CollectionView extends React.Component { switch (this.props.Document.viewType) { case CollectionViewType.Freeform: { subItems.push({ description: "Custom", icon: "fingerprint", event: CollectionFreeFormView.AddCustomLayout(this.props.Document, this.props.fieldKey) }); + subItems.push({ description: "Pivot", icon: "fingerprint", event: () => CollectionFreeFormView.SetPivotLayout(this.props.Document) }); break; } } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 7ba13e961..17c4e83b0 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -37,6 +37,7 @@ import "./CollectionFreeFormView.scss"; import { MarqueeView } from "./MarqueeView"; import React = require("react"); import { DocumentType, Docs } from "../../../documents/Documents"; +import { RouteStore } from "../../../../server/RouteStore"; library.add(faEye as any, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt, faCompass, faUpload, faBraille, faChalkboard); @@ -48,6 +49,20 @@ export const panZoomSchema = createSchema({ arrangeInit: ScriptField, }); +export namespace PivotView { + + export let arrangeInit: string; + export let arrangeScript: string; + + export async function loadLayouts() { + let response = await fetch(Utils.prepend("/layoutscripts")); + let scripts = JSON.parse(await response.text()); + arrangeInit = scripts[0]; + arrangeScript = scripts[1]; + } + +} + type PanZoomDocument = makeInterface<[typeof panZoomSchema, typeof positionSchema, typeof pageSchema]>; const PanZoomDocument = makeInterface(panZoomSchema, positionSchema, pageSchema); @@ -787,6 +802,23 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { }; } + public static SetPivotLayout = (target: Doc) => { + let setSpecifiedLayoutField = (originalText: string, key: string, params: Record, requiredType?: string) => { + const script = CompileScript(originalText, { + params, + requiredType, + typecheck: false + }); + if (!script.compiled) { + console.log(script.errors.map(error => error.messageText).join("\n")); + return; + } + target[key] = new ScriptField(script); + }; + setSpecifiedLayoutField(PivotView.arrangeInit, "arrangeInit", { collection: "Doc", docs: "Doc[]" }, undefined); + setSpecifiedLayoutField(PivotView.arrangeScript, "arrangeScript", { doc: "Doc", index: "number", collection: "Doc", state: "any", docs: "Doc[]" }, "{x: number, y: number, width?: number, height?: number}"); + } + render() { const easing = () => this.props.Document.panTransformType === "Ease"; Doc.UpdateDocumentExtensionForField(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey); diff --git a/src/scraping/buxton/scraper.py b/src/scraping/buxton/scraper.py index f0f45d8f9..1c19118fd 100644 --- a/src/scraping/buxton/scraper.py +++ b/src/scraping/buxton/scraper.py @@ -17,6 +17,7 @@ dist = "../../server/public/files" db = MongoClient("localhost", 27017)["Dash"] target_collection = db.newDocuments +target_doc_title = "Workspace 1" schema_guids = [] common_proto_id = "" @@ -69,7 +70,7 @@ def text_doc_map(string_list): return listify(proxify_guids(list(map(guid_map, string_list)))) -def write_schema(parse_results, display_fields, storage_key): +def write_collection(parse_results, display_fields, storage_key, viewType=2): view_guids = parse_results["child_guids"] data_doc = parse_results["schema"] @@ -90,7 +91,7 @@ def write_schema(parse_results, display_fields, storage_key): "zoomBasis": 1, "zIndex": 2, "libraryBrush": False, - "viewType": 2 + "viewType": viewType }, "__type": "Doc" } @@ -237,7 +238,7 @@ def parse_document(file_name: str): copyfile(dir_path + "/" + image, dir_path + "/" + image.replace(".", "_o.", 1)) copyfile(dir_path + "/" + image, dir_path + - "/" + image.replace(".", "_m.", 1)) + "/" + image.replace(".", "_m.", 1)) print(f"extracted {count} images...") def sanitize(line): return re.sub("[\n\t]+", "", line).replace(u"\u00A0", " ").replace( @@ -381,22 +382,22 @@ candidates = 0 for file_name in os.listdir(source): if file_name.endswith('.docx'): candidates += 1 - schema_guids.append(write_schema( + schema_guids.append(write_collection( parse_document(file_name), ["title", "data"], "image_data")) print("writing parent schema...") -parent_guid = write_schema({ +parent_guid = write_collection({ "schema": { "_id": guid(), "fields": {}, "__type": "Doc" }, "child_guids": schema_guids -}, ["title", "short_description", "original_price"], "data") +}, ["title", "short_description", "original_price"], "data", 1) print("appending parent schema to main workspace...\n") target_collection.update_one( - {"fields.title": "WS collection 1"}, + {"fields.title": target_doc_title}, {"$push": {"fields.data.fields": {"fieldId": parent_guid, "__type": "proxy"}}} ) diff --git a/src/scraping/buxton/scripts/initialization.txt b/src/scraping/buxton/scripts/initialization.txt new file mode 100644 index 000000000..53f3f0d53 --- /dev/null +++ b/src/scraping/buxton/scripts/initialization.txt @@ -0,0 +1,46 @@ +const field = collection.pivotField || "title"; +const width = collection.pivotWidth || 200; + +const groups = new Map; + +for (const doc of docs) { + const val = doc[field]; + if (val === undefined) continue; + + const l = groups.get(val); + if (l) { + l.push(doc); + } else { + groups.set(val, [doc]); + } + +} + +let minSize = Infinity; + +groups.forEach((val, key) => { + minSize = Math.min(minSize, val.length); +}); + +const numCols = collection.pivotNumColumns || Math.ceil(Math.sqrt(minSize)); + +const docMap = new Map; +const groupNames = []; + +let x = 0; +groups.forEach((val, key) => { + let y = 0; + let xCount = 0; + groupNames.push({type:"text", text:String(key), x, y:width + 50, width: width * 1.25 * numCols, height:100, fontSize:collection.pivotFontSize}); + for (const doc of val) { + docMap.set(doc, {x: x + xCount * width * 1.25, y:-y, width, height:width}); + xCount++; + if (xCount >= numCols) { + xCount = 0; + y += width * 1.25; + } + } + x += width * 1.25 * (numCols + 1); +}); + +return {state:{ map: docMap}, views:groupNames }; \ No newline at end of file diff --git a/src/scraping/buxton/scripts/layout.txt b/src/scraping/buxton/scripts/layout.txt new file mode 100644 index 000000000..46b6dbaac --- /dev/null +++ b/src/scraping/buxton/scripts/layout.txt @@ -0,0 +1 @@ +return state.map.get(doc) \ No newline at end of file diff --git a/src/server/index.ts b/src/server/index.ts index 1e811c1b2..d735a6d8c 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -148,24 +148,33 @@ app.get("/pull", (req, res) => res.redirect("/"); })); -app.get("/buxton/:clear", (req, res) => { - if (req.params.clear === "true") { - deleteFields().then(() => upload_buxton_docs(res)); - } else { - upload_buxton_docs(res); - } -}); - -let upload_buxton_docs = (res: Response) => { +app.get("/buxton", (req, res) => { let buxton_scraping = path.join(__dirname, '../scraping/buxton'); exec('python scraper.py', { cwd: buxton_scraping }, (err, stdout, sterr) => { if (err) { res.send(err.message); return; } + console.log(stdout); res.redirect("/"); }); -}; +}); + +app.get('/layoutscripts', (req, res) => { + let scripts: string[] = []; + let handler = (err: NodeJS.ErrnoException | null, data: Buffer) => { + if (err) { + console.log(err.message); + return; + } + scripts.push(data.toString()); + if (scripts.length === 2) { + res.send(JSON.stringify(scripts)); + } + }; + fs.readFile(path.join(__dirname, '../scraping/buxton/scripts/initialization.txt'), handler); + fs.readFile(path.join(__dirname, '../scraping/buxton/scripts/layout.txt'), handler); +}); app.get("/version", (req, res) => { exec('"C:\\Program Files\\Git\\bin\\git.exe" rev-parse HEAD', (err, stdout, stderr) => { diff --git a/src/server/remapUrl.ts b/src/server/remapUrl.ts index 69c766d56..5218a239a 100644 --- a/src/server/remapUrl.ts +++ b/src/server/remapUrl.ts @@ -2,6 +2,8 @@ import { Database } from "./database"; import { Search } from "./Search"; import * as path from 'path'; +//npx ts-node src/server/remapUrl.ts + const suffixMap: { [type: string]: true } = { "video": true, "pdf": true, -- cgit v1.2.3-70-g09d2 From 4d3962cf221cb2421835c7016562433077e7b200 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Wed, 7 Aug 2019 01:48:15 -0400 Subject: pivot view script retrieval and context menu behavior improvements --- src/client/views/collections/CollectionView.tsx | 14 ++++-- .../collectionFreeForm/CollectionFreeFormView.tsx | 12 ++--- src/scraping/buxton/source/Silverlight.dmg | Bin 0 -> 15097394 bytes src/server/index.ts | 52 ++++++++++++--------- 4 files changed, 44 insertions(+), 34 deletions(-) create mode 100644 src/scraping/buxton/source/Silverlight.dmg (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 59572b7e7..60ede17e7 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -1,6 +1,6 @@ import { library } from '@fortawesome/fontawesome-svg-core'; import { faEye } from '@fortawesome/free-regular-svg-icons'; -import { faColumns, faEllipsisV, faFingerprint, faImage, faProjectDiagram, faSignature, faSquare, faTh, faThList, faTree } from '@fortawesome/free-solid-svg-icons'; +import { faColumns, faEllipsisV, faFingerprint, faImage, faProjectDiagram, faSignature, faSquare, faTh, faThList, faTree, faCopy } from '@fortawesome/free-solid-svg-icons'; import { action, IReactionDisposer, observable, reaction, runInAction } from 'mobx'; import { observer } from "mobx-react"; import * as React from 'react'; @@ -20,7 +20,7 @@ import { CollectionTreeView } from "./CollectionTreeView"; import { CollectionViewBaseChrome } from './CollectionViewChromes'; export const COLLECTION_BORDER_WIDTH = 2; -library.add(faTh, faTree, faSquare, faProjectDiagram, faSignature, faThList, faFingerprint, faColumns, faEllipsisV, faImage, faEye as any); +library.add(faTh, faTree, faSquare, faProjectDiagram, faSignature, faThList, faFingerprint, faColumns, faEllipsisV, faImage, faEye as any, faCopy); @observer export class CollectionView extends React.Component { @@ -86,7 +86,13 @@ export class CollectionView extends React.Component { onContextMenu = (e: React.MouseEvent): void => { if (!this.isAnnotationOverlay && !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 let subItems: ContextMenuProps[] = []; - subItems.push({ description: "Freeform", event: () => this.props.Document.viewType = CollectionViewType.Freeform, icon: "signature" }); + subItems.push({ + description: "Freeform", event: () => { + this.props.Document.viewType = CollectionViewType.Freeform; + delete this.props.Document.arrangeInit; + delete this.props.Document.arrangeScript; + }, icon: "signature" + }); if (CollectionBaseView.InSafeMode()) { ContextMenu.Instance.addItem({ description: "Test Freeform", event: () => this.props.Document.viewType = CollectionViewType.Invalid, icon: "project-diagram" }); } @@ -97,7 +103,7 @@ export class CollectionView extends React.Component { switch (this.props.Document.viewType) { case CollectionViewType.Freeform: { subItems.push({ description: "Custom", icon: "fingerprint", event: CollectionFreeFormView.AddCustomLayout(this.props.Document, this.props.fieldKey) }); - subItems.push({ description: "Pivot", icon: "fingerprint", event: () => CollectionFreeFormView.SetPivotLayout(this.props.Document) }); + subItems.push({ description: "Pivot", icon: "copy", event: () => CollectionFreeFormView.SetPivotLayout(this.props.Document) }); break; } } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 17c4e83b0..110ac2f25 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -51,14 +51,10 @@ export const panZoomSchema = createSchema({ export namespace PivotView { - export let arrangeInit: string; - export let arrangeScript: string; + export let scripts: { arrangeInit: string, arrangeScript: string }; export async function loadLayouts() { - let response = await fetch(Utils.prepend("/layoutscripts")); - let scripts = JSON.parse(await response.text()); - arrangeInit = scripts[0]; - arrangeScript = scripts[1]; + scripts = JSON.parse(await (await fetch(Utils.prepend("/layoutscripts"))).text()); } } @@ -815,8 +811,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } target[key] = new ScriptField(script); }; - setSpecifiedLayoutField(PivotView.arrangeInit, "arrangeInit", { collection: "Doc", docs: "Doc[]" }, undefined); - setSpecifiedLayoutField(PivotView.arrangeScript, "arrangeScript", { doc: "Doc", index: "number", collection: "Doc", state: "any", docs: "Doc[]" }, "{x: number, y: number, width?: number, height?: number}"); + setSpecifiedLayoutField(PivotView.scripts.arrangeInit, "arrangeInit", { collection: "Doc", docs: "Doc[]" }, undefined); + setSpecifiedLayoutField(PivotView.scripts.arrangeScript, "arrangeScript", { doc: "Doc", index: "number", collection: "Doc", state: "any", docs: "Doc[]" }, "{x: number, y: number, width?: number, height?: number}"); } render() { diff --git a/src/scraping/buxton/source/Silverlight.dmg b/src/scraping/buxton/source/Silverlight.dmg new file mode 100644 index 000000000..d88290362 Binary files /dev/null and b/src/scraping/buxton/source/Silverlight.dmg differ diff --git a/src/server/index.ts b/src/server/index.ts index d735a6d8c..a0101e3f8 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -1,6 +1,6 @@ require('dotenv').config(); import * as bodyParser from 'body-parser'; -import { exec } from 'child_process'; +import { exec, ExecOptions } from 'child_process'; import * as cookieParser from 'cookie-parser'; import * as express from 'express'; import * as session from 'express-session'; @@ -149,31 +149,39 @@ app.get("/pull", (req, res) => })); app.get("/buxton", (req, res) => { - let buxton_scraping = path.join(__dirname, '../scraping/buxton'); - exec('python scraper.py', { cwd: buxton_scraping }, (err, stdout, sterr) => { - if (err) { - res.send(err.message); - return; + let cwd = '../scraping/buxton'; + + let onResolved = (stdout: string) => { console.log(stdout); res.redirect("/"); }; + let onRejected = (err: any) => { console.error(err.message); res.send(err); }; + let tryPython3 = () => command_line('python3 scraper.py', cwd).then(onResolved, onRejected); + + command_line('python scraper.py', cwd).then(onResolved, tryPython3); +}); + +const command_line = (command: string, fromDirectory?: string) => { + return new Promise((resolve, reject) => { + let options: ExecOptions = {}; + if (fromDirectory) { + options.cwd = path.join(__dirname, fromDirectory); } - console.log(stdout); - res.redirect("/"); + exec(command, options, (err, stdout) => err ? reject(err) : resolve(stdout)); }); -}); +}; + +const read_text_file = (relativePath: string) => { + let target = path.join(__dirname, relativePath); + return new Promise((resolve, reject) => { + fs.readFile(target, (err, data) => err ? reject(err) : resolve(data.toString())); + }); +}; app.get('/layoutscripts', (req, res) => { - let scripts: string[] = []; - let handler = (err: NodeJS.ErrnoException | null, data: Buffer) => { - if (err) { - console.log(err.message); - return; - } - scripts.push(data.toString()); - if (scripts.length === 2) { - res.send(JSON.stringify(scripts)); - } - }; - fs.readFile(path.join(__dirname, '../scraping/buxton/scripts/initialization.txt'), handler); - fs.readFile(path.join(__dirname, '../scraping/buxton/scripts/layout.txt'), handler); + let prefix = '../scraping/buxton/scripts/'; + read_text_file(prefix + 'initialization.txt').then(arrangeInit => { + read_text_file(prefix + 'layout.txt').then(arrangeScript => { + res.send(JSON.stringify({ arrangeInit, arrangeScript })); + }); + }); }); app.get("/version", (req, res) => { -- cgit v1.2.3-70-g09d2 From adb91b035bd18ff407ce0b2decc07c779282c008 Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 7 Aug 2019 12:40:45 -0400 Subject: added zooming to pdfs --- src/client/views/Main.tsx | 5 ++ .../collectionFreeForm/CollectionFreeFormView.tsx | 63 ++++++++++------------ src/client/views/nodes/PDFBox.scss | 3 ++ src/client/views/nodes/PDFBox.tsx | 59 ++++++++------------ src/client/views/pdf/PDFViewer.tsx | 2 +- src/client/views/pdf/Page.tsx | 29 +++++----- 6 files changed, 75 insertions(+), 86 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 1cf13aa74..5fd42c0df 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -39,5 +39,10 @@ let swapDocs = async () => { (await Cast(CurrentUserUtils.UserDocument.sidebar, Doc))!.chromeStatus = "disabled"; CurrentUserUtils.UserDocument.chromeStatus = "disabled"; await swapDocs(); + document.getElementById('root')!.addEventListener('wheel', event => { + if (event.ctrlKey) { + event.preventDefault() + } + }, true); ReactDOM.render(, document.getElementById('root')); })(); \ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index a08a12426..d347e02b6 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -352,12 +352,11 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @action onPointerWheel = (e: React.WheelEvent): void => { if (BoolCast(this.props.Document.lockedPosition)) return; - // if (!this.props.active()) { - // return; - // } - if (this.props.Document.type === "pdf") { + if (!e.ctrlKey && this.props.Document.scrollY !== undefined) { + e.stopPropagation(); return; } + let childSelected = this.childDocs.some(doc => { var dv = DocumentManager.Instance.getDocumentView(doc); return dv && SelectionManager.IsSelected(dv) ? true : false; @@ -366,21 +365,20 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { return; } e.stopPropagation(); - const coefficient = 1000; - - if (e.ctrlKey) { - let deltaScale = (1 - (e.deltaY / coefficient)); - let nw = this.nativeWidth * deltaScale; - let nh = this.nativeHeight * deltaScale; - if (nw && nh) { - this.props.Document.nativeWidth = nw; - this.props.Document.nativeHeight = nh; - } - e.stopPropagation(); - e.preventDefault(); - } else { - // if (modes[e.deltaMode] === 'pixels') coefficient = 50; - // else if (modes[e.deltaMode] === 'lines') coefficient = 1000; // This should correspond to line-height?? + + // bcz: this changes the nativewidth/height, but ImageBox will just revert it back to its defaults. need more logic to fix. + // if (e.ctrlKey && this.props.Document.scrollY === undefined) { + // let deltaScale = (1 - (e.deltaY / coefficient)); + // let nw = this.nativeWidth * deltaScale; + // let nh = this.nativeHeight * deltaScale; + // if (nw && nh) { + // this.props.Document.nativeWidth = nw; + // this.props.Document.nativeHeight = nh; + // } + // e.preventDefault(); + // } + // else + { let deltaScale = e.deltaY > 0 ? (1 / 1.1) : 1.1; if (deltaScale * this.zoomScaling() < 1 && this.isAnnotationOverlay) { deltaScale = 1 / this.zoomScaling(); @@ -392,21 +390,21 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { let 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); - e.stopPropagation(); + e.preventDefault(); } } @action setPan(panX: number, panY: number) { - if (BoolCast(this.props.Document.lockedPosition)) return; - this.props.Document.panTransformType = "None"; - var scale = this.getLocalTransform().inverse().Scale; - const newPanX = Math.min((1 - 1 / scale) * this.nativeWidth, Math.max(0, panX)); - const newPanY = Math.min((1 - 1 / scale) * this.nativeHeight, Math.max(0, panY)); - this.props.Document.panX = this.isAnnotationOverlay ? newPanX : panX; - this.props.Document.panY = this.isAnnotationOverlay && StrCast(this.props.Document.backgroundLayout).indexOf("PDFBox") === -1 ? newPanY : panY; - if (this.props.Document.scrollY) { - this.props.Document.scrollY = panY - scale * this.props.Document[HeightSym](); + if (!BoolCast(this.props.Document.lockedPosition)) { + this.props.Document.panTransformType = "None"; + var scale = this.getLocalTransform().inverse().Scale; + const newPanX = Math.min((1 - 1 / scale) * this.nativeWidth, Math.max(0, panX)); + const newPanY = Math.min((this.props.Document.scrollHeight !== undefined ? NumCast(this.props.Document.scrollHeight) : (1 - 1 / scale) * this.nativeHeight), Math.max(0, panY)); + this.props.Document.panX = this.isAnnotationOverlay ? newPanX : panX; + this.props.Document.panY = this.isAnnotationOverlay ? newPanY : panY; + if (this.props.Document.scrollHeight !== undefined) this.props.Document.scrollY = this.isAnnotationOverlay ? newPanY : panY; + else this.props.Document.panY = this.isAnnotationOverlay ? newPanY : panY; } } @@ -490,12 +488,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { this.Document.scale = scale; } - getScale = () => { - if (this.Document.scale) { - return this.Document.scale; - } - return 1; - } + getScale = () => this.Document.scale ? this.Document.scale : 1; getChildDocumentViewProps(childDocLayout: Doc): DocumentViewProps { diff --git a/src/client/views/nodes/PDFBox.scss b/src/client/views/nodes/PDFBox.scss index a1bab0409..c88a94c28 100644 --- a/src/client/views/nodes/PDFBox.scss +++ b/src/client/views/nodes/PDFBox.scss @@ -5,6 +5,9 @@ height: 100%; overflow-y: scroll; overflow-x: hidden; + .pdfBox-scrollHack { + pointer-events: none; + } } .pdfBox-cont { diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 56e720bf7..2759b46d4 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -30,10 +30,11 @@ export class PDFBox extends DocComponent(PdfDocumen @observable private _flyout: boolean = false; @observable private _alt = false; - @observable private _scrollY: number = 0; @observable private _pdf: Opt; + @computed get containingCollectionDocument() { return this.props.ContainingCollectionView && this.props.ContainingCollectionView.props.Document; } @computed get dataDoc() { return BoolCast(this.props.Document.isTemplate) && this.props.DataDoc ? this.props.DataDoc : this.props.Document; } + @computed get fieldExtensionDoc() { return Doc.resolvedFieldDataDoc(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey, "true"); } private _mainCont: React.RefObject = React.createRef(); private _reactionDisposer?: IReactionDisposer; @@ -62,16 +63,16 @@ export class PDFBox extends DocComponent(PdfDocumen } public GetPage() { - return Math.floor(NumCast(this.props.Document.scrollY) / NumCast(this.dataDoc.pdfHeight)) + 1; + return Math.floor(NumCast(this.props.Document.scrollY) / NumCast(this.dataDoc.nativeHeight)) + 1; } @action public BackPage() { - let cp = Math.ceil(NumCast(this.props.Document.scrollY) / NumCast(this.dataDoc.pdfHeight)) + 1; + let cp = Math.ceil(NumCast(this.props.Document.scrollY) / NumCast(this.dataDoc.nativeHeight)) + 1; cp = cp - 1; if (cp > 0) { this.props.Document.curPage = cp; - this.props.Document.scrollY = (cp - 1) * NumCast(this.dataDoc.pdfHeight); + this.props.Document.scrollY = (cp - 1) * NumCast(this.dataDoc.nativeHeight); } } @@ -79,7 +80,7 @@ export class PDFBox extends DocComponent(PdfDocumen public GotoPage(p: number) { if (p > 0 && p <= NumCast(this.props.Document.numPages)) { this.props.Document.curPage = p; - this.props.Document.scrollY = (p - 1) * NumCast(this.dataDoc.pdfHeight); + this.props.Document.scrollY = (p - 1) * NumCast(this.dataDoc.nativeHeight); } } @@ -88,31 +89,16 @@ export class PDFBox extends DocComponent(PdfDocumen let cp = this.GetPage() + 1; if (cp <= NumCast(this.props.Document.numPages)) { this.props.Document.curPage = cp; - this.props.Document.scrollY = (cp - 1) * NumCast(this.dataDoc.pdfHeight); + this.props.Document.scrollY = (cp - 1) * NumCast(this.dataDoc.nativeHeight); } } - scrollTo = (y: number) => { - this._mainCont.current && this._mainCont.current.scrollTo({ top: Math.max(y - (this._mainCont.current.offsetHeight / 2), 0), behavior: "auto" }); - } - @action setPanY = (y: number) => { this.containingCollectionDocument && (this.containingCollectionDocument.panY = y); } - private newKeyChange = (e: React.ChangeEvent) => { - this._keyValue = e.currentTarget.value; - } - - private newValueChange = (e: React.ChangeEvent) => { - this._valueValue = e.currentTarget.value; - } - - private newScriptChange = (e: React.ChangeEvent) => { - this._scriptValue = e.currentTarget.value; - } - + @action private applyFilter = () => { let scriptText = this._scriptValue.length > 0 ? this._scriptValue : this._keyValue.length > 0 && this._valueValue.length > 0 ? @@ -121,7 +107,10 @@ export class PDFBox extends DocComponent(PdfDocumen script.compiled && (this.props.Document.filterScript = new ScriptField(script)); } - @action + scrollTo = (y: number) => { + this._mainCont.current && this._mainCont.current.scrollTo({ top: Math.max(y - (this._mainCont.current.offsetHeight / 2), 0), behavior: "auto" }); + } + private resetFilters = () => { this._keyValue = this._valueValue = ""; this._scriptValue = "return true"; @@ -130,6 +119,9 @@ export class PDFBox extends DocComponent(PdfDocumen this._scriptRef.current && (this._scriptRef.current.value = ""); this.applyFilter(); } + private newKeyChange = (e: React.ChangeEvent) => this._keyValue = e.currentTarget.value; + private newValueChange = (e: React.ChangeEvent) => this._valueValue = e.currentTarget.value; + private newScriptChange = (e: React.ChangeEvent) => this._scriptValue = e.currentTarget.value; settingsPanel() { return !this.props.active() ? (null) : @@ -176,12 +168,12 @@ export class PDFBox extends DocComponent(PdfDocumen loaded = (nw: number, nh: number, np: number) => { this.dataDoc.numPages = np; - if (!this.dataDoc.nativeWidth || !this.dataDoc.nativeHeight) { + if (!this.dataDoc.nativeWidth || !this.dataDoc.nativeHeight || !this.dataDoc.scrollHeight) { let oldaspect = NumCast(this.dataDoc.nativeHeight) / NumCast(this.dataDoc.nativeWidth, 1); this.dataDoc.nativeWidth = nw; this.dataDoc.nativeHeight = this.dataDoc.nativeHeight ? nw * oldaspect : nh; - this.containingCollectionDocument && (this.containingCollectionDocument.pdfHeight = nh); - this.dataDoc.height = nh * (this.dataDoc[WidthSym]() / nw); + this.dataDoc.height = this.dataDoc[WidthSym]() * (nh / nw); + this.dataDoc.scrollHeight = np * this.dataDoc.nativeHeight; } } @@ -189,14 +181,10 @@ export class PDFBox extends DocComponent(PdfDocumen onScroll = (e: React.UIEvent) => { if (e.currentTarget && this.containingCollectionDocument) { this.containingCollectionDocument.panTransformType = "None"; - this.containingCollectionDocument.scrollY = this._scrollY = e.currentTarget.scrollTop; + this.containingCollectionDocument.scrollY = e.currentTarget.scrollTop; } } - @computed get fieldExtensionDoc() { - return Doc.resolvedFieldDataDoc(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey, "true"); - } - render() { const pdfUrl = Cast(this.props.Document.data, PdfField); let classname = "pdfBox-cont" + (this.props.active() && !InkingControl.Instance.selectedTool && !this._alt ? "-interactive" : ""); @@ -205,14 +193,13 @@ export class PDFBox extends DocComponent(PdfDocumen
{ e.stopPropagation(); }}> - +
+ {this.settingsPanel()} -
- ); +
); } } \ No newline at end of file diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 7c445c373..021c04723 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -160,7 +160,7 @@ export class PDFViewer extends React.Component { })))); this.props.loaded(Math.max(...this._pageSizes.map(i => i.width)), this._pageSizes[0].height, this.props.pdf.numPages); - let startY = NumCast(this.props.Document.startY); + let startY = NumCast(this.props.Document.startY, NumCast(this.props.Document.scrollY)); this.props.setPanY && this.props.setPanY(startY); this.props.Document.scrollY = startY + 1; } diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx index a15bed255..6de2db427 100644 --- a/src/client/views/pdf/Page.tsx +++ b/src/client/views/pdf/Page.tsx @@ -143,6 +143,7 @@ export default class Page extends React.Component { @action onPointerDown = (e: React.PointerEvent): void => { // if alt+left click, drag and annotate + if (this.props.Document.scale !== 1) return; if (e.altKey && e.button === 0) { e.stopPropagation(); } @@ -197,21 +198,21 @@ export default class Page extends React.Component { onSelectEnd = (e: PointerEvent): void => { if (this._marqueeing) { this._marqueeing = false; - if (this._marquee.current) { // make a copy of the marquee - let copy = document.createElement("div"); - let style = this._marquee.current.style; - copy.style.left = style.left; - copy.style.top = style.top; - copy.style.width = style.width; - copy.style.height = style.height; - copy.style.border = style.border; - copy.style.opacity = style.opacity; - copy.className = "pdfPage-annotationBox"; - this.props.createAnnotation(copy, this.props.page); - this._marquee.current.style.opacity = "0"; - } - if (this._marqueeWidth > 10 || this._marqueeHeight > 10) { + if (this._marquee.current) { // make a copy of the marquee + let copy = document.createElement("div"); + let style = this._marquee.current.style; + copy.style.left = style.left; + copy.style.top = style.top; + copy.style.width = style.width; + copy.style.height = style.height; + copy.style.border = style.border; + copy.style.opacity = style.opacity; + copy.className = "pdfPage-annotationBox"; + this.props.createAnnotation(copy, this.props.page); + this._marquee.current.style.opacity = "0"; + } + if (!e.ctrlKey) { PDFMenu.Instance.Status = "snippet"; PDFMenu.Instance.Marquee = { left: this._marqueeX, top: this._marqueeY, width: this._marqueeWidth, height: this._marqueeHeight }; -- cgit v1.2.3-70-g09d2 From 221acd0cfb4831435d1d1b61b86c2cc5e3d3b413 Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 7 Aug 2019 12:50:58 -0400 Subject: got rid of scrollY from pdfs! --- src/client/views/collections/CollectionPDFView.tsx | 16 +--------------- .../collectionFreeForm/CollectionFreeFormView.tsx | 6 ++---- src/client/views/nodes/PDFBox.tsx | 18 +++++++++--------- src/client/views/pdf/PDFViewer.tsx | 21 ++++++++++----------- 4 files changed, 22 insertions(+), 39 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx index 3736ebada..8eda4d9ee 100644 --- a/src/client/views/collections/CollectionPDFView.tsx +++ b/src/client/views/collections/CollectionPDFView.tsx @@ -1,7 +1,6 @@ -import { action, IReactionDisposer, observable, reaction, computed } from "mobx"; +import { computed } from "mobx"; import { observer } from "mobx-react"; import { Id } from "../../../new_fields/FieldSymbols"; -import { NumCast } from "../../../new_fields/Types"; import { emptyFunction } from "../../../Utils"; import { ContextMenu } from "../ContextMenu"; import { FieldView, FieldViewProps } from "../nodes/FieldView"; @@ -19,21 +18,8 @@ export class CollectionPDFView extends React.Component { } private _pdfBox?: PDFBox; - private _reactionDisposer?: IReactionDisposer; private _buttonTray: React.RefObject = React.createRef(); - componentDidMount() { - this._reactionDisposer = reaction( - () => NumCast(this.props.Document.scrollY), - () => this.props.Document.panY = NumCast(this.props.Document.scrollY), - { fireImmediately: true } - ); - } - - componentWillUnmount() { - this._reactionDisposer && this._reactionDisposer(); - } - @computed get uIButtons() { return ( diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index d347e02b6..8322625f1 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -352,7 +352,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @action onPointerWheel = (e: React.WheelEvent): void => { if (BoolCast(this.props.Document.lockedPosition)) return; - if (!e.ctrlKey && this.props.Document.scrollY !== undefined) { + if (!e.ctrlKey && this.props.Document.scrollHeight !== undefined) { // things that can scroll vertically should do that instead of zooming e.stopPropagation(); return; } @@ -367,7 +367,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { e.stopPropagation(); // bcz: this changes the nativewidth/height, but ImageBox will just revert it back to its defaults. need more logic to fix. - // if (e.ctrlKey && this.props.Document.scrollY === undefined) { + // if (e.ctrlKey && this.props.Document.scrollHeight === undefined) { // let deltaScale = (1 - (e.deltaY / coefficient)); // let nw = this.nativeWidth * deltaScale; // let nh = this.nativeHeight * deltaScale; @@ -403,8 +403,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { const newPanY = Math.min((this.props.Document.scrollHeight !== undefined ? NumCast(this.props.Document.scrollHeight) : (1 - 1 / scale) * this.nativeHeight), Math.max(0, panY)); this.props.Document.panX = this.isAnnotationOverlay ? newPanX : panX; this.props.Document.panY = this.isAnnotationOverlay ? newPanY : panY; - if (this.props.Document.scrollHeight !== undefined) this.props.Document.scrollY = this.isAnnotationOverlay ? newPanY : panY; - else this.props.Document.panY = this.isAnnotationOverlay ? newPanY : panY; } } diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 2759b46d4..e9207404e 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -53,8 +53,8 @@ export class PDFBox extends DocComponent(PdfDocumen Pdfjs.getDocument(pdfUrl.url.pathname).promise.then(pdf => runInAction(() => this._pdf = pdf)); } this._reactionDisposer = reaction( - () => this.props.Document.scrollY, - () => this._mainCont.current && this._mainCont.current.scrollTo({ top: NumCast(this.Document.scrollY), behavior: "auto" }) + () => this.props.Document.panY, + () => this._mainCont.current && this._mainCont.current.scrollTo({ top: NumCast(this.Document.panY), behavior: "auto" }) ); } @@ -63,16 +63,16 @@ export class PDFBox extends DocComponent(PdfDocumen } public GetPage() { - return Math.floor(NumCast(this.props.Document.scrollY) / NumCast(this.dataDoc.nativeHeight)) + 1; + return Math.floor(NumCast(this.props.Document.panY) / NumCast(this.dataDoc.nativeHeight)) + 1; } @action public BackPage() { - let cp = Math.ceil(NumCast(this.props.Document.scrollY) / NumCast(this.dataDoc.nativeHeight)) + 1; + let cp = Math.ceil(NumCast(this.props.Document.panY) / NumCast(this.dataDoc.nativeHeight)) + 1; cp = cp - 1; if (cp > 0) { this.props.Document.curPage = cp; - this.props.Document.scrollY = (cp - 1) * NumCast(this.dataDoc.nativeHeight); + this.props.Document.panY = (cp - 1) * NumCast(this.dataDoc.nativeHeight); } } @@ -80,7 +80,7 @@ export class PDFBox extends DocComponent(PdfDocumen public GotoPage(p: number) { if (p > 0 && p <= NumCast(this.props.Document.numPages)) { this.props.Document.curPage = p; - this.props.Document.scrollY = (p - 1) * NumCast(this.dataDoc.nativeHeight); + this.props.Document.panY = (p - 1) * NumCast(this.dataDoc.nativeHeight); } } @@ -89,7 +89,7 @@ export class PDFBox extends DocComponent(PdfDocumen let cp = this.GetPage() + 1; if (cp <= NumCast(this.props.Document.numPages)) { this.props.Document.curPage = cp; - this.props.Document.scrollY = (cp - 1) * NumCast(this.dataDoc.nativeHeight); + this.props.Document.panY = (cp - 1) * NumCast(this.dataDoc.nativeHeight); } } @@ -181,7 +181,7 @@ export class PDFBox extends DocComponent(PdfDocumen onScroll = (e: React.UIEvent) => { if (e.currentTarget && this.containingCollectionDocument) { this.containingCollectionDocument.panTransformType = "None"; - this.containingCollectionDocument.scrollY = e.currentTarget.scrollTop; + this.containingCollectionDocument.panY = e.currentTarget.scrollTop; } } @@ -195,7 +195,7 @@ export class PDFBox extends DocComponent(PdfDocumen style={{ marginTop: `${this.containingCollectionDocument ? NumCast(this.containingCollectionDocument.panY) : 0}px` }} ref={this._mainCont}>
- diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 021c04723..f3281047a 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -31,7 +31,7 @@ interface IViewerProps { fieldExtensionDoc: Doc; fieldKey: string; loaded: (nw: number, nh: number, np: number) => void; - scrollY: number; + panY: number; scrollTo: (y: number) => void; active: () => boolean; setPanY?: (n: number) => void; @@ -64,14 +64,14 @@ export class PDFViewer extends React.Component { private _searchString: string = ""; private _selectionText: string = ""; - @computed get scrollY(): number { return this.props.scrollY; } + @computed get panY(): number { return this.props.panY; } // startIndex: where to start rendering pages - @computed get startIndex(): number { return Math.max(0, this.getPageFromScroll(this.scrollY) - this._pageBuffer); } + @computed get startIndex(): number { return Math.max(0, this.getPageFromScroll(this.panY) - this._pageBuffer); } // endIndex: where to end rendering pages @computed get endIndex(): number { - return Math.min(this.props.pdf.numPages - 1, this.getPageFromScroll(this.scrollY + (this._pageSizes[0] ? this._pageSizes[0].height : 0)) + this._pageBuffer); + return Math.min(this.props.pdf.numPages - 1, this.getPageFromScroll(this.panY + (this._pageSizes[0] ? this._pageSizes[0].height : 0)) + this._pageBuffer); } @computed get filteredAnnotations() { @@ -81,7 +81,7 @@ export class PDFViewer extends React.Component { }); } - componentDidUpdate = (prevProps: IViewerProps) => this.scrollY !== prevProps.scrollY && this.renderPages(); + componentDidUpdate = (prevProps: IViewerProps) => this.panY !== prevProps.panY && this.renderPages(); componentDidMount = async () => { await this.initialLoad(); @@ -160,9 +160,8 @@ export class PDFViewer extends React.Component { })))); this.props.loaded(Math.max(...this._pageSizes.map(i => i.width)), this._pageSizes[0].height, this.props.pdf.numPages); - let startY = NumCast(this.props.Document.startY, NumCast(this.props.Document.scrollY)); + let startY = NumCast(this.props.Document.startY, NumCast(this.props.Document.panY)); this.props.setPanY && this.props.setPanY(startY); - this.props.Document.scrollY = startY + 1; } } @@ -435,7 +434,7 @@ export class PDFViewer extends React.Component { )}
e.stopPropagation()} - style={{ bottom: -this.props.scrollY, left: `${this._searching ? 0 : 100}%` }}> + style={{ bottom: -this.props.panY, left: `${this._searching ? 0 : 100}%` }}>
; } + // clusterDocuments = () => { + // DocumentManager.Instance.DocumentViews(); + // } + + + @action diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 29f9b1429..9344b43d2 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,6 +1,6 @@ import { library } from "@fortawesome/fontawesome-svg-core"; import { faEye } from "@fortawesome/free-regular-svg-icons"; -import { faCompass, faCompressArrowsAlt, faExpandArrowsAlt, faPaintBrush, faTable, faUpload } from "@fortawesome/free-solid-svg-icons"; +import { faCompass, faCompressArrowsAlt, faExpandArrowsAlt, faPaintBrush, faTable, faUpload, faBrain } from "@fortawesome/free-solid-svg-icons"; import { action, computed } from "mobx"; import { observer } from "mobx-react"; import { Doc, DocListCastAsync, HeightSym, WidthSym } from "../../../../new_fields/Doc"; @@ -37,8 +37,9 @@ import "./CollectionFreeFormView.scss"; import { MarqueeView } from "./MarqueeView"; import React = require("react"); import v5 = require("uuid/v5"); +import { ClientRecommender } from "../../../ClientRecommender"; -library.add(faEye, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt, faCompass, faUpload); +library.add(faEye, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt, faCompass, faUpload, faBrain); export const panZoomSchema = createSchema({ panX: "number", @@ -596,6 +597,20 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { input.click(); } }); + ContextMenu.Instance.addItem({ + description: "Recommender System", + event: async () => { + new ClientRecommender(); + let activedocs = this.getActiveDocuments(); + await Promise.all(activedocs.map((doc: Doc) => { + console.log(StrCast(doc.title)); + const extdoc = doc.data_ext as Doc; + return ClientRecommender.Instance.extractText(doc, extdoc ? extdoc : doc); + })); + console.log(ClientRecommender.Instance.createDistanceMatrix()); + }, + icon: "brain" + }); } diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 161226c0d..660772c0e 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -31,7 +31,7 @@ import { faEye } from '@fortawesome/free-regular-svg-icons'; import { ComputedField } from '../../../new_fields/ScriptField'; import { CompileScript } from '../../util/Scripting'; import { thisExpression } from 'babel-types'; -import { Recommender } from '../../../server/Recommender'; +//import { Recommender } from '../../../server/Recommender'; import requestPromise = require('request-promise'); var requestImageSize = require('../../util/request-image-size'); var path = require('path'); @@ -244,17 +244,7 @@ export class ImageBox extends DocComponent(ImageD } extractText = () => { - let data = StrCast(this.dataDoc.title); - console.log(data); - let converter = (results: any) => { - let keyterms = new List(); - results.documents.forEach((doc: any) => { - let keyPhrases = doc.keyPhrases; - keyPhrases.map((kp: string) => keyterms.push(kp)); - }); - return keyterms; - }; - CognitiveServices.Text.Manager.analyzer(this.extensionDoc, ["key words"], data, converter); + //Recommender.Instance.extractText(this.dataDoc, this.extensionDoc); // request recommender //fetch(Utils.prepend("/recommender"), { body: body, method: "POST", headers: { "content-type": "application/json" } }).then((value) => console.log(value)); } diff --git a/src/server/Recommender.ts b/src/server/Recommender.ts index 3c71f3aa1..ea59703c3 100644 --- a/src/server/Recommender.ts +++ b/src/server/Recommender.ts @@ -1,4 +1,10 @@ +//import { Doc } from "../new_fields/Doc"; +//import { StrCast } from "../new_fields/Types"; +//import { List } from "../new_fields/List"; +//import { CognitiveServices } from "../client/cognitive_services/CognitiveServices"; + var w2v = require('word2vec'); +var assert = require('assert'); export class Recommender { @@ -10,6 +16,10 @@ export class Recommender { Recommender.Instance = this; } + /*** + * Loads pre-trained model from word2vec + */ + private loadModel(): Promise { let self = this; return new Promise(res => { @@ -20,6 +30,10 @@ export class Recommender { }); } + /*** + * Testing + */ + public async testModel() { if (!this._model) { await this.loadModel(); @@ -33,6 +47,10 @@ export class Recommender { } } + /*** + * Tests if instance exists + */ + public async testInstance(text: string) { if (!this._model) { await this.loadModel(); @@ -40,14 +58,21 @@ export class Recommender { console.log(text); } + /*** + * Uses model to convert words to vectors + */ + public async vectorize(text: string[]) { if (!this._model) { await this.loadModel(); } if (this._model) { let word_vecs = this._model.getVectors(text); - console.log(word_vecs[0]); return word_vecs; } } + + + + } -- cgit v1.2.3-70-g09d2 From 50d7ffb3303cf06ced84b9788b95578fff2e92da Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Wed, 7 Aug 2019 20:14:53 -0400 Subject: pivot viewer native code --- src/client/views/Main.tsx | 2 +- src/client/views/collections/CollectionView.tsx | 5 +- .../views/collections/CollectionViewChromes.tsx | 33 +++- .../collectionFreeForm/CollectionFreeFormView.tsx | 203 +++++++++++++++++---- 4 files changed, 205 insertions(+), 38 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index daa778ed3..8be633f80 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -34,7 +34,7 @@ let swapDocs = async () => { DocServer.init(window.location.protocol, window.location.hostname, 4321, info.email); await Docs.Prototypes.initialize(); await CurrentUserUtils.loadUserDocument(info); - await PivotView.loadLayouts(); + // await PivotView.loadLayouts(); // updates old user documents to prevent chrome on tree view. (await Cast(CurrentUserUtils.UserDocument.workspaces, Doc))!.chromeStatus = "disabled"; (await Cast(CurrentUserUtils.UserDocument.recentlyClosed, Doc))!.chromeStatus = "disabled"; diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 60ede17e7..7a402798e 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -89,8 +89,7 @@ export class CollectionView extends React.Component { subItems.push({ description: "Freeform", event: () => { this.props.Document.viewType = CollectionViewType.Freeform; - delete this.props.Document.arrangeInit; - delete this.props.Document.arrangeScript; + delete this.props.Document.usePivotLayout; }, icon: "signature" }); if (CollectionBaseView.InSafeMode()) { @@ -103,7 +102,7 @@ export class CollectionView extends React.Component { switch (this.props.Document.viewType) { case CollectionViewType.Freeform: { subItems.push({ description: "Custom", icon: "fingerprint", event: CollectionFreeFormView.AddCustomLayout(this.props.Document, this.props.fieldKey) }); - subItems.push({ description: "Pivot", icon: "copy", event: () => CollectionFreeFormView.SetPivotLayout(this.props.Document) }); + subItems.push({ description: "Pivot", icon: "copy", event: () => this.props.Document.usePivotLayout = true }); break; } } diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index 1b2561953..e1ac79da6 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -3,7 +3,7 @@ import { CollectionView } from "./CollectionView"; import "./CollectionViewChromes.scss"; import { CollectionViewType } from "./CollectionBaseView"; import { undoBatch } from "../../util/UndoManager"; -import { action, observable, runInAction, computed, IObservable, IObservableValue } from "mobx"; +import { action, observable, runInAction, computed, IObservable, IObservableValue, reaction, autorun } from "mobx"; import { observer } from "mobx-react"; import { Doc, DocListCast } from "../../../new_fields/Doc"; import { DocLike } from "../MetadataEntryMenu"; @@ -187,6 +187,36 @@ export class CollectionViewBaseChrome extends React.Component { + if (!this.document.usePivotLayout) { + return (null); + } + return () => this.pivotKeyDisplay = e.currentTarget.value)} + onKeyPress={action((e: React.KeyboardEvent) => { + let value = e.currentTarget.value; + if (e.which === 13) { + this.pivotKey = value; + this.pivotKeyDisplay = ""; + } + })} />); + } + render() { return (
@@ -219,6 +249,7 @@ export class CollectionViewBaseChrome extends React.Component { }} onPointerDown={this.openViewSpecs} /> + {this.getPivotInput()}
{ + let collection = target.Document; + const field = StrCast(collection.pivotField) || "title"; + const width = NumCast(collection.pivotWidth) || 200; + + const groups = new Map, Doc[]>(); + + for (const doc of target.childDocs) { + const val = doc[field]; + if (val === undefined) continue; + + const l = groups.get(val); + if (l) { + l.push(doc); + } else { + groups.set(val, [doc]); + } + + } + + let minSize = Infinity; + + groups.forEach((val, key) => { + minSize = Math.min(minSize, val.length); + }); + + const numCols = NumCast(collection.pivotNumColumns) || Math.ceil(Math.sqrt(minSize)); + const fontSize = NumCast(collection.pivotFontSize); + + const docMap = new Map(); + const groupNames: PivotData[] = []; + + let x = 0; + groups.forEach((val, key) => { + let y = 0; + let xCount = 0; + groupNames.push({ + type: "text", + text: String(key), + x, + y: width + 50, + width: width * 1.25 * numCols, + height: 100, fontSize: fontSize + }); + for (const doc of val) { + docMap.set(doc, { + x: x + xCount * width * 1.25, + y: -y, + width, + height: width + }); + xCount++; + if (xCount >= numCols) { + xCount = 0; + y += width * 1.25; + } + } + x += width * 1.25 * (numCols + 1); + }); + + let elements = target.viewDefsToJSX(groupNames); + let curPage = FieldValue(target.Document.curPage, -1); + + let docViews = target.childDocs.filter(doc => doc instanceof Doc).reduce((prev, doc) => { + var page = NumCast(doc.page, -1); + if ((Math.abs(Math.round(page) - Math.round(curPage)) < 3) || page === -1) { + let minim = BoolCast(doc.isMinimized); + if (minim === undefined || !minim) { + let defaultPosition = (): ViewDefBounds => { + return { + x: NumCast(doc.x), + y: NumCast(doc.y), + z: NumCast(doc.z), + width: NumCast(doc.width), + height: NumCast(doc.height) + }; + }; + const pos = docMap.get(doc) || defaultPosition(); + prev.push({ + ele: ( + ), + bounds: { + x: pos.x, + y: pos.y, + z: pos.z, + width: NumCast(pos.width), + height: NumCast(pos.height) + } + }); + } + } + return prev; + }, elements); + + target.resetSelectOnLoaded(); + + return docViews; + }; + } type PanZoomDocument = makeInterface<[typeof panZoomSchema, typeof positionSchema, typeof pageSchema]>; @@ -508,9 +638,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { return 1; } - getChildDocumentViewProps(childDocLayout: Doc): DocumentViewProps { - let self = this; let pair = Doc.GetLayoutDataDocPair(this.props.Document, this.props.DataDoc, this.props.fieldKey, childDocLayout); return { DataDoc: pair.data, @@ -569,7 +697,19 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { return result.result === undefined ? { x: Cast(doc.x, "number"), y: Cast(doc.y, "number"), z: Cast(doc.z, "number"), width: Cast(doc.width, "number"), height: Cast(doc.height, "number") } : result.result; } - private viewDefToJSX(viewDef: any): { ele: JSX.Element, bounds?: { x: number, y: number, z?: number, width: number, height: number } } | undefined { + viewDefsToJSX = (views: any[]) => { + let elements: ViewDefResult[] = []; + if (Array.isArray(views)) { + elements = views.reduce((prev, ele) => { + const jsx = this.viewDefToJSX(ele); + jsx && prev.push(jsx); + return prev; + }, elements); + } + return elements; + } + + private viewDefToJSX(viewDef: any): Opt { if (viewDef.type === "text") { const text = Cast(viewDef.text, "string"); const x = Cast(viewDef.x, "number"); @@ -598,20 +738,14 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { const script = this.Document.arrangeScript; let state: any = undefined; const docs = this.childDocs; - let elements: { ele: JSX.Element, bounds?: { x: number, y: number, z?: number, width: number, height: number } }[] = []; + let elements: ViewDefResult[] = []; if (initScript) { const initResult = initScript.script.run({ docs, collection: this.Document }); if (initResult.success) { const result = initResult.result; const { state: scriptState, views } = result; state = scriptState; - if (Array.isArray(views)) { - elements = views.reduce((prev, ele) => { - const jsx = this.viewDefToJSX(ele); - jsx && prev.push(jsx); - return prev; - }, elements); - } + elements = this.viewDefsToJSX(views); } } let docviews = docs.filter(doc => doc instanceof Doc).reduce((prev, doc) => { @@ -633,14 +767,17 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { return prev; }, elements); - setTimeout(() => this._selectOnLoaded = "", 600);// bcz: surely there must be a better way .... + this.resetSelectOnLoaded(); return docviews; } + resetSelectOnLoaded = () => setTimeout(() => this._selectOnLoaded = "", 600);// bcz: surely there must be a better way .... + @computed.struct get views() { - return this.elements.filter(ele => ele.bounds && !ele.bounds.z).map(ele => ele.ele); + let source = this.Document.usePivotLayout === true ? PivotView.elements(this) : this.elements; + return source.filter(ele => ele.bounds && !ele.bounds.z).map(ele => ele.ele); } @computed.struct get overlayViews() { @@ -798,22 +935,22 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { }; } - public static SetPivotLayout = (target: Doc) => { - let setSpecifiedLayoutField = (originalText: string, key: string, params: Record, requiredType?: string) => { - const script = CompileScript(originalText, { - params, - requiredType, - typecheck: false - }); - if (!script.compiled) { - console.log(script.errors.map(error => error.messageText).join("\n")); - return; - } - target[key] = new ScriptField(script); - }; - setSpecifiedLayoutField(PivotView.scripts.arrangeInit, "arrangeInit", { collection: "Doc", docs: "Doc[]" }, undefined); - setSpecifiedLayoutField(PivotView.scripts.arrangeScript, "arrangeScript", { doc: "Doc", index: "number", collection: "Doc", state: "any", docs: "Doc[]" }, "{x: number, y: number, width?: number, height?: number}"); - } + // public static SetPivotLayout = (target: Doc) => { + // let setSpecifiedLayoutField = (originalText: string, key: string, params: Record, requiredType?: string) => { + // const script = CompileScript(originalText, { + // params, + // requiredType, + // typecheck: false + // }); + // if (!script.compiled) { + // console.log(script.errors.map(error => error.messageText).join("\n")); + // return; + // } + // target[key] = new ScriptField(script); + // }; + // setSpecifiedLayoutField(PivotView.scripts.arrangeInit, "arrangeInit", { collection: "Doc", docs: "Doc[]" }, undefined); + // setSpecifiedLayoutField(PivotView.scripts.arrangeScript, "arrangeScript", { doc: "Doc", index: "number", collection: "Doc", state: "any", docs: "Doc[]" }, "{x: number, y: number, width?: number, height?: number}"); + // } render() { const easing = () => this.props.Document.panTransformType === "Ease"; -- cgit v1.2.3-70-g09d2 From 17f28e393e0c24fcace33a3ecd5564bc766fe685 Mon Sep 17 00:00:00 2001 From: ab Date: Thu, 8 Aug 2019 13:00:51 -0400 Subject: fuck you react --- src/client/ClientRecommender.ts | 101 -------------- src/client/ClientRecommender.tsx | 148 +++++++++++++++++++++ .../collectionFreeForm/CollectionFreeFormView.tsx | 4 +- src/server/Recommender.ts | 2 + 4 files changed, 153 insertions(+), 102 deletions(-) delete mode 100644 src/client/ClientRecommender.ts create mode 100644 src/client/ClientRecommender.tsx (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/ClientRecommender.ts b/src/client/ClientRecommender.ts deleted file mode 100644 index 7ff79ab50..000000000 --- a/src/client/ClientRecommender.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { Doc } from "../new_fields/Doc"; -import { StrCast } from "../new_fields/Types"; -import { List } from "../new_fields/List"; -import { CognitiveServices } from "./cognitive_services/CognitiveServices"; - - -var assert = require('assert'); - -export class ClientRecommender { - - static Instance: ClientRecommender; - private docVectors: Set; - - constructor() { - //console.log("creating client recommender..."); - ClientRecommender.Instance = this; - this.docVectors = new Set(); - } - - - /*** - * Computes the cosine similarity between two vectors in Euclidean space. - */ - - private distance(vector1: number[], vector2: number[]) { - assert(vector1.length === vector2.length, "Vectors are not the same length"); - var dotproduct = 0; - var mA = 0; - var mB = 0; - for (let i = 0; i < vector1.length; i++) { // here you missed the i++ - dotproduct += (vector1[i] * vector2[i]); - mA += (vector1[i] * vector1[i]); - mB += (vector2[i] * vector2[i]); - } - mA = Math.sqrt(mA); - mB = Math.sqrt(mB); - var similarity = (dotproduct) / ((mA) * (mB)); // here you needed extra brackets - return similarity; - } - - /*** - * Computes the mean of a set of vectors - */ - - public mean(paragraph: Set) { - const n = 200; - const num_words = paragraph.size; - let meanVector = new Array(n).fill(0); // mean vector - paragraph.forEach((wordvec: number[]) => { - for (let i = 0; i < n; i++) { - meanVector[i] += wordvec[i]; - } - }); - meanVector = meanVector.map(x => x / num_words); - this.addToDocSet(meanVector); - return meanVector; - } - - private addToDocSet(vector: number[]) { - if (this.docVectors) { - this.docVectors.add(vector); - } - } - - /*** - * Uses Cognitive Services to extract keywords from a document - */ - - public async extractText(dataDoc: Doc, extDoc: Doc) { - let data = StrCast(dataDoc.title); - //console.log(data); - let converter = (results: any) => { - let keyterms = new List(); - results.documents.forEach((doc: any) => { - let keyPhrases = doc.keyPhrases; - keyPhrases.map((kp: string) => keyterms.push(kp)); - }); - return keyterms; - }; - await CognitiveServices.Text.Manager.analyzer(extDoc, ["key words"], data, converter); - } - - /*** - * Creates distance matrix for all Documents analyzed - */ - - public createDistanceMatrix(documents: Set = this.docVectors) { - const documents_list = Array.from(documents); - const n = documents_list.length; - var matrix = new Array(n).fill(0).map(() => new Array(n).fill(0)); - for (let i = 0; i < n; i++) { - var doc1 = documents_list[i]; - for (let j = 0; j < n; j++) { - var doc2 = documents_list[j]; - matrix[i][j] = this.distance(doc1, doc2); - } - } - return matrix; - } - -} \ No newline at end of file diff --git a/src/client/ClientRecommender.tsx b/src/client/ClientRecommender.tsx new file mode 100644 index 000000000..2344ee490 --- /dev/null +++ b/src/client/ClientRecommender.tsx @@ -0,0 +1,148 @@ +import { Doc } from "../new_fields/Doc"; +import { StrCast } from "../new_fields/Types"; +import { List } from "../new_fields/List"; +import { CognitiveServices } from "./cognitive_services/CognitiveServices"; +import React = require("react"); +import { observer } from "mobx-react"; +import { observable, action, computed, reaction } from "mobx"; +var assert = require('assert'); +import Table from 'react-bootstrap/Table'; + +export interface RecommenderProps { + title: string; +} + +@observer +export class ClientRecommender extends React.Component { + + static Instance: ClientRecommender; + private docVectors: Set; + private corr_matrix = observable([[0, 0], [0, 0]]); + @observable private firstnum = 0; + //@observable private corr_matrix: number[][] = [[0, 0], [0, 0]]; + + constructor(props: RecommenderProps) { + //console.log("creating client recommender..."); + super(props); + ClientRecommender.Instance = this; + this.docVectors = new Set(); + //this.corr_matrix = [[0, 0], [0, 0]]; + } + + + /*** + * Computes the cosine similarity between two vectors in Euclidean space. + */ + + private distance(vector1: number[], vector2: number[]) { + assert(vector1.length === vector2.length, "Vectors are not the same length"); + var dotproduct = 0; + var mA = 0; + var mB = 0; + for (let i = 0; i < vector1.length; i++) { // here you missed the i++ + dotproduct += (vector1[i] * vector2[i]); + mA += (vector1[i] * vector1[i]); + mB += (vector2[i] * vector2[i]); + } + mA = Math.sqrt(mA); + mB = Math.sqrt(mB); + var similarity = (dotproduct) / ((mA) * (mB)); // here you needed extra brackets + return similarity; + } + + /*** + * Computes the mean of a set of vectors + */ + + public mean(paragraph: Set) { + const n = 200; + const num_words = paragraph.size; + let meanVector = new Array(n).fill(0); // mean vector + paragraph.forEach((wordvec: number[]) => { + for (let i = 0; i < n; i++) { + meanVector[i] += wordvec[i]; + } + }); + meanVector = meanVector.map(x => x / num_words); + this.addToDocSet(meanVector); + return meanVector; + } + + private addToDocSet(vector: number[]) { + if (this.docVectors) { + this.docVectors.add(vector); + } + } + + /*** + * Uses Cognitive Services to extract keywords from a document + */ + + public async extractText(dataDoc: Doc, extDoc: Doc) { + let data = StrCast(dataDoc.title); + //console.log(data); + let converter = (results: any) => { + let keyterms = new List(); + results.documents.forEach((doc: any) => { + let keyPhrases = doc.keyPhrases; + keyPhrases.map((kp: string) => keyterms.push(kp)); + }); + return keyterms; + }; + await CognitiveServices.Text.Manager.analyzer(extDoc, ["key words"], data, converter); + } + + /*** + * Creates distance matrix for all Documents analyzed + */ + + @action + public createDistanceMatrix(documents: Set = this.docVectors) { + //this.corr_matrix[0][0] = 500; + this.firstnum = 500; + const documents_list = Array.from(documents); + const n = documents_list.length; + var matrix = new Array(n).fill(0).map(() => new Array(n).fill(0)); + for (let i = 0; i < n; i++) { + var doc1 = documents_list[i]; + for (let j = 0; j < n; j++) { + var doc2 = documents_list[j]; + matrix[i][j] = this.distance(doc1, doc2); + } + } + //this.corr_matrix = matrix; + + return matrix; + } + + @computed get first_num() { + return this.firstnum; + } + + dumb_reaction = reaction( + () => this.first_num, + number => { + console.log("number has changed", number); + this.forceUpdate(); + } + ); + + render() { + return (
+

{this.props.title ? this.props.title : "hello"}

+ + + + + + + + + + + +
{this.first_num}{this.corr_matrix[0][1]}
{this.corr_matrix[1][0]}{this.corr_matrix[1][1]}
+
); + } + +} \ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 9344b43d2..5259b9b49 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -523,6 +523,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { super.setCursorPosition(this.getTransform().transformPoint(e.clientX, e.clientY)); } + @action onContextMenu = (e: React.MouseEvent) => { let layoutItems: ContextMenuProps[] = []; layoutItems.push({ @@ -600,7 +601,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { ContextMenu.Instance.addItem({ description: "Recommender System", event: async () => { - new ClientRecommender(); + // if (!ClientRecommender.Instance) new ClientRecommender({ title: "Client Recommender" }); let activedocs = this.getActiveDocuments(); await Promise.all(activedocs.map((doc: Doc) => { console.log(StrCast(doc.title)); @@ -715,6 +716,7 @@ class CollectionFreeFormViewPannableContents extends React.Component otherwise, reactions won't fire return
{this.props.children} +
; } } \ No newline at end of file diff --git a/src/server/Recommender.ts b/src/server/Recommender.ts index ea59703c3..d175b67c7 100644 --- a/src/server/Recommender.ts +++ b/src/server/Recommender.ts @@ -10,6 +10,7 @@ export class Recommender { private _model: any; static Instance: Recommender; + private dimension: number = 0; constructor() { console.log("creating recommender..."); @@ -25,6 +26,7 @@ export class Recommender { return new Promise(res => { w2v.loadModel("./node_modules/word2vec/vectors.txt", function (err: any, model: any) { self._model = model; + self.dimension = model.size; res(model); }); }); -- cgit v1.2.3-70-g09d2 From 116f218c2eeec377fb465027bcfaa7521d9af492 Mon Sep 17 00:00:00 2001 From: ab Date: Thu, 8 Aug 2019 17:48:58 -0400 Subject: euclidian --- src/client/ClientRecommender.scss | 8 ++ src/client/ClientRecommender.tsx | 100 +++++++++++++-------- .../collectionFreeForm/CollectionFreeFormView.tsx | 3 +- 3 files changed, 71 insertions(+), 40 deletions(-) create mode 100644 src/client/ClientRecommender.scss (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/ClientRecommender.scss b/src/client/ClientRecommender.scss new file mode 100644 index 000000000..710d80f34 --- /dev/null +++ b/src/client/ClientRecommender.scss @@ -0,0 +1,8 @@ +@import "/views/globalCssVariables.scss"; + +.space{ + border: 1px dashed blue; + border-spacing: 25px; + border-collapse: separate; + align-content: center; +} \ No newline at end of file diff --git a/src/client/ClientRecommender.tsx b/src/client/ClientRecommender.tsx index 2344ee490..0793f0887 100644 --- a/src/client/ClientRecommender.tsx +++ b/src/client/ClientRecommender.tsx @@ -6,7 +6,7 @@ import React = require("react"); import { observer } from "mobx-react"; import { observable, action, computed, reaction } from "mobx"; var assert = require('assert'); -import Table from 'react-bootstrap/Table'; +import "./ClientRecommender.scss"; export interface RecommenderProps { title: string; @@ -17,37 +17,53 @@ export class ClientRecommender extends React.Component { static Instance: ClientRecommender; private docVectors: Set; - private corr_matrix = observable([[0, 0], [0, 0]]); - @observable private firstnum = 0; - //@observable private corr_matrix: number[][] = [[0, 0], [0, 0]]; + @observable private corr_matrix = [[0, 0], [0, 0]]; constructor(props: RecommenderProps) { //console.log("creating client recommender..."); super(props); - ClientRecommender.Instance = this; + if (!ClientRecommender.Instance) ClientRecommender.Instance = this; this.docVectors = new Set(); //this.corr_matrix = [[0, 0], [0, 0]]; } + @action + public reset_docs() { + this.docVectors = new Set(); + this.corr_matrix = [[0, 0], [0, 0]]; + } /*** * Computes the cosine similarity between two vectors in Euclidean space. */ - private distance(vector1: number[], vector2: number[]) { + private distance(vector1: number[], vector2: number[], metric: string = "cosine") { assert(vector1.length === vector2.length, "Vectors are not the same length"); - var dotproduct = 0; - var mA = 0; - var mB = 0; - for (let i = 0; i < vector1.length; i++) { // here you missed the i++ - dotproduct += (vector1[i] * vector2[i]); - mA += (vector1[i] * vector1[i]); - mB += (vector2[i] * vector2[i]); + let similarity: number; + switch (metric) { + case "cosine": + var dotproduct = 0; + var mA = 0; + var mB = 0; + for (let i = 0; i < vector1.length; i++) { // here you missed the i++ + dotproduct += (vector1[i] * vector2[i]); + mA += (vector1[i] * vector1[i]); + mB += (vector2[i] * vector2[i]); + } + mA = Math.sqrt(mA); + mB = Math.sqrt(mB); + similarity = (dotproduct) / ((mA) * (mB)); // here you needed extra brackets + return similarity; + case "euclidian": + var sum = 0; + for (let i = 0; i < vector1.length; i++) { + sum += Math.pow(vector1[i] - vector2[i], 2); + } + similarity = Math.sqrt(sum); + return similarity; + default: + return 0; } - mA = Math.sqrt(mA); - mB = Math.sqrt(mB); - var similarity = (dotproduct) / ((mA) * (mB)); // here you needed extra brackets - return similarity; } /*** @@ -98,8 +114,6 @@ export class ClientRecommender extends React.Component { @action public createDistanceMatrix(documents: Set = this.docVectors) { - //this.corr_matrix[0][0] = 500; - this.firstnum = 500; const documents_list = Array.from(documents); const n = documents_list.length; var matrix = new Array(n).fill(0).map(() => new Array(n).fill(0)); @@ -107,40 +121,48 @@ export class ClientRecommender extends React.Component { var doc1 = documents_list[i]; for (let j = 0; j < n; j++) { var doc2 = documents_list[j]; - matrix[i][j] = this.distance(doc1, doc2); + matrix[i][j] = this.distance(doc1, doc2, "euclidian"); } } - //this.corr_matrix = matrix; - + this.corr_matrix = matrix; return matrix; } - @computed get first_num() { - return this.firstnum; - } - - dumb_reaction = reaction( - () => this.first_num, - number => { - console.log("number has changed", number); - this.forceUpdate(); + @computed + private get generateRows() { + const n = this.corr_matrix.length; + let rows: React.ReactElement[] = []; + for (let i = 0; i < n; i++) { + let children: React.ReactElement[] = []; + for (let j = 0; j < n; j++) { + let cell = React.createElement("td", this.corr_matrix[i][j]); + children.push(cell); + } + let row = React.createElement("tr", { children: children }); + rows.push(row); } - ); + return rows; + } render() { return (

{this.props.title ? this.props.title : "hello"}

- + {/*
- - - + + + - - - + + + +
{this.first_num}{this.corr_matrix[0][1]}
{this.corr_matrix[0][0].toFixed(4)}{this.corr_matrix[0][1].toFixed(4)}
{this.corr_matrix[1][0]}{this.corr_matrix[1][1]}
{this.corr_matrix[1][0].toFixed(4)}{this.corr_matrix[1][1].toFixed(4)}
*/} + + + {this.generateRows} +
); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 5259b9b49..2b9f32136 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -603,6 +603,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { event: async () => { // if (!ClientRecommender.Instance) new ClientRecommender({ title: "Client Recommender" }); let activedocs = this.getActiveDocuments(); + ClientRecommender.Instance.reset_docs(); await Promise.all(activedocs.map((doc: Doc) => { console.log(StrCast(doc.title)); const extdoc = doc.data_ext as Doc; @@ -716,7 +717,7 @@ class CollectionFreeFormViewPannableContents extends React.Component otherwise, reactions won't fire return
{this.props.children} - +
; } } \ No newline at end of file -- cgit v1.2.3-70-g09d2 From b8ab5a823ae22b021c09dfd713b77211a51b3eae Mon Sep 17 00:00:00 2001 From: ab Date: Fri, 9 Aug 2019 17:04:25 -0400 Subject: idk man --- solr-8.1.1/server/solr/dash/conf/schema.xml | 2 +- src/client/ClientRecommender.scss | 4 ++++ src/client/ClientRecommender.tsx | 17 ++++++++++------- src/client/util/SearchUtil.ts | 21 ++++++++++++++++++++- src/client/views/SearchBox.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 6 +++++- src/server/Search.ts | 2 +- 7 files changed, 42 insertions(+), 12 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/solr-8.1.1/server/solr/dash/conf/schema.xml b/solr-8.1.1/server/solr/dash/conf/schema.xml index 8610786af..c0a4bab07 100644 --- a/solr-8.1.1/server/solr/dash/conf/schema.xml +++ b/solr-8.1.1/server/solr/dash/conf/schema.xml @@ -52,7 +52,7 @@ - + diff --git a/src/client/ClientRecommender.scss b/src/client/ClientRecommender.scss index 710d80f34..49163cdc8 100644 --- a/src/client/ClientRecommender.scss +++ b/src/client/ClientRecommender.scss @@ -5,4 +5,8 @@ border-spacing: 25px; border-collapse: separate; align-content: center; +} + +.wrapper{ + text-align: -webkit-center; } \ No newline at end of file diff --git a/src/client/ClientRecommender.tsx b/src/client/ClientRecommender.tsx index 0793f0887..ddaa8a7fc 100644 --- a/src/client/ClientRecommender.tsx +++ b/src/client/ClientRecommender.tsx @@ -7,6 +7,7 @@ import { observer } from "mobx-react"; import { observable, action, computed, reaction } from "mobx"; var assert = require('assert'); import "./ClientRecommender.scss"; +import { JSXElement } from "babel-types"; export interface RecommenderProps { title: string; @@ -131,22 +132,24 @@ export class ClientRecommender extends React.Component { @computed private get generateRows() { const n = this.corr_matrix.length; - let rows: React.ReactElement[] = []; + let rows: JSX.Element[] = []; for (let i = 0; i < n; i++) { - let children: React.ReactElement[] = []; + let children: JSX.Element[] = []; for (let j = 0; j < n; j++) { - let cell = React.createElement("td", this.corr_matrix[i][j]); + //let cell = React.createElement("td", this.corr_matrix[i][j]); + let cell = {this.corr_matrix[i][j].toFixed(4)}; children.push(cell); } - let row = React.createElement("tr", { children: children }); + //let row = React.createElement("tr", { children: children, key: i }); + let row = {children}; rows.push(row); } return rows; } render() { - return (
-

{this.props.title ? this.props.title : "hello"}

+ return (
+

{this.props.title ? this.props.title : "hello"}

{/* @@ -159,7 +162,7 @@ export class ClientRecommender extends React.Component {
*/} - +
{this.generateRows} diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts index ee5a83710..3a3ba1803 100644 --- a/src/client/util/SearchUtil.ts +++ b/src/client/util/SearchUtil.ts @@ -77,4 +77,23 @@ export namespace SearchUtil { aliasContexts.forEach(result => contexts.aliasContexts.push(...result.ids)); return contexts; } -} \ No newline at end of file + + export async function GetAllDocs() { + const query = "*"; + let response = await rp.get(Utils.prepend('/search'), { + qs: { + query + } + }); + let res: string[] = JSON.parse(response); + const fields = await DocServer.GetRefFields(res); + const docs: Doc[] = []; + for (const id of res) { + const field = fields[id]; + if (field instanceof Doc) { + docs.push(field); + } + } + return docs; + } +} diff --git a/src/client/views/SearchBox.tsx b/src/client/views/SearchBox.tsx index 33cb63df5..17f99fa05 100644 --- a/src/client/views/SearchBox.tsx +++ b/src/client/views/SearchBox.tsx @@ -47,7 +47,7 @@ export class SearchBox extends React.Component { } @action - getResults = async (query: string) => { + public getResults = async (query: string) => { let response = await rp.get(Utils.prepend('/search'), { qs: { query diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 2b9f32136..0beb0086b 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -38,6 +38,8 @@ import { MarqueeView } from "./MarqueeView"; import React = require("react"); import v5 = require("uuid/v5"); import { ClientRecommender } from "../../../ClientRecommender"; +import { SearchUtil } from "../../../util/SearchUtil"; +import { SearchBox } from "../../SearchBox"; library.add(faEye, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt, faCompass, faUpload, faBrain); @@ -603,9 +605,11 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { event: async () => { // if (!ClientRecommender.Instance) new ClientRecommender({ title: "Client Recommender" }); let activedocs = this.getActiveDocuments(); + let allDocs = await SearchUtil.GetAllDocs(); + allDocs.forEach(doc => console.log(doc.title)); ClientRecommender.Instance.reset_docs(); await Promise.all(activedocs.map((doc: Doc) => { - console.log(StrCast(doc.title)); + //console.log(StrCast(doc.title)); const extdoc = doc.data_ext as Doc; return ClientRecommender.Instance.extractText(doc, extdoc ? extdoc : doc); })); diff --git a/src/server/Search.ts b/src/server/Search.ts index 723dc101b..44c1b1298 100644 --- a/src/server/Search.ts +++ b/src/server/Search.ts @@ -14,7 +14,7 @@ export class Search { }); return res; } catch (e) { - // console.warn("Search error: " + e + document); + console.warn("Search error: " + e + document); } } -- cgit v1.2.3-70-g09d2 From 9dd2a31b72e5e527e2dae3b68f856ab8da879e93 Mon Sep 17 00:00:00 2001 From: ab Date: Mon, 12 Aug 2019 16:41:23 -0400 Subject: documentation --- package.json | 2 +- src/client/ClientRecommender.tsx | 18 +++++----- src/client/cognitive_services/CognitiveServices.ts | 42 ++++++++++++---------- src/client/util/SearchUtil.ts | 13 ++++--- .../collectionFreeForm/CollectionFreeFormView.tsx | 1 + src/server/Recommender.ts | 1 + 6 files changed, 45 insertions(+), 32 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/package.json b/package.json index 1e2c74411..1c7a10ac8 100644 --- a/package.json +++ b/package.json @@ -225,4 +225,4 @@ "xoauth2": "^1.2.0", "youtube": "^0.1.0" } -} \ No newline at end of file +} diff --git a/src/client/ClientRecommender.tsx b/src/client/ClientRecommender.tsx index ddaa8a7fc..63f85c737 100644 --- a/src/client/ClientRecommender.tsx +++ b/src/client/ClientRecommender.tsx @@ -75,13 +75,15 @@ export class ClientRecommender extends React.Component { const n = 200; const num_words = paragraph.size; let meanVector = new Array(n).fill(0); // mean vector - paragraph.forEach((wordvec: number[]) => { - for (let i = 0; i < n; i++) { - meanVector[i] += wordvec[i]; - } - }); - meanVector = meanVector.map(x => x / num_words); - this.addToDocSet(meanVector); + if (num_words > 0) { // check to see if paragraph actually was vectorized + paragraph.forEach((wordvec: number[]) => { + for (let i = 0; i < n; i++) { + meanVector[i] += wordvec[i]; + } + }); + meanVector = meanVector.map(x => x / num_words); + this.addToDocSet(meanVector); + } return meanVector; } @@ -106,7 +108,7 @@ export class ClientRecommender extends React.Component { }); return keyterms; }; - await CognitiveServices.Text.Manager.analyzer(extDoc, ["key words"], data, converter); + await CognitiveServices.Text.Appliers.analyzer(extDoc, ["key words"], data, converter); } /*** diff --git a/src/client/cognitive_services/CognitiveServices.ts b/src/client/cognitive_services/CognitiveServices.ts index 954a05585..75d0760ed 100644 --- a/src/client/cognitive_services/CognitiveServices.ts +++ b/src/client/cognitive_services/CognitiveServices.ts @@ -258,32 +258,38 @@ export namespace CognitiveServices { }; console.log("requested!"); return request.post(options); - }, - analyzer: async (target: Doc, keys: string[], data: string, converter: Converter) => { - let results = await ExecuteQuery(Service.Text, Manager, data); + } + }; + + export namespace Appliers { + + export async function vectorize(keyterms: any) { + console.log("vectorizing..."); + //keyterms = ["father", "king"]; + let args = { method: 'POST', uri: Utils.prepend("/recommender"), body: { keyphrases: keyterms }, json: true }; + await requestPromise.post(args).then(async (wordvecs) => { + var vectorValues = new Set(); + wordvecs.forEach((wordvec: any) => { + //console.log(wordvec.word); + vectorValues.add(wordvec.values as number[]); + }); + ClientRecommender.Instance.mean(vectorValues); + //console.log(vectorValues.size); + }); + } + + export const analyzer = async (target: Doc, keys: string[], data: string, converter: Converter) => { + let results = await ExecuteQuery(Service.Text, Manager, data); console.log(results); let keyterms = converter(results); //target[keys[0]] = Docs.Get.DocumentHierarchyFromJson(results, "Key Word Analysis"); target[keys[0]] = keyterms; console.log("analyzed!"); await vectorize(keyterms); - } - }; - async function vectorize(keyterms: any) { - console.log("vectorizing..."); - //keyterms = ["father", "king"]; - let args = { method: 'POST', uri: Utils.prepend("/recommender"), body: { keyphrases: keyterms }, json: true }; - await requestPromise.post(args).then(async (wordvecs) => { - var vectorValues = new Set(); - wordvecs.forEach((wordvec: any) => { - //console.log(wordvec.word); - vectorValues.add(wordvec.values as number[]); - }); - ClientRecommender.Instance.mean(vectorValues); - //console.log(vectorValues.size); - }); + }; } } + } \ No newline at end of file diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts index 3a3ba1803..1fce995d7 100644 --- a/src/client/util/SearchUtil.ts +++ b/src/client/util/SearchUtil.ts @@ -82,18 +82,21 @@ export namespace SearchUtil { const query = "*"; let response = await rp.get(Utils.prepend('/search'), { qs: { - query + q: query } }); - let res: string[] = JSON.parse(response); - const fields = await DocServer.GetRefFields(res); + let result: IdSearchResult = JSON.parse(response); + const { ids, numFound, highlighting } = result; + const docMap = await DocServer.GetRefFields(ids); const docs: Doc[] = []; - for (const id of res) { - const field = fields[id]; + for (const id of ids) { + const field = docMap[id]; if (field instanceof Doc) { docs.push(field); } } return docs; + // const docs = ids.map((id: string) => docMap[id]).filter((doc: any) => doc instanceof Doc); + // return docs as Doc[]; } } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index e9791df4e..d1e8031fd 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -894,6 +894,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { let activedocs = this.getActiveDocuments(); let allDocs = await SearchUtil.GetAllDocs(); allDocs.forEach(doc => console.log(doc.title)); + // clears internal representation of documents as vectors ClientRecommender.Instance.reset_docs(); await Promise.all(activedocs.map((doc: Doc) => { //console.log(StrCast(doc.title)); diff --git a/src/server/Recommender.ts b/src/server/Recommender.ts index d175b67c7..1c95d7ea4 100644 --- a/src/server/Recommender.ts +++ b/src/server/Recommender.ts @@ -70,6 +70,7 @@ export class Recommender { } if (this._model) { let word_vecs = this._model.getVectors(text); + return word_vecs; } } -- cgit v1.2.3-70-g09d2