From bd6b9c40f150fab76e8907c45e29fa809f9acae0 Mon Sep 17 00:00:00 2001 From: usodhi <61431818+usodhi@users.noreply.github.com> Date: Fri, 2 Apr 2021 19:04:09 -0400 Subject: dashboard sharing initial setup, inherits acls from dashboard - looks like it works --- src/client/documents/Documents.ts | 4 ++-- src/client/util/CurrentUserUtils.ts | 20 +++++++++++++++----- src/client/views/DocComponent.tsx | 10 ++++++---- src/fields/Doc.ts | 9 ++++++++- src/fields/util.ts | 15 ++++++++++++++- 5 files changed, 45 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index f02298f36..2a679ec95 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -836,8 +836,8 @@ export namespace Docs { return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { schemaHeaders: new List(schemaHeaders), ...options, _viewType: CollectionViewType.Schema }); } - export function TreeDocument(documents: Array, options: DocumentOptions, id?: string) { - return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { ...options, _viewType: CollectionViewType.Tree }, id); + export function TreeDocument(documents: Array, options: DocumentOptions, id?: string, protoId?: string) { + return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { ...options, _viewType: CollectionViewType.Tree }, id, undefined, protoId); } export function StackingDocument(documents: Array, options: DocumentOptions, id?: string, protoId?: string) { diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 849020392..f1357e3d7 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -35,6 +35,7 @@ import { UndoManager } from "./UndoManager"; import { SnappingManager } from "./SnappingManager"; import { InkTool } from "../../fields/InkField"; import { computedFn } from "mobx-utils"; +import { SharingManager } from "./SharingManager"; export let resolvedPorts: { server: number, socket: number }; @@ -907,9 +908,9 @@ export class CurrentUserUtils { if (doc.mySharedDocs === undefined) { let sharedDocs = Docs.newAccount ? undefined : await DocServer.GetRefField(sharingDocumentId + "outer"); if (!sharedDocs) { - sharedDocs = Docs.Create.StackingDocument([], { - title: "My SharedDocs", childDropAction: "alias", system: true, contentPointerEvents: "none", childLimitHeight: 0, _yMargin: 50, _gridGap: 15, - _showTitle: "title", ignoreClick: true, _lockedPosition: true, "acl-Public": SharingPermissions.Add, "_acl-Public": SharingPermissions.Add, _chromeHidden: true, + sharedDocs = Docs.Create.TreeDocument([], { + title: "My SharedDocs", childDropAction: "alias", system: true, contentPointerEvents: "all", childLimitHeight: 0, _yMargin: 50, _gridGap: 15, + _showTitle: "title", ignoreClick: false, _lockedPosition: true, "acl-Public": SharingPermissions.Add, "_acl-Public": SharingPermissions.Add, _chromeHidden: true, }, sharingDocumentId + "outer", sharingDocumentId); (sharedDocs as Doc)["acl-Public"] = (sharedDocs as Doc)[DataSym]["acl-Public"] = SharingPermissions.Add; } @@ -1188,8 +1189,10 @@ export class CurrentUserUtils { const toggleComic = ScriptField.MakeScript(`toggleComicMode()`); const snapshotDashboard = ScriptField.MakeScript(`snapshotDashboard()`); const createDashboard = ScriptField.MakeScript(`createNewDashboard()`); - dashboardDoc.contextMenuScripts = new List([toggleTheme!, toggleComic!, snapshotDashboard!, createDashboard!]); - dashboardDoc.contextMenuLabels = new List(["Toggle Theme Colors", "Toggle Comic Mode", "Snapshot Dashboard", "Create Dashboard"]); + const shareDashboard = ScriptField.MakeScript(`shareDashboard()`); + const addToDashboards = ScriptField.MakeScript(`addToDashboards(self)`); + dashboardDoc.contextMenuScripts = new List([toggleTheme!, toggleComic!, snapshotDashboard!, createDashboard!, shareDashboard!, addToDashboards!]); + dashboardDoc.contextMenuLabels = new List(["Toggle Theme Colors", "Toggle Comic Mode", "Snapshot Dashboard", "Create Dashboard", "Share Dashboard", "Add to Dashboards"]); Doc.AddDocToList(dashboards, "data", dashboardDoc); CurrentUserUtils.openDashboard(userDoc, dashboardDoc); @@ -1241,3 +1244,10 @@ Scripting.addGlobal(function links(doc: any) { return new List(LinkManager.Insta "returns all the links to the document or its annotations", "(doc: any)"); Scripting.addGlobal(function importDocument() { return CurrentUserUtils.importDocument(); }, "imports files from device directly into the import sidebar"); +Scripting.addGlobal(function shareDashboard() { + CurrentUserUtils.ActiveDashboard.isShared = true; + SharingManager.Instance.open(undefined, CurrentUserUtils.ActiveDashboard); +}, + "opens sharing dialog for Dashboard"); +Scripting.addGlobal(function addToDashboards(dashboard: Doc) { Doc.AddDocToList(CurrentUserUtils.MyDashboards, "data", dashboard); }, + "adds Dashboard to set of Dashboards"); \ No newline at end of file diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index 90449ab6c..447daeb02 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -7,7 +7,7 @@ import { InteractionUtils } from '../util/InteractionUtils'; import { List } from '../../fields/List'; import { DateField } from '../../fields/DateField'; import { ScriptField } from '../../fields/ScriptField'; -import { GetEffectiveAcl, SharingPermissions, distributeAcls, denormalizeEmail } from '../../fields/util'; +import { GetEffectiveAcl, SharingPermissions, distributeAcls, denormalizeEmail, inheritParentAcls } from '../../fields/util'; import { CurrentUserUtils } from '../util/CurrentUserUtils'; import { DocUtils } from '../documents/Documents'; import { returnFalse } from '../../Utils'; @@ -198,15 +198,15 @@ export function ViewBoxAnnotatableComponent

{ for (const [key, value] of Object.entries(this.props.Document[AclSym])) { - if (d.author === denormalizeEmail(key.substring(4)) && !d.aliasOf) distributeAcls(key, SharingPermissions.Admin, d, true); - //else if (this.props.Document[key] === SharingPermissions.Admin) distributeAcls(key, SharingPermissions.Add, d, true); - // else distributeAcls(key, this.AclMap.get(value) as SharingPermissions, d, true); + if (d.author === denormalizeEmail(key.substring(4)) && !d.aliasOf) distributeAcls(key, SharingPermissions.Admin, d); } }); } if (effectiveAcl === AclAddonly) { added.map(doc => { + + if ([AclAdmin, AclEdit].includes(GetEffectiveAcl(doc))) inheritParentAcls(CurrentUserUtils.ActiveDashboard, doc); doc.context = this.props.Document; if (annotationKey ?? this._annotationKey) Doc.GetProto(doc).annotationOn = this.props.Document; this.props.layerProvider?.(doc, true); @@ -220,6 +220,8 @@ export function ViewBoxAnnotatableComponent

; if (annoDocs) annoDocs.push(...added); diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 5b3e21e34..b37c2fdfe 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -22,8 +22,9 @@ import { listSpec } from "./Schema"; import { ComputedField, ScriptField } from "./ScriptField"; import { Cast, FieldValue, NumCast, StrCast, ToConstructor } from "./Types"; import { AudioField, ImageField, PdfField, VideoField, WebField } from "./URLField"; -import { deleteProperty, GetEffectiveAcl, getField, getter, makeEditable, makeReadOnly, normalizeEmail, setter, SharingPermissions, updateFunction } from "./util"; +import { deleteProperty, getField, getter, inheritParentAcls, makeEditable, makeReadOnly, normalizeEmail, setter, SharingPermissions, updateFunction } from "./util"; import JSZip = require("jszip"); +import { CurrentUserUtils } from "../client/util/CurrentUserUtils"; export namespace Field { export function toKeyValueString(doc: Doc, key: string): string { @@ -424,6 +425,9 @@ export namespace Doc { return Array.from(results); } + /** + * @returns the index of doc toFind in list of docs, -1 otherwise + */ export function IndexOf(toFind: Doc, list: Doc[], allowProtos: boolean = true) { let index = list.reduce((p, v, i) => (v instanceof Doc && v === toFind) ? i : p, -1); index = allowProtos && index !== -1 ? index : list.reduce((p, v, i) => (v instanceof Doc && Doc.AreProtosEqual(v, toFind)) ? i : p, -1); @@ -1148,6 +1152,9 @@ export namespace Doc { dragFactory["dragFactory-count"] = NumCast(dragFactory["dragFactory-count"]) + 1; Doc.SetInPlace(ndoc, "title", ndoc.title + " " + NumCast(dragFactory["dragFactory-count"]).toString(), true); } + + if (ndoc) inheritParentAcls(CurrentUserUtils.ActiveDashboard, ndoc); + return ndoc; } export function delegateDragFactory(dragFactory: Doc) { diff --git a/src/fields/util.ts b/src/fields/util.ts index ea91cc057..a4c99928a 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -131,6 +131,19 @@ export function denormalizeEmail(email: string) { // playgroundMode = !playgroundMode; // } + +/** + * Copies parent's acl fields to the child + */ +export function inheritParentAcls(parent: Doc, child: Doc) { + if (parent.isShared) { + const dataDoc = parent[DataSym]; + for (const key of Object.keys(dataDoc)) { + key.startsWith("acl") && distributeAcls(key, dataDoc[key], child); + } + } +} + /** * These are the various levels of access a user can have to a document. * @@ -245,7 +258,7 @@ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc dataDocChanged = true; } - // maps over the aliases of the document + // maps over the links of the document const links = DocListCast(dataDoc.links); links.forEach(link => distributeAcls(key, acl, link, inheritingFromCollection, visited)); -- cgit v1.2.3-70-g09d2 From d252d6dba8b789215ed8da5b66889a26b06a2a18 Mon Sep 17 00:00:00 2001 From: usodhi <61431818+usodhi@users.noreply.github.com> Date: Sat, 3 Apr 2021 20:13:58 -0400 Subject: dashboard sharing works, aliases to go --- src/client/util/CurrentUserUtils.ts | 7 +++---- src/client/util/SharingManager.tsx | 24 +++++++++++++++++++++++- src/client/views/PropertiesView.tsx | 2 +- src/fields/Doc.ts | 2 +- 4 files changed, 28 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index f1357e3d7..fdceb60f3 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -1189,7 +1189,7 @@ export class CurrentUserUtils { const toggleComic = ScriptField.MakeScript(`toggleComicMode()`); const snapshotDashboard = ScriptField.MakeScript(`snapshotDashboard()`); const createDashboard = ScriptField.MakeScript(`createNewDashboard()`); - const shareDashboard = ScriptField.MakeScript(`shareDashboard()`); + const shareDashboard = ScriptField.MakeScript(`shareDashboard(self)`); const addToDashboards = ScriptField.MakeScript(`addToDashboards(self)`); dashboardDoc.contextMenuScripts = new List([toggleTheme!, toggleComic!, snapshotDashboard!, createDashboard!, shareDashboard!, addToDashboards!]); dashboardDoc.contextMenuLabels = new List(["Toggle Theme Colors", "Toggle Comic Mode", "Snapshot Dashboard", "Create Dashboard", "Share Dashboard", "Add to Dashboards"]); @@ -1244,9 +1244,8 @@ Scripting.addGlobal(function links(doc: any) { return new List(LinkManager.Insta "returns all the links to the document or its annotations", "(doc: any)"); Scripting.addGlobal(function importDocument() { return CurrentUserUtils.importDocument(); }, "imports files from device directly into the import sidebar"); -Scripting.addGlobal(function shareDashboard() { - CurrentUserUtils.ActiveDashboard.isShared = true; - SharingManager.Instance.open(undefined, CurrentUserUtils.ActiveDashboard); +Scripting.addGlobal(function shareDashboard(dashboard: Doc) { + SharingManager.Instance.open(undefined, dashboard); }, "opens sharing dialog for Dashboard"); Scripting.addGlobal(function addToDashboards(dashboard: Doc) { Doc.AddDocToList(CurrentUserUtils.MyDashboards, "data", dashboard); }, diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx index ded56d1da..ca14154b2 100644 --- a/src/client/util/SharingManager.tsx +++ b/src/client/util/SharingManager.tsx @@ -5,7 +5,7 @@ import { observer } from "mobx-react"; import * as React from "react"; import Select from "react-select"; import * as RequestPromise from "request-promise"; -import { AclAddonly, AclAdmin, AclEdit, AclPrivate, AclReadonly, AclSym, DataSym, Doc, DocListCast, DocListCastAsync, Opt } from "../../fields/Doc"; +import { AclAddonly, AclAdmin, AclEdit, AclPrivate, AclReadonly, AclSym, AclUnset, DataSym, Doc, DocListCast, DocListCastAsync, Opt } from "../../fields/Doc"; import { List } from "../../fields/List"; import { Cast, StrCast } from "../../fields/Types"; import { distributeAcls, GetEffectiveAcl, normalizeEmail, SharingPermissions, TraceMobx } from "../../fields/util"; @@ -17,6 +17,7 @@ import { MainViewModal } from "../views/MainViewModal"; import { DocumentView } from "../views/nodes/DocumentView"; import { TaskCompletionBox } from "../views/nodes/TaskCompletedBox"; import { SearchBox } from "../views/search/SearchBox"; +import { CurrentUserUtils } from "./CurrentUserUtils"; import { DocumentManager } from "./DocumentManager"; import { GroupManager, UserOptions } from "./GroupManager"; import { GroupMemberView } from "./GroupMemberView"; @@ -170,6 +171,7 @@ export class SharingManager extends React.Component<{}> { doc.author === Doc.CurrentUserEmail && !doc[myAcl] && distributeAcls(myAcl, SharingPermissions.Admin, doc); distributeAcls(acl, permission as SharingPermissions, doc); + this.setDashboardBackground(doc, permission as SharingPermissions); if (permission !== SharingPermissions.None) return Doc.AddDocToList(sharingDoc, storage, doc); else return GetEffectiveAcl(doc, user.email) === AclPrivate && Doc.RemoveDocFromList(sharingDoc, storage, (doc.aliasOf as Doc || doc)); }).some(success => !success); @@ -192,6 +194,7 @@ export class SharingManager extends React.Component<{}> { return !docs.map(doc => { doc.author === Doc.CurrentUserEmail && !doc[`acl-${Doc.CurrentUserEmailNormalized}`] && distributeAcls(`acl-${Doc.CurrentUserEmailNormalized}`, SharingPermissions.Admin, doc); distributeAcls(acl, permission as SharingPermissions, doc); + this.setDashboardBackground(doc, permission as SharingPermissions); if (group instanceof Doc) { const members: string[] = JSON.parse(StrCast(group.members)); @@ -246,6 +249,25 @@ export class SharingManager extends React.Component<{}> { } } + /** + * Sets the background of the Dashboard if it has been shared as a visual indicator + */ + setDashboardBackground = async (doc: Doc, permission: SharingPermissions) => { + if (Doc.IndexOf(doc, DocListCast(CurrentUserUtils.MyDashboards.data)) !== -1) { + if (permission !== SharingPermissions.None) { + doc.isShared = true; + doc.backgroundColor = "green"; + } + else { + const acls = doc[DataSym][AclSym]; + if (Object.keys(acls).every(key => key === `acl-${Doc.CurrentUserEmailNormalized}` ? true : [AclUnset, AclPrivate].includes(acls[key]))) { + doc.isShared = undefined; + doc.backgroundColor = undefined; + } + } + } + } + /** * Removes the documents shared with a user through a group when the user is removed from the group. * @param group diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index c8ce8bfeb..0fc6c75d0 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -400,7 +400,7 @@ export class PropertiesView extends React.Component { const showAdmin = effectiveAcls.every(acl => acl === AclAdmin); // users in common between all docs - const commonKeys = intersection(...docs.map(doc => this.layoutDocAcls ? doc?.[AclSym] && Object.keys(doc[AclSym]) : doc?.[DataSym][AclSym] && Object.keys(doc[DataSym][AclSym]))); + const commonKeys: string[] = intersection(...docs.map(doc => this.layoutDocAcls ? doc?.[AclSym] && Object.keys(doc[AclSym]) : doc?.[DataSym][AclSym] && Object.keys(doc[DataSym][AclSym]))); const tableEntries = []; diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index b37c2fdfe..1719a6445 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -22,7 +22,7 @@ import { listSpec } from "./Schema"; import { ComputedField, ScriptField } from "./ScriptField"; import { Cast, FieldValue, NumCast, StrCast, ToConstructor } from "./Types"; import { AudioField, ImageField, PdfField, VideoField, WebField } from "./URLField"; -import { deleteProperty, getField, getter, inheritParentAcls, makeEditable, makeReadOnly, normalizeEmail, setter, SharingPermissions, updateFunction } from "./util"; +import { deleteProperty, GetEffectiveAcl, getField, getter, inheritParentAcls, makeEditable, makeReadOnly, normalizeEmail, setter, SharingPermissions, updateFunction } from "./util"; import JSZip = require("jszip"); import { CurrentUserUtils } from "../client/util/CurrentUserUtils"; -- cgit v1.2.3-70-g09d2 From b901d5b16b6a4d53d7975a318017dc9630966abf Mon Sep 17 00:00:00 2001 From: usodhi <61431818+usodhi@users.noreply.github.com> Date: Sat, 3 Apr 2021 22:24:34 -0400 Subject: made dashboard option visible --- src/client/views/search/SearchBox.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index 5c168d8a9..4cbdd622f 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -530,7 +530,7 @@ export class SearchBox extends ViewBoxBaseComponent

CurrentUserUtils.createNewDashboard(Doc.UserDoc()))}> New -- cgit v1.2.3-70-g09d2 From a80143dca8309463af954d09ec1e6d30aa6e3fd1 Mon Sep 17 00:00:00 2001 From: usodhi <61431818+usodhi@users.noreply.github.com> Date: Sat, 3 Apr 2021 22:32:58 -0400 Subject: revised previous --- src/client/views/search/SearchBox.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index 4cbdd622f..d3a023ec9 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -530,7 +530,7 @@ export class SearchBox extends ViewBoxBaseComponent
CurrentUserUtils.createNewDashboard(Doc.UserDoc()))}> New -- cgit v1.2.3-70-g09d2 From 0bc38e1ca78a5a2ee21d99ef511f2f744d8c67bb Mon Sep 17 00:00:00 2001 From: usodhi <61431818+usodhi@users.noreply.github.com> Date: Sun, 4 Apr 2021 01:55:12 -0400 Subject: added datadoc print to console --- src/client/views/nodes/DocumentView.tsx | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 26cf52f17..3870cbed0 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -740,6 +740,7 @@ export class DocumentViewInternal extends DocComponent this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "add:right"), icon: "layer-group" }); helpItems.push({ description: "Text Shortcuts Ctrl+/", event: () => this.props.addDocTab(Docs.Create.PdfDocument(Utils.prepend("/assets/cheat-sheet.pdf"), { _width: 300, _height: 300 }), "add:right"), icon: "keyboard" }); !Doc.UserDoc().novice && helpItems.push({ description: "Print Document in Console", event: () => console.log(this.props.Document), icon: "hand-point-right" }); + !Doc.UserDoc().novice && helpItems.push({ description: "Print DataDoc in Console", event: () => console.log(this.props.Document[DataSym]), icon: "hand-point-right" }); cm.addItem({ description: "Help...", noexpand: true, subitems: helpItems, icon: "question" }); if (!this.topMost) e?.stopPropagation(); // DocumentViews should stop propagation of this event -- cgit v1.2.3-70-g09d2 From 95a42c92c9b4b2af8703afe85ece4e32975a3047 Mon Sep 17 00:00:00 2001 From: usodhi <61431818+usodhi@users.noreply.github.com> Date: Tue, 13 Apr 2021 10:39:36 -0400 Subject: typos and minor changes --- src/client/DocServer.ts | 2 +- src/client/util/CurrentUserUtils.ts | 1 - src/fields/Doc.ts | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index 1d7497cf8..59278d2af 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -225,7 +225,7 @@ export namespace DocServer { * the server if the document has not been cached. * @param id the id of the requested document */ - const _GetRefFieldImpl = (id: string, force: boolean = false): Promise> => { + const _GetRefFieldImpl = async (id: string, force: boolean = false): Promise> => { // an initial pass through the cache to determine whether the document needs to be fetched, // is already in the process of being fetched or already exists in the // cache diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index b7c2d60d8..86f563b7e 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -516,7 +516,6 @@ export class CurrentUserUtils { { title: "Import", target: Cast(doc.myImportPanel, Doc, null), icon: "upload", click: 'selectMainMenu(self)' }, { title: "Recently Closed", target: Cast(doc.myRecentlyClosedDocs, Doc, null), icon: "archive", click: 'selectMainMenu(self)' }, { title: "Sharing", target: Cast(doc.mySharedDocs, Doc, null), icon: "users", click: 'selectMainMenu(self)', watchedDocuments: doc.mySharedDocs as Doc }, - // { title: "Filter", target: Cast(doc.currentFilter, Doc, null), icon: "filter", click: 'selectMainMenu(self)' }, { title: "Pres. Trails", target: Cast(doc.myPresentations, Doc, null), icon: "pres-trail", click: 'selectMainMenu(self)' }, { title: "Help", target: undefined as any, icon: "question-circle", click: 'selectMainMenu(self)' }, { title: "Settings", target: undefined as any, icon: "cog", click: 'selectMainMenu(self)' }, diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 30e8b60bd..478334038 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -539,7 +539,7 @@ export namespace Doc { const clones = await Promise.all(docs.map(async d => Doc.makeClone(d, cloneMap, rtfs, exclusions, dontCreate, asBranch))); !dontCreate && assignKey(new List(clones)); } else if (doc[key] instanceof Doc) { - assignKey(key.includes("layout[") ? undefined : key.startsWith("layout") ? doc[key] as Doc : await Doc.makeClone(doc[key] as Doc, cloneMap, rtfs, exclusions, dontCreate, asBranch)); // reference documents except copy documents that are expanded teplate fields + assignKey(key.includes("layout[") ? undefined : key.startsWith("layout") ? doc[key] as Doc : await Doc.makeClone(doc[key] as Doc, cloneMap, rtfs, exclusions, dontCreate, asBranch)); // reference documents except copy documents that are expanded template fields } else { !dontCreate && assignKey(ObjectField.MakeCopy(field)); if (field instanceof RichTextField) { @@ -562,7 +562,7 @@ export namespace Doc { } else if (field instanceof ObjectField) { await copyObjectField(field); } else if (field instanceof Promise) { - debugger; //This shouldn't happend... + debugger; //This shouldn't happen... } else { assignKey(field); } -- cgit v1.2.3-70-g09d2 From 2e76877dc1c9c5b1c226f5bd0394d17cabfec0b4 Mon Sep 17 00:00:00 2001 From: usodhi <61431818+usodhi@users.noreply.github.com> Date: Mon, 17 May 2021 18:01:44 -0400 Subject: trying dynamic off screen docs --- src/client/documents/Documents.ts | 20 ++++++++-- src/client/util/CurrentUserUtils.ts | 33 ++++++++++++++--- src/client/util/SharingManager.tsx | 40 ++++++++++++-------- .../views/collections/CollectionDockingView.tsx | 43 ++++++++++++++-------- src/client/views/collections/TreeView.tsx | 9 ++++- src/fields/util.ts | 18 +++++---- 6 files changed, 115 insertions(+), 48 deletions(-) (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 1e2919bad..906603d78 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -648,8 +648,9 @@ export namespace Docs { * constructor just generates a new GUID. This is currently used * only when creating a DockDocument from the current user's already existing * main document. + * @param layoutData whether the fieldKey field on the layout doc should store the data or the data doc */ - function InstanceFromProto(proto: Doc, data: Field | undefined, options: DocumentOptions, delegId?: string, fieldKey: string = "data", protoId?: string) { + function InstanceFromProto(proto: Doc, data: Field | undefined, options: DocumentOptions, delegId?: string, fieldKey: string = "data", protoId?: string, layoutData?: boolean) { const viewKeys = ["x", "y", "system"]; // keys that should be addded to the view document even though they don't begin with an "_" const { omit: dataProps, extract: viewProps } = OmitKeys(options, viewKeys, "^_"); @@ -660,7 +661,17 @@ export namespace Docs { dataProps[`${fieldKey}-lastModified`] = new DateField; dataProps["acl-Override"] = "None"; dataProps["acl-Public"] = Doc.UserDoc()?.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Add; - dataProps[fieldKey] = data; + + if (layoutData) { + viewProps[fieldKey] = data; + const list = new List(); + console.log(DocListCast(data)); + DocListCast(data).forEach(doc => { + list.push(...DocListCast(doc.data)); + }); + dataProps[fieldKey + "-all"] = list; + } + else dataProps[fieldKey] = data; // so that the list of annotations is already initialised, prevents issues in addonly. // without this, if a doc has no annotations but the user has AddOnly privileges, they won't be able to add an annotation because they would have needed to create the field's list which they don't have permissions to do. dataProps[fieldKey + "-annotations"] = new List(); @@ -891,7 +902,7 @@ export namespace Docs { export function DockDocument(documents: Array, config: string, options: DocumentOptions, id?: string) { const tabs = TreeDocument(documents, { title: "On-Screen Tabs", childDontRegisterViews: true, freezeChildren: "remove|add", treeViewExpandedViewLock: true, treeViewExpandedView: "data", _fitWidth: true, system: true }); const all = TreeDocument([], { title: "Off-Screen Tabs", childDontRegisterViews: true, freezeChildren: "add", treeViewExpandedViewLock: true, treeViewExpandedView: "data", system: true }); - return InstanceFromProto(Prototypes.get(DocumentType.COL), new List([tabs, all]), { freezeChildren: "remove|add", treeViewExpandedViewLock: true, treeViewExpandedView: "data", ...options, _viewType: CollectionViewType.Docking, dockingConfig: config }, id); + return InstanceFromProto(Prototypes.get(DocumentType.COL), new List([tabs, all]), { freezeChildren: "remove|add", treeViewExpandedViewLock: true, treeViewExpandedView: "data", ...options, _viewType: CollectionViewType.Docking, dockingConfig: config }, id, undefined, undefined, true); } export function DirectoryImportDocument(options: DocumentOptions = {}) { @@ -1426,4 +1437,7 @@ Scripting.addGlobal(function generateLinkTitle(self: Doc) { const anchor2title = self.anchor2 && self.anchor2 !== self ? Cast(self.anchor2, Doc, null).title : ""; const relation = self.linkRelationship || "to"; return `${anchor1title} (${relation}) ${anchor2title}`; +}); +Scripting.addGlobal(function openTabAlias(tab: Doc) { + CollectionDockingView.AddSplit(Doc.MakeAlias(tab), "right"); }); \ No newline at end of file diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 5dbded00e..6fdf649a4 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -750,7 +750,7 @@ export class CurrentUserUtils { title: "My Dashboards", _height: 400, childHideLinkButton: true, treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, _forceActive: true, childDropAction: "alias", treeViewTruncateTitleWidth: 150, ignoreClick: true, - _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", system: true + _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", treeViewType: "fileSystem", isFolder: true, system: true })); const newDashboard = ScriptField.MakeScript(`createNewDashboard(Doc.UserDoc())`); (doc.myDashboards as any as Doc).contextMenuScripts = new List([newDashboard!]); @@ -851,7 +851,6 @@ export class CurrentUserUtils { CurrentUserUtils.setupPresentations(doc); CurrentUserUtils.setupFilesystem(doc); CurrentUserUtils.setupRecentlyClosedDocs(doc); - // CurrentUserUtils.setupFilterDocs(doc); CurrentUserUtils.setupUserDoc(doc); } @@ -1186,7 +1185,11 @@ export class CurrentUserUtils { title: `Untitled Tab ${NumCast(emptyPane["dragFactory-count"])}`, }; const freeformDoc = CurrentUserUtils.GuestTarget || Docs.Create.FreeformDocument([], freeformOptions); - const dashboardDoc = Docs.Create.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600 }], { title: `Dashboard ${dashboardCount}` }, id, "row"); + const dashboardDoc = Docs.Create.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600 }], { title: `Dashboard ${dashboardCount}` }, id, "row"); // add isFolder:true here? + freeformDoc.context = dashboardDoc; + + DocListCast(dashboardDoc.data)[1].data = ComputedField.MakeFunction(`dynamicOffScreenDocs(dashboardDoc)`, { dashboardDoc: Doc.name }, { dashboardDoc }) as any; + Doc.AddDocToList(myPresentations, "data", presentation); userDoc.activePresentation = presentation; const toggleTheme = ScriptField.MakeScript(`self.darkScheme = !self.darkScheme`); @@ -1252,7 +1255,25 @@ Scripting.addGlobal(function shareDashboard(dashboard: Doc) { SharingManager.Instance.open(undefined, dashboard); }, "opens sharing dialog for Dashboard"); -Scripting.addGlobal(function addToDashboards(dashboard: Doc) { Doc.AddDocToList(CurrentUserUtils.MyDashboards, "data", dashboard); }, +Scripting.addGlobal(function addToDashboards(dashboard: Doc) { + const dashboardAlias = Doc.MakeAlias(dashboard); + dashboardAlias.data = new List(DocListCast(dashboard.data).map(tabFolder => Doc.MakeAlias(tabFolder))); + // DocListCast(dashboardAlias.data).forEach(tabFolder => { + // tabFolder.data = new List(DocListCast(tabFolder.data).map(tab => Doc.MakeAlias(tab))); + // }); + Doc.AddDocToList(CurrentUserUtils.MyDashboards, "data", dashboardAlias); + CurrentUserUtils.openDashboard(Doc.UserDoc(), dashboardAlias); +}, "adds Dashboard to set of Dashboards"); -Scripting.addGlobal(function toggleComicMode() { Doc.UserDoc().renderStyle = Doc.UserDoc().renderStyle === "comic" ? undefined : "comic"; }, - "toggle between regular rendeing and an informal sketch/comic style"); + +Scripting.addGlobal(function dynamicOffScreenDocs(dashboard: Doc) { + const allDocs = DocListCast(dashboard[DataSym]["data-all"]); + console.log(allDocs); + const onScreenTab = DocListCast(dashboard.data)[0]; + const onScreenDocs = DocListCast(onScreenTab.data); + return allDocs.reduce((result: Doc[], doc) => { + !onScreenDocs.includes(doc) && (result.push(doc)); + // console.log(doc); + return result; + }, []); +}); diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx index 2f8ecd4ee..18f254cd6 100644 --- a/src/client/util/SharingManager.tsx +++ b/src/client/util/SharingManager.tsx @@ -173,10 +173,14 @@ export class SharingManager extends React.Component<{}> { const target = targetDoc || this.targetDoc!; const acl = `acl-${normalizeEmail(user.email)}`; const myAcl = `acl-${Doc.CurrentUserEmailNormalized}`; + console.log(DocListCast(CurrentUserUtils.MyDashboards.data)); + console.log(target); + console.log(DocListCast(CurrentUserUtils.MyDashboards.data).indexOf(target)); + const isDashboard = DocListCast(CurrentUserUtils.MyDashboards.data).indexOf(target) !== -1; const docs = SelectionManager.Views().length < 2 ? [target] : SelectionManager.Views().map(docView => docView.props.Document); return !docs.map(doc => { - doc.author === Doc.CurrentUserEmail && !doc[myAcl] && distributeAcls(myAcl, SharingPermissions.Admin, doc); + doc.author === Doc.CurrentUserEmail && !doc[myAcl] && distributeAcls(myAcl, SharingPermissions.Admin, doc, undefined, undefined, isDashboard); if (permission === SharingPermissions.None) { if (doc[acl] && doc[acl] !== SharingPermissions.None) doc.numUsersShared = NumCast(doc.numUsersShared, 1) - 1; @@ -185,7 +189,7 @@ export class SharingManager extends React.Component<{}> { if (!doc[acl] || doc[acl] === SharingPermissions.None) doc.numUsersShared = NumCast(doc.numUsersShared, 0) + 1; } - distributeAcls(acl, permission as SharingPermissions, doc); + distributeAcls(acl, permission as SharingPermissions, doc, undefined, undefined, isDashboard); this.setDashboardBackground(doc, permission as SharingPermissions); if (permission !== SharingPermissions.None) return Doc.AddDocToList(sharingDoc, storage, doc); @@ -203,12 +207,13 @@ export class SharingManager extends React.Component<{}> { const target = targetDoc || this.targetDoc!; const key = normalizeEmail(StrCast(group.title)); const acl = `acl-${key}`; + const isDashboard = DocListCast(CurrentUserUtils.MyDashboards.data).indexOf(target) !== -1; const docs = SelectionManager.Views().length < 2 ? [target] : SelectionManager.Views().map(docView => docView.props.Document); // ! ensures it returns true if document has been shared successfully, false otherwise return !docs.map(doc => { - doc.author === Doc.CurrentUserEmail && !doc[`acl-${Doc.CurrentUserEmailNormalized}`] && distributeAcls(`acl-${Doc.CurrentUserEmailNormalized}`, SharingPermissions.Admin, doc); + doc.author === Doc.CurrentUserEmail && !doc[`acl-${Doc.CurrentUserEmailNormalized}`] && distributeAcls(`acl-${Doc.CurrentUserEmailNormalized}`, SharingPermissions.Admin, doc, undefined, undefined, isDashboard); if (permission === SharingPermissions.None) { if (doc[acl] && doc[acl] !== SharingPermissions.None) doc.numGroupsShared = NumCast(doc.numGroupsShared, 1) - 1; @@ -217,7 +222,7 @@ export class SharingManager extends React.Component<{}> { if (!doc[acl] || doc[acl] === SharingPermissions.None) doc.numGroupsShared = NumCast(doc.numGroupsShared, 0) + 1; } - distributeAcls(acl, permission as SharingPermissions, doc); + distributeAcls(acl, permission as SharingPermissions, doc, undefined, undefined, isDashboard); this.setDashboardBackground(doc, permission as SharingPermissions); if (group instanceof Doc) { @@ -267,8 +272,10 @@ export class SharingManager extends React.Component<{}> { }); } else { + const dashboards = DocListCast(CurrentUserUtils.MyDashboards.data); docs.forEach(doc => { - if (GetEffectiveAcl(doc) === AclAdmin) distributeAcls(`acl-${shareWith}`, permission, doc); + const isDashboard = dashboards.indexOf(doc) !== -1; + if (GetEffectiveAcl(doc) === AclAdmin) distributeAcls(`acl-${shareWith}`, permission, doc, undefined, undefined, isDashboard); }); } } @@ -316,10 +323,11 @@ export class SharingManager extends React.Component<{}> { */ removeGroup = (group: Doc) => { if (group.docsShared) { + const dashboards = DocListCast(CurrentUserUtils.MyDashboards.data); DocListCast(group.docsShared).forEach(doc => { const acl = `acl-${StrCast(group.title)}`; - - distributeAcls(acl, SharingPermissions.None, doc); + const isDashboard = dashboards.indexOf(doc) !== -1; + distributeAcls(acl, SharingPermissions.None, doc, undefined, undefined, isDashboard); const members: string[] = JSON.parse(StrCast(group.members)); const users: ValidatedUser[] = this.users.filter(({ user: { email } }) => members.includes(email)); @@ -445,16 +453,16 @@ export class SharingManager extends React.Component<{}> { } } - distributeOverCollection = (targetDoc?: Doc) => { - const target = targetDoc || this.targetDoc!; + // distributeOverCollection = (targetDoc?: Doc) => { + // const target = targetDoc || this.targetDoc!; - const docs = SelectionManager.Views().length < 2 ? [target] : SelectionManager.Views().map(docView => docView.props.Document); - docs.forEach(doc => { - for (const [key, value] of Object.entries(doc[AclSym])) { - distributeAcls(key, this.AclMap.get(value)! as SharingPermissions, target); - } - }); - } + // const docs = SelectionManager.Views().length < 2 ? [target] : SelectionManager.Views().map(docView => docView.props.Document); + // docs.forEach(doc => { + // for (const [key, value] of Object.entries(doc[AclSym])) { + // distributeAcls(key, this.AclMap.get(value)! as SharingPermissions, target); + // } + // }); + // } /** * Sorting algorithm to sort users. diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 388f9a909..819667834 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -4,7 +4,7 @@ import { action, IReactionDisposer, observable, reaction, runInAction } from "mo import { observer } from "mobx-react"; import * as ReactDOM from 'react-dom'; import * as GoldenLayout from "../../../client/goldenLayout"; -import { Doc, DocListCast, Opt, DocListCastAsync } from "../../../fields/Doc"; +import { Doc, DocListCast, Opt, DocListCastAsync, DataSym } from "../../../fields/Doc"; import { Id } from '../../../fields/FieldSymbols'; import { InkTool } from '../../../fields/InkField'; import { List } from '../../../fields/List'; @@ -24,6 +24,7 @@ import React = require("react"); import { DocumentType } from '../../documents/DocumentTypes'; import { listSpec } from '../../../fields/Schema'; import { LightboxView } from '../LightboxView'; +import { inheritParentAcls } from '../../../fields/util'; const _global = (window /* browser */ || global /* node */) as any; @observer @@ -160,6 +161,7 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) { } const instance = CollectionDockingView.Instance; if (!instance) return false; + else Doc.AddDocToList(instance.props.Document[DataSym], "data-all", document); const docContentConfig = CollectionDockingView.makeDocumentConfig(document, panelName); if (!pullSide && stack) { @@ -381,15 +383,22 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) { setTimeout(async () => { const sublists = await DocListCastAsync(this.props.Document[this.props.fieldKey]); const tabs = sublists && Cast(sublists[0], Doc, null); - const other = sublists && Cast(sublists[1], Doc, null); + // const other = sublists && Cast(sublists[1], Doc, null); const tabdocs = await DocListCastAsync(tabs?.data); - const otherdocs = await DocListCastAsync(other?.data); - tabs && (Doc.GetProto(tabs).data = new List(docs)); - const otherSet = new Set(); - otherdocs?.filter(doc => !docs.includes(doc)).forEach(doc => otherSet.add(doc)); - tabdocs?.filter(doc => !docs.includes(doc) && doc.type !== DocumentType.KVP).forEach(doc => otherSet.add(doc)); - const vals = Array.from(otherSet.values()).filter(val => val instanceof Doc).map(d => d).filter(d => d.type !== DocumentType.KVP); - other && (Doc.GetProto(other).data = new List(vals)); + // const otherdocs = await DocListCastAsync(other?.data); + if (tabs) { + tabs.data = new List(docs); + // DocListCast(tabs.aliases).forEach(tab => tab !== tabs && (tab.data = new List(docs))); + } + // const otherSet = new Set(); + // otherdocs?.filter(doc => !docs.includes(doc)).forEach(doc => otherSet.add(doc)); + // tabdocs?.filter(doc => !docs.includes(doc) && doc.type !== DocumentType.KVP).forEach(doc => otherSet.add(doc)); + // const vals = Array.from(otherSet.values()).filter(val => val instanceof Doc).map(d => d).filter(d => d.type !== DocumentType.KVP); + // this.props.Document[DataSym][this.props.fieldKey + "-all"] = new List([...docs, ...vals]); + // if (other) { + // other.data = new List(vals); + // // DocListCast(other.aliases).forEach(tab => tab !== other && (tab.data = new List(vals))); + // } }, 0); } @@ -399,7 +408,7 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) { tab.reactComponents?.forEach((ele: any) => ReactDOM.unmountComponentAtNode(ele)); } tabCreated = (tab: any) => { - tab.contentItem.element[0]?.firstChild?.firstChild?.InitTab?.(tab); // have to explicitly initialize tabs that reuse contents from previous abs (ie, when dragging a tab around a new tab is created for the old content) + tab.contentItem.element[0]?.firstChild?.firstChild?.InitTab?.(tab); // have to explicitly initialize tabs that reuse contents from previous tabs (ie, when dragging a tab around a new tab is created for the old content) } stackCreated = (stack: any) => { @@ -407,9 +416,11 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) { if (e.target === stack.header?.element[0] && e.button === 2) { const emptyPane = CurrentUserUtils.EmptyPane; emptyPane["dragFactory-count"] = NumCast(emptyPane["dragFactory-count"]) + 1; - CollectionDockingView.AddSplit(Docs.Create.FreeformDocument([], { - _width: this.props.PanelWidth(), _height: this.props.PanelHeight(), _fitWidth: true, title: `Untitled Tab ${NumCast(emptyPane["dragFactory-count"])}` - }), "", stack); + const docToAdd = Docs.Create.FreeformDocument([], { + _width: this.props.PanelWidth(), _height: this.props.PanelHeight(), _fitWidth: true, title: `Untitled Tab ${NumCast(emptyPane["dragFactory-count"])}`, + }); + this.props.Document.isShared && inheritParentAcls(this.props.Document, docToAdd); + CollectionDockingView.AddSplit(docToAdd, "", stack); } }); @@ -430,9 +441,11 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) { // stack.config.fixed = !stack.config.fixed; // force the stack to have a fixed size const emptyPane = CurrentUserUtils.EmptyPane; emptyPane["dragFactory-count"] = NumCast(emptyPane["dragFactory-count"]) + 1; - CollectionDockingView.AddSplit(Docs.Create.FreeformDocument([], { + const docToAdd = Docs.Create.FreeformDocument([], { _width: this.props.PanelWidth(), _height: this.props.PanelHeight(), _fitWidth: true, title: `Untitled Tab ${NumCast(emptyPane["dragFactory-count"])}` - }), "", stack); + }); + this.props.Document.isShared && inheritParentAcls(this.props.Document, docToAdd); + CollectionDockingView.AddSplit(docToAdd, "", stack); })); } diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 2e98fb508..ba4af2a6d 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -151,7 +151,10 @@ export class TreeView extends React.Component { this.treeViewOpen = !this.treeViewOpen; } else { // choose an appropriate alias or make one. --- choose the first alias that (1) user owns, (2) has no context field ... otherwise make a new alias + // this.props.addDocTab(CurrentUserUtils.ActiveDashboard.isShared ? Doc.MakeAlias(this.props.document) : this.props.document, "add:right"); + // choose an appropriate alias or make one -- -- choose the first alias that (1) the user owns, (2) has no context field - if I own it and someone else does not have it open,, otherwise create an alias this.props.addDocTab(this.props.document, "add:right"); + } } constructor(props: any) { @@ -507,7 +510,11 @@ export class TreeView extends React.Component { [{ script: ScriptField.MakeFunction(`DocFocusOrOpen(self)`)!, label: "Focus or Open" }]; } onChildClick = () => this.props.onChildClick?.() ?? (this._editTitleScript?.() || ScriptCast(this.doc.treeChildClick)); - onChildDoubleClick = () => (!this.props.treeView.outlineMode && this._openScript?.()) || ScriptCast(this.doc.treeChildDoubleClick); + + onChildDoubleClick = () => { + console.log(this.props.document.onChildDoubleClick); + return (!this.props.treeView.outlineMode && this._openScript?.()) || ScriptCast(this.doc.treeChildDoubleClick) + }; refocus = () => this.props.treeView.props.focus(this.props.treeView.props.Document); ignoreEvent = (e: any) => { diff --git a/src/fields/util.ts b/src/fields/util.ts index a4c99928a..882c7fee8 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -136,11 +136,9 @@ export function denormalizeEmail(email: string) { * Copies parent's acl fields to the child */ export function inheritParentAcls(parent: Doc, child: Doc) { - if (parent.isShared) { - const dataDoc = parent[DataSym]; - for (const key of Object.keys(dataDoc)) { - key.startsWith("acl") && distributeAcls(key, dataDoc[key], child); - } + const dataDoc = parent[DataSym]; + for (const key of Object.keys(dataDoc)) { + key.startsWith("acl") && distributeAcls(key, dataDoc[key], child); } } @@ -228,7 +226,7 @@ function getEffectiveAcl(target: any, user?: string): symbol { * @param inheritingFromCollection whether the target is being assigned rights after being dragged into a collection (and so is inheriting the acls from the collection) * inheritingFromCollection is not currently being used but could be used if acl assignment defaults change */ -export function distributeAcls(key: string, acl: SharingPermissions, target: Doc, inheritingFromCollection?: boolean, visited?: Doc[]) { +export function distributeAcls(key: string, acl: SharingPermissions, target: Doc, inheritingFromCollection?: boolean, visited?: Doc[], isDashboard?: boolean) { if (!visited) visited = [] as Doc[]; if (visited.includes(target)) return; visited.push(target); @@ -249,6 +247,12 @@ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc if (GetEffectiveAcl(target) === AclAdmin && (!inheritingFromCollection || !target[key] || HierarchyMapping.get(StrCast(target[key]))! > HierarchyMapping.get(acl)!)) { target[key] = acl; layoutDocChanged = true; + + if (isDashboard) { + DocListCast(target[Doc.LayoutFieldKey(target)]).forEach(d => { + distributeAcls(key, acl, d, inheritingFromCollection, visited); + }); + } } if (dataDoc && (!inheritingFromCollection || !dataDoc[key] || HierarchyMapping.get(StrCast(dataDoc[key]))! > HierarchyMapping.get(acl)!)) { @@ -263,7 +267,7 @@ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc links.forEach(link => distributeAcls(key, acl, link, inheritingFromCollection, visited)); // maps over the children of the document - DocListCast(dataDoc[Doc.LayoutFieldKey(dataDoc)]).map(d => { + DocListCast(dataDoc[Doc.LayoutFieldKey(dataDoc) + (isDashboard ? "-all" : "")]).map(d => { // this is now on the layoutdoc instead - figure out the "data-all" approach for the datadoc // if (GetEffectiveAcl(d) === AclAdmin && (!inheritingFromCollection || !d[key] || HierarchyMapping.get(StrCast(d[key]))! > HierarchyMapping.get(acl)!)) { distributeAcls(key, acl, d, inheritingFromCollection, visited); // } -- cgit v1.2.3-70-g09d2 From 7c18243dd38656b63334f48d9270d912ce6384fa Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 17 May 2021 18:45:01 -0400 Subject: fixes for offscreen tabs --- src/client/util/CurrentUserUtils.ts | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 6fdf649a4..a8327ae93 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -1187,8 +1187,8 @@ export class CurrentUserUtils { const freeformDoc = CurrentUserUtils.GuestTarget || Docs.Create.FreeformDocument([], freeformOptions); const dashboardDoc = Docs.Create.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600 }], { title: `Dashboard ${dashboardCount}` }, id, "row"); // add isFolder:true here? freeformDoc.context = dashboardDoc; - - DocListCast(dashboardDoc.data)[1].data = ComputedField.MakeFunction(`dynamicOffScreenDocs(dashboardDoc)`, { dashboardDoc: Doc.name }, { dashboardDoc }) as any; + DocListCast(dashboardDoc.data).forEach(doc => doc.dashboard = dashboardDoc); + DocListCast(dashboardDoc.data)[1].data = ComputedField.MakeFunction(`dynamicOffScreenDocs(self.dashboard)`) as any; Doc.AddDocToList(myPresentations, "data", presentation); userDoc.activePresentation = presentation; @@ -1267,13 +1267,16 @@ Scripting.addGlobal(function addToDashboards(dashboard: Doc) { "adds Dashboard to set of Dashboards"); Scripting.addGlobal(function dynamicOffScreenDocs(dashboard: Doc) { - const allDocs = DocListCast(dashboard[DataSym]["data-all"]); - console.log(allDocs); - const onScreenTab = DocListCast(dashboard.data)[0]; - const onScreenDocs = DocListCast(onScreenTab.data); - return allDocs.reduce((result: Doc[], doc) => { - !onScreenDocs.includes(doc) && (result.push(doc)); - // console.log(doc); - return result; - }, []); + if (dashboard[DataSym] instanceof Doc) { + const allDocs = DocListCast(dashboard[DataSym]["data-all"]); + console.log(allDocs); + const onScreenTab = DocListCast(dashboard.data)[0]; + const onScreenDocs = DocListCast(onScreenTab.data); + return new List(allDocs.reduce((result: Doc[], doc) => { + !onScreenDocs.includes(doc) && (result.push(doc)); + // console.log(doc); + return result; + }, [])); + } + return []; }); -- cgit v1.2.3-70-g09d2 From 77c16aa9f00a9d1b5e31ddf5a68d56f183f13691 Mon Sep 17 00:00:00 2001 From: usodhi <61431818+usodhi@users.noreply.github.com> Date: Thu, 20 May 2021 12:47:46 -0400 Subject: dashboard sharing, aliases now work? needs more testing --- src/client/util/CurrentUserUtils.ts | 19 +++++++++++++------ .../views/collections/CollectionDockingView.tsx | 6 +++++- 2 files changed, 18 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index a8327ae93..e143887fa 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -1255,12 +1255,20 @@ Scripting.addGlobal(function shareDashboard(dashboard: Doc) { SharingManager.Instance.open(undefined, dashboard); }, "opens sharing dialog for Dashboard"); -Scripting.addGlobal(function addToDashboards(dashboard: Doc) { +Scripting.addGlobal(async function addToDashboards(dashboard: Doc) { const dashboardAlias = Doc.MakeAlias(dashboard); + const dockingConfig = JSON.parse(StrCast(dashboardAlias.dockingConfig)); + dockingConfig.content = []; + dashboardAlias.dockingConfig = JSON.stringify(dockingConfig); + + const allDocs = await DocListCastAsync(dashboard[DataSym]["data-all"]); + + dashboardAlias["data-all"] = new List((allDocs || []).map(doc => Doc.MakeAlias(doc))); + dashboardAlias.data = new List(DocListCast(dashboard.data).map(tabFolder => Doc.MakeAlias(tabFolder))); - // DocListCast(dashboardAlias.data).forEach(tabFolder => { - // tabFolder.data = new List(DocListCast(tabFolder.data).map(tab => Doc.MakeAlias(tab))); - // }); + DocListCast(dashboardAlias.data).forEach(doc => doc.dashboard = dashboardAlias); + DocListCast(dashboardAlias.data)[0].data = new List(); + DocListCast(dashboardAlias.data)[1].data = ComputedField.MakeFunction(`dynamicOffScreenDocs(self.dashboard)`) as any; Doc.AddDocToList(CurrentUserUtils.MyDashboards, "data", dashboardAlias); CurrentUserUtils.openDashboard(Doc.UserDoc(), dashboardAlias); }, @@ -1268,13 +1276,12 @@ Scripting.addGlobal(function addToDashboards(dashboard: Doc) { Scripting.addGlobal(function dynamicOffScreenDocs(dashboard: Doc) { if (dashboard[DataSym] instanceof Doc) { - const allDocs = DocListCast(dashboard[DataSym]["data-all"]); + const allDocs = DocListCast(dashboard["data-all"]); console.log(allDocs); const onScreenTab = DocListCast(dashboard.data)[0]; const onScreenDocs = DocListCast(onScreenTab.data); return new List(allDocs.reduce((result: Doc[], doc) => { !onScreenDocs.includes(doc) && (result.push(doc)); - // console.log(doc); return result; }, [])); } diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 819667834..235fe8950 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -161,7 +161,11 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) { } const instance = CollectionDockingView.Instance; if (!instance) return false; - else Doc.AddDocToList(instance.props.Document[DataSym], "data-all", document); + else { + const docList = DocListCast(instance.props.Document[DataSym]["data-all"]); + !docList.includes(document) && !docList.includes(document.aliasOf as Doc) && Doc.AddDocToList(instance.props.Document[DataSym], "data-all", document); + DocListCast(instance.props.Document[DataSym]["aliases"]).forEach(alias => !alias.aliasOf && alias !== instance.props.Document && Doc.AddDocToList(alias, "data-all", Doc.MakeAlias(document))); + } const docContentConfig = CollectionDockingView.makeDocumentConfig(document, panelName); if (!pullSide && stack) { -- cgit v1.2.3-70-g09d2 From 64dbd28badac3e0689ea38d92e4f6c660967ccce Mon Sep 17 00:00:00 2001 From: usodhi <61431818+usodhi@users.noreply.github.com> Date: Sun, 30 May 2021 17:27:31 -0400 Subject: cleanup --- src/client/views/collections/TreeView.tsx | 1 - src/fields/util.ts | 8 +++----- 2 files changed, 3 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index ba4af2a6d..fc4361935 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -512,7 +512,6 @@ export class TreeView extends React.Component { onChildClick = () => this.props.onChildClick?.() ?? (this._editTitleScript?.() || ScriptCast(this.doc.treeChildClick)); onChildDoubleClick = () => { - console.log(this.props.document.onChildDoubleClick); return (!this.props.treeView.outlineMode && this._openScript?.()) || ScriptCast(this.doc.treeChildDoubleClick) }; diff --git a/src/fields/util.ts b/src/fields/util.ts index 882c7fee8..f0cc20d74 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -267,23 +267,21 @@ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc links.forEach(link => distributeAcls(key, acl, link, inheritingFromCollection, visited)); // maps over the children of the document - DocListCast(dataDoc[Doc.LayoutFieldKey(dataDoc) + (isDashboard ? "-all" : "")]).map(d => { // this is now on the layoutdoc instead - figure out the "data-all" approach for the datadoc - // if (GetEffectiveAcl(d) === AclAdmin && (!inheritingFromCollection || !d[key] || HierarchyMapping.get(StrCast(d[key]))! > HierarchyMapping.get(acl)!)) { + DocListCast(dataDoc[Doc.LayoutFieldKey(dataDoc) + (isDashboard ? "-all" : "")]).map(d => { distributeAcls(key, acl, d, inheritingFromCollection, visited); // } const data = d[DataSym]; - if (data) {// && GetEffectiveAcl(data) === AclAdmin && (!inheritingFromCollection || !data[key] || HierarchyMapping.get(StrCast(data[key]))! > HierarchyMapping.get(acl)!)) { + if (data) { distributeAcls(key, acl, data, inheritingFromCollection, visited); } }); // maps over the annotations of the document DocListCast(dataDoc[Doc.LayoutFieldKey(dataDoc) + "-annotations"]).map(d => { - // if (GetEffectiveAcl(d) === AclAdmin && (!inheritingFromCollection || !d[key] || HierarchyMapping.get(StrCast(d[key]))! > HierarchyMapping.get(acl)!)) { distributeAcls(key, acl, d, inheritingFromCollection, visited); // } const data = d[DataSym]; - if (data) {// && GetEffectiveAcl(data) === AclAdmin && (!inheritingFromCollection || !data[key] || HierarchyMapping.get(StrCast(data[key]))! > HierarchyMapping.get(acl)!)) { + if (data) { distributeAcls(key, acl, data, inheritingFromCollection, visited); } }); -- cgit v1.2.3-70-g09d2 From 7a31b05aa21d5cf99fac1ad031ab745266ca3fda Mon Sep 17 00:00:00 2001 From: usodhi <61431818+usodhi@users.noreply.github.com> Date: Sun, 30 May 2021 18:03:31 -0400 Subject: sharingmanagaer cleanup --- src/client/util/SharingManager.tsx | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx index 18f254cd6..db23941c7 100644 --- a/src/client/util/SharingManager.tsx +++ b/src/client/util/SharingManager.tsx @@ -39,7 +39,7 @@ interface GroupedOptions { } // const SharingKey = "sharingPermissions"; -// const PublicKey = "publicLinkPermissions"; +// const PublicKey = "all"; // const DefaultColor = "black"; // used to differentiate between individuals and groups when sharing @@ -91,7 +91,7 @@ export class SharingManager extends React.Component<{}> { ]); // private get linkVisible() { - // return this.sharingDoc ? this.sharingDoc[PublicKey] !== SharingPermissions.None : false; + // return this.targetDoc ? this.targetDoc["acl-" + PublicKey] !== SharingPermissions.None : false; // } public open = (target?: DocumentView, target_doc?: Doc) => { @@ -173,9 +173,6 @@ export class SharingManager extends React.Component<{}> { const target = targetDoc || this.targetDoc!; const acl = `acl-${normalizeEmail(user.email)}`; const myAcl = `acl-${Doc.CurrentUserEmailNormalized}`; - console.log(DocListCast(CurrentUserUtils.MyDashboards.data)); - console.log(target); - console.log(DocListCast(CurrentUserUtils.MyDashboards.data).indexOf(target)); const isDashboard = DocListCast(CurrentUserUtils.MyDashboards.data).indexOf(target) !== -1; const docs = SelectionManager.Views().length < 2 ? [target] : SelectionManager.Views().map(docView => docView.props.Document); @@ -340,11 +337,11 @@ export class SharingManager extends React.Component<{}> { // private setExternalSharing = (permission: string) => { - // const sharingDoc = this.sharingDoc; - // if (!sharingDoc) { + // const targetDoc = this.targetDoc; + // if (!targetDoc) { // return; // } - // sharingDoc[PublicKey] = permission; + // targetDoc["acl-" + PublicKey] = permission; // } // private get sharingUrl() { @@ -595,7 +592,7 @@ export class SharingManager extends React.Component<{}> { // the list of groups shared with const groupListMap: (Doc | { title: string })[] = groups.filter(({ title }) => docs.length > 1 ? commonKeys.includes(`acl-${normalizeEmail(StrCast(title))}`) : true); - groupListMap.unshift({ title: "Public" });//, { title: "Override" }); + groupListMap.unshift({ title: "Public" });//, { title: "ALL" }); const groupListContents = groupListMap.map(group => { const groupKey = `acl-${StrCast(group.title)}`; const uniform = docs.every(doc => this.layoutDocAcls ? doc?.[AclSym]?.[groupKey] === docs[0]?.[AclSym]?.[groupKey] : doc?.[DataSym]?.[AclSym]?.[groupKey] === docs[0]?.[DataSym]?.[AclSym]?.[groupKey]); @@ -644,6 +641,11 @@ export class SharingManager extends React.Component<{}> {
+ {/* {this.linkVisible ? +
+ {this.sharingUrl} +
: + (null)} */} {
this.changeSearchScope("")} /> - Dashboard - -
-
- -
-
- -
; - } - setSearchFilter = action((collectionView: { props: { Document: Doc } }, docsForFilter: Doc[] | undefined) => { if (collectionView) { const docFilters = Cast(this.props.Document._docFilters, listSpec("string"), null); @@ -564,7 +529,6 @@ export class SearchBox extends ViewBoxBaseComponent
} - {this.scopeButtons} -- cgit v1.2.3-70-g09d2 From 886439bdb812b54a756587be2a2f12e8ced67159 Mon Sep 17 00:00:00 2001 From: usodhi <61431818+usodhi@users.noreply.github.com> Date: Thu, 24 Jun 2021 18:22:06 -0400 Subject: pre-initialised annos list to prevent addonly privilege issues + some cleanup --- src/client/views/SidebarAnnos.tsx | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx index 59ff1c340..dcdc4f776 100644 --- a/src/client/views/SidebarAnnos.tsx +++ b/src/client/views/SidebarAnnos.tsx @@ -31,18 +31,22 @@ interface ExtraProps { } @observer export class SidebarAnnos extends React.Component { + constructor(props: Readonly) { + super(props); + this.props.dataDoc[this.sidebarKey] = new List(); + } _stackRef = React.createRef(); @computed get allHashtags() { const keys = new Set(); - DocListCast(this.props.rootDoc[this.sidebarKey()]).forEach(doc => SearchBox.documentKeys(doc).forEach(key => keys.add(key))); + DocListCast(this.props.rootDoc[this.sidebarKey]).forEach(doc => SearchBox.documentKeys(doc).forEach(key => keys.add(key))); return Array.from(keys.keys()).filter(key => key[0]).filter(key => !key.startsWith("_") && (key[0] === "#" || key[0] === key[0].toUpperCase())).sort(); } @computed get allUsers() { const keys = new Set(); - DocListCast(this.props.rootDoc[this.sidebarKey()]).forEach(doc => keys.add(StrCast(doc.author))); + DocListCast(this.props.rootDoc[this.sidebarKey]).forEach(doc => keys.add(StrCast(doc.author))); return Array.from(keys.keys()).sort(); } - get filtersKey() { return "_" + this.sidebarKey() + "-docFilters"; } + get filtersKey() { return "_" + this.sidebarKey + "-docFilters"; } anchorMenuClick = (anchor: Doc) => { const startup = StrListCast(this.props.rootDoc.docFilters).map(filter => filter.split(":")[0]).join(" "); @@ -59,7 +63,7 @@ export class SidebarAnnos extends React.Component { this._stackRef.current?.focusDocument(target); } makeDocUnfiltered = (doc: Doc) => { - if (DocListCast(this.props.rootDoc[this.sidebarKey()]).includes(doc)) { + if (DocListCast(this.props.rootDoc[this.sidebarKey]).includes(doc)) { if (this.props.layoutDoc[this.filtersKey]) { this.props.layoutDoc[this.filtersKey] = new List(); return true; @@ -67,14 +71,15 @@ export class SidebarAnnos extends React.Component { } return false; } - sidebarKey = () => this.props.fieldKey + "-sidebar"; + + get sidebarKey() { return this.props.fieldKey + "-sidebar"; } filtersHeight = () => 38; screenToLocalTransform = () => this.props.ScreenToLocalTransform().translate(Doc.NativeWidth(this.props.dataDoc), 0).scale(this.props.scaling?.() || 1); panelWidth = () => !this.props.layoutDoc._showSidebar ? 0 : this.props.layoutDoc.type === DocumentType.RTF ? this.props.PanelWidth() : (NumCast(this.props.layoutDoc.nativeWidth) - Doc.NativeWidth(this.props.dataDoc)) * this.props.PanelWidth() / NumCast(this.props.layoutDoc.nativeWidth); panelHeight = () => this.props.PanelHeight() - this.filtersHeight(); - addDocument = (doc: Doc | Doc[]) => this.props.sidebarAddDocument(doc, this.sidebarKey()); - moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean) => this.props.moveDocument(doc, targetCollection, addDocument, this.sidebarKey()); - removeDocument = (doc: Doc | Doc[]) => this.props.removeDocument(doc, this.sidebarKey()); + addDocument = (doc: Doc | Doc[]) => this.props.sidebarAddDocument(doc, this.sidebarKey); + moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean) => this.props.moveDocument(doc, targetCollection, addDocument, this.sidebarKey); + removeDocument = (doc: Doc | Doc[]) => this.props.removeDocument(doc, this.sidebarKey); docFilters = () => [...StrListCast(this.props.layoutDoc._docFilters), ...StrListCast(this.props.layoutDoc[this.filtersKey])]; sidebarStyleProvider = (doc: Opt, props: Opt, property: string) => { @@ -85,14 +90,14 @@ export class SidebarAnnos extends React.Component { const renderTag = (tag: string) => { const active = StrListCast(this.props.rootDoc[this.filtersKey]).includes(`${tag}:${tag}:check`); return
Doc.setDocFilter(this.props.rootDoc, tag, tag, "check", true, this.sidebarKey(), e.shiftKey)}> + onClick={e => Doc.setDocFilter(this.props.rootDoc, tag, tag, "check", true, this.sidebarKey, e.shiftKey)}> {tag}
; }; const renderUsers = (user: string) => { const active = StrListCast(this.props.rootDoc[this.filtersKey]).includes(`author:${user}:check`); return
Doc.setDocFilter(this.props.rootDoc, "author", user, "check", true, this.sidebarKey(), e.shiftKey)}> + onClick={e => Doc.setDocFilter(this.props.rootDoc, "author", user, "check", true, this.sidebarKey, e.shiftKey)}> {user}
; }; @@ -116,7 +121,7 @@ export class SidebarAnnos extends React.Component { PanelWidth={this.panelWidth} styleProvider={this.sidebarStyleProvider} docFilters={this.docFilters} - scaleField={this.sidebarKey() + "-scale"} + scaleField={this.sidebarKey + "-scale"} isAnnotationOverlay={false} select={emptyFunction} scaling={returnOne} @@ -129,7 +134,7 @@ export class SidebarAnnos extends React.Component { ScreenToLocalTransform={this.screenToLocalTransform} renderDepth={this.props.renderDepth + 1} viewType={CollectionViewType.Stacking} - fieldKey={this.sidebarKey()} + fieldKey={this.sidebarKey} pointerEvents={"all"} /> -- cgit v1.2.3-70-g09d2 From 2ac055ce068c2380a76c03d962b1e8b218c213de Mon Sep 17 00:00:00 2001 From: usodhi <61431818+usodhi@users.noreply.github.com> Date: Thu, 24 Jun 2021 18:22:25 -0400 Subject: more cleanup --- src/client/util/GroupMemberView.tsx | 1 - src/client/views/DocComponent.tsx | 7 ------- 2 files changed, 8 deletions(-) (limited to 'src') diff --git a/src/client/util/GroupMemberView.tsx b/src/client/util/GroupMemberView.tsx index 927200ed3..b7f89794d 100644 --- a/src/client/util/GroupMemberView.tsx +++ b/src/client/util/GroupMemberView.tsx @@ -50,7 +50,6 @@ export class GroupMemberView extends React.Component { onChange={selectedOption => GroupManager.Instance.addMemberToGroup(this.props.group, (selectedOption as UserOptions).value)} placeholder={"Add members"} value={null} - closeMenuOnSelect={true} styles={{ dropdownIndicator: (base, state) => ({ ...base, diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index 2baf9fbda..fc2a968fe 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -107,13 +107,6 @@ export function ViewBoxAnnotatableComponent

([ - [AclPrivate, SharingPermissions.None], - [AclReadonly, SharingPermissions.View], - [AclAddonly, SharingPermissions.Add], - [AclEdit, SharingPermissions.Edit], - [AclAdmin, SharingPermissions.Admin] - ]); lookupField = (field: string) => ScriptCast((this.layoutDoc as any).lookupField)?.script.run({ self: this.layoutDoc, data: this.rootDoc, field: field }).result; -- cgit v1.2.3-70-g09d2 From 9d03a05ae686768a542da499b6d5e1ce4d9c20fd Mon Sep 17 00:00:00 2001 From: usodhi <61431818+usodhi@users.noreply.github.com> Date: Sun, 27 Jun 2021 16:18:55 -0400 Subject: can delete dashboards --- src/client/util/CurrentUserUtils.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 8b3597d57..9f01b165f 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -1214,8 +1214,9 @@ export class CurrentUserUtils { const createDashboard = ScriptField.MakeScript(`createNewDashboard()`); const shareDashboard = ScriptField.MakeScript(`shareDashboard(self)`); const addToDashboards = ScriptField.MakeScript(`addToDashboards(self)`); - dashboardDoc.contextMenuScripts = new List([toggleTheme!, toggleComic!, snapshotDashboard!, createDashboard!, shareDashboard!, addToDashboards!]); - dashboardDoc.contextMenuLabels = new List(["Toggle Theme Colors", "Toggle Comic Mode", "Snapshot Dashboard", "Create Dashboard", "Share Dashboard", "Add to Dashboards"]); + const removeDashboard = ScriptField.MakeScript('removeDashboard(self)'); + dashboardDoc.contextMenuScripts = new List([toggleTheme!, toggleComic!, snapshotDashboard!, createDashboard!, shareDashboard!, addToDashboards!, removeDashboard!]); + dashboardDoc.contextMenuLabels = new List(["Toggle Theme Colors", "Toggle Comic Mode", "Snapshot Dashboard", "Create Dashboard", "Share Dashboard", "Add to Dashboards", "Remove Dashboard"]); Doc.AddDocToList(dashboards, "data", dashboardDoc); CurrentUserUtils.openDashboard(userDoc, dashboardDoc); @@ -1271,6 +1272,15 @@ Scripting.addGlobal(function shareDashboard(dashboard: Doc) { SharingManager.Instance.open(undefined, dashboard); }, "opens sharing dialog for Dashboard"); +Scripting.addGlobal(async function removeDashboard(dashboard: Doc) { + console.log(dashboard); + const dashboards = await DocListCastAsync(CurrentUserUtils.MyDashboards.data); + if (dashboards && dashboards.length > 1) { + if (dashboard === CurrentUserUtils.ActiveDashboard) CurrentUserUtils.openDashboard(Doc.UserDoc(), dashboards.find(doc => doc !== dashboard)!); + Doc.RemoveDocFromList(CurrentUserUtils.MyDashboards, "data", dashboard); + } +}, + "Remove Dashboard from Dashboards"); Scripting.addGlobal(async function addToDashboards(dashboard: Doc) { const dashboardAlias = Doc.MakeAlias(dashboard); -- cgit v1.2.3-70-g09d2 From d6e313be26323d7e8265714665c71e2d571764ae Mon Sep 17 00:00:00 2001 From: usodhi <61431818+usodhi@users.noreply.github.com> Date: Sun, 27 Jun 2021 17:20:59 -0400 Subject: whoops --- src/client/util/CurrentUserUtils.ts | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 9f01b165f..4584d3282 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -1273,7 +1273,6 @@ Scripting.addGlobal(function shareDashboard(dashboard: Doc) { }, "opens sharing dialog for Dashboard"); Scripting.addGlobal(async function removeDashboard(dashboard: Doc) { - console.log(dashboard); const dashboards = await DocListCastAsync(CurrentUserUtils.MyDashboards.data); if (dashboards && dashboards.length > 1) { if (dashboard === CurrentUserUtils.ActiveDashboard) CurrentUserUtils.openDashboard(Doc.UserDoc(), dashboards.find(doc => doc !== dashboard)!); -- cgit v1.2.3-70-g09d2 From 4cb75250bacbd08f4ae2c6ef6b4a00472bc890c3 Mon Sep 17 00:00:00 2001 From: dg314 Date: Mon, 28 Jun 2021 15:25:41 -0400 Subject: db update --- src/client/views/GlobalKeyHandler.ts | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index cbaa706e0..d92cba3eb 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -225,7 +225,6 @@ export class KeyManager { PromiseValue(Cast(Doc.UserDoc()["tabs-button-tools"], Doc)).then(pv => pv && (pv.onClick as ScriptField).script.run({ this: pv })); break; case "f": - SearchBox.Instance._searchFullDB = "My Stuff"; SearchBox.Instance.enter(undefined); break; case "o": -- cgit v1.2.3-70-g09d2 From 48dbde117728e4b36bae11f0f16a796059ecf7ee Mon Sep 17 00:00:00 2001 From: dg314 Date: Sat, 17 Jul 2021 15:13:39 -0400 Subject: initial search panel --- src/client/util/CurrentUserUtils.ts | 27 ++++- src/client/views/MainView.tsx | 11 +- src/client/views/StyleProvider.tsx | 2 +- .../views/collections/CollectionSchemaView.tsx | 2 +- src/client/views/collections/SchemaTable.tsx | 3 +- src/client/views/search/SearchBox.tsx | 117 ++------------------- 6 files changed, 41 insertions(+), 121 deletions(-) (limited to 'src') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 12733e815..596ccd9a6 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -35,6 +35,8 @@ import { UndoManager } from "./UndoManager"; import { SnappingManager } from "./SnappingManager"; import { InkTool } from "../../fields/InkField"; import { computedFn } from "mobx-utils"; +import { CollectionSchemaBooleanCell } from "../views/collections/CollectionSchemaCells"; +import { Console } from "console"; export let resolvedPorts: { server: number, socket: number }; @@ -53,6 +55,7 @@ export class CurrentUserUtils { @observable public static GuestDashboard: Doc | undefined; @observable public static GuestMobile: Doc | undefined; @observable public static propertiesWidth: number = 0; + @observable public static searchPanelWidth: number = 0; // sets up the default User Templates - slideView, headerView static setupUserTemplateButtons(doc: Doc) { @@ -516,6 +519,7 @@ export class CurrentUserUtils { static async menuBtnDescriptions(doc: Doc) { return [ { title: "Dashboards", target: Cast(doc.myDashboards, Doc, null), icon: "desktop", click: 'selectMainMenu(self)' }, + { title: "Search", target: Cast(doc.mySearchPanel, Doc, null), icon: "search", click: 'selectMainMenu(self)' }, { title: "My Files", target: Cast(doc.myFilesystem, Doc, null), icon: "file", click: 'selectMainMenu(self)' }, { title: "Tools", target: Cast(doc.myTools, Doc, null), icon: "wrench", click: 'selectMainMenu(self)' }, { title: "Import", target: Cast(doc.myImportPanel, Doc, null), icon: "upload", click: 'selectMainMenu(self)' }, @@ -529,14 +533,15 @@ export class CurrentUserUtils { ]; } - static setupSearchPanel(doc: Doc) { + /*static setupSearchPanel(doc: Doc) { if (doc.mySearchPanelDoc === undefined) { doc.mySearchPanelDoc = new PrefetchProxy(Docs.Create.SearchDocument({ _width: 500, _height: 300, backgroundColor: "dimGray", ignoreClick: true, _searchDoc: true, childDropAction: "alias", _lockedPosition: true, _viewType: CollectionViewType.Schema, title: "sidebar search stack", system: true })) as any as Doc; } - } + }*/ + static async setupMenuPanel(doc: Doc, sharingDocumentId: string, linkDatabaseId: string) { if (doc.menuStack === undefined) { await this.setupSharingSidebar(doc, sharingDocumentId, linkDatabaseId); // sets up the right sidebar collection for mobile upload documents and sharing @@ -807,6 +812,7 @@ export class CurrentUserUtils { (doc.myRecentlyClosedDocs as any as Doc).contextMenuLabels = new List(["Clear All"]); } } + static setupFilterDocs(doc: Doc) { // setup Filter item if (doc.currentFilter === undefined) { @@ -939,6 +945,21 @@ export class CurrentUserUtils { } } + // Search sidebar is where searches within the document are performed + static setupSearchSidebar(doc: Doc) { + if (doc.mySearchPanelDoc === undefined) { + doc.mySearchPanelDoc = new PrefetchProxy(Docs.Create.SearchDocument({ + _width: 500, _height: 300, backgroundColor: "dimGray", ignoreClick: true, _searchDoc: true, + childDropAction: "alias", _lockedPosition: true, _viewType: CollectionViewType.Schema, title: "sidebar search stack", system: true + })) as any as Doc; + } + if (doc.mySearchPanel === undefined) { + const searchPanelDoc = Cast(doc.mySearchPanelDoc, Doc, null); + //const newUpload = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("importDocument()"), toolTip: "Import External document", _stayInCollection: true, _hideContextMenu: true, title: "Import", icon: "upload", system: true }); + doc.mySearchPanel = new PrefetchProxy(Docs.Create.StackingDocument([searchPanelDoc], { title: "Search", _yMargin: 20, ignoreClick: true, _chromeHidden: true, _stayInCollection: true, _hideContextMenu: true, _lockedPosition: true, system: true })); + } + } + static setupClickEditorTemplates(doc: Doc) { if (doc["clickFuncs-child"] === undefined) { // to use this function, select it from the context menu of a collection. then edit the onChildClick script. Add two Doc variables: 'target' and 'thisContainer', then assign 'target' to some target collection. After that, clicking on any document in the initial collection will open it in the target @@ -1023,8 +1044,8 @@ export class CurrentUserUtils { this.setupDefaultIconTemplates(doc); // creates a set of icon templates triggered by the document deoration icon this.setupDocTemplates(doc); // sets up the template menu of templates this.setupImportSidebar(doc); + this.setupSearchSidebar(doc); // sets up the search sidebar this.setupActiveMobileMenu(doc); // sets up the current mobile menu for Dash Mobile - this.setupSearchPanel(doc); this.setupOverlays(doc); // documents in overlay layer this.setupDockedButtons(doc); // the bottom bar of font icons await this.setupSidebarButtons(doc); // the pop-out left sidebar of tools/panels diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 4eeb1fc95..bc9c6f4d2 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -180,8 +180,8 @@ export class MainView extends React.Component { const targClass = targets[0].className.toString(); if (SearchBox.Instance._searchbarOpen || SearchBox.Instance.open) { const check = targets.some((thing) => - (thing.className === "collectionSchemaView-searchContainer" || (thing as any)?.dataset.icon === "filter" || - thing.className === "collectionSchema-header-menuOptions")); + (thing.className === "collectionSchemaView-searchContainer" || (thing as any)?.dataset.icon === "filter" || + thing.className === "collectionSchema-header-menuOptions")); !check && SearchBox.Instance.resetSearch(true); } !targClass.includes("contextMenu") && ContextMenu.Instance.closeMenu(); @@ -388,7 +388,6 @@ export class MainView extends React.Component { SettingsManager.Instance.open(); break; case "Catalog": - SearchBox.Instance._searchFullDB = "My Stuff"; SearchBox.Instance.enter(undefined); break; case "Help": @@ -523,7 +522,7 @@ export class MainView extends React.Component { ; } - @computed get search() { + /*@computed get search() { TraceMobx(); return

; - } + }*/ @computed get invisibleWebBox() { // see note under the makeLink method in HypothesisUtils.ts return !DocumentLinksButton.invisibleWebDoc ? null : @@ -604,7 +603,7 @@ export class MainView extends React.Component { - {this.search} + {/*this.search*/} {LinkDescriptionPopup.descriptionPopup ? : null} {DocumentLinksButton.LinkEditorDocView ? : (null)} diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 9e61351c4..e670420d1 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -100,7 +100,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt 400 || col.alpha() < 0.25) return "black"; diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index b33c437a9..971dd5cbf 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -556,7 +556,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { style={{ overflow: this.props.scrollOverflow === true ? "scroll" : undefined, backgroundColor: "white", pointerEvents: this.props.Document._searchDoc !== undefined && !this.props.isContentActive() && !SnappingManager.GetIsDragging() ? "none" : undefined, - width: name === "collectionSchemaView-searchContainer" ? "auto" : this.props.PanelWidth() || "100%", height: this.props.PanelHeight() || "100%", position: "relative", + width: this.props.PanelWidth() || "100%", height: this.props.PanelHeight() || "100%", position: "relative", }} >
{
this.changeSorting(col)} style={{ width: 21, padding: 1, display: "inline", zIndex: 1, background: "inherit", cursor: "hand" }}>
+ {this.props.Document._chromeHidden || this.props.addDocument == returnFalse ? undefined :
+ new
}
; return { @@ -559,7 +560,7 @@ export class SchemaTable extends React.Component { onPointerDown={this.props.onPointerDown} onClick={this.props.onClick} onWheel={e => this.props.active(true) && e.stopPropagation()} onDrop={e => this.props.onDrop(e, {})} onContextMenu={this.onContextMenu} > {this.reactTable} - {this.props.Document._chromeHidden ? undefined :
+ new
} + {this.props.Document._chromeHidden || this.props.addDocument == returnFalse ? undefined :
+ new
} {!this._showDoc ? (null) :
(); - @observable _undoBackground: string | undefined = ""; @observable _icons: string[] = this._allIcons; @@ -116,62 +114,6 @@ export class SearchBox extends ViewBoxBaseComponent i === 0 ? newWords.push(key + mod + word) : newWords.push("AND " + key + mod + word)); - query = `(${query}) AND (${newWords.join(" ")})`; - } - else { - for (let i = 0; i < values.length; i++) { - const mod = "_t:"; - const newWords: string[] = []; - const oldWords = values[i].split(" "); - oldWords.forEach((word, i) => i === 0 ? newWords.push(key + mod + word) : newWords.push("AND " + key + mod + word)); - const v = "(" + newWords.join(" ") + ")"; - if (i === 0) { - query = `(${query}) AND (${v}` + (values.length === 1 ? ")" : ""); - } - else query = query + " OR " + v + (i === values.length - 1 ? ")" : ""); - } - } - } - - return query.replace(/-\s+/g, ''); - } - @action filterDocsByType(docs: Doc[]) { const finalDocs: Doc[] = []; @@ -340,7 +282,6 @@ export class SearchBox extends ViewBoxBaseComponent { - const res = await this.getAllResults(this.getFinalQuery(StrCast(this.layoutDoc._searchString))); - const filtered = this.filterDocsByType(res.docs); - const docs = filtered.map(doc => Doc.GetT(doc, "isPrototype", "boolean", true) ? Doc.MakeDelegate(doc) : Doc.MakeAlias(doc)); - let x = 0; - let y = 0; - for (const doc of docs.map(d => Doc.Layout(d))) { - doc.x = x; - doc.y = y; - const size = 200; - const aspect = Doc.NativeHeight(doc) / (Doc.NativeWidth(doc) || 1); - if (aspect > 1) { - doc._height = size; - doc._width = size / aspect; - } else if (aspect > 0) { - doc._width = size; - doc._height = size * aspect; - } else { - doc._width = size; - doc._height = size; - } - x += 250; - if (x > 1000) { - x = 0; - y += 300; - } - } - const headers = Cast(this.props.Document._schemaHeaders, listSpec(SchemaHeaderField), []).map(h => { const v = h[Copy](); v.color = "#f1efeb"; return v; }); - return Docs.Create.SchemaDocument(headers, DocListCast(this.dataDoc[this.fieldKey]), { _autoHeight: true, _viewType: CollectionViewType.Schema, title: StrCast(this.layoutDoc._searchString) }); - } - @action.bound openSearch(e: React.SyntheticEvent) { e.stopPropagation(); @@ -479,6 +389,7 @@ export class SearchBox extends ViewBoxBaseComponent
@@ -487,7 +398,7 @@ export class SearchBox extends ViewBoxBaseComponent window.location.assign(Utils.prepend("/logout"))}> Logoff -
+
DocServer.UPDATE_SERVER_CACHE()}> {`UI project`} @@ -499,10 +410,10 @@ export class SearchBox extends ViewBoxBaseComponent
CurrentUserUtils.createNewDashboard(Doc.UserDoc()))}> New -
+
CurrentUserUtils.snapshotDashboard(Doc.UserDoc()))}> Snapshot -
+
@@ -511,24 +422,12 @@ export class SearchBox extends ViewBoxBaseComponent
- drag search results as collection
}> -
StrCast(this.layoutDoc._searchString) ? this.startDragCollection() : undefined)} icon={"search"} size="lg" - style={{ cursor: "hand", color: "black", padding: 1, position: "relative" }} />
- +
{`${this._results.length}` + " of " + `${this.realTotalResults}`}
- {Doc.UserDoc().noviceMode ? (null) :
- only display documents matching search
} > -
- { e.stopPropagation(); SetupDrag(this.collectionRef, () => this.layoutDoc._searchString ? this.startDragCollection() : undefined); }} - onClick={action(() => this.setSearchFilter(this.currentSelectedCollection, this.filter ? undefined : this.docsforfilter))} /> -
- -
} -- cgit v1.2.3-70-g09d2 From 82c9db3e24baddeccafb67d2edc1a834f508f95a Mon Sep 17 00:00:00 2001 From: dg314 Date: Sat, 17 Jul 2021 15:33:43 -0400 Subject: search box --- src/client/views/search/SearchBox.tsx | 23 ----------------------- 1 file changed, 23 deletions(-) (limited to 'src') diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index 740a28825..cc4590969 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -393,29 +393,6 @@ export class SearchBox extends ViewBoxBaseComponent
-
-
- {`${Doc.CurrentUserEmail}`} -
window.location.assign(Utils.prepend("/logout"))}> - Logoff -
-
-
DocServer.UPDATE_SERVER_CACHE()}> - {`UI project`} -
-
- -
CurrentUserUtils.createNewDashboard(Doc.UserDoc()))}> - New -
-
CurrentUserUtils.snapshotDashboard(Doc.UserDoc()))}> - Snapshot -
-
-
Date: Sat, 17 Jul 2021 16:23:29 -0400 Subject: preventing alias of on-screen doc from being added to off-screen doc list --- src/client/util/CurrentUserUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index f3ba7334b..c96a6f656 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -1319,7 +1319,7 @@ Scripting.addGlobal(function dynamicOffScreenDocs(dashboard: Doc) { const onScreenTab = DocListCast(dashboard.data)[0]; const onScreenDocs = DocListCast(onScreenTab.data); return new List(allDocs.reduce((result: Doc[], doc) => { - !onScreenDocs.includes(doc) && (result.push(doc)); + !onScreenDocs.includes(doc) && !onScreenDocs.includes(doc.aliasOf as Doc) && (result.push(doc)); return result; }, [])); } -- cgit v1.2.3-70-g09d2 From 16c2a900e9116474caa67e4d5de15e2c51477292 Mon Sep 17 00:00:00 2001 From: vkalev Date: Tue, 27 Jul 2021 18:54:53 -0400 Subject: changing format of controls/handles + adding color enums --- src/client/views/InkControls.tsx | 73 ++++++++++++++++++--------------- src/client/views/InkHandles.tsx | 13 +++--- src/client/views/InkStrokeProperties.ts | 38 +++++++++-------- src/client/views/InkingStroke.tsx | 40 +++++++----------- 4 files changed, 84 insertions(+), 80 deletions(-) (limited to 'src') diff --git a/src/client/views/InkControls.tsx b/src/client/views/InkControls.tsx index 23f22c774..090af10cc 100644 --- a/src/client/views/InkControls.tsx +++ b/src/client/views/InkControls.tsx @@ -6,8 +6,13 @@ import { setupMoveUpEvents, emptyFunction } from "../../Utils"; import { UndoManager } from "../util/UndoManager"; import { ControlPoint, InkData, PointData } from "../../fields/InkField"; import { Transform } from "../util/Transform"; +import { Colors } from "./global/globalEnums"; +import { Doc } from "../../fields/Doc"; +import { listSpec } from "../../fields/Schema"; +import { Cast } from "../../fields/Types"; export interface InkControlProps { + inkDoc: Doc; data: InkData; addedPoints: PointData[]; format: number[]; @@ -30,19 +35,22 @@ export class InkControls extends React.Component { const controlUndo = UndoManager.StartBatch("DocDecs set radius"); const screenScale = this.props.ScreenToLocalTransform().Scale; const order = controlIndex % 4; - const handleIndexA = order === 2 ? controlIndex - 1 : controlIndex - 2; + const handleIndexA = order === 2 ? controlIndex - 1 : controlIndex - 2; const handleIndexB = order === 2 ? controlIndex + 2 : controlIndex + 1; + const brokenIndices = Cast(this.props.inkDoc, listSpec("number")); setupMoveUpEvents(this, e, (e: PointerEvent, down: number[], delta: number[]) => { InkStrokeProperties.Instance?.moveControl(-delta[0] * screenScale, -delta[1] * screenScale, controlIndex); return false; }, - () => controlUndo?.end(), - emptyFunction); - // action((e: PointerEvent, doubleTap: boolean | undefined) => - // { if (doubleTap && InkStrokeProperties.Instance?._brokenIndices.includes(controlIndex)) { - // InkStrokeProperties.Instance?.snapHandleTangent(controlIndex, handleIndexA, handleIndexB); - // }})); + () => controlUndo?.end(), + brokenIndices ? + action((e: PointerEvent, doubleTap: boolean | undefined) => { + if (doubleTap && brokenIndices.includes(controlIndex)) { + InkStrokeProperties.Instance?.snapHandleTangent(controlIndex, handleIndexA, handleIndexB); + } + }) + : emptyFunction); } } @@ -75,7 +83,7 @@ export class InkControls extends React.Component { @action onLeaveControl = () => { this._overControl = -1; }; @action onEnterAddPoint = (i: number) => { this._overAddPoint = i; }; @action onLeaveAddPoint = () => { this._overAddPoint = -1; }; - + render() { const formatInstance = InkStrokeProperties.Instance; if (!formatInstance) return (null); @@ -90,41 +98,42 @@ export class InkControls extends React.Component { } } const addedPoints = this.props.addedPoints; - const [left, top, scaleX, scaleY, strokeWidth, dotsize] = this.props.format; + const [left, top, scaleX, scaleY, strokeWidth] = this.props.format; return ( <> {addedPoints.map((pts, i) => - { formatInstance?.addPoints(pts.X, pts.Y, addedPoints, i, controlPoints); }} - onMouseEnter={() => this.onEnterAddPoint(i)} - onMouseLeave={this.onLeaveAddPoint} - pointerEvents="all" + { formatInstance?.addPoints(pts.X, pts.Y, addedPoints, i, controlPoints); }} + onMouseEnter={() => this.onEnterAddPoint(i)} + onMouseLeave={this.onLeaveAddPoint} + pointerEvents="all" cursor="all-scroll" /> )} {controlPoints.map((control, i) => - { - this.changeCurrPoint(control.I); - this.onControlDown(e, control.I); }} - onMouseEnter={() => this.onEnterControl(i)} - onMouseLeave={this.onLeaveControl} - pointerEvents="all" + { + this.changeCurrPoint(control.I); + this.onControlDown(e, control.I); + }} + onMouseEnter={() => this.onEnterControl(i)} + onMouseLeave={this.onLeaveControl} + pointerEvents="all" cursor="default" /> diff --git a/src/client/views/InkHandles.tsx b/src/client/views/InkHandles.tsx index 28b6dd820..6e890e184 100644 --- a/src/client/views/InkHandles.tsx +++ b/src/client/views/InkHandles.tsx @@ -10,6 +10,7 @@ import { Doc } from "../../fields/Doc"; import { listSpec } from "../../fields/Schema"; import { List } from "../../fields/List"; import { Cast } from "../../fields/Types"; +import { Colors } from "./global/globalEnums"; export interface InkHandlesProps { inkDoc: Doc; @@ -80,7 +81,7 @@ export class InkHandles extends React.Component { handleLines.push({ X1: data[i].X, Y1: data[i].Y, X2: data[i + 1].X, Y2: data[i + 1].Y, X3: data[i + 3].X, Y3: data[i + 3].Y, dot1: i + 1, dot2: i + 2 }); } } - const [left, top, scaleX, scaleY, strokeWidth, dotsize] = this.props.format; + const [left, top, scaleX, scaleY, strokeWidth] = this.props.format; return ( <> @@ -91,7 +92,7 @@ export class InkHandles extends React.Component { cy={(pts.Y - top - strokeWidth / 2) * scaleY + strokeWidth / 2} r={strokeWidth / 2} strokeWidth={0} - fill="#1F85DE" + fill={Colors.MEDIUM_BLUE} onPointerDown={(e) => this.onHandleDown(e, pts.I)} pointerEvents="all" cursor="default" @@ -104,16 +105,16 @@ export class InkHandles extends React.Component { y1={(pts.Y1 - top - strokeWidth / 2) * scaleY + strokeWidth / 2} x2={(pts.X2 - left - strokeWidth / 2) * scaleX + strokeWidth / 2} y2={(pts.Y2 - top - strokeWidth / 2) * scaleY + strokeWidth / 2} - stroke="#1F85DE" - strokeWidth={dotsize / 8} + stroke={Colors.MEDIUM_BLUE} + strokeWidth={strokeWidth / 4} display={(pts.dot1 === formatInstance._currentPoint || pts.dot2 === formatInstance._currentPoint) ? "inherit" : "none"} /> )} diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts index 1a3585f3e..de8cf80bd 100644 --- a/src/client/views/InkStrokeProperties.ts +++ b/src/client/views/InkStrokeProperties.ts @@ -35,7 +35,7 @@ export class InkStrokeProperties { * @param func The inputted function. * @param requireCurrPoint Indicates whether the current selected point is needed. */ - applyFunction = (func: (doc: Doc, ink: InkData, ptsXscale: number, ptsYscale: number) => { X: number, Y: number }[] | undefined, requireCurrPoint: boolean = false) => { + applyFunction = (func: (doc: Doc, ink: InkData, ptsXscale: number, ptsYscale: number) => { X: number, Y: number }[] | undefined, requireCurrPoint: boolean = false) => { var appliedFunc = false; this.selectedInk?.forEach(action(inkView => { if (this.selectedInk?.length === 1 && (!requireCurrPoint || this._currentPoint !== -1)) { @@ -91,16 +91,16 @@ export class InkStrokeProperties { }); } } - if (end === 0) end = points.length-1; + if (end === 0) end = points.length - 1; // Index of new control point with regards to the ink data. const newIndex = Math.floor(counter / 2) * 4 + 2; // Creating new ink data with the new control point and handle points inputted. for (let i = 0; i < ink.length; i++) { - if (i === newIndex) { - const [handleA, handleB] = this.getNewHandlePoints(points.slice(start, index+1), points.slice(index, end), newControl); + if (i === newIndex) { + const [handleA, handleB] = this.getNewHandlePoints(points.slice(start, index + 1), points.slice(index, end), newControl); newPoints.push(handleA, newControl, newControl, handleB); // Adjusting the magnitude of the left handle line of the right neighboring control point. - const [rightControl, rightHandle] = [points[end], ink[i]]; + const [rightControl, rightHandle] = [points[end], ink[i]]; const scaledVector = this.getScaledHandlePoint(false, start, end, index, rightControl, rightHandle); rightHandle && newPoints.push({ X: rightControl.X - scaledVector.X, Y: rightControl.Y - scaledVector.Y }); } else if (i === newIndex - 1) { @@ -111,14 +111,14 @@ export class InkStrokeProperties { } else { ink[i] && newPoints.push({ X: ink[i].X, Y: ink[i].Y }); } - + } let brokenIndices = Cast(doc.brokenInkIndices, listSpec("number")); // Updating the indices of the control points whose handle tangency has been broken. if (brokenIndices) { - brokenIndices = new List(brokenIndices.map((control) => { + brokenIndices = new List(brokenIndices.map((control) => { if (control >= newIndex) { - return control + 4; + return control + 4; } else { return control; } @@ -158,7 +158,7 @@ export class InkStrokeProperties { getNewHandlePoints = (C: PointData[], D: PointData[], newControl: PointData) => { const [m, n] = [C.length, D.length]; let handleSizeA = Math.sqrt((Math.pow(newControl.X - C[0].X, 2)) + (Math.pow(newControl.Y - C[0].Y, 2))); - let handleSizeB = Math.sqrt((Math.pow(D[n-1].X - newControl.X, 2)) + (Math.pow(D[n-1].Y - newControl.Y, 2))); + let handleSizeB = Math.sqrt((Math.pow(D[n - 1].X - newControl.X, 2)) + (Math.pow(D[n - 1].Y - newControl.Y, 2))); // Scaling adjustments to improve the ratio between the magnitudes of the two handle lines. // (Ensures that the new point added doesn't augment the inital shape of the curve much). if (handleSizeA < 75 && handleSizeB < 75) { @@ -173,7 +173,7 @@ export class InkStrokeProperties { handleSizeB *= 2; } // Finding the last leg of the derivative curve of C. - const dC = { X: (handleSizeA / n) * (C[m-1].X - C[m-2].X), Y: (handleSizeA / n) * (C[m-1].Y - C[m-2].Y) }; + const dC = { X: (handleSizeA / n) * (C[m - 1].X - C[m - 2].X), Y: (handleSizeA / n) * (C[m - 1].Y - C[m - 2].Y) }; // Finding the first leg of the derivative curve of D. const dD = { X: (handleSizeB / m) * (D[1].X - D[0].X), Y: (handleSizeB / m) * (D[1].Y - D[0].Y) }; const handleA = { X: newControl.X - dC.X, Y: newControl.Y - dC.Y }; @@ -259,13 +259,17 @@ export class InkStrokeProperties { snapHandleTangent = (controlIndex: number, handleIndexA: number, handleIndexB: number) => { this.applyFunction((doc: Doc, ink: InkData) => { - // doc.brokenIndices.splice(this._brokenIndices.indexOf(controlIndex), 1); - const [controlPoint, handleA, handleB] = [ink[controlIndex], ink[handleIndexA], ink[handleIndexB]]; - const oppositeHandleA = this.rotatePoint(handleA, controlPoint, Math.PI); - const angleDifference = this.angleChange(handleB, oppositeHandleA, controlPoint); - const newHandleB = this.rotatePoint(handleB, controlPoint, angleDifference); - ink[handleIndexB] = newHandleB; - return ink; + const brokenIndices = Cast(doc.brokenInkIndices, listSpec("number")); + if (brokenIndices) { + brokenIndices.splice(brokenIndices.indexOf(controlIndex), 1); + doc.brokenInkIndices = brokenIndices; + const [controlPoint, handleA, handleB] = [ink[controlIndex], ink[handleIndexA], ink[handleIndexB]]; + const oppositeHandleA = this.rotatePoint(handleA, controlPoint, Math.PI); + const angleDifference = this.angleChange(handleB, oppositeHandleA, controlPoint); + const newHandleB = this.rotatePoint(handleB, controlPoint, angleDifference); + ink[handleIndexB] = newHandleB; + return ink; + } }); } diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index bd71aaf19..a8f32118c 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -19,6 +19,7 @@ import { InkStrokeProperties } from "./InkStrokeProperties"; import { CurrentUserUtils } from "../util/CurrentUserUtils"; import { InkControls } from "./InkControls"; import { InkHandles } from "./InkHandles"; +import { Colors } from "./global/globalEnums"; type InkDocument = makeInterface<[typeof documentSchema]>; const InkDocument = makeInterface(documentSchema); @@ -66,6 +67,9 @@ export class InkingStroke extends ViewBoxBaseComponent 1 && lineRight - lineLeft > 1, - false); + const inkLine = InteractionUtils.CreatePolyline(data, left, top, strokeColor, strokeWidth, strokeWidth, StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "none"), StrCast(this.layoutDoc.strokeStartMarker), + StrCast(this.layoutDoc.strokeEndMarker), StrCast(this.layoutDoc.strokeDash), scaleX, scaleY, "", "none", this.props.isSelected() && strokeWidth <= 5 && lineBottom - lineTop > 1 && lineRight - lineLeft > 1, false); // Thin blue line indicating that the current ink stroke is selected. - const selectedLine = InteractionUtils.CreatePolyline( - data, lineLeft - strokeWidth * 3, lineTop - strokeWidth * 3, "#1F85DE", strokeWidth / 6, - strokeWidth / 6, StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "none"), - StrCast(this.layoutDoc.strokeStartMarker), StrCast(this.layoutDoc.strokeEndMarker), - StrCast(this.layoutDoc.strokeDash), scaleX, scaleY, "", "none", - this.props.isSelected() && strokeWidth <= 5 && lineBottom - lineTop > 1 && lineRight - lineLeft > 1, - false); + const selectedLine = InteractionUtils.CreatePolyline(data, left - strokeWidth / 3, top - strokeWidth / 3, Colors.MEDIUM_BLUE, strokeWidth / 6, strokeWidth / 6, StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "none"), + StrCast(this.layoutDoc.strokeStartMarker), StrCast(this.layoutDoc.strokeEndMarker), StrCast(this.layoutDoc.strokeDash), scaleX, scaleY, "", "none", this.props.isSelected() && strokeWidth <= 5 && lineBottom - lineTop > 1 && lineRight - lineLeft > 1, false); // Invisible polygonal line that enables the ink to be selected by the user. - const clickableLine = InteractionUtils.CreatePolyline(data, left, top, - this.props.isSelected() && strokeWidth > 5 ? strokeColor : "transparent", strokeWidth, - strokeWidth + 15, StrCast(this.layoutDoc.strokeBezier), - StrCast(this.layoutDoc.fillColor, "none"), "none", "none", undefined, scaleX, scaleY, "", - this.props.layerProvider?.(this.props.Document) === false ? "none" : "visiblepainted", false, true); + const clickableLine = InteractionUtils.CreatePolyline(data, left, top, this.props.isSelected() && strokeWidth > 5 ? strokeColor : "transparent", strokeWidth, strokeWidth + 15, StrCast(this.layoutDoc.strokeBezier), + StrCast(this.layoutDoc.fillColor, "none"), "none", "none", undefined, scaleX, scaleY, "", this.props.layerProvider?.(this.props.Document) === false ? "none" : "visiblepainted", false, true); // Set of points rendered upon the ink that can be added if a user clicks on one. - const addedPoints = InteractionUtils.CreatePoints(data, left, top, strokeColor, strokeWidth, strokeWidth, - StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "none"), - StrCast(this.layoutDoc.strokeStartMarker), StrCast(this.layoutDoc.strokeEndMarker), - StrCast(this.layoutDoc.strokeDash), scaleX, scaleY, "", "none", - this.props.isSelected() && strokeWidth <= 5, false); + const addedPoints = InteractionUtils.CreatePoints(data, left, top, strokeColor, strokeWidth, strokeWidth, StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "none"), StrCast(this.layoutDoc.strokeStartMarker), + StrCast(this.layoutDoc.strokeEndMarker), StrCast(this.layoutDoc.strokeDash), scaleX, scaleY, "", "none", this.props.isSelected() && strokeWidth <= 5, false); return ( : ""} -- cgit v1.2.3-70-g09d2 From ea6000690022d43b6bc8e1a546d28729a59faf7b Mon Sep 17 00:00:00 2001 From: vkalev Date: Wed, 28 Jul 2021 13:14:10 -0400 Subject: snapping broken tangency added --- src/client/views/InkControls.tsx | 14 ++++++-------- src/client/views/InkHandles.tsx | 1 + src/client/views/InkStrokeProperties.ts | 18 +++++++++++------- 3 files changed, 18 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/client/views/InkControls.tsx b/src/client/views/InkControls.tsx index 090af10cc..6213a4075 100644 --- a/src/client/views/InkControls.tsx +++ b/src/client/views/InkControls.tsx @@ -37,20 +37,18 @@ export class InkControls extends React.Component { const order = controlIndex % 4; const handleIndexA = order === 2 ? controlIndex - 1 : controlIndex - 2; const handleIndexB = order === 2 ? controlIndex + 2 : controlIndex + 1; - const brokenIndices = Cast(this.props.inkDoc, listSpec("number")); + const brokenIndices = Cast(this.props.inkDoc.brokenInkIndices, listSpec("number")); setupMoveUpEvents(this, e, (e: PointerEvent, down: number[], delta: number[]) => { InkStrokeProperties.Instance?.moveControl(-delta[0] * screenScale, -delta[1] * screenScale, controlIndex); return false; }, () => controlUndo?.end(), - brokenIndices ? - action((e: PointerEvent, doubleTap: boolean | undefined) => { - if (doubleTap && brokenIndices.includes(controlIndex)) { - InkStrokeProperties.Instance?.snapHandleTangent(controlIndex, handleIndexA, handleIndexB); - } - }) - : emptyFunction); + action((e: PointerEvent, doubleTap: boolean | undefined) => { + if (doubleTap && brokenIndices && brokenIndices.includes(controlIndex)) { + InkStrokeProperties.Instance?.snapHandleTangent(controlIndex, handleIndexA, handleIndexB); + } + })); } } diff --git a/src/client/views/InkHandles.tsx b/src/client/views/InkHandles.tsx index 6e890e184..f1eb4b9db 100644 --- a/src/client/views/InkHandles.tsx +++ b/src/client/views/InkHandles.tsx @@ -51,6 +51,7 @@ export class InkHandles extends React.Component { onBreakTangent = (e: KeyboardEvent, controlIndex: number) => { const doc: Doc = this.props.inkDoc; if (["Alt"].includes(e.key)) { + e.stopPropagation(); if (doc) { const brokenIndices = Cast(doc.brokenInkIndices, listSpec("number")) || new List; if (brokenIndices && !brokenIndices.includes(controlIndex)) { diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts index de8cf80bd..76ca5b5ec 100644 --- a/src/client/views/InkStrokeProperties.ts +++ b/src/client/views/InkStrokeProperties.ts @@ -257,6 +257,11 @@ export class InkStrokeProperties { return newPoints; }) + /** + * Snaps a control point with broken tangency back to synced rotation. + * @param handleIndexA The handle point that retains its current position. + * @param handleIndexB The handle point that is rotated to be 180 degrees from its opposite. + */ snapHandleTangent = (controlIndex: number, handleIndexA: number, handleIndexB: number) => { this.applyFunction((doc: Doc, ink: InkData) => { const brokenIndices = Cast(doc.brokenInkIndices, listSpec("number")); @@ -278,13 +283,12 @@ export class InkStrokeProperties { */ @action rotatePoint = (target: PointData, origin: PointData, angle: number) => { - target.X -= origin.X; - target.Y -= origin.Y; - const newX = Math.cos(angle) * target.X - Math.sin(angle) * target.Y; - const newY = Math.sin(angle) * target.X + Math.cos(angle) * target.Y; - target.X = newX + origin.X; - target.Y = newY + origin.Y; - return target; + let rotatedTarget = { X: target.X - origin.X, Y: target.Y - origin.Y }; + const newX = Math.cos(angle) * rotatedTarget.X - Math.sin(angle) * rotatedTarget.Y; + const newY = Math.sin(angle) * rotatedTarget.X + Math.cos(angle) * rotatedTarget.Y; + rotatedTarget.X = newX + origin.X; + rotatedTarget.Y = newY + origin.Y; + return rotatedTarget; } /** -- cgit v1.2.3-70-g09d2 From 405114b0a2440939e89052539eb91f479e8d4176 Mon Sep 17 00:00:00 2001 From: Aubrey-Li <63608597+Aubrey-Li@users.noreply.github.com> Date: Wed, 28 Jul 2021 16:07:08 -0700 Subject: fix tree view collection drop shadow --- src/client/views/nodes/DocumentView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 60fa462ad..2b0d8fe91 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -979,7 +979,7 @@ export class DocumentViewInternal extends DocComponent Date: Thu, 29 Jul 2021 09:51:50 -0400 Subject: deselecting an ink stroke properly exits edit view --- src/client/views/InkingStroke.tsx | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index a8f32118c..21059b330 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -65,11 +65,19 @@ export class InkingStroke extends ViewBoxBaseComponent { + if (!this.props.isSelected() && this._properties) { + this._properties._controlButton = false; + } + } + render() { TraceMobx(); - // if (!this.props.isSelected() && this._properties) { - // this._properties._controlButton = false; - // } + this.toggleControlButton(); // Extracting the ink data and formatting information of the current ink stroke. const data: InkData = Cast(this.dataDoc[this.fieldKey], InkField)?.inkData ?? []; const inkDoc: Doc = this.layoutDoc; -- cgit v1.2.3-70-g09d2 From fc1559fd74bde212f418b27806b68a76748153ad Mon Sep 17 00:00:00 2001 From: dg314 Date: Thu, 29 Jul 2021 15:12:03 -0400 Subject: search panel updates --- src/client/util/CurrentUserUtils.ts | 11 +- src/client/views/MainView.tsx | 6 +- src/client/views/search/SearchBox.scss | 173 ++++-------- src/client/views/search/SearchBox.tsx | 491 +++++++++++++++------------------ 4 files changed, 291 insertions(+), 390 deletions(-) (limited to 'src') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 596ccd9a6..31384da3b 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -947,17 +947,12 @@ export class CurrentUserUtils { // Search sidebar is where searches within the document are performed static setupSearchSidebar(doc: Doc) { - if (doc.mySearchPanelDoc === undefined) { - doc.mySearchPanelDoc = new PrefetchProxy(Docs.Create.SearchDocument({ - _width: 500, _height: 300, backgroundColor: "dimGray", ignoreClick: true, _searchDoc: true, + if (doc.mySearchPanel === undefined) { + doc.mySearchPanel = new PrefetchProxy(Docs.Create.SearchDocument({ + backgroundColor: "dimGray", ignoreClick: true, _searchDoc: true, childDropAction: "alias", _lockedPosition: true, _viewType: CollectionViewType.Schema, title: "sidebar search stack", system: true })) as any as Doc; } - if (doc.mySearchPanel === undefined) { - const searchPanelDoc = Cast(doc.mySearchPanelDoc, Doc, null); - //const newUpload = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("importDocument()"), toolTip: "Import External document", _stayInCollection: true, _hideContextMenu: true, title: "Import", icon: "upload", system: true }); - doc.mySearchPanel = new PrefetchProxy(Docs.Create.StackingDocument([searchPanelDoc], { title: "Search", _yMargin: 20, ignoreClick: true, _chromeHidden: true, _stayInCollection: true, _hideContextMenu: true, _lockedPosition: true, system: true })); - } } static setupClickEditorTemplates(doc: Doc) { diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index bc9c6f4d2..0d957518b 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -178,12 +178,12 @@ export class MainView extends React.Component { const targets = document.elementsFromPoint(e.x, e.y); if (targets.length) { const targClass = targets[0].className.toString(); - if (SearchBox.Instance._searchbarOpen || SearchBox.Instance.open) { + /*if (SearchBox.Instance._resultsOpen) { const check = targets.some((thing) => (thing.className === "collectionSchemaView-searchContainer" || (thing as any)?.dataset.icon === "filter" || thing.className === "collectionSchema-header-menuOptions")); !check && SearchBox.Instance.resetSearch(true); - } + }*/ !targClass.includes("contextMenu") && ContextMenu.Instance.closeMenu(); !["timeline-menu-desc", "timeline-menu-item", "timeline-menu-input"].includes(targClass) && TimelineMenu.Instance.closeMenu(); } @@ -192,7 +192,7 @@ export class MainView extends React.Component { initEventListeners = () => { window.addEventListener("drop", e => e.preventDefault(), false); // prevent default behavior of navigating to a new web page window.addEventListener("dragover", e => e.preventDefault(), false); - document.addEventListener("pointermove", action(e => SearchBox.Instance._undoBackground = UndoManager.batchCounter ? "#000000a8" : undefined)); + //document.addEventListener("pointermove", action(e => SearchBox.Instance._undoBackground = UndoManager.batchCounter ? "#000000a8" : undefined)); document.addEventListener("pointerdown", this.globalPointerDown); document.addEventListener("click", (e: MouseEvent) => { if (!e.cancelBubble) { diff --git a/src/client/views/search/SearchBox.scss b/src/client/views/search/SearchBox.scss index 4f5b7e41a..f8e994da7 100644 --- a/src/client/views/search/SearchBox.scss +++ b/src/client/views/search/SearchBox.scss @@ -2,141 +2,84 @@ @import "./NaviconButton.scss"; .searchBox-container { - display: flex; - flex-direction: column; width: 100%; height: 100%; - position: relative; font-size: 10px; line-height: 1; - overflow-y: auto; - overflow-x: visible; - background: lightgrey; - overflow: visible; + background: none; z-index: 1000; + padding: 0px; + cursor: default; .searchBox-bar { - height: $searchpanel-height; + width: 100%; + height: 35px; display: flex; justify-content: center; align-items: center; - background-color: black; + background-color: none; + padding: 5px; - .searchBox-lozenges { - position: absolute; - left: 15; - display: flex; - - .searchBox-lozenge-user, - .searchBox-lozenge-dashboard, - .searchBox-lozenge { - height: 18px; - padding: 4px; - margin-right: 5px; - display: flex; - align-items: center; - border: grey 1px solid; - .searchBox-logoff, - .searchBox-dashboards { - border-radius: 3px; - background: olivedrab; - color: white; - display: none; - margin-left: 5px; - padding: 1px 2px 1px 2px; - cursor: pointer; - } - .searchBox-logoff { - background: red; - } - - .searchBox-dashSelect{ - border: none; - background-color: transparent; + .searchBox-type { + display: block; + width: 50px; + outline: none; + padding: 1px 5px 1px 5px; + color: black; + height: 25px; + border: 1px solid black; + } - &:hover { - cursor: pointer; - } - } - } - .searchBox-lozenge-user:hover { - .searchBox-logoff { - display:inline-block; - } - } - .searchBox-lozenge-dashboard:hover { - .searchBox-dashboards { - display:inline-block; - } - } + .searchBox-input { + display: block; + width: calc(100% - 50px); + outline: none; + padding: 1px 5px 1px 5px; + color: black; + height: 25px; + border: 1px solid black; } - .searchBox-query { - position: relative; + } + + .searchBox-results-container { + display: flex; + flex-direction: column; + width: 100%; + height: 100%; + justify-content: "center"; + + .searchBox-results-count { display: flex; - width: 450; + color: gray; + margin-left: 5px; } - .searchBox-barChild { + + .searchBox-results-scroll-view { + margin-top: 10px; + display: inline-block; + width: 100%; + height: calc(100% - 55px); + overflow-y: scroll; - &.searchBox-collection { - flex: 0 1 auto; - margin-left: 2px; - margin-right: 2px - } + .searchBox-results-scroll-view-result { + display: inline-block; + vertical-align: middle; + width: 100%; + height: 40px; + cursor: pointer; + font-size: 15px; + padding: 10px; - &.searchBox-input { - margin:5px; - border-radius:20px; - border:black; - display: block; - width: 130px; - -webkit-transition: width 0.4s; - transition: width 0.4s; - align-self: stretch; - outline:none; - &:focus { - width: 500px; - outline:none; + &.searchBox-results-scroll-view-result-selected { + background: gray; } - } - &.searchBox-filter { - align-self: stretch; - button{ - transform:none; - &:hover { - transform: none; - } - } - } - &.searchBox-submit { - margin-left: 2px; - margin-right: 2px - } - - &.searchBox-close { - color: $light-color; - max-height: $searchpanel-height; + .titletitle { + display: relative; + float: left; + left: 50px; + } } } - } -} - -.searchBox-results { - display: flex; - flex-direction: column; - top: 300px; - display: flex; - flex-direction: column; - height: 100%; - overflow: visible; - - .no-result { - width: 500px; - background: $light-color-secondary; - padding: 10px; - height: 50px; - text-transform: uppercase; - text-align: left; - font-weight: bold; } } \ No newline at end of file diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index cc4590969..374a754bf 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -3,7 +3,7 @@ import { Tooltip } from '@material-ui/core'; import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { Doc, DocListCast, Field, Opt, DocListCastAsync, DataSym, HeightSym } from '../../../fields/Doc'; +import { Doc, DocListCast, Field, Opt, DocListCastAsync, DataSym, HeightSym, FieldsSym } from '../../../fields/Doc'; import { documentSchema } from "../../../fields/documentSchemas"; import { Copy, Id, ToString } from '../../../fields/FieldSymbols'; import { List } from '../../../fields/List'; @@ -26,6 +26,9 @@ import "./SearchBox.scss"; import { undoBatch } from "../../util/UndoManager"; import { DocServer } from "../../DocServer"; import { MainView } from "../MainView"; +import { DocumentManager } from "../../util/DocumentManager"; +import { CollectionSchemaBooleanCell } from "../collections/CollectionSchemaCells"; +import { transpileModule } from "typescript"; export const searchSchema = createSchema({ Document: Doc }); @@ -38,33 +41,18 @@ export class SearchBox extends ViewBoxBaseComponent; private _resultsSet = new Map(); private _inputRef = React.createRef(); - private _maxSearchIndex: number = 0; - private _curRequest?: Promise = undefined; private _disposers: { [name: string]: IReactionDisposer } = {}; private _blockedTypes = [DocumentType.PRESELEMENT, DocumentType.KVP, DocumentType.FILTER, DocumentType.SEARCH, DocumentType.SEARCHITEM, DocumentType.FONTICON, DocumentType.BUTTON, DocumentType.SCRIPTING]; - private docsforfilter: Doc[] | undefined = []; - private realTotalResults: number = 0; - private newsearchstring = ""; - - @observable _undoBackground: string | undefined = ""; + @observable _searchString = ""; + @observable _docTypeString = "all"; @observable _icons: string[] = this._allIcons; @observable _results: [Doc, string[], string[]][] = []; - @observable _visibleElements: JSX.Element[] = []; - @observable _visibleDocuments: Doc[] = []; + @observable _selectedResult: Doc | undefined = undefined; @observable _deletedDocsStatus: boolean = false; @observable _onlyAliases: boolean = true; - @observable _searchbarOpen = false; - @observable _noResults = ""; - @observable _pageStart = 0; - @observable open = false; - @observable children = 0; @computed get filter() { return this._results?.length && (this.currentSelectedCollection?.props.Document._searchFilterDocs || this.currentSelectedCollection?.props.Document._docFilters); } constructor(props: any) { @@ -76,8 +64,6 @@ export class SearchBox extends ViewBoxBaseComponent this.props.Document._docFilters, - (filters: any) => this.setSearchFilter(this.currentSelectedCollection, !this.filter ? undefined : this.docsforfilter)); }); componentWillUnmount() { @@ -86,32 +72,25 @@ export class SearchBox extends ViewBoxBaseComponent) => { - this.newsearchstring = e.target.value; - if (e.target.value === "") { - console.log("Reset start"); - this.docsforfilter = undefined; - this.setSearchFilter(this.currentSelectedCollection, undefined); - this.resetSearch(false); - - this.open = false; - this._results = []; - this._resultsSet.clear(); - this._visibleElements = []; - this._numTotalResults = -1; - this._endIndex = -1; - this._curRequest = undefined; - this._maxSearchIndex = 0; - } + onInputChange = action((e: React.ChangeEvent) => { + this._searchString = e.target.value; + this.submitSearch(); }); - enter = action((e: React.KeyboardEvent | undefined) => { + onSelectChange = action((e: React.ChangeEvent) => { + this._docTypeString = e.target.value; + this.submitSearch(); + }); + + /*enter = action((e: React.KeyboardEvent | undefined) => { if (!e || e.key === "Enter") { - this.layoutDoc._searchString = this.newsearchstring; - this._pageStart = 0; - this.open = true; this.submitSearch(); } + });*/ + + onResultClick = action((doc: Doc) => { + this.selectElement(doc); + this._selectedResult = doc; }); @action @@ -126,21 +105,6 @@ export class SearchBox extends ViewBoxBaseComponent void) { - let newarray: Doc[] = []; - while (docs.length > 0) { - newarray = []; - await Promise.all(docs.filter(d => d).map(async d => { - const fieldKey = Doc.LayoutFieldKey(d); - const annos = !Field.toString(Doc.LayoutField(d) as Field).includes("CollectionView"); - const data = d[annos ? fieldKey + "-annotations" : fieldKey]; - const docs = await DocListCastAsync(data); - docs && newarray.push(...docs); - func(d); - })); - docs = newarray; - } - } static foreachRecursiveDoc(docs: Doc[], func: (doc: Doc) => void) { let newarray: Doc[] = []; while (docs.length > 0) { @@ -172,15 +136,7 @@ export class SearchBox extends ViewBoxBaseComponent r[0]); - this.setSearchFilter(selectedCollection, this.filter && found.length ? this.docsforfilter : undefined); - this._numTotalResults = found.length; - this.realTotalResults = found.length; } - else { - this._noResults = "No collection selected :("; - } - } static documentKeys(doc: Doc) { @@ -197,246 +153,253 @@ export class SearchBox extends ViewBoxBaseComponent { - this.resetSearch(false); - - //this.props.Document._docFilters = new List(); - this._noResults = ""; + this.resetSearch(); this.dataDoc[this.fieldKey] = new List([]); - this.children = 0; - let query = StrCast(this.layoutDoc._searchString); + let query = StrCast(this._searchString); Doc.SetSearchQuery(query); this._results = []; this._resultsSet.clear(); - this._visibleElements = []; - this._visibleDocuments = []; if (query) { - this._endIndex = 12; - this._maxSearchIndex = 0; - this._numTotalResults = -1; this.searchCollection(query); - runInAction(() => { - this.open = this._searchbarOpen = true; - this.resultsScrolled(); - }); } } - getAllResults = async (query: string) => { - return SearchUtil.Search(query, true, { fq: this.filterQuery, start: 0, rows: 10000000 }); - } + resetSearch = action(() => { + this._results.forEach(result => { + Doc.UnBrushDoc(result[0]); + Doc.ClearSearchMatches(); + }); + }); - private get filterQuery() { - const baseExpr = "NOT system_b:true"; - const authorExpr = undefined; - const includeDeleted = this._deletedDocsStatus ? "" : " NOT deleted_b:true"; - const typeExpr = this._onlyAliases ? "NOT {!join from=id to=proto_i}type_t:*" : `(type_t:* OR {!join from=id to=proto_i}type_t:*) ${this._blockedTypes.map(type => `NOT ({!join from=id to=proto_i}type_t:${type}) AND NOT type_t:${type}`).join(" AND ")}`; - // fq: type_t:collection OR {!join from=id to=proto_i}type_t:collection q:text_t:hello - return [baseExpr, authorExpr, includeDeleted, typeExpr].filter(q => q).join(" AND ").replace(/AND $/, ""); + selectElement = async (doc: Doc) => { + await DocumentManager.Instance.jumpToDocument(doc, true); // documents open in new tab instead of on right } - @computed get primarySort() { - const suffixMap = (type: ColumnType) => { - switch (type) { - case ColumnType.Date: return "_d"; - case ColumnType.String: return "_t"; - case ColumnType.Boolean: return "_b"; - case ColumnType.Number: return "_n"; + render() { + const results = this._results.map(result => { + var className = "searchBox-results-scroll-view-result"; + + if (this._selectedResult == result[0]) { + className += " searchBox-results-scroll-view-result-selected" } - }; - const headers = Cast(this.props.Document._schemaHeaders, listSpec(SchemaHeaderField), []); - return headers.reduce((p: Opt, header: SchemaHeaderField) => p || (header.desc !== undefined && suffixMap(header.type) ? (header.heading + suffixMap(header.type) + (header.desc ? " desc" : " asc")) : undefined), undefined); - } - searchDatabase = async (query: string) => { - this._lockPromise && (await this._lockPromise); - this._lockPromise = new Promise(async res => { - while (this._results.length <= this._endIndex && (this._numTotalResults === -1 || this._maxSearchIndex < this._numTotalResults)) { - this._curRequest = SearchUtil.Search(query, true, { onlyAliases: true, allowAliases: true, /*sort: this.primarySort,*/ fq: this.filterQuery, start: 0, rows: this._numResultsPerPage, hl: "on", "hl.fl": "*", }).then(action(async (res: SearchUtil.DocSearchResult) => { - // happens at the beginning - this.realTotalResults = res.numFound <= 0 ? 0 : res.numFound; - if (res.numFound !== this._numTotalResults && this._numTotalResults === -1) { - this._numTotalResults = res.numFound; - } - const highlighting = res.highlighting || {}; - const highlightList = res.docs.map(doc => highlighting[doc[Id]]); - const lines = new Map(); - res.docs.map((doc, i) => lines.set(doc[Id], res.lines[i])); - const docs = res.docs; - const highlights: typeof res.highlighting = {}; - docs.forEach((doc, index) => highlights[doc[Id]] = highlightList[index]); - const filteredDocs = this.filterDocsByType(docs); - - runInAction(() => filteredDocs.forEach((doc, i) => { - const index = this._resultsSet.get(doc); - const highlight = highlights[doc[Id]]; - const line = lines.get(doc[Id]) || []; - const hlights = highlight ? Object.keys(highlight).map(key => key.substring(0, key.length - 2)).filter(k => k) : []; - // if (this.findCommonElements(hlights)) { - // } - if (index === undefined) { - this._resultsSet.set(doc, this._results.length); - this._results.push([doc, hlights, line]); - } else { - this._results[index][1].push(...hlights); - this._results[index][2].push(...line); - } - })); - - this._curRequest = undefined; - })); - this._maxSearchIndex += this._numResultsPerPage; - - await this._curRequest; + if (this._docTypeString == "all" || this._docTypeString == result[0].type) { + return (
this.onResultClick(result[0])} className={className}>
{result[0].title}
) } - this.resultsScrolled(); + return null; + }) - const selectedCollection = this.currentSelectedCollection;//SelectionManager.SelectedDocuments()[0]; - this.docsforfilter = this._results.map(r => r[0]); - this.setSearchFilter(selectedCollection, this.filter ? this.docsforfilter : undefined); - res(); - }); - return this._lockPromise; + results.filter(result => result) + + return ( +
+
+ + +
+
+
+ {`${results.length}` + " result" + (results.length == 1 ? "" : "s")} +
+
+ {results} +
+
+
+ ); } +} + + + +/* +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { Tooltip } from '@material-ui/core'; +import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx'; +import { observer } from 'mobx-react'; +import * as React from 'react'; +import { Doc, DocListCast, Field, Opt, DocListCastAsync, DataSym, HeightSym, FieldsSym } from '../../../fields/Doc'; +import { documentSchema } from "../../../fields/documentSchemas"; +import { Copy, Id, ToString } from '../../../fields/FieldSymbols'; +import { List } from '../../../fields/List'; +import { createSchema, listSpec, makeInterface } from '../../../fields/Schema'; +import { SchemaHeaderField } from '../../../fields/SchemaHeaderField'; +import { Cast, NumCast, StrCast } from '../../../fields/Types'; +import { emptyFunction, returnFalse, returnZero, setupMoveUpEvents, Utils } from '../../../Utils'; +import { Docs } from '../../documents/Documents'; +import { DocumentType } from "../../documents/DocumentTypes"; +import { CurrentUserUtils } from "../../util/CurrentUserUtils"; +import { SetupDrag } from '../../util/DragManager'; +import { SearchUtil } from '../../util/SearchUtil'; +import { Transform } from '../../util/Transform'; +import { CollectionDockingView } from "../collections/CollectionDockingView"; +import { CollectionSchemaView, ColumnType } from "../collections/CollectionSchemaView"; +import { CollectionViewType } from '../collections/CollectionView'; +import { ViewBoxBaseComponent } from "../DocComponent"; +import { FieldView, FieldViewProps } from '../nodes/FieldView'; +import "./SearchBox.scss"; +import { undoBatch } from "../../util/UndoManager"; +import { DocServer } from "../../DocServer"; +import { MainView } from "../MainView"; +import { SelectionManager } from "../../util/SelectionManager"; +import { CollectionSchemaBooleanCell } from "../collections/CollectionSchemaCells"; +import { transpileModule } from "typescript"; +import { DocumentManager } from "../../util/DocumentManager"; + +export const searchSchema = createSchema({ Document: Doc }); + +type SearchBoxDocument = makeInterface<[typeof documentSchema, typeof searchSchema]>; +const SearchBoxDocument = makeInterface(documentSchema, searchSchema); + +@observer +export class SearchBox extends ViewBoxBaseComponent(SearchBoxDocument) { + public static LayoutString(fieldKey: string) { return FieldView.LayoutString(SearchBox, fieldKey); } + public static Instance: SearchBox; + + @observable _searchString = ""; + @observable _docTypeString = "all"; + @observable _results: [Doc, string[], string[]][] = []; + @observable _selectedResult: Doc | undefined = undefined; + @observable _deletedDocsStatus: boolean = false; + @observable _onlyAliases: boolean = true; - @action.bound - openSearch(e: React.SyntheticEvent) { - e.stopPropagation(); - this._results.forEach(result => Doc.BrushDoc(result[0])); + constructor(props: any) { + super(props); + SearchBox.Instance = this; } - resetSearch = action((close: boolean) => { - this._results.forEach(result => { - Doc.UnBrushDoc(result[0]); - Doc.ClearSearchMatches(); - }); - close && (this.open = this._searchbarOpen = false); + onInputChange = action((e: React.ChangeEvent) => { + this._searchString = e.target.value; + this.submitSearch(); }); - @action.bound - closeResults() { - this._results = []; - this._resultsSet.clear(); - this._visibleElements = []; - this._visibleDocuments = []; - this._numTotalResults = -1; - this._endIndex = -1; - this._curRequest = undefined; - } + onSelectChange = action((e: React.ChangeEvent) => { + this._docTypeString = e.target.value; + this.submitSearch(); + }); - @action - resultsScrolled = (e?: React.UIEvent) => { - this._endIndex = 30; - const headers = new Set(["title", "author", "text", "type", "data", "*lastModified", "context"]); + onResultClick = action((doc: Doc) => { + this.selectElement(doc); + this._selectedResult = doc; + }); - if (this._numTotalResults <= this._maxSearchIndex) { - this._numTotalResults = this._results.length; + static foreachRecursiveDoc(docs: Doc[], func: (doc: Doc) => void) { + const blockedTypes = [DocumentType.PRESELEMENT, DocumentType.KVP, DocumentType.FILTER, DocumentType.SEARCH, DocumentType.SEARCHITEM, DocumentType.FONTICON, DocumentType.BUTTON, DocumentType.SCRIPTING]; + let newarray: Doc[] = []; + while (docs.length > 0) { + newarray = []; + docs.filter(d => d).forEach(d => { + const dtype = StrCast(d.type, "string") as DocumentType; + if (dtype && !blockedTypes.includes(dtype)) { + const fieldKey = Doc.LayoutFieldKey(d); + const annos = !Field.toString(Doc.LayoutField(d) as Field).includes("CollectionView"); + const data = d[annos ? fieldKey + "-annotations" : fieldKey]; + data && newarray.push(...DocListCast(data)); + func(d); + } + }); + docs = newarray; } + } - // only hit right at the beginning - // visibleElements is all of the elements (even the ones you can't see) - if (this._visibleElements.length !== this._numTotalResults) { - // undefined until a searchitem is put in there - this._visibleElements = Array(this._numTotalResults === -1 ? 0 : this._numTotalResults); - this._visibleDocuments = Array(this._numTotalResults === -1 ? 0 : this._numTotalResults); - } - let max = this._numResultsPerPage; - max > this._results.length ? max = this._results.length : console.log(""); - for (let i = this._pageStart; i < max; i++) { - //if the index is out of the window then put a placeholder in - //should ones that have already been found get set to placeholders? - - let result: [Doc, string[], string[]] | undefined = undefined; - - result = this._results[i]; - if (result) { - const highlights = Array.from([...Array.from(new Set(result[1]).values())]); - const lines = new List(result[2]); - highlights.forEach((item) => headers.add(item)); - Doc.SetSearchMatch(result[0], { searchMatch: 1 }); - if (i < this._visibleDocuments.length) { - this._visibleDocuments[i] = result[0]; - Doc.BrushDoc(result[0]); - Doc.AddDocToList(this.dataDoc, this.props.fieldKey, result[0]); - this.children++; + @action + searchCollection(query: string) { + const selectedCollection = CollectionDockingView.Instance; + query = query.toLowerCase(); + + if (selectedCollection !== undefined) { + console.log("hello111") + // this._currentSelectedCollection = selectedCollection; + const docs = DocListCast(selectedCollection.dataDoc[Doc.LayoutFieldKey(selectedCollection.dataDoc)]); + const found: [Doc, string[], string[]][] = []; + SearchBox.foreachRecursiveDoc(docs, (doc: Doc) => { + console.log("HELLO") + if (this._docTypeString == "all" || this._docTypeString == doc.type) { + const hlights = new Set(); + SearchBox.documentKeys(doc).forEach(key => Field.toString(doc[key] as Field).toLowerCase().includes(query) && hlights.add(key)); + Array.from(hlights.keys()).length > 0 && found.push([doc, Array.from(hlights.keys()), []]); } - } - } - if (this.props.Document._schemaHeaders === undefined) { - this.props.Document._schemaHeaders = new List([new SchemaHeaderField("title", "#f1efeb")]); - } - if (this._maxSearchIndex >= this._numTotalResults) { - this._visibleElements.length = this._results.length; - this._visibleDocuments.length = this._results.length; + }); + + this._results = found; + //this.setSearchFilter(selectedCollection, this.filter && found.length ? this._docsforfilter : undefined); } } - getTransform = () => this.props.ScreenToLocalTransform().translate(-5, -65);// listBox padding-left and pres-box-cont minHeight - panelHeight = () => this.props.PanelHeight(); - selectElement = (doc: Doc) => { /* this.gotoDocument(this.childDocs.indexOf(doc), NumCasst(this.layoutDoc._itemIndex)); */ }; - returnHeight = () => NumCast(this.layoutDoc._height); - returnLength = () => Math.min(window.innerWidth, 51 + 205 * Cast(this.props.Document._schemaHeaders, listSpec(SchemaHeaderField), []).length); - - setSearchFilter = action((collectionView: { props: { Document: Doc } }, docsForFilter: Doc[] | undefined) => { - if (collectionView) { - const docFilters = Cast(this.props.Document._docFilters, listSpec("string"), null); - collectionView.props.Document._searchFilterDocs = docsForFilter?.length ? new List(docsForFilter) : undefined; - collectionView.props.Document._docFilters = docsForFilter?.length && docFilters?.length ? new List(docFilters) : undefined; + static documentKeys(doc: Doc) { + const keys: { [key: string]: boolean } = {}; + // bcz: ugh. this is untracked since otherwise a large collection of documents will blast the server for all their fields. + // then as each document's fields come back, we update the documents _proxies. Each time we do this, the whole schema will be + // invalidated and re-rendered. This workaround will inquire all of the document fields before the options button is clicked. + // then by the time the options button is clicked, all of the fields should be in place. If a new field is added while this menu + // is displayed (unlikely) it won't show up until something else changes. + //TODO Types + Doc.GetAllPrototypes(doc).map(proto => Object.keys(proto).forEach(key => keys[key] = false)); + return Array.from(Object.keys(keys)); + } + + @action + submitSearch = async () => { + Doc.ClearSearchMatches(); + this._results = []; + + this.dataDoc[this.fieldKey] = new List([]); + let query = StrCast(this._searchString); + Doc.SetSearchQuery(query); + this._results = []; + + if (query) { + this.searchCollection(query); } - }); + } + + selectElement = async (doc: Doc) => { + await DocumentManager.Instance.jumpToDocument(doc, true); // documents open in new tab instead of on right + } render() { - const myDashboards = DocListCast(CurrentUserUtils.MyDashboards.data); + const results = this._results.map(result => { + var className = "searchBox-results-scroll-view-result"; + + if (this._selectedResult == result[0]) { + className += " searchBox-results-scroll-view-result-selected" + } + + return (
this.onResultClick(result[0])} className={className}>
{result[0].title}
) + }) return (
-
-
- -
-
- -
-
- {`${this._results.length}` + " of " + `${this.realTotalResults}`} -
-
-
+
+ +
- {!this._searchbarOpen ? (null) : -
r?.focus()}> -
-
- window.innerWidth || this.children > 6 ? true : false} - focus={this.selectElement} - ScreenToLocalTransform={Transform.Identity} - /> -
setupMoveUpEvents(this, e, (e: PointerEvent, down: number[], delta: number[]) => { - this.props.Document._height = NumCast(this.props.Document._height) + delta[1]; - return false; - }, returnFalse, emptyFunction)} - > - -
-
-
+
+
+ {`${this._results.length}` + " result" + (this._results.length == 1 ? "" : "s")}
- } +
+ {results} +
+
); } -} \ No newline at end of file +}*/ \ No newline at end of file -- cgit v1.2.3-70-g09d2 From b1361eec6d3f554d4927931c339b5c169b9a54a7 Mon Sep 17 00:00:00 2001 From: geireann Date: Sat, 31 Jul 2021 22:23:55 -0400 Subject: mini css changes --- src/client/views/DocumentButtonBar.scss | 1 - src/client/views/topbar/TopBar.scss | 9 ++++++--- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/client/views/DocumentButtonBar.scss b/src/client/views/DocumentButtonBar.scss index 171e7134f..a112f4745 100644 --- a/src/client/views/DocumentButtonBar.scss +++ b/src/client/views/DocumentButtonBar.scss @@ -46,7 +46,6 @@ $linkGap : 3px; .documentButtonBar { display: flex; flex-direction: row; - gap: 3px; } .documentButtonBar-button { diff --git a/src/client/views/topbar/TopBar.scss b/src/client/views/topbar/TopBar.scss index ac6ec9b30..164cc29cd 100644 --- a/src/client/views/topbar/TopBar.scss +++ b/src/client/views/topbar/TopBar.scss @@ -50,12 +50,15 @@ align-items: center; gap: 5px; + .topbar-dashboards { + display: flex; + flex-direction: row; + } + .topbar-lozenge-dashboard { display: flex; - .topbar-dashboards { - display: inline-flex; - } + .topbar-dashSelect { border: none; -- cgit v1.2.3-70-g09d2 From f59495f0aa5ba65b358f9430f55c653ed0fc3d70 Mon Sep 17 00:00:00 2001 From: Aubrey-Li <63608597+Aubrey-Li@users.noreply.github.com> Date: Sat, 31 Jul 2021 22:26:48 -0700 Subject: small UI changes --- src/client/views/global/globalCssVariables.scss | 22 +++++++++++----------- src/client/views/nodes/DocumentView.tsx | 4 ++-- 2 files changed, 13 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/client/views/global/globalCssVariables.scss b/src/client/views/global/globalCssVariables.scss index 1b881ba43..7556f8b8a 100644 --- a/src/client/views/global/globalCssVariables.scss +++ b/src/client/views/global/globalCssVariables.scss @@ -1,15 +1,15 @@ -@import url("https://fonts.googleapis.com/css?family=Noto+Sans:400,700|Crimson+Text:400,400i,700"); +@import url("https://fonts.googleapis.com/css2?family=Roboto&display=swap"); // colors $white: #ffffff; -$light-gray:#dfdfdf; -$medium-gray: #9F9F9F; +$light-gray: #dfdfdf; +$medium-gray: #9f9f9f; $dark-gray: #323232; $black: #000000; -$light-blue: #BDDDF5; -$medium-blue: #4476F7; -$pink: #E0217D; -$yellow: #F5D747; +$light-blue: #bdddf5; +$medium-blue: #4476f7; +$pink: #e0217d; +$yellow: #f5d747; $close-red: #e48282; @@ -24,7 +24,7 @@ $large-padding: 32px; $icon-size: 28px; // fonts -$sans-serif: "Noto Sans", sans-serif; +$sans-serif: "Roboto", sans-serif; $large-header: 16px; $body-text: 12px; $small-text: 9px; @@ -41,7 +41,7 @@ $contextMenu-zindex: 100000; // context menu shows up over everything $radialMenu-zindex: 100000; // context menu shows up over everything // borders -$standard-border: solid 1px #9F9F9F; +$standard-border: solid 1px #9f9f9f; $searchpanel-height: 32px; $mainTextInput-zindex: 999; // then text input overlay so that it's context menu will appear over decorations, etc @@ -49,7 +49,7 @@ $docDecorations-zindex: 998; // then doc decorations appear over everything else $remoteCursors-zindex: 997; // ... not sure what level the remote cursors should go -- is this right? $COLLECTION_BORDER_WIDTH: 0; $SCHEMA_DIVIDER_WIDTH: 4; -$MINIMIZED_ICON_SIZE:24; +$MINIMIZED_ICON_SIZE: 24; $MAX_ROW_HEIGHT: 44px; $DFLT_IMAGE_NATIVE_DIM: 900px; $MENU_PANEL_WIDTH: 60px; @@ -67,4 +67,4 @@ $TREE_BULLET_WIDTH: 20px; DFLT_IMAGE_NATIVE_DIM: $DFLT_IMAGE_NATIVE_DIM; MENU_PANEL_WIDTH: $MENU_PANEL_WIDTH; TREE_BULLET_WIDTH: $TREE_BULLET_WIDTH; -} \ No newline at end of file +} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index df4cba01b..97ad37a08 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -971,7 +971,7 @@ export class DocumentViewInternal extends DocComponent Date: Sat, 31 Jul 2021 22:35:07 -0700 Subject: unified Properties font to Roboto --- src/client/views/PropertiesView.scss | 28 +++------------------------- 1 file changed, 3 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/client/views/PropertiesView.scss b/src/client/views/PropertiesView.scss index fa45a065d..934ede732 100644 --- a/src/client/views/PropertiesView.scss +++ b/src/client/views/PropertiesView.scss @@ -1,6 +1,6 @@ .propertiesView { height: 100%; - font-family: "Noto Sans"; + font-family: "Roboto"; cursor: auto; overflow-x: hidden; @@ -28,9 +28,7 @@ color: grey; cursor: pointer; } - } - } .propertiesView-name { @@ -80,7 +78,6 @@ padding-bottom: 10px; padding-top: 8px; } - } .propertiesView-sharing { @@ -140,8 +137,6 @@ } } - - .change-buttons { display: flex; @@ -216,7 +211,6 @@ } } - .propertiesView-appearance { //border-bottom: 1px solid black; //padding: 8.5px; @@ -305,7 +299,7 @@ .notify-button-icon { width: 6px; height: 6.5px; - margin-left: .5px; + margin-left: 0.5px; } &:hover { @@ -331,7 +325,6 @@ } .propertiesView-sharingTable { - // whatever's commented out - add it back in when adding the buttons // border: 1.5px solid black; @@ -347,7 +340,6 @@ width: 92%; .propertiesView-sharingTable-item { - display: flex; // padding: 5px; padding: 3px; @@ -421,7 +413,6 @@ cursor: pointer; } } - } .propertiesView-fields-checkbox { @@ -468,7 +459,6 @@ } .propertiesView-contexts { - .propertiesView-contexts-title { font-weight: bold; font-size: 12.5px; @@ -499,11 +489,9 @@ overflow: hidden; padding: 10px; } - } .propertiesView-layout { - .propertiesView-layout-title { font-weight: bold; font-size: 12.5px; @@ -534,7 +522,6 @@ overflow: hidden; padding: 10px; } - } .propertiesView-presTrails { @@ -576,7 +563,6 @@ } .inking-button { - display: flex; .inking-button-points { @@ -635,7 +621,6 @@ } .inputBox { - margin-top: 10px; display: flex; height: 19px; @@ -658,7 +643,6 @@ } .inputBox-button { - .inputBox-button-up { background-color: #333333; height: 9px; @@ -690,7 +674,6 @@ cursor: pointer; } } - } } @@ -767,7 +750,6 @@ } .widthAndDash { - .width { .width-top { display: flex; @@ -792,13 +774,11 @@ } .arrows { - display: flex; margin-bottom: 3px; margin-left: 4px; .arrows-head { - display: flex; margin-right: 35px; @@ -827,7 +807,6 @@ } .dashed { - display: flex; margin-left: 64px; margin-bottom: 6px; @@ -856,7 +835,6 @@ } } - .properties-flyout { grid-column: 2/4; -} \ No newline at end of file +} -- cgit v1.2.3-70-g09d2 From 149b2de414812063bc8c81305f284f74a24481cb Mon Sep 17 00:00:00 2001 From: geireann Date: Sun, 1 Aug 2021 18:45:21 -0400 Subject: small ui tweaks --- src/client/util/DragManager.ts | 9 +++ src/client/views/EditableView.scss | 8 ++- src/client/views/PropertiesView.scss | 9 ++- .../views/collections/CollectionLinearView.scss | 3 + src/client/views/nodes/LinkDescriptionPopup.scss | 65 ++++++++-------------- 5 files changed, 46 insertions(+), 48 deletions(-) (limited to 'src') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index c4842e88a..5e16de617 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -15,6 +15,15 @@ import { SnappingManager } from "./SnappingManager"; import { UndoManager } from "./UndoManager"; export type dropActionType = "alias" | "copy" | "move" | "same" | "proto" | "none" | undefined; // undefined = move, "same" = move but don't call removeDropProperties + +/** + * Initialize drag + * @param _reference: The HTMLElement that is being dragged + * @param docFunc: The Dash document being moved + * @param moveFunc: The function called when the document is moved + * @param dropAction: What to do with the document when it is dropped + * @param dragStarted: Method to call when the drag is started + */ export function SetupDrag( _reference: React.RefObject, docFunc: () => Doc | Promise | undefined, diff --git a/src/client/views/EditableView.scss b/src/client/views/EditableView.scss index 5dc0c1962..1aebedf2e 100644 --- a/src/client/views/EditableView.scss +++ b/src/client/views/EditableView.scss @@ -26,4 +26,10 @@ width: 100%; background: inherit; pointer-events: all; -} \ No newline at end of file +} + +.editableView-input:focus { + border: none; + outline: none; +} + \ No newline at end of file diff --git a/src/client/views/PropertiesView.scss b/src/client/views/PropertiesView.scss index 934ede732..321b83f52 100644 --- a/src/client/views/PropertiesView.scss +++ b/src/client/views/PropertiesView.scss @@ -1,3 +1,5 @@ +@import "./global/globalCssVariables.scss"; + .propertiesView { height: 100%; font-family: "Roboto"; @@ -823,15 +825,12 @@ } .editable-title { - border: none; padding: 6px; padding-bottom: 2px; - background: #eeeeee; - border-top: 1px solid; - border-left: 1px solid; + border: solid 1px $dark-gray; &:hover { - border: 0.75px solid rgb(122, 28, 28); + border: 0.75px solid $medium-blue; } } diff --git a/src/client/views/collections/CollectionLinearView.scss b/src/client/views/collections/CollectionLinearView.scss index 913a65774..46e40489b 100644 --- a/src/client/views/collections/CollectionLinearView.scss +++ b/src/client/views/collections/CollectionLinearView.scss @@ -22,6 +22,7 @@ .bottomPopup-background { background: $medium-blue; display: flex; + border-radius: 10px; height: 35; transform: translate3d(6px, 0px, 0px); align-content: center; @@ -40,6 +41,7 @@ } .bottomPopup-descriptions { + cursor:pointer; display: inline; white-space: nowrap; padding-left: 8px; @@ -52,6 +54,7 @@ } .bottomPopup-exit { + cursor:pointer; display: inline; white-space: nowrap; margin-right: 10px; diff --git a/src/client/views/nodes/LinkDescriptionPopup.scss b/src/client/views/nodes/LinkDescriptionPopup.scss index d92823ccc..a8db5d360 100644 --- a/src/client/views/nodes/LinkDescriptionPopup.scss +++ b/src/client/views/nodes/LinkDescriptionPopup.scss @@ -1,9 +1,13 @@ +@import "../global/globalCssVariables.scss"; + .linkDescriptionPopup { display: flex; - - border: 1px solid rgb(170, 26, 26); - + flex-direction: row; + justify-content: center; + align-items: center; + border: 2px solid $medium-blue; + background-color: $white; width: auto; position: absolute; @@ -11,17 +15,11 @@ z-index: 10000; border-radius: 10px; font-size: 12px; - //white-space: nowrap; - - background-color: rgba(250, 250, 250, 0.95); - padding-top: 9px; - padding-bottom: 9px; - padding-left: 9px; - padding-right: 9px; + gap: 5px; + padding: 9px; .linkDescriptionPopup-input { float: left; - background-color: rgba(250, 250, 250, 0.95); color: rgb(100, 100, 100); border: none; min-width: 160px; @@ -30,46 +28,29 @@ .linkDescriptionPopup-btn { float: right; - justify-content: center; vertical-align: middle; - .linkDescriptionPopup-btn-dismiss { - background-color: white; - color: black; + cursor: pointer; display: inline; - right: 0; - border-radius: 10px; - border: 1px solid black; - padding: 3px; - font-size: 9px; - text-align: center; - position: relative; - margin-right: 4px; - justify-content: center; - - &:hover{ - cursor: pointer; - } + white-space: nowrap; + padding: 5px; + vertical-align: middle; + background-color: $close-red; + border-radius: 3px; + color: black; } .linkDescriptionPopup-btn-add { - background-color: black; - color: white; + cursor: pointer; display: inline; - right: 0; - border-radius: 10px; - border: 1px solid black; - padding: 3px; - font-size: 9px; - text-align: center; - position: relative; - justify-content: center; - - &:hover{ - cursor: pointer; - } + white-space: nowrap; + padding: 5px; + vertical-align: middle; + background-color: $light-blue; + border-radius: 3px; + color: black; } } -- cgit v1.2.3-70-g09d2 From 0546ecf205b7d2b76f341a7157beebf95fb888a8 Mon Sep 17 00:00:00 2001 From: bobzel Date: Sun, 1 Aug 2021 22:43:46 -0400 Subject: made url server references relative. --- src/Utils.ts | 1 - .../apis/google_docs/GooglePhotosClientUtils.ts | 2 +- src/client/documents/Documents.ts | 90 ++-------------------- src/client/util/HypothesisUtils.ts | 2 +- src/client/views/collections/CollectionSubView.tsx | 2 +- .../views/collections/CollectionTimeView.tsx | 2 +- src/client/views/nodes/AudioBox.tsx | 2 +- src/client/views/nodes/DocumentLinksButton.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 6 +- src/client/views/nodes/FieldView.tsx | 6 +- src/client/views/nodes/ImageBox.tsx | 2 +- src/client/views/nodes/LinkDocPreview.tsx | 4 +- src/client/views/nodes/PDFBox.tsx | 24 ------ src/client/views/nodes/ScreenshotBox.tsx | 4 +- src/client/views/nodes/VideoBox.tsx | 8 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 6 +- .../views/nodes/formattedText/RichTextMenu.tsx | 8 +- src/client/views/pdf/AnchorMenu.tsx | 1 - src/fields/Doc.ts | 12 ++- src/fields/URLField.ts | 15 +++- src/mobile/ImageUpload.tsx | 2 +- src/server/server_Initialization.ts | 3 +- 22 files changed, 58 insertions(+), 146 deletions(-) (limited to 'src') diff --git a/src/Utils.ts b/src/Utils.ts index d87c3cc6b..194c38a6f 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -67,7 +67,6 @@ export namespace Utils { export function prepend(extension: string): string { return window.location.origin + extension; } - export function fileUrl(filename: string): string { return prepend(`/files/${filename}`); } diff --git a/src/client/apis/google_docs/GooglePhotosClientUtils.ts b/src/client/apis/google_docs/GooglePhotosClientUtils.ts index 899e65a16..ff9460b62 100644 --- a/src/client/apis/google_docs/GooglePhotosClientUtils.ts +++ b/src/client/apis/google_docs/GooglePhotosClientUtils.ts @@ -285,7 +285,7 @@ export namespace GooglePhotos { const photos = await endpoint(); const albumId = StrCast(collection.albumId); if (albumId && albumId.length) { - const enrichment = new photos.TextEnrichment(content || Utils.prepend("/doc/" + collection[Id])); + const enrichment = new photos.TextEnrichment(content || Doc.globalServerPath(collection)); const position = new photos.AlbumPosition(photos.AlbumPosition.POSITIONS.FIRST_IN_ALBUM); const enrichmentItem = await photos.albums.addEnrichment(albumId, enrichment, position); if (enrichmentItem) { diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index e863b4198..ac52b0acf 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -549,84 +549,6 @@ export namespace Docs { */ export namespace Create { - /** - * Synchronously returns a collection into which - * the device documents will be put. This is initially empty, - * but gets populated by updates from the web socket. When everything is over, - * this function cleans up after itself. - * s - * Look at Websocket.ts for the server-side counterpart to this - * function. - */ - export function Buxton() { - let responded = false; - const loading = new Doc; - loading.title = "Please wait for the import script..."; - const parent = TreeDocument([loading], { - title: "The Buxton Collection", - _width: 400, - _height: 400 - }); - const parentProto = Doc.GetProto(parent); - const { _socket } = DocServer; - - // just in case, clean up - _socket.off(MessageStore.BuxtonDocumentResult.Message); - _socket.off(MessageStore.BuxtonImportComplete.Message); - - // this is where the client handles the receipt of a new valid parsed document - Utils.AddServerHandler(_socket, MessageStore.BuxtonDocumentResult, ({ device, invalid: errors }) => { - if (!responded) { - responded = true; - parentProto.data = new List(); - } - if (device) { - const { title, __images, additionalMedia } = device; - delete device.__images; - delete device.additionalMedia; - const { ImageDocument, StackingDocument } = Docs.Create; - const constructed = __images.map(({ url, nativeWidth, nativeHeight }) => ({ url: Utils.prepend(url), nativeWidth, nativeHeight })); - const deviceImages = constructed.map(({ url, nativeWidth, nativeHeight }, i) => { - const imageDoc = ImageDocument(url, { - title: `image${i}.${extname(url)}`, - _nativeWidth: nativeWidth, - _nativeHeight: nativeHeight - }); - const media = additionalMedia[i]; - if (media) { - for (const key of Object.keys(media)) { - imageDoc[`additionalMedia_${key}`] = Utils.prepend(`/files/${key}/buxton/${media[key]}`); - } - } - return imageDoc; - }); - // the main document we create - const doc = StackingDocument(deviceImages, { title, hero: new ImageField(constructed[0].url) }); - doc.nameAliases = new List([title.toLowerCase()]); - // add the parsed attributes to this main document - Doc.Get.FromJson({ data: device, appendToExisting: { targetDoc: Doc.GetProto(doc) } }); - Doc.AddDocToList(parentProto, "data", doc); - } else if (errors) { - console.log("Documents:" + errors); - } else { - alert("A Buxton document import was completely empty (??)"); - } - }); - - // when the import is complete, we stop listening for these creation - // and termination events and alert the user - Utils.AddServerHandler(_socket, MessageStore.BuxtonImportComplete, ({ deviceCount, errorCount }) => { - _socket.off(MessageStore.BuxtonDocumentResult.Message); - _socket.off(MessageStore.BuxtonImportComplete.Message); - alert(`Successfully imported ${deviceCount} device${deviceCount === 1 ? "" : "s"}, with ${errorCount} error${errorCount === 1 ? "" : "s"}, in ${(Date.now() - startTime) / 1000} seconds.`); - }); - const startTime = Date.now(); - Utils.Emit(_socket, MessageStore.BeginBuxtonImport, ""); // signal the server to start importing - return parent; // synchronously return the collection, to be populateds - } - - Scripting.addGlobal(Buxton); - /** * This function receives the relevant document prototype and uses * it to create a new of that base-level prototype, or the @@ -675,7 +597,7 @@ export namespace Docs { } export function ImageDocument(url: string, options: DocumentOptions = {}) { - const imgField = new ImageField(new URL(url)); + const imgField = new ImageField(url); return InstanceFromProto(Prototypes.get(DocumentType.IMG), imgField, { title: path.basename(url), ...options }); } @@ -689,11 +611,11 @@ export namespace Docs { } export function VideoDocument(url: string, options: DocumentOptions = {}) { - return InstanceFromProto(Prototypes.get(DocumentType.VID), new VideoField(new URL(url)), options); + return InstanceFromProto(Prototypes.get(DocumentType.VID), new VideoField(url), options); } export function YoutubeDocument(url: string, options: DocumentOptions = {}) { - return InstanceFromProto(Prototypes.get(DocumentType.YOUTUBE), new YoutubeField(new URL(url)), options); + return InstanceFromProto(Prototypes.get(DocumentType.YOUTUBE), new YoutubeField(url), options); } export function WebCamDocument(url: string, options: DocumentOptions = {}) { @@ -709,7 +631,7 @@ export namespace Docs { } export function AudioDocument(url: string, options: DocumentOptions = {}) { - return InstanceFromProto(Prototypes.get(DocumentType.AUDIO), new AudioField(new URL(url)), + return InstanceFromProto(Prototypes.get(DocumentType.AUDIO), new AudioField(url), { ...options, backgroundColor: ComputedField.MakeFunction("this._mediaState === 'playing' ? 'green':'gray'") as any }); } @@ -782,11 +704,11 @@ export namespace Docs { } export function PdfDocument(url: string, options: DocumentOptions = {}) { - return InstanceFromProto(Prototypes.get(DocumentType.PDF), new PdfField(new URL(url)), options); + return InstanceFromProto(Prototypes.get(DocumentType.PDF), new PdfField(url), options); } export function WebDocument(url: string, options: DocumentOptions = {}) { - return InstanceFromProto(Prototypes.get(DocumentType.WEB), url ? new WebField(new URL(url)) : undefined, options); + return InstanceFromProto(Prototypes.get(DocumentType.WEB), url ? new WebField(url) : undefined, options); } export function HtmlDocument(html: string, options: DocumentOptions = {}) { diff --git a/src/client/util/HypothesisUtils.ts b/src/client/util/HypothesisUtils.ts index 8ddfce772..635673025 100644 --- a/src/client/util/HypothesisUtils.ts +++ b/src/client/util/HypothesisUtils.ts @@ -126,7 +126,7 @@ export namespace Hypothesis { }); const annotationId = StrCast(linkDoc.annotationId); - const linkUrl = Utils.prepend("/doc/" + sourceDoc[Id]); + const linkUrl = Doc.globalServerPath(sourceDoc); const interval = setInterval(() => {// keep trying to edit until annotations have loaded and editing is successful !success && document.dispatchEvent(new CustomEvent<{ targetUrl: string, id: string }>("deleteLink", { detail: { targetUrl: linkUrl, id: annotationId }, diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index a5d27f038..0d9b64d24 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -303,7 +303,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: } else { const path = window.location.origin + "/doc/"; if (text.startsWith(path)) { - const docid = text.replace(Utils.prepend("/doc/"), "").split("?")[0]; + const docid = text.replace(Doc.globalServerPath(), "").split("?")[0]; DocServer.GetRefField(docid).then(f => { if (f instanceof Doc) { if (options.x || options.y) { f.x = options.x; f.y = options.y; } // should be in CollectionFreeFormView diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 339163510..08b5e6bac 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -37,7 +37,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { @observable _focusRangeFilters: Opt; getAnchor = () => { - const anchor = Docs.Create.HTMLAnchorDocument({ + const anchor = Docs.Create.HTMLAnchorDocument([], { title: ComputedField.MakeFunction(`"${this.pivotField}"])`) as any, annotationOn: this.rootDoc }); diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index a2e36f12e..82bad971d 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -196,7 +196,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent { const [{ result }] = await Networking.UploadFilesToServer(e.data); if (!(result instanceof Error)) { - this.props.Document[this.props.fieldKey] = new AudioField(Utils.prepend(result.accessPaths.agnostic.client)); + this.props.Document[this.props.fieldKey] = new AudioField(result.accessPaths.agnostic.client); } }; this._recordStart = new Date().getTime(); diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx index ddc36daa1..aa3f10188 100644 --- a/src/client/views/nodes/DocumentLinksButton.tsx +++ b/src/client/views/nodes/DocumentLinksButton.tsx @@ -194,7 +194,7 @@ export class DocumentLinksButton extends React.Component GooglePhotos.Query.TagChildImages(this.props.Document), icon: "caret-square-right" }); moreItems.push({ description: "Write Back Link to Album", event: () => GooglePhotos.Transactions.AddTextEnrichment(this.props.Document), icon: "caret-square-right" }); } - moreItems.push({ description: "Copy ID", event: () => Utils.CopyText(Utils.prepend("/doc/" + this.props.Document[Id])), icon: "fingerprint" }); + moreItems.push({ description: "Copy ID", event: () => Utils.CopyText(Doc.globalServerPath(this.props.Document)), icon: "fingerprint" }); } } @@ -760,7 +760,7 @@ export class DocumentViewInternal extends DocComponent this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "add:right"), icon: "layer-group" }); - helpItems.push({ description: "Text Shortcuts Ctrl+/", event: () => this.props.addDocTab(Docs.Create.PdfDocument(Utils.prepend("/assets/cheat-sheet.pdf"), { _width: 300, _height: 300 }), "add:right"), icon: "keyboard" }); + helpItems.push({ description: "Text Shortcuts Ctrl+/", event: () => this.props.addDocTab(Docs.Create.PdfDocument("/assets/cheat-sheet.pdf", { _width: 300, _height: 300 }), "add:right"), icon: "keyboard" }); !Doc.UserDoc().novice && helpItems.push({ description: "Print Document in Console", event: () => console.log(this.props.Document), icon: "hand-point-right" }); cm.addItem({ description: "Help...", noexpand: true, subitems: helpItems, icon: "question" }); } @@ -885,7 +885,7 @@ export class DocumentViewInternal extends DocComponent { const [{ result }] = await Networking.UploadFilesToServer(e.data); if (!(result instanceof Error)) { - const audioDoc = Docs.Create.AudioDocument(Utils.prepend(result.accessPaths.agnostic.client), { title: "audio test", _width: 200, _height: 32 }); + const audioDoc = Docs.Create.AudioDocument(result.accessPaths.agnostic.client, { title: "audio test", _width: 200, _height: 32 }); audioDoc.treeViewExpandedView = "layout"; const audioAnnos = Cast(self.dataDoc[self.LayoutFieldKey + "-audioAnnotations"], listSpec(Doc)); if (audioAnnos === undefined) { diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 86250c9d1..ebbc1138a 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -64,9 +64,9 @@ export class FieldView extends React.Component { // else if (field instaceof PresBox) { // return ; // } - else if (field instanceof VideoField) { - return ; - } + // else if (field instanceof VideoField) { + // return ; + // } // else if (field instanceof AudioField) { // return ; //} diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index cfd43bb62..2c0106960 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -238,7 +238,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent { @computed get href() { if (this.props.hrefs?.length) { const href = this.props.hrefs[this._hrefInd]; - if (href.indexOf(Utils.prepend("/doc/")) !== 0) { // link to a web page URL -- try to show a preview + if (href.indexOf(Doc.localServerPath()) !== 0) { // link to a web page URL -- try to show a preview if (href.startsWith("https://en.wikipedia.org/wiki/")) { wiki().page(href.replace("https://en.wikipedia.org/wiki/", "")).then(page => page.summary().then(action(summary => this._toolTipText = summary.substring(0, 500)))); } else { setTimeout(action(() => this._toolTipText = "url => " + href)); } } else { // hyperlink to a document .. decode doc id and retrieve from the server. this will trigger vals() being invalidated - const anchorDoc = href.replace(Utils.prepend("/doc/"), "").split("?")[0]; + const anchorDoc = href.replace(Doc.localServerPath(), "").split("?")[0]; anchorDoc && DocServer.GetRefField(anchorDoc).then(action(anchor => { if (anchor instanceof Doc && DocListCast(anchor.links).length) { this._linkDoc = DocListCast(anchor.links)[0]; diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 8f61e252b..0b451e2b4 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -53,30 +53,6 @@ export class PDFBox extends ViewBoxAnnotatableComponent this._pdf = PDFBox.pdfcache.get(this.pdfUrl!.url.href)); else if (PDFBox.pdfpromise.get(this.pdfUrl.url.href)) PDFBox.pdfpromise.get(this.pdfUrl.url.href)?.then(action(pdf => this._pdf = pdf)); } - - const backup = "oldPath"; - const href = this.pdfUrl?.url.href; - if (href) { - const pathCorrectionTest = /upload\_[a-z0-9]{32}.(.*)/g; - const matches = pathCorrectionTest.exec(href); - // console.log("\nHere's the { url } being fed into the outer regex:"); - // console.log(href); - // console.log("And here's the 'properPath' build from the captured filename:\n"); - if (matches !== null && href.startsWith(window.location.origin)) { - const properPath = Utils.prepend(`/files/pdfs/${matches[0]}`); - //console.log(properPath); - if (!properPath.includes(href)) { - console.log(`The two (url and proper path) were not equal`); - const proto = Doc.GetProto(this.props.Document); - proto[this.props.fieldKey] = new PdfField(properPath); - proto[backup] = href; - } else { - //console.log(`The two (url and proper path) were equal`); - } - } else { - console.log("Outer matches was null!"); - } - } } componentWillUnmount() { this._selectReactionDisposer?.(); } diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx index 700f8a7d3..0e235a62d 100644 --- a/src/client/views/nodes/ScreenshotBox.tsx +++ b/src/client/views/nodes/ScreenshotBox.tsx @@ -227,7 +227,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent { const [{ result }] = await Networking.UploadFilesToServer(aud_chunks); if (!(result instanceof Error)) { - this.dataDoc[this.props.fieldKey + "-audio"] = new AudioField(Utils.prepend(result.accessPaths.agnostic.client)); + this.dataDoc[this.props.fieldKey + "-audio"] = new AudioField(result.accessPaths.agnostic.client); } }; this._videoRef!.srcObject = await (navigator.mediaDevices as any).getDisplayMedia({ video: true }); @@ -244,7 +244,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent { const aspect = this.player!.videoWidth / this.player!.videoHeight; Doc.SetNativeWidth(this.dataDoc, this.player!.videoWidth); @@ -182,8 +178,8 @@ export class VideoBox extends ViewBoxAnnotatableComponent { - const url = this.choosePath(Utils.prepend(relative)); + private createRealSummaryLink = (imagePath: string, downX?: number, downY?: number) => { + const url = !imagePath.startsWith("/") ? Utils.CorsProxy(imagePath) : imagePath; const width = this.layoutDoc._width || 1; const height = this.layoutDoc._height || 0; const imageSummary = Docs.Create.ImageDocument(url, { diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 140d39929..f7e9ee028 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -371,7 +371,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp this._searchIndex = ++this._searchIndex > flattened.length - 1 ? 0 : this._searchIndex; const anchor = Docs.Create.TextanchorDocument(); const alink = DocUtils.MakeLink({ doc: anchor }, { doc: target }, "automatic")!; - const allAnchors = [{ href: Utils.prepend("/doc/" + anchor[Id]), title: "a link", anchorId: anchor[Id] }]; + const allAnchors = [{ href: Doc.localServerPath(anchor), title: "a link", anchorId: anchor[Id] }]; const link = this._editorView!.state.schema.marks.linkAnchor.create({ allAnchors, title: "auto link", location }); tr = tr.addMark(flattened[i].from, flattened[i].to, link); }); @@ -705,7 +705,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp let tr = state.tr.addMark(sel.from, sel.to, splitter); if (sel.from !== sel.to) { const anchor = anchorDoc ?? Docs.Create.TextanchorDocument({ title: this._editorView?.state.doc.textBetween(sel.from, sel.to) }); - const href = targetHref ?? Utils.prepend("/doc/" + anchor[Id]); + const href = targetHref ?? Doc.localServerPath(anchor); if (anchor !== anchorDoc) this.addDocument(anchor); tr.doc.nodesBetween(sel.from, sel.to, (node: any, pos: number, parent: any) => { if (node.firstChild === null && node.marks.find((m: Mark) => m.type.name === schema.marks.splitter.name)) { @@ -1042,7 +1042,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } const marks = [...node.marks]; const linkIndex = marks.findIndex(mark => mark.type.name === "link"); - const allLinks = [{ href: Utils.prepend(`/doc/${linkId}`), title, linkId }]; + const allLinks = [{ href: Doc.globalServerPath(linkId), title, linkId }]; const link = view.state.schema.mark(view.state.schema.marks.linkAnchor, { allLinks, location: "add:right", title, docref: true }); marks.splice(linkIndex === -1 ? 0 : linkIndex, 1, link); return node.mark(marks); diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index a6f8ff2e2..fb4114023 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -821,8 +821,8 @@ export class RichTextMenu extends AntimodeMenu { if (link) { const href = link.attrs.allAnchors.length > 0 ? link.attrs.allAnchors[0].href : undefined; if (href) { - if (href.indexOf(Utils.prepend("/doc/")) === 0) { - const linkclicked = href.replace(Utils.prepend("/doc/"), "").split("?")[0]; + if (href.indexOf(Doc.localServerPath()) === 0) { + const linkclicked = href.replace(Doc.localServerPath(), "").split("?")[0]; if (linkclicked) { const linkDoc = await DocServer.GetRefField(linkclicked); if (linkDoc instanceof Doc) { @@ -864,8 +864,8 @@ export class RichTextMenu extends AntimodeMenu { const allAnchors = linkAnchor.attrs.allAnchors.slice(); this.TextView.RemoveAnchorFromSelection(allAnchors); // bcz: Argh ... this will remove the link from the document even it's anchored somewhere else in the text which happens if only part of the anchor text was selected. - allAnchors.filter((aref: any) => aref?.href.indexOf(Utils.prepend("/doc/")) === 0).forEach((aref: any) => { - const anchorId = aref.href.replace(Utils.prepend("/doc/"), "").split("?")[0]; + allAnchors.filter((aref: any) => aref?.href.indexOf(Doc.localServerPath()) === 0).forEach((aref: any) => { + const anchorId = aref.href.replace(Doc.localServerPath(), "").split("?")[0]; anchorId && DocServer.GetRefField(anchorId).then(linkDoc => LinkManager.Instance.deleteLink(linkDoc as Doc)); }); } diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx index 70ca19842..55816ed52 100644 --- a/src/client/views/pdf/AnchorMenu.tsx +++ b/src/client/views/pdf/AnchorMenu.tsx @@ -85,7 +85,6 @@ export class AnchorMenu extends AntimodeMenu { @action toggleLinkPopup = (e: React.MouseEvent) => { //ignore the potential null type error because this method cannot be called unless the user selects text and clicks the link button - console.log(window.getSelection().toString()) //change popup visibility field to visible this._showLinkPopup = !this._showLinkPopup; } diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 111fd3f0d..a7e5d8541 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -596,7 +596,7 @@ export namespace Doc { const mapped = cloneMap.get(id); return href + (mapped ? mapped[Id] : id); }; - const regex = `(${Utils.prepend("/doc/")})([^"]*)`; + const regex = `(${Doc.localServerPath()})([^"]*)`; const re = new RegExp(regex, "g"); copy[key] = new RichTextField(field.Data.replace(/("textId":|"audioId":|"anchorId":)"([^"]+)"/g, replacer).replace(re, replacer2), field.Text); }); @@ -896,6 +896,16 @@ export namespace Doc { return true; } + + // converts a document id to a url path on the server + export function globalServerPath(doc: Doc | string = ""): string { + return Utils.prepend("/doc/" + (doc instanceof Doc ? doc[Id] : doc)); + } + // converts a document id to a url path on the server + export function localServerPath(doc?: Doc): string { + return "/doc/" + (doc ? doc[Id] : ""); + } + export function overlapping(doc1: Doc, doc2: Doc, clusterDistance: number) { const doc2Layout = Doc.Layout(doc2); const doc1Layout = Doc.Layout(doc1); diff --git a/src/fields/URLField.ts b/src/fields/URLField.ts index fb71160ca..d96e8a70a 100644 --- a/src/fields/URLField.ts +++ b/src/fields/URLField.ts @@ -3,14 +3,17 @@ import { serializable, custom } from "serializr"; import { ObjectField } from "./ObjectField"; import { ToScriptString, ToString, Copy } from "./FieldSymbols"; import { Scripting, scriptingGlobal } from "../client/util/Scripting"; +import { Utils } from "../Utils"; function url() { return custom( function (value: URL) { - return value.href; + return value.origin === window.location.origin ? + value.pathname : + value.href; }, function (jsonValue: string) { - return new URL(jsonValue); + return new URL(jsonValue, window.location.origin); } ); } @@ -24,15 +27,21 @@ export abstract class URLField extends ObjectField { constructor(url: URL | string) { super(); if (typeof url === "string") { - url = new URL(url); + url = url.startsWith("http") ? new URL(url) : new URL(url, window.location.origin); } this.url = url; } [ToScriptString]() { + if (Utils.prepend(this.url.pathname) === this.url.href) { + return `new ${this.constructor.name}("${this.url.pathname}")`; + } return `new ${this.constructor.name}("${this.url.href}")`; } [ToString]() { + if (Utils.prepend(this.url.pathname) === this.url.href) { + return this.url.pathname; + } return this.url.href; } diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx index 98696496f..f910d765e 100644 --- a/src/mobile/ImageUpload.tsx +++ b/src/mobile/ImageUpload.tsx @@ -50,7 +50,7 @@ export class Uploader extends React.Component { if (result instanceof Error) { return; } - const path = Utils.prepend(result.accessPaths.agnostic.client); + const path = result.accessPaths.agnostic.client; let doc = null; // Case 1: File is a video if (file.type === "video/mp4") { diff --git a/src/server/server_Initialization.ts b/src/server/server_Initialization.ts index e40f2b8e5..0f4a067fc 100644 --- a/src/server/server_Initialization.ts +++ b/src/server/server_Initialization.ts @@ -142,8 +142,9 @@ function registerCorsProxy(server: express.Express) { const headerCharRegex = /[^\t\x20-\x7e\x80-\xff]/; server.use("/corsProxy", async (req, res) => { - const requrl = decodeURIComponent(req.url.substring(1)); const referer = req.headers.referer ? decodeURIComponent(req.headers.referer) : ""; + const requrlraw = decodeURIComponent(req.url.substring(1)); + const requrl = requrlraw.startsWith("/") ? referer + requrlraw : requrlraw; // cors weirdness here... // if the referer is a cors page and the cors() route (I think) redirected to /corsProxy/ and the requested url path was relative, // then we redirect again to the cors referer and just add the relative path. -- cgit v1.2.3-70-g09d2 From 2abbe23a9c6054e4ff5314333bba25b88554d1ec Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 3 Aug 2021 11:41:48 -0400 Subject: fixed links being blown away in sidebars. --- src/client/views/SidebarAnnos.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx index 010418be5..7b11723c3 100644 --- a/src/client/views/SidebarAnnos.tsx +++ b/src/client/views/SidebarAnnos.tsx @@ -33,7 +33,7 @@ interface ExtraProps { export class SidebarAnnos extends React.Component { constructor(props: Readonly) { super(props); - this.props.dataDoc[this.sidebarKey] = new List(); + // this.props.dataDoc[this.sidebarKey] = new List(); // bcz: can't do this here. it blows away existing things and isn't a robust solution for making sure the field exists -- instead this should happen when the document is created and/or shared } _stackRef = React.createRef(); @computed get allHashtags() { -- cgit v1.2.3-70-g09d2 From 0e8aef275346b4ba3bc1bb91fda17a335c307bf1 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 3 Aug 2021 13:09:48 -0400 Subject: fixed using viewSpecs when following links to set filters/viewType properly. --- src/client/util/DocumentManager.ts | 2 +- src/client/views/collections/CollectionSubView.tsx | 6 +++--- .../collectionFreeForm/CollectionFreeFormView.tsx | 17 ++++++++++++----- src/client/views/nodes/DocumentView.tsx | 14 ++++++++------ 4 files changed, 24 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 5b092258a..9c6100249 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -163,7 +163,7 @@ export class DocumentManager { const targetDocContext = contextDoc || annotatedDoc; const targetDocContextView = targetDocContext && getFirstDocView(targetDocContext); const focusView = !docView && targetDoc.type === DocumentType.MARKER && annoContainerView ? annoContainerView : docView; - if (!docView && annoContainerView && !focusView) { + if (!docView && annoContainerView) { annoContainerView.focus(targetDoc); // this allows something like a PDF view to remove its doc filters to expose the target so that it can be found in the retry code below } if (focusView) { diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 0d9b64d24..3b143aeef 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -82,13 +82,13 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: return Cast(this.dataField, listSpec(Doc)); } docFilters = () => { - return [...this.props.docFilters(), ...Cast(this.props.Document._docFilters, listSpec("string"), [])]; + return (this.props.docFilters?.() ?? Cast(this.props.Document._docFilters, listSpec("string"), [])); } docRangeFilters = () => { - return [...this.props.docRangeFilters(), ...Cast(this.props.Document._docRangeFilters, listSpec("string"), [])]; + return (this.props.docRangeFilters?.() ?? Cast(this.props.Document._docRangeFilters, listSpec("string"), [])); } searchFilterDocs = () => { - return [...this.props.searchFilterDocs(), ...DocListCast(this.props.Document._searchFilterDocs)]; + return this.props.searchFilterDocs?.() ?? DocListCast(this.props.Document._searchFilterDocs); } @computed.struct get childDocs() { TraceMobx(); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 143d8e070..ecc93285e 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -159,8 +159,8 @@ export class CollectionFreeFormView extends CollectionSubView this.fitToContent || force ? this.fitToContentVals : undefined; - freeformDocFilters = () => this._focusFilters || this.docFilters(); - freeformRangeDocFilters = () => this._focusRangeFilters || this.docRangeFilters(); + freeformDocFilters = () => this._focusFilters; + freeformRangeDocFilters = () => this._focusRangeFilters; reverseNativeScaling = () => this.fitToContent ? true : false; panX = () => this.freeformData()?.bounds.cx ?? NumCast(this.Document._panX); panY = () => this.freeformData()?.bounds.cy ?? NumCast(this.Document._panY); @@ -1197,14 +1197,21 @@ export class CollectionFreeFormView extends CollectionSubView(StrListCast(anchor.docFilters)); - this.layoutDoc._docRangeFilters = new List(StrListCast(anchor.docRangeFilters)); + } else { + if (anchor.docFilters) { + this.layoutDoc._docFilters = new List(StrListCast(anchor.docFilters)); + } + if (anchor.docRangeFilters) { + this.layoutDoc._docRangeFilters = new List(StrListCast(anchor.docRangeFilters)); + } } return 0; } getAnchor = () => { + if (this.props.Document.annotationOn) { + return this.rootDoc; + } const anchor = Docs.Create.TextanchorDocument({ title: StrCast(this.layoutDoc._viewType), annotationOn: this.rootDoc }); const proto = Doc.GetProto(anchor); proto[ViewSpecPrefix + "_viewType"] = this.layoutDoc._viewType; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index f716eb7b1..c218b805e 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -64,7 +64,7 @@ export enum ViewAdjustment { doNothing = 0 } -export const ViewSpecPrefix = "_VIEW"; // field prefix for anchor fields that are immediately copied over to the target document when link is followed. Other anchor properties will be copied over in the specific setViewSpec() method on their view (which allows for seting preview values instead of writing to the document) +export const ViewSpecPrefix = "viewSpec"; // field prefix for anchor fields that are immediately copied over to the target document when link is followed. Other anchor properties will be copied over in the specific setViewSpec() method on their view (which allows for seting preview values instead of writing to the document) export interface DocFocusOptions { originalTarget?: Doc; // set in JumpToDocument, used by TabDocView to determine whether to fit contents to tab @@ -105,9 +105,9 @@ export interface DocumentViewSharedProps { styleProvider: Opt; focus: DocFocusFunc; fitWidth?: () => boolean; - docFilters: () => string[]; - docRangeFilters: () => string[]; - searchFilterDocs: () => Doc[]; + docFilters?: () => Opt; + docRangeFilters?: () => Opt; + searchFilterDocs?: () => Opt; whenChildContentsActiveChanged: (isActive: boolean) => void; rootSelected: (outsideReaction?: boolean) => boolean; // whether the root of a template has been selected addDocTab: (doc: Doc, where: string) => boolean; @@ -421,7 +421,9 @@ export class DocumentViewInternal extends DocComponent { LightboxView.SetCookie(StrCast(anchor["cookies-set"])); // copying over _VIEW fields immediately allows the view type to switch to create the right _componentView - Array.from(Object.keys(Doc.GetProto(anchor))).filter(key => key.startsWith(ViewSpecPrefix)).forEach(spec => this.layoutDoc[spec.replace(ViewSpecPrefix, "")] = ((field) => field instanceof ObjectField ? ObjectField.MakeCopy(field) : field)(anchor[spec])); + Array.from(Object.keys(Doc.GetProto(anchor))).filter(key => key.startsWith(ViewSpecPrefix)).forEach(spec => { + this.layoutDoc[spec.replace(ViewSpecPrefix, "")] = ((field) => field instanceof ObjectField ? ObjectField.MakeCopy(field) : field)(anchor[spec]); + }); // after a timeout, the right _componentView should have been created, so call it to update its view spec values setTimeout(() => this._componentView?.setViewSpec?.(anchor, LinkDocPreview.LinkInfo ? true : false)); const focusSpeed = this._componentView?.scrollFocus?.(anchor, !LinkDocPreview.LinkInfo); // bcz: smooth parameter should really be passed into focus() instead of inferred here @@ -837,7 +839,7 @@ export class DocumentViewInternal extends DocComponent !d.hidden); + const filtered = DocUtils.FilterDocs(this.rootDoc.type === DocumentType.RTF ? this.allLinks : this.directLinks, this.props.docFilters?.() ?? [], []).filter(d => !d.hidden); return filtered.map((link, i) =>
Date: Wed, 4 Aug 2021 03:19:16 -0400 Subject: search panel updates --- src/client/util/CurrentUserUtils.ts | 27 ++++++----- src/client/views/GlobalKeyHandler.ts | 7 ++- src/client/views/MainView.tsx | 37 -------------- src/client/views/search/SearchBox.scss | 19 ++++++-- src/client/views/search/SearchBox.tsx | 89 +++++++++++++++++----------------- 5 files changed, 81 insertions(+), 98 deletions(-) (limited to 'src') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 31384da3b..734b96b1e 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -46,6 +46,7 @@ export class CurrentUserUtils { //TODO tfs: these should be temporary... private static mainDocId: string | undefined; + public static searchBtn: Doc; public static get id() { return this.curr_id; } public static get MainDocId() { return this.mainDocId; } public static set MainDocId(id: string | undefined) { this.mainDocId = id; } @@ -533,15 +534,6 @@ export class CurrentUserUtils { ]; } - /*static setupSearchPanel(doc: Doc) { - if (doc.mySearchPanelDoc === undefined) { - doc.mySearchPanelDoc = new PrefetchProxy(Docs.Create.SearchDocument({ - _width: 500, _height: 300, backgroundColor: "dimGray", ignoreClick: true, _searchDoc: true, - childDropAction: "alias", _lockedPosition: true, _viewType: CollectionViewType.Schema, title: "sidebar search stack", system: true - })) as any as Doc; - } - }*/ - static async setupMenuPanel(doc: Doc, sharingDocumentId: string, linkDatabaseId: string) { if (doc.menuStack === undefined) { await this.setupSharingSidebar(doc, sharingDocumentId, linkDatabaseId); // sets up the right sidebar collection for mobile upload documents and sharing @@ -562,10 +554,23 @@ export class CurrentUserUtils { _height: 60, watchedDocuments, onClick: ScriptField.MakeScript(click, { scriptContext: "any" }) - })); + }) + ); + + menuBtns.forEach(menuBtn => { + if (menuBtn.title == "Search") { + this.searchBtn = menuBtn; + } + }); // hack -- last button is assumed to be the userDoc menuBtns[menuBtns.length - 1].hidden = ComputedField.MakeFunction("IsNoviceMode()"); + menuBtns.forEach(menuBtn => { + if (menuBtn.title == "Search") { + doc.searchBtn = menuBtn + } + }) + doc.menuStack = new PrefetchProxy(Docs.Create.StackingDocument(menuBtns, { title: "menuItemPanel", childDropAction: "alias", @@ -950,7 +955,7 @@ export class CurrentUserUtils { if (doc.mySearchPanel === undefined) { doc.mySearchPanel = new PrefetchProxy(Docs.Create.SearchDocument({ backgroundColor: "dimGray", ignoreClick: true, _searchDoc: true, - childDropAction: "alias", _lockedPosition: true, _viewType: CollectionViewType.Schema, title: "sidebar search stack", system: true + childDropAction: "alias", _lockedPosition: true, _viewType: CollectionViewType.Schema, title: "Search Sidebar", system: true })) as any as Doc; } } diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index d92cba3eb..2a3cb36c7 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -27,7 +27,6 @@ import { LightboxView } from "./LightboxView"; import { MainView } from "./MainView"; import { DocumentLinksButton } from "./nodes/DocumentLinksButton"; import { AnchorMenu } from "./pdf/AnchorMenu"; -import { SearchBox } from "./search/SearchBox"; import { CurrentUserUtils } from "../util/CurrentUserUtils"; import { SettingsManager } from "../util/SettingsManager"; @@ -225,7 +224,11 @@ export class KeyManager { PromiseValue(Cast(Doc.UserDoc()["tabs-button-tools"], Doc)).then(pv => pv && (pv.onClick as ScriptField).script.run({ this: pv })); break; case "f": - SearchBox.Instance.enter(undefined); + const searchBtn = Doc.UserDoc().searchBtn as Doc; + + if (searchBtn) { + MainView.Instance.selectMenu(searchBtn); + } break; case "o": const target = SelectionManager.Views()[0]; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 0d957518b..35222e91f 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -387,9 +387,6 @@ export class MainView extends React.Component { case "Settings": SettingsManager.Instance.open(); break; - case "Catalog": - SearchBox.Instance.enter(undefined); - break; case "Help": break; default: @@ -522,40 +519,6 @@ export class MainView extends React.Component { ; } - /*@computed get search() { - TraceMobx(); - return
- -
; - }*/ - @computed get invisibleWebBox() { // see note under the makeLink method in HypothesisUtils.ts return !DocumentLinksButton.invisibleWebDoc ? null :
diff --git a/src/client/views/search/SearchBox.scss b/src/client/views/search/SearchBox.scss index f8e994da7..e4d1ac6a3 100644 --- a/src/client/views/search/SearchBox.scss +++ b/src/client/views/search/SearchBox.scss @@ -22,17 +22,18 @@ .searchBox-type { display: block; - width: 50px; + width: 55px; outline: none; padding: 1px 5px 1px 5px; color: black; height: 25px; border: 1px solid black; + border-right: 0px; } .searchBox-input { display: block; - width: calc(100% - 50px); + width: calc(100% - 55px); outline: none; padding: 1px 5px 1px 5px; color: black; @@ -74,10 +75,20 @@ background: gray; } - .titletitle { + .searchBox-result-title { display: relative; float: left; - left: 50px; + width: calc(100% - 60px); + text-align: left; + } + + .searchBox-result-type { + font-size: 12px; + display: relative; + float: right; + width: 60px; + text-align: right; + color: #333; } } } diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index 374a754bf..3cbb4b3b1 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -35,29 +35,30 @@ export const searchSchema = createSchema({ Document: Doc }); type SearchBoxDocument = makeInterface<[typeof documentSchema, typeof searchSchema]>; const SearchBoxDocument = makeInterface(documentSchema, searchSchema); +const selectValues = ["all", "rtf", "image", "pdf", "web", "video", "audio", "collection"] + @observer export class SearchBox extends ViewBoxBaseComponent(SearchBoxDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(SearchBox, fieldKey); } public static Instance: SearchBox; - private _allIcons: string[] = [DocumentType.INK, DocumentType.AUDIO, DocumentType.COL, DocumentType.IMG, DocumentType.LINK, DocumentType.PDF, DocumentType.RTF, DocumentType.VID, DocumentType.WEB]; private _resultsSet = new Map(); private _inputRef = React.createRef(); - private _disposers: { [name: string]: IReactionDisposer } = {}; - private _blockedTypes = [DocumentType.PRESELEMENT, DocumentType.KVP, DocumentType.FILTER, DocumentType.SEARCH, DocumentType.SEARCHITEM, DocumentType.FONTICON, DocumentType.BUTTON, DocumentType.SCRIPTING]; @observable _searchString = ""; @observable _docTypeString = "all"; - @observable _icons: string[] = this._allIcons; @observable _results: [Doc, string[], string[]][] = []; @observable _selectedResult: Doc | undefined = undefined; @observable _deletedDocsStatus: boolean = false; @observable _onlyAliases: boolean = true; - @computed get filter() { return this._results?.length && (this.currentSelectedCollection?.props.Document._searchFilterDocs || this.currentSelectedCollection?.props.Document._docFilters); } constructor(props: any) { super(props); SearchBox.Instance = this; + this._searchString = "reset_search"; + this.submitSearch(); + this._searchString = ""; + this.submitSearch(); } componentDidMount = action(() => { @@ -67,11 +68,9 @@ export class SearchBox extends ViewBoxBaseComponent disposer?.()); + this.resetSearch; } - @computed get currentSelectedCollection() { return CollectionDockingView.Instance; } - onInputChange = action((e: React.ChangeEvent) => { this._searchString = e.target.value; this.submitSearch(); @@ -79,32 +78,13 @@ export class SearchBox extends ViewBoxBaseComponent) => { this._docTypeString = e.target.value; - this.submitSearch(); }); - /*enter = action((e: React.KeyboardEvent | undefined) => { - if (!e || e.key === "Enter") { - this.submitSearch(); - } - });*/ - onResultClick = action((doc: Doc) => { this.selectElement(doc); this._selectedResult = doc; }); - @action - filterDocsByType(docs: Doc[]) { - const finalDocs: Doc[] = []; - docs.forEach(doc => { - const layoutresult = StrCast(doc.type, "string") as DocumentType; - if (layoutresult && !this._blockedTypes.includes(layoutresult) && this._icons.includes(layoutresult)) { - finalDocs.push(doc); - } - }); - return finalDocs; - } - static foreachRecursiveDoc(docs: Doc[], func: (doc: Doc) => void) { let newarray: Doc[] = []; while (docs.length > 0) { @@ -120,23 +100,39 @@ export class SearchBox extends ViewBoxBaseComponent { - const hlights = new Set(); - SearchBox.documentKeys(doc).forEach(key => Field.toString(doc[key] as Field).toLowerCase().includes(query) && hlights.add(key)); - Array.from(hlights.keys()).length > 0 && found.push([doc, Array.from(hlights.keys()), []]); + const dtype = StrCast(doc.type, "string") as DocumentType; + if (dtype && !blockedTypes.includes(dtype)) { + const hlights = new Set(); + SearchBox.documentKeys(doc).forEach(key => Field.toString(doc[key] as Field).toLowerCase().includes(query) && hlights.add(key)); + Array.from(hlights.keys()).length > 0 && this._results.push([doc, Array.from(hlights.keys()), []]); + } }); - - this._results = found; } + + this._results = Array.from(new Set(this._results)) + this._selectedResult = undefined } static documentKeys(doc: Doc) { @@ -155,7 +151,7 @@ export class SearchBox extends ViewBoxBaseComponent { this.resetSearch(); - this.dataDoc[this.fieldKey] = new List([]); + //this.dataDoc[this.fieldKey] = new List([]); let query = StrCast(this._searchString); Doc.SetSearchQuery(query); this._results = []; @@ -169,6 +165,7 @@ export class SearchBox extends ViewBoxBaseComponent { this._results.forEach(result => { Doc.UnBrushDoc(result[0]); + Doc.UnHighlightDoc(result[0]); Doc.ClearSearchMatches(); }); }); @@ -178,6 +175,8 @@ export class SearchBox extends ViewBoxBaseComponent { var className = "searchBox-results-scroll-view-result"; @@ -186,28 +185,30 @@ export class SearchBox extends ViewBoxBaseComponent this.onResultClick(result[0])} className={className}>
{result[0].title}
) + validResults++; + return (
this.onResultClick(result[0])} className={className}>
{result[0].title}
{SearchBox.formatType(StrCast(result[0].type))}
) } return null; }) - results.filter(result => result) + results.filter(result => result); + + const selectOptions = selectValues.map(value => { + return + }) return (
- +
- {`${results.length}` + " result" + (results.length == 1 ? "" : "s")} + {`${validResults}` + " result" + (validResults == 1 ? "" : "s")}
{results} -- cgit v1.2.3-70-g09d2 From 70f98c6d4d3e457a05e7c84260bf33580ee0166a Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 4 Aug 2021 10:34:25 -0400 Subject: restructured filters again so that filter icons show whether a document has a filter or inherits one. following a link with a view spec overrides only locally set filters (not inherited ones). --- src/client/views/.DS_Store | Bin 10244 -> 10244 bytes .../views/collections/CollectionSchemaView.tsx | 4 +-- .../views/collections/CollectionStackingView.tsx | 4 +-- src/client/views/collections/CollectionSubView.tsx | 29 ++++++++++++--------- .../views/collections/CollectionTimeView.tsx | 12 +++------ src/client/views/collections/CollectionView.tsx | 14 +++++++--- src/client/views/collections/TabDocView.tsx | 9 ++++--- .../collectionFreeForm/CollectionFreeFormView.tsx | 8 ++---- .../CollectionMulticolumnView.tsx | 4 +-- .../CollectionMultirowView.tsx | 4 +-- .../collectionSchema/CollectionSchemaView.tsx | 4 +-- src/client/views/nodes/DocumentView.tsx | 6 ++--- 12 files changed, 50 insertions(+), 48 deletions(-) (limited to 'src') diff --git a/src/client/views/.DS_Store b/src/client/views/.DS_Store index 33e624ef4..e4ac87aad 100644 Binary files a/src/client/views/.DS_Store and b/src/client/views/.DS_Store differ diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index e1e04915a..380f82813 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -413,8 +413,8 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { isContentActive={returnTrue} isDocumentActive={returnFalse} ScreenToLocalTransform={this.getPreviewTransform} - docFilters={this.docFilters} - docRangeFilters={this.docRangeFilters} + docFilters={this.childDocFilters} + docRangeFilters={this.childDocRangeFilters} searchFilterDocs={this.searchFilterDocs} styleProvider={DefaultStyleProvider} layerProvider={undefined} diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 7aa8dfd56..b9bc83d49 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -239,10 +239,10 @@ export class CollectionStackingView extends CollectionSubView; + SetSubView: (subView: any) => void; } export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: X) { @@ -30,6 +31,8 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: private gestureDisposer?: GestureUtils.GestureEventDisposer; protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer; protected _mainCont?: HTMLDivElement; + @observable _focusFilters: Opt; // docFilters that are overridden when previewing a link to an anchor which has docFilters set on it + @observable _focusRangeFilters: Opt; // docRangeFilters that are overridden when previewing a link to an anchor which has docRangeFilters set on it protected createDashEventsTarget = (ele: HTMLDivElement) => { //used for stacking and masonry view this.dropDisposer?.(); this.gestureDisposer?.(); @@ -45,6 +48,10 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: this.createDashEventsTarget(ele); } + componentDidMount() { + this.props.SetSubView(this); + } + componentWillUnmount() { this.gestureDisposer?.(); this._multiTouchDisposer?.(); @@ -81,15 +88,13 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: get childDocList() { return Cast(this.dataField, listSpec(Doc)); } - docFilters = () => { - return (this.props.docFilters?.() ?? Cast(this.props.Document._docFilters, listSpec("string"), [])); - } - docRangeFilters = () => { - return (this.props.docRangeFilters?.() ?? Cast(this.props.Document._docRangeFilters, listSpec("string"), [])); - } - searchFilterDocs = () => { - return this.props.searchFilterDocs?.() ?? DocListCast(this.props.Document._searchFilterDocs); - } + collectionFilters = () => this._focusFilters ?? Cast(this.props.Document._docFilters, listSpec("string"), []); + collectionRangeDocFilters = () => this._focusRangeFilters ?? Cast(this.props.Document._docRangeFilters, listSpec("string"), []); + childDocFilters = () => [...this.props.docFilters(), ...this.collectionFilters()]; + childDocRangeFilters = () => [...(this.props.docRangeFilters?.() || []), ...this.collectionRangeDocFilters()]; + IsFiltered = () => this.collectionFilters().length || this.collectionRangeDocFilters().length ? "hasFilter" : + this.props.docFilters().length || this.props.docRangeFilters().length ? "inheritsFilter" : undefined; + searchFilterDocs = () => this.props.searchFilterDocs?.() ?? DocListCast(this.props.Document._searchFilterDocs); @computed.struct get childDocs() { TraceMobx(); let rawdocs: (Doc | Promise)[] = []; @@ -108,8 +113,8 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: const viewSpecScript = Cast(this.props.Document.viewSpecScript, ScriptField); const childDocs = viewSpecScript ? docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result) : docs; - const docFilters = this.docFilters(); - const docRangeFilters = this.docRangeFilters(); + const docFilters = this.childDocFilters(); + const docRangeFilters = this.childDocRangeFilters(); const searchDocs = this.searchFilterDocs(); if (this.props.Document.dontRegisterView || (!docFilters.length && !docRangeFilters.length && !searchDocs.length)) { return childDocs.filter(cd => !cd.cookies); // remove any documents that require a cookie if there are no filters to provide one diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 08b5e6bac..292dfd77c 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -32,9 +32,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { @observable _collapsed: boolean = false; @observable _childClickedScript: Opt; @observable _viewDefDivClick: Opt; - @observable _focusDocFilters: Opt; // fields that get overridden by a focus anchor @observable _focusPivotField: Opt; - @observable _focusRangeFilters: Opt; getAnchor = () => { const anchor = Docs.Create.HTMLAnchorDocument([], { @@ -72,9 +70,9 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { @action setViewSpec = (anchor: Doc, preview: boolean) => { if (preview) { // if in preview, then override document's fields with view spec + this._focusFilters = StrListCast(Doc.GetProto(anchor).docFilters); + this._focusRangeFilters = StrListCast(Doc.GetProto(anchor).docRangeFilters); this._focusPivotField = StrCast(anchor.pivotField); - this._focusDocFilters = StrListCast(anchor.docFilters); - this._focusRangeFilters = StrListCast(anchor.docRangeFilters); } else if (anchor.pivotField !== undefined) { // otherwise set document's fields based on anchor view spec this.layoutDoc._prevFilterIndex = 1; this.layoutDoc._pivotField = StrCast(anchor.pivotField); @@ -84,8 +82,6 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { return 0; } - pivotDocFilters = () => this._focusDocFilters || this.props.docFilters(); - pivotDocRangeFilters = () => this._focusRangeFilters || this.props.docRangeFilters(); layoutEngine = () => this._layoutEngine; toggleVisibility = action(() => this._collapsed = !this._collapsed); @@ -139,10 +135,8 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { return
{ + console.log("Setting sub", subView); + return this._subView = subView + }), addDocument: this.addDocument, moveDocument: this.moveDocument, removeDocument: this.removeDocument, @@ -260,8 +266,8 @@ export class CollectionView extends ViewBoxAnnotatableComponent { runInAction(() => CurrentUserUtils.propertiesWidth = 250); e.stopPropagation(); }} + style={{ position: 'absolute', top: '1%', right: '1%', cursor: "pointer", padding: 1, color: this.showFilterIcon === "hasFilter" ? '#18c718bd' : "orange", zIndex: 1 }} + onPointerDown={action(e => { this.props.select(false); CurrentUserUtils.propertiesWidth = 250; e.stopPropagation(); })} /> : (null)}
); diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index a24f1eb7a..623e0f58d 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -363,8 +363,8 @@ export class TabDocView extends React.Component { PanelHeight={this.PanelHeight} layerProvider={this.layerProvider} styleProvider={DefaultStyleProvider} - docFilters={CollectionDockingView.Instance.docFilters} - docRangeFilters={CollectionDockingView.Instance.docRangeFilters} + docFilters={CollectionDockingView.Instance.childDocFilters} + docRangeFilters={CollectionDockingView.Instance.childDocRangeFilters} searchFilterDocs={CollectionDockingView.Instance.searchFilterDocs} addDocument={undefined} removeDocument={undefined} @@ -468,6 +468,7 @@ export class TabMinimapView extends React.Component {
this} CollectionView={undefined} ContainingCollectionView={undefined} ContainingCollectionDoc={undefined} @@ -496,8 +497,8 @@ export class TabMinimapView extends React.Component { layerProvider={undefined} addDocTab={this.props.addDocTab} pinToPres={TabDocView.PinDoc} - docFilters={CollectionDockingView.Instance.docFilters} - docRangeFilters={CollectionDockingView.Instance.docRangeFilters} + docFilters={CollectionDockingView.Instance.childDocFilters} + docRangeFilters={CollectionDockingView.Instance.childDocRangeFilters} searchFilterDocs={CollectionDockingView.Instance.searchFilterDocs} fitContentsToDoc={returnTrue} /> diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index ecc93285e..ba6222605 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -110,8 +110,6 @@ export class CollectionFreeFormView extends CollectionSubView(); @observable _marqueeRef = React.createRef(); @observable _keyframeEditing = false; - @observable _focusFilters: Opt; // docFilters that are overridden when previewing a link to an anchor which has docFilters set on it - @observable _focusRangeFilters: Opt; // docRangeFilters that are overridden when previewing a link to an anchor which has docRangeFilters set on it @observable ChildDrag: DocumentView | undefined; // child document view being dragged. needed to update drop areas of groups when a group item is dragged. @computed get views() { return this._layoutElements.filter(ele => ele.bounds && !ele.bounds.z).map(ele => ele.ele); } @@ -159,8 +157,6 @@ export class CollectionFreeFormView extends CollectionSubView this.fitToContent || force ? this.fitToContentVals : undefined; - freeformDocFilters = () => this._focusFilters; - freeformRangeDocFilters = () => this._focusRangeFilters; reverseNativeScaling = () => this.fitToContent ? true : false; panX = () => this.freeformData()?.bounds.cx ?? NumCast(this.Document._panX); panY = () => this.freeformData()?.bounds.cy ?? NumCast(this.Document._panY); @@ -1030,8 +1026,8 @@ export class CollectionFreeFormView extends CollectionSubView doc) { isContentActive={returnTrue} isDocumentActive={returnFalse} ScreenToLocalTransform={this.getPreviewTransform} - docFilters={this.docFilters} - docRangeFilters={this.docRangeFilters} + docFilters={this.childDocFilters} + docRangeFilters={this.childDocRangeFilters} searchFilterDocs={this.searchFilterDocs} styleProvider={DefaultStyleProvider} layerProvider={undefined} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index c218b805e..bea219831 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -105,9 +105,9 @@ export interface DocumentViewSharedProps { styleProvider: Opt; focus: DocFocusFunc; fitWidth?: () => boolean; - docFilters?: () => Opt; - docRangeFilters?: () => Opt; - searchFilterDocs?: () => Opt; + docFilters: () => string[]; + docRangeFilters: () => string[]; + searchFilterDocs: () => Doc[]; whenChildContentsActiveChanged: (isActive: boolean) => void; rootSelected: (outsideReaction?: boolean) => boolean; // whether the root of a template has been selected addDocTab: (doc: Doc, where: string) => boolean; -- cgit v1.2.3-70-g09d2 From 3c78da4d7724ca411486083176e394b18177231d Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 4 Aug 2021 13:55:36 -0400 Subject: from last --- src/client/views/collections/CollectionSubView.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index e5f266acf..a9b5ce465 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -22,7 +22,7 @@ import ReactLoading from 'react-loading'; export interface SubCollectionViewProps extends CollectionViewProps { CollectionView: Opt; - SetSubView: (subView: any) => void; + SetSubView?: (subView: any) => void; } export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: X) { @@ -49,7 +49,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: } componentDidMount() { - this.props.SetSubView(this); + this.props.SetSubView?.(this); } componentWillUnmount() { -- cgit v1.2.3-70-g09d2 From 43119dc3fc8b156f9e15deab7b2e3dd5b541d7af Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 4 Aug 2021 20:14:30 -0400 Subject: fixed toggle ink as a mask. --- src/client/views/InkingStroke.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 21059b330..63cefbf67 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -44,14 +44,13 @@ export class InkingStroke extends ViewBoxBaseComponent { + public static toggleMask = action((inkDoc: Doc) => { inkDoc.isInkMask = !inkDoc.isInkMask; inkDoc._backgroundColor = inkDoc.isInkMask ? "rgba(0,0,0,0.7)" : undefined; inkDoc.mixBlendMode = inkDoc.isInkMask ? "hard-light" : undefined; inkDoc.color = "#9b9b9bff"; inkDoc._stayInCollection = inkDoc.isInkMask ? true : undefined; - } + }); /** * Handles the movement of the entire ink object when the user clicks and drags. -- cgit v1.2.3-70-g09d2 From 8907b0f7ecd8aa8b25fbe4138eef4ed3d3b249ba Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 4 Aug 2021 21:29:03 -0400 Subject: fixed setting of ink pen mode. --- src/client/views/collections/CollectionMenu.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index a9b978c4e..8f4df4a92 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -665,7 +665,7 @@ export class CollectionFreeFormViewChrome extends React.Component { + const func = action((e: React.MouseEvent | React.PointerEvent, i: number, keep: boolean) => { this._keepPrimitiveMode = keep; if (this._selectedPrimitive !== i) { this._selectedPrimitive = i; @@ -683,13 +683,14 @@ export class CollectionFreeFormViewChrome extends React.Component {this._draw.map((icon, i) => {this._title[i]}
} placement="bottom"> -- cgit v1.2.3-70-g09d2 From 6d9c65bf95091b0d5ee7e3097995fc9e2ead4415 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 5 Aug 2021 11:21:04 -0400 Subject: improved opening sidebar when following a link to a sidebar annotation. Still needs work when link is from outside of the sidebar document and on first click. --- src/client/views/SidebarAnnos.tsx | 5 +++-- src/client/views/nodes/PDFBox.tsx | 26 +++++++++++++++------- src/client/views/nodes/WebBox.tsx | 24 ++++++++++++++------ .../views/nodes/formattedText/FormattedTextBox.tsx | 21 ++++++++++++----- 4 files changed, 53 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx index 7b11723c3..f1d168a22 100644 --- a/src/client/views/SidebarAnnos.tsx +++ b/src/client/views/SidebarAnnos.tsx @@ -23,6 +23,7 @@ interface ExtraProps { layoutDoc: Doc; rootDoc: Doc; dataDoc: Doc; + showSidebar: boolean; whenChildContentsActiveChanged: (isActive: boolean) => void; ScreenToLocalTransform: () => Transform; sidebarAddDocument: (doc: (Doc | Doc[]), suffix: string) => boolean; @@ -75,7 +76,7 @@ export class SidebarAnnos extends React.Component { get sidebarKey() { return this.props.fieldKey + "-sidebar"; } filtersHeight = () => 38; screenToLocalTransform = () => this.props.ScreenToLocalTransform().translate(Doc.NativeWidth(this.props.dataDoc), 0).scale(this.props.scaling?.() || 1); - panelWidth = () => !this.props.layoutDoc._showSidebar ? 0 : this.props.layoutDoc.type === DocumentType.RTF ? this.props.PanelWidth() : (NumCast(this.props.layoutDoc.nativeWidth) - Doc.NativeWidth(this.props.dataDoc)) * this.props.PanelWidth() / NumCast(this.props.layoutDoc.nativeWidth); + panelWidth = () => !this.props.showSidebar ? 0 : this.props.layoutDoc.type === DocumentType.RTF ? this.props.PanelWidth() : (NumCast(this.props.layoutDoc.nativeWidth) - Doc.NativeWidth(this.props.dataDoc)) * this.props.PanelWidth() / NumCast(this.props.layoutDoc.nativeWidth); panelHeight = () => this.props.PanelHeight() - this.filtersHeight(); addDocument = (doc: Doc | Doc[]) => this.props.sidebarAddDocument(doc, this.sidebarKey); moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean) => this.props.moveDocument(doc, targetCollection, addDocument, this.sidebarKey); @@ -103,7 +104,7 @@ export class SidebarAnnos extends React.Component { {user}
; }; - return !this.props.layoutDoc._showSidebar ? (null) : + return !this.props.showSidebar ? (null) :
{ + if (DocListCast(this.props.Document[this.fieldKey + "-sidebar"]).includes(doc) && !this.SidebarShown) { + this.toggleSidebar(!smooth); + } if (this._sidebarRef?.current?.makeDocUnfiltered(doc)) return 1; this._initialScrollTarget = doc; return this._pdfViewer?.scrollFocus(doc, smooth); @@ -141,15 +144,18 @@ export class PDFBox extends ViewBoxAnnotatableComponent this.toggleSidebar()); } - toggleSidebar = action(() => { + toggleSidebar = action((preview: boolean = false) => { const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + "-nativeWidth"]); const ratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? 250 : 0) + nativeWidth) / nativeWidth; const curNativeWidth = NumCast(this.layoutDoc.nativeWidth, nativeWidth); - this.layoutDoc.nativeWidth = nativeWidth * ratio; - this.layoutDoc._width = this.layoutDoc[WidthSym]() * nativeWidth * ratio / curNativeWidth; - this.layoutDoc._showSidebar = nativeWidth !== this.layoutDoc._nativeWidth; + if (preview) this._showSidebar = true; + else { + this.layoutDoc.nativeWidth = nativeWidth * ratio; + this.layoutDoc._width = this.layoutDoc[WidthSym]() * nativeWidth * ratio / curNativeWidth; + this.layoutDoc._showSidebar = nativeWidth !== this.layoutDoc._nativeWidth; + } }); settingsPanel() { const pageBtns = <> @@ -202,7 +208,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent
; } - sidebarWidth = () => !this.layoutDoc._showSidebar ? 0 : (NumCast(this.layoutDoc.nativeWidth) - Doc.NativeWidth(this.dataDoc)) * this.props.PanelWidth() / NumCast(this.layoutDoc.nativeWidth); + sidebarWidth = () => !this.SidebarShown ? 0 : (NumCast(this.layoutDoc.nativeWidth) - Doc.NativeWidth(this.dataDoc)) * this.props.PanelWidth() / NumCast(this.layoutDoc.nativeWidth); specificContextMenu = (e: React.MouseEvent): void => { const funcs: ContextMenuProps[] = []; @@ -223,6 +229,9 @@ export class PDFBox extends ViewBoxAnnotatableComponent this._sidebarRef.current?.anchorMenuClick; + @observable _showSidebar = false; + @computed get SidebarShown() { return this._showSidebar || this.layoutDoc._showSidebar ? true : false; } + @computed get renderPdfView() { TraceMobx(); @@ -255,6 +264,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent this.urlEditor; // controls to be added to the top bar when a document of this type is selected scrollFocus = (doc: Doc, smooth: boolean) => { + if (DocListCast(this.props.Document[this.fieldKey + "-sidebar"]).includes(doc) && !this.SidebarShown) { + this.toggleSidebar(!smooth); + } if (this._sidebarRef?.current?.makeDocUnfiltered(doc)) return 1; if (doc !== this.rootDoc && this._outerRef.current) { const windowHeight = this.props.PanelHeight() / (this.props.scaling?.() || 1); @@ -449,17 +452,20 @@ export class WebBox extends ViewBoxAnnotatableComponent this.toggleSidebar()); } - toggleSidebar = action(() => { + toggleSidebar = action((preview: boolean = false) => { const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + "-nativeWidth"]); const ratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? 250 : 0) + nativeWidth) / nativeWidth; const curNativeWidth = NumCast(this.layoutDoc.nativeWidth, nativeWidth); - this.layoutDoc.nativeWidth = nativeWidth * ratio; - this.layoutDoc._width = this.layoutDoc[WidthSym]() * nativeWidth * ratio / curNativeWidth; - this.layoutDoc._showSidebar = nativeWidth !== this.layoutDoc._nativeWidth; + if (preview) this._showSidebar; + else { + this.layoutDoc.nativeWidth = nativeWidth * ratio; + this.layoutDoc._width = this.layoutDoc[WidthSym]() * nativeWidth * ratio / curNativeWidth; + this.layoutDoc._showSidebar = nativeWidth !== this.layoutDoc._nativeWidth; + } }); - sidebarWidth = () => !this.layoutDoc._showSidebar ? 0 : (NumCast(this.layoutDoc.nativeWidth) - Doc.NativeWidth(this.dataDoc)) * this.props.PanelWidth() / NumCast(this.layoutDoc.nativeWidth); + sidebarWidth = () => !this.SidebarShown ? 0 : (NumCast(this.layoutDoc.nativeWidth) - Doc.NativeWidth(this.dataDoc)) * this.props.PanelWidth() / NumCast(this.layoutDoc.nativeWidth); @computed get content() { return
) }
; + } + @observable _showSidebar = false; + @computed get SidebarShown() { return this._showSidebar || this.layoutDoc._showSidebar ? true : false; } showInfo = action((anno: Opt) => this._overlayAnnoInfo = anno); setPreviewCursor = (func?: (x: number, y: number, drag: boolean) => void) => this._setPreviewCursor = func; @@ -548,10 +557,11 @@ export class WebBox extends ViewBoxAnnotatableComponent { + toggleSidebar = (preview: boolean = false) => { const prevWidth = this.sidebarWidth(); - this.layoutDoc._showSidebar = ((this.layoutDoc._sidebarWidthPercent = StrCast(this.layoutDoc._sidebarWidthPercent, "0%") === "0%" ? "50%" : "0%")) !== "0%"; - this.layoutDoc._width = this.layoutDoc._showSidebar ? NumCast(this.layoutDoc._width) * 2 : Math.max(20, NumCast(this.layoutDoc._width) - prevWidth); + if (preview) this._showSidebar = true; + else this.layoutDoc._showSidebar = ((this.layoutDoc._sidebarWidthPercent = StrCast(this.layoutDoc._sidebarWidthPercent, "0%") === "0%" ? "50%" : "0%")) !== "0%"; + + this.layoutDoc._width = !preview && this.SidebarShown ? NumCast(this.layoutDoc._width) * 2 : Math.max(20, NumCast(this.layoutDoc._width) - prevWidth); } sidebarDown = (e: React.PointerEvent) => { setupMoveUpEvents(this, e, this.sidebarMove, emptyFunction, () => setTimeout(this.toggleSidebar), false); @@ -726,6 +731,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } scrollFocus = (textAnchor: Doc, smooth: boolean) => { + if (DocListCast(this.Document[this.fieldKey + "-sidebar"]).includes(textAnchor) && !this.SidebarShown) { + this.toggleSidebar(!smooth); + } const textAnchorId = textAnchor[Id]; const findAnchorFrag = (frag: Fragment, editor: EditorView) => { const nodes: Node[] = []; @@ -1468,10 +1476,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp return ComponentTag === CollectionStackingView ?
- {(this.props.noSidebar || this.Document._noSidebar) || this.props.dontSelectOnLoad || !this.layoutDoc._showSidebar || this.sidebarWidthPercent === "0%" ? (null) : this.sidebarCollection} + {(this.props.noSidebar || this.Document._noSidebar) || this.props.dontSelectOnLoad || !this.SidebarShown || this.sidebarWidthPercent === "0%" ? (null) : this.sidebarCollection} {(this.props.noSidebar || this.Document._noSidebar) || this.props.dontSelectOnLoad || this.Document._singleLine ? (null) : this.sidebarHandle} {!this.layoutDoc._showAudio ? (null) : this.audioHandle}
-- cgit v1.2.3-70-g09d2 From b9d72dd3ed3b800ef9bd1f6695ac37e14d21f675 Mon Sep 17 00:00:00 2001 From: geireann Date: Thu, 5 Aug 2021 15:18:00 -0400 Subject: removed drop shadow from MyTools sidebar --- src/client/util/CurrentUserUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 66f9d060f..e1cbaf125 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -748,7 +748,7 @@ export class CurrentUserUtils { if (doc.myTools === undefined) { const toolsStack = new PrefetchProxy(Docs.Create.StackingDocument([doc.myCreators as Doc, doc.myColorPicker as Doc], { title: "My Tools", _width: 500, _yMargin: 20, ignoreClick: true, _lockedPosition: true, _forceActive: true, - system: true, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, + system: true, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, boxShadow: "0 0", })) as any as Doc; doc.myTools = toolsStack; -- cgit v1.2.3-70-g09d2 From d511c116330c3a125e6557aa5be70392aca4914b Mon Sep 17 00:00:00 2001 From: dg314 Date: Thu, 5 Aug 2021 16:38:00 -0400 Subject: comments --- src/client/views/MainView.tsx | 6 - .../views/collections/CollectionSchemaHeaders.tsx | 2 +- src/client/views/search/SearchBox.scss | 22 +- src/client/views/search/SearchBox.tsx | 382 +++++++++------------ 4 files changed, 177 insertions(+), 235 deletions(-) (limited to 'src') diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 35222e91f..97c88930e 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -178,12 +178,6 @@ export class MainView extends React.Component { const targets = document.elementsFromPoint(e.x, e.y); if (targets.length) { const targClass = targets[0].className.toString(); - /*if (SearchBox.Instance._resultsOpen) { - const check = targets.some((thing) => - (thing.className === "collectionSchemaView-searchContainer" || (thing as any)?.dataset.icon === "filter" || - thing.className === "collectionSchema-header-menuOptions")); - !check && SearchBox.Instance.resetSearch(true); - }*/ !targClass.includes("contextMenu") && ContextMenu.Instance.closeMenu(); !["timeline-menu-desc", "timeline-menu-item", "timeline-menu-input"].includes(targClass) && TimelineMenu.Instance.closeMenu(); } diff --git a/src/client/views/collections/CollectionSchemaHeaders.tsx b/src/client/views/collections/CollectionSchemaHeaders.tsx index 3b52e6408..c98dcd1d0 100644 --- a/src/client/views/collections/CollectionSchemaHeaders.tsx +++ b/src/client/views/collections/CollectionSchemaHeaders.tsx @@ -424,7 +424,7 @@ export class KeysDropdown extends React.Component { e.target.checked === true ? Doc.setDocFilter(this.props.Document, this._key, key, "check") : Doc.setDocFilter(this.props.Document, this._key, key, "remove"); e.target.checked === true ? this.closeResultsVisibility = "contents" : console.log(""); e.target.checked === true ? this.props.col.setColor("green") : this.updateFilter(); - e.target.checked === true && SearchBox.Instance.filter === true ? Doc.setDocFilter(docs[0], this._key, key, "check") : Doc.setDocFilter(docs[0], this._key, key, "remove"); + e.target.checked === true ? Doc.setDocFilter(docs[0], this._key, key, "check") : Doc.setDocFilter(docs[0], this._key, key, "remove"); }} checked={bool} /> diff --git a/src/client/views/search/SearchBox.scss b/src/client/views/search/SearchBox.scss index e4d1ac6a3..e7526dac8 100644 --- a/src/client/views/search/SearchBox.scss +++ b/src/client/views/search/SearchBox.scss @@ -66,13 +66,13 @@ display: inline-block; vertical-align: middle; width: 100%; - height: 40px; + height: 50px; cursor: pointer; font-size: 15px; - padding: 10px; + padding: 11px; &.searchBox-results-scroll-view-result-selected { - background: gray; + background: #999; } .searchBox-result-title { @@ -84,11 +84,25 @@ .searchBox-result-type { font-size: 12px; + margin-top: 6px; display: relative; float: right; width: 60px; text-align: right; - color: #333; + color: #222; + } + + .searchBox-result-keys { + font-size: 10px; + margin-top: 1px; + display: relative; + float: left; + width: 100%; + text-align: left; + color: #555; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } } } diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index 3cbb4b3b1..8ef09aa56 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -27,66 +27,105 @@ import { undoBatch } from "../../util/UndoManager"; import { DocServer } from "../../DocServer"; import { MainView } from "../MainView"; import { DocumentManager } from "../../util/DocumentManager"; -import { CollectionSchemaBooleanCell } from "../collections/CollectionSchemaCells"; -import { transpileModule } from "typescript"; export const searchSchema = createSchema({ Document: Doc }); type SearchBoxDocument = makeInterface<[typeof documentSchema, typeof searchSchema]>; const SearchBoxDocument = makeInterface(documentSchema, searchSchema); -const selectValues = ["all", "rtf", "image", "pdf", "web", "video", "audio", "collection"] - +/** + * This is the SearchBox component. It represents the search box input and results in + * the search panel on the left side of the screen. + */ @observer export class SearchBox extends ViewBoxBaseComponent(SearchBoxDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(SearchBox, fieldKey); } public static Instance: SearchBox; - private _resultsSet = new Map(); private _inputRef = React.createRef(); + private _selectedCollection = CollectionDockingView.Instance; @observable _searchString = ""; @observable _docTypeString = "all"; - @observable _results: [Doc, string[], string[]][] = []; + @observable _results: [Doc, string[]][] = []; @observable _selectedResult: Doc | undefined = undefined; @observable _deletedDocsStatus: boolean = false; @observable _onlyAliases: boolean = true; + /** + * This is the constructor for the SearchBox class. + */ constructor(props: any) { super(props); SearchBox.Instance = this; - this._searchString = "reset_search"; - this.submitSearch(); - this._searchString = ""; - this.submitSearch(); } + /** + * This method is called when the SearchBox component is first mounted. When the user opens + * the search panel, the search input box is automatically selected. This allows the user to + * type in the search input box immediately, without needing clicking on it first. + */ componentDidMount = action(() => { if (this._inputRef.current) { this._inputRef.current.focus(); } }); + /** + * This method is called when the SearchBox component is about to be unmounted. When the user + * closes the search panel, the search and its results are reset. + */ componentWillUnmount() { - this.resetSearch; + this.resetSearch(); } + /** + * This method is called when the text in the search input box is modified by the user. The + * _searchString is updated to the new value of the text in the input box and submitSearch + * is called to update the search results accordingly. + * + * (Note: There is no longer a need to press enter to submit a search. Any update to the input + * causes a search to be submitted automatically.) + */ onInputChange = action((e: React.ChangeEvent) => { this._searchString = e.target.value; this.submitSearch(); }); + /** + * This method is called when the option in the select drop-down menu is changed. The + * _docTypeString is updated to the new value of the option in the drop-down menu. This + * is used to filter the results of the search to documents of a specific type. + * + * (Note: This doesn't affect the results array, so there is no need to submit a new + * search here. The results of the search on the _searchString query are simply filtered + * by type directly before rendering them.) + */ onSelectChange = action((e: React.ChangeEvent) => { this._docTypeString = e.target.value; }); + /** + * @param {Doc} doc - doc of the search result that has been clicked on + * + * This method is called when the user clicks on a search result. The _selectedResult is + * updated accordingly and the doc is highlighted with the selectElement method. + */ onResultClick = action((doc: Doc) => { this.selectElement(doc); this._selectedResult = doc; }); - static foreachRecursiveDoc(docs: Doc[], func: (doc: Doc) => void) { + /** + * @param {Doc[]} docs - docs to be searched through recursively + * @param {number, Doc => void} func - function to be called on each doc + * + * This method iterates through an array of docs and all docs within those docs, calling + * the function func on each doc. + */ + static foreachRecursiveDoc(docs: Doc[], func: (depth: number, doc: Doc) => void) { let newarray: Doc[] = []; + var depth = 0; while (docs.length > 0) { newarray = []; docs.filter(d => d).forEach(d => { @@ -94,12 +133,45 @@ export class SearchBox extends ViewBoxBaseComponent void} func - function to be called on each doc + * + * This method iterates asynchronously through an array of docs and all docs within those + * docs, calling the function func on each doc. + */ + static async foreachRecursiveDocAsync(docs: Doc[], func: (depth: number, doc: Doc) => void) { + let newarray: Doc[] = []; + var depth = 0; + while (docs.length > 0) { + newarray = []; + await Promise.all(docs.filter(d => d).map(async d => { + const fieldKey = Doc.LayoutFieldKey(d); + const annos = !Field.toString(Doc.LayoutField(d) as Field).includes("CollectionView"); + const data = d[annos ? fieldKey + "-annotations" : fieldKey]; + const docs = await DocListCastAsync(data); + docs && newarray.push(...docs); + func(depth, d); + })); + docs = newarray; + depth++; + } + } + + /** + * @param {String} type - string representing the type of a doc + * + * This method converts a doc type string of any length to a 3-letter doc type string in + * which the first letter is capitalized. This is used when displaying the type on the + * right side of each search result. + */ static formatType(type: String): String { if (type == "pdf") { return "PDF"; @@ -111,57 +183,75 @@ export class SearchBox extends ViewBoxBaseComponent { + if (this._selectedCollection !== undefined) { + const docs = DocListCast(this._selectedCollection.dataDoc[Doc.LayoutFieldKey(this._selectedCollection.dataDoc)]); + const docIDs: String[] = [] + SearchBox.foreachRecursiveDoc(docs, (depth: number, doc: Doc) => { const dtype = StrCast(doc.type, "string") as DocumentType; - if (dtype && !blockedTypes.includes(dtype)) { + if (dtype && !blockedTypes.includes(dtype) && !docIDs.includes(doc[Id]) && depth > 0) { const hlights = new Set(); SearchBox.documentKeys(doc).forEach(key => Field.toString(doc[key] as Field).toLowerCase().includes(query) && hlights.add(key)); - Array.from(hlights.keys()).length > 0 && this._results.push([doc, Array.from(hlights.keys()), []]); + blockedKeys.forEach(key => { + hlights.delete(key); + }) + Array.from(hlights.keys()).length > 0 && this._results.push([doc, Array.from(hlights.keys())]); } + docIDs.push(doc[Id]) }); } - - this._results = Array.from(new Set(this._results)) - this._selectedResult = undefined } + /** + * @param {Doc} doc - doc for which keys are returned + * + * This method returns a list of a document doc's keys. + */ static documentKeys(doc: Doc) { const keys: { [key: string]: boolean } = {}; - // bcz: ugh. this is untracked since otherwise a large collection of documents will blast the server for all their fields. - // then as each document's fields come back, we update the documents _proxies. Each time we do this, the whole schema will be - // invalidated and re-rendered. This workaround will inquire all of the document fields before the options button is clicked. - // then by the time the options button is clicked, all of the fields should be in place. If a new field is added while this menu - // is displayed (unlikely) it won't show up until something else changes. - //TODO Types Doc.GetAllPrototypes(doc).map(proto => Object.keys(proto).forEach(key => keys[key] = false)); return Array.from(Object.keys(keys)); } + /** + * This method submits a search with the _searchString as its query and updates + * the results array accordingly. + */ @action submitSearch = async () => { this.resetSearch(); - //this.dataDoc[this.fieldKey] = new List([]); let query = StrCast(this._searchString); Doc.SetSearchQuery(query); this._results = []; - this._resultsSet.clear(); if (query) { this.searchCollection(query); } } + /** + * This method resets the search by iterating through each result and removing all + * brushes and highlights. All search matches are cleared as well. + */ resetSearch = action(() => { this._results.forEach(result => { Doc.UnBrushDoc(result[0]); @@ -170,10 +260,32 @@ export class SearchBox extends ViewBoxBaseComponent { - await DocumentManager.Instance.jumpToDocument(doc, true); // documents open in new tab instead of on right + await DocumentManager.Instance.jumpToDocument(doc, true); + } + + /** + * This method returns a JSX list of the options in the select drop-down menu, which + * is used to filter the types of documents that appear in the search results. + */ + @computed + public get selectOptions() { + const selectValues = ["all", "rtf", "image", "pdf", "web", "video", "audio", "collection"] + + return selectValues.map(value => { + return + }) } + /** + * This method renders the search input box, select drop-down menu, and search results. + */ render() { var validResults = 0; @@ -186,7 +298,19 @@ export class SearchBox extends ViewBoxBaseComponent this.onResultClick(result[0])} className={className}>
{result[0].title}
{SearchBox.formatType(StrCast(result[0].type))}
) + return ( +
this.onResultClick(result[0])} className={className}> +
+ {result[0].title} +
+
+ {SearchBox.formatType(StrCast(result[0].type))} +
+
+ {result[1].join(", ")} +
+
+ ) } return null; @@ -194,15 +318,11 @@ export class SearchBox extends ViewBoxBaseComponent result); - const selectOptions = selectValues.map(value => { - return - }) - return (
@@ -217,190 +337,4 @@ export class SearchBox extends ViewBoxBaseComponent ); } -} - - - -/* -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { Tooltip } from '@material-ui/core'; -import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx'; -import { observer } from 'mobx-react'; -import * as React from 'react'; -import { Doc, DocListCast, Field, Opt, DocListCastAsync, DataSym, HeightSym, FieldsSym } from '../../../fields/Doc'; -import { documentSchema } from "../../../fields/documentSchemas"; -import { Copy, Id, ToString } from '../../../fields/FieldSymbols'; -import { List } from '../../../fields/List'; -import { createSchema, listSpec, makeInterface } from '../../../fields/Schema'; -import { SchemaHeaderField } from '../../../fields/SchemaHeaderField'; -import { Cast, NumCast, StrCast } from '../../../fields/Types'; -import { emptyFunction, returnFalse, returnZero, setupMoveUpEvents, Utils } from '../../../Utils'; -import { Docs } from '../../documents/Documents'; -import { DocumentType } from "../../documents/DocumentTypes"; -import { CurrentUserUtils } from "../../util/CurrentUserUtils"; -import { SetupDrag } from '../../util/DragManager'; -import { SearchUtil } from '../../util/SearchUtil'; -import { Transform } from '../../util/Transform'; -import { CollectionDockingView } from "../collections/CollectionDockingView"; -import { CollectionSchemaView, ColumnType } from "../collections/CollectionSchemaView"; -import { CollectionViewType } from '../collections/CollectionView'; -import { ViewBoxBaseComponent } from "../DocComponent"; -import { FieldView, FieldViewProps } from '../nodes/FieldView'; -import "./SearchBox.scss"; -import { undoBatch } from "../../util/UndoManager"; -import { DocServer } from "../../DocServer"; -import { MainView } from "../MainView"; -import { SelectionManager } from "../../util/SelectionManager"; -import { CollectionSchemaBooleanCell } from "../collections/CollectionSchemaCells"; -import { transpileModule } from "typescript"; -import { DocumentManager } from "../../util/DocumentManager"; - -export const searchSchema = createSchema({ Document: Doc }); - -type SearchBoxDocument = makeInterface<[typeof documentSchema, typeof searchSchema]>; -const SearchBoxDocument = makeInterface(documentSchema, searchSchema); - -@observer -export class SearchBox extends ViewBoxBaseComponent(SearchBoxDocument) { - public static LayoutString(fieldKey: string) { return FieldView.LayoutString(SearchBox, fieldKey); } - public static Instance: SearchBox; - - @observable _searchString = ""; - @observable _docTypeString = "all"; - @observable _results: [Doc, string[], string[]][] = []; - @observable _selectedResult: Doc | undefined = undefined; - @observable _deletedDocsStatus: boolean = false; - @observable _onlyAliases: boolean = true; - - constructor(props: any) { - super(props); - SearchBox.Instance = this; - } - - onInputChange = action((e: React.ChangeEvent) => { - this._searchString = e.target.value; - this.submitSearch(); - }); - - onSelectChange = action((e: React.ChangeEvent) => { - this._docTypeString = e.target.value; - this.submitSearch(); - }); - - onResultClick = action((doc: Doc) => { - this.selectElement(doc); - this._selectedResult = doc; - }); - - static foreachRecursiveDoc(docs: Doc[], func: (doc: Doc) => void) { - const blockedTypes = [DocumentType.PRESELEMENT, DocumentType.KVP, DocumentType.FILTER, DocumentType.SEARCH, DocumentType.SEARCHITEM, DocumentType.FONTICON, DocumentType.BUTTON, DocumentType.SCRIPTING]; - let newarray: Doc[] = []; - while (docs.length > 0) { - newarray = []; - docs.filter(d => d).forEach(d => { - const dtype = StrCast(d.type, "string") as DocumentType; - if (dtype && !blockedTypes.includes(dtype)) { - const fieldKey = Doc.LayoutFieldKey(d); - const annos = !Field.toString(Doc.LayoutField(d) as Field).includes("CollectionView"); - const data = d[annos ? fieldKey + "-annotations" : fieldKey]; - data && newarray.push(...DocListCast(data)); - func(d); - } - }); - docs = newarray; - } - } - - @action - searchCollection(query: string) { - const selectedCollection = CollectionDockingView.Instance; - query = query.toLowerCase(); - - if (selectedCollection !== undefined) { - console.log("hello111") - // this._currentSelectedCollection = selectedCollection; - const docs = DocListCast(selectedCollection.dataDoc[Doc.LayoutFieldKey(selectedCollection.dataDoc)]); - const found: [Doc, string[], string[]][] = []; - SearchBox.foreachRecursiveDoc(docs, (doc: Doc) => { - console.log("HELLO") - if (this._docTypeString == "all" || this._docTypeString == doc.type) { - const hlights = new Set(); - SearchBox.documentKeys(doc).forEach(key => Field.toString(doc[key] as Field).toLowerCase().includes(query) && hlights.add(key)); - Array.from(hlights.keys()).length > 0 && found.push([doc, Array.from(hlights.keys()), []]); - } - }); - - this._results = found; - //this.setSearchFilter(selectedCollection, this.filter && found.length ? this._docsforfilter : undefined); - } - } - - static documentKeys(doc: Doc) { - const keys: { [key: string]: boolean } = {}; - // bcz: ugh. this is untracked since otherwise a large collection of documents will blast the server for all their fields. - // then as each document's fields come back, we update the documents _proxies. Each time we do this, the whole schema will be - // invalidated and re-rendered. This workaround will inquire all of the document fields before the options button is clicked. - // then by the time the options button is clicked, all of the fields should be in place. If a new field is added while this menu - // is displayed (unlikely) it won't show up until something else changes. - //TODO Types - Doc.GetAllPrototypes(doc).map(proto => Object.keys(proto).forEach(key => keys[key] = false)); - return Array.from(Object.keys(keys)); - } - - @action - submitSearch = async () => { - Doc.ClearSearchMatches(); - this._results = []; - - this.dataDoc[this.fieldKey] = new List([]); - let query = StrCast(this._searchString); - Doc.SetSearchQuery(query); - this._results = []; - - if (query) { - this.searchCollection(query); - } - } - - selectElement = async (doc: Doc) => { - await DocumentManager.Instance.jumpToDocument(doc, true); // documents open in new tab instead of on right - } - - render() { - const results = this._results.map(result => { - var className = "searchBox-results-scroll-view-result"; - - if (this._selectedResult == result[0]) { - className += " searchBox-results-scroll-view-result-selected" - } - - return (
this.onResultClick(result[0])} className={className}>
{result[0].title}
) - }) - - return ( -
-
- - -
-
-
- {`${this._results.length}` + " result" + (this._results.length == 1 ? "" : "s")} -
-
- {results} -
-
-
- ); - } -}*/ \ No newline at end of file +} \ No newline at end of file -- cgit v1.2.3-70-g09d2 From f4c61d4c92182dc6598a8b6c7460baa52c65ebdc Mon Sep 17 00:00:00 2001 From: dg314 Date: Thu, 5 Aug 2021 16:46:55 -0400 Subject: imports --- src/client/views/search/SearchBox.tsx | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index 8ef09aa56..66012e3f4 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -1,32 +1,17 @@ -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { Tooltip } from '@material-ui/core'; -import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx'; +import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { Doc, DocListCast, Field, Opt, DocListCastAsync, DataSym, HeightSym, FieldsSym } from '../../../fields/Doc'; +import { Doc, DocListCast, DocListCastAsync, Field } from '../../../fields/Doc'; import { documentSchema } from "../../../fields/documentSchemas"; -import { Copy, Id, ToString } from '../../../fields/FieldSymbols'; -import { List } from '../../../fields/List'; -import { createSchema, listSpec, makeInterface } from '../../../fields/Schema'; -import { SchemaHeaderField } from '../../../fields/SchemaHeaderField'; -import { Cast, NumCast, StrCast } from '../../../fields/Types'; -import { emptyFunction, returnFalse, returnZero, setupMoveUpEvents, Utils } from '../../../Utils'; -import { Docs } from '../../documents/Documents'; +import { Id } from '../../../fields/FieldSymbols'; +import { createSchema, makeInterface } from '../../../fields/Schema'; +import { StrCast } from '../../../fields/Types'; import { DocumentType } from "../../documents/DocumentTypes"; -import { CurrentUserUtils } from "../../util/CurrentUserUtils"; -import { SetupDrag } from '../../util/DragManager'; -import { SearchUtil } from '../../util/SearchUtil'; -import { Transform } from '../../util/Transform'; +import { DocumentManager } from "../../util/DocumentManager"; import { CollectionDockingView } from "../collections/CollectionDockingView"; -import { CollectionSchemaView, ColumnType } from "../collections/CollectionSchemaView"; -import { CollectionViewType } from '../collections/CollectionView'; import { ViewBoxBaseComponent } from "../DocComponent"; import { FieldView, FieldViewProps } from '../nodes/FieldView'; import "./SearchBox.scss"; -import { undoBatch } from "../../util/UndoManager"; -import { DocServer } from "../../DocServer"; -import { MainView } from "../MainView"; -import { DocumentManager } from "../../util/DocumentManager"; export const searchSchema = createSchema({ Document: Doc }); -- cgit v1.2.3-70-g09d2 From 5550d58f16a0df090cde5a3605f6307b17e70758 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 5 Aug 2021 17:22:42 -0400 Subject: fixed so that links to sidebar annos show the sidebar in a LinkPreview --- src/client/views/SidebarAnnos.tsx | 3 +- src/client/views/collections/CollectionView.tsx | 5 +- src/client/views/nodes/PDFBox.tsx | 68 ++++++++++++++-------- src/client/views/nodes/WebBox.tsx | 35 ++++++----- .../views/nodes/formattedText/FormattedTextBox.tsx | 1 + src/client/views/pdf/PDFViewer.tsx | 2 - 6 files changed, 70 insertions(+), 44 deletions(-) (limited to 'src') diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx index f1d168a22..1f9763d18 100644 --- a/src/client/views/SidebarAnnos.tsx +++ b/src/client/views/SidebarAnnos.tsx @@ -24,6 +24,7 @@ interface ExtraProps { rootDoc: Doc; dataDoc: Doc; showSidebar: boolean; + nativeWidth: number; whenChildContentsActiveChanged: (isActive: boolean) => void; ScreenToLocalTransform: () => Transform; sidebarAddDocument: (doc: (Doc | Doc[]), suffix: string) => boolean; @@ -76,7 +77,7 @@ export class SidebarAnnos extends React.Component { get sidebarKey() { return this.props.fieldKey + "-sidebar"; } filtersHeight = () => 38; screenToLocalTransform = () => this.props.ScreenToLocalTransform().translate(Doc.NativeWidth(this.props.dataDoc), 0).scale(this.props.scaling?.() || 1); - panelWidth = () => !this.props.showSidebar ? 0 : this.props.layoutDoc.type === DocumentType.RTF ? this.props.PanelWidth() : (NumCast(this.props.layoutDoc.nativeWidth) - Doc.NativeWidth(this.props.dataDoc)) * this.props.PanelWidth() / NumCast(this.props.layoutDoc.nativeWidth); + panelWidth = () => !this.props.showSidebar ? 0 : this.props.layoutDoc.type === DocumentType.RTF ? this.props.PanelWidth() : (NumCast(this.props.nativeWidth) - Doc.NativeWidth(this.props.dataDoc)) * this.props.PanelWidth() / NumCast(this.props.nativeWidth); panelHeight = () => this.props.PanelHeight() - this.filtersHeight(); addDocument = (doc: Doc | Doc[]) => this.props.sidebarAddDocument(doc, this.sidebarKey); moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean) => this.props.moveDocument(doc, targetCollection, addDocument, this.sidebarKey); diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 2718cbbbf..2ae06d2f4 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -245,10 +245,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent { - console.log("Setting sub", subView); - return this._subView = subView - }), + SetSubView: action((subView: any) => this._subView = subView), addDocument: this.addDocument, moveDocument: this.moveDocument, removeDocument: this.removeDocument, diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index fc8fa4eef..b1f2070f8 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -9,7 +9,7 @@ import { makeInterface } from "../../../fields/Schema"; import { Cast, NumCast, StrCast, BoolCast } from '../../../fields/Types'; import { PdfField } from "../../../fields/URLField"; import { TraceMobx } from '../../../fields/util'; -import { Utils, setupMoveUpEvents, emptyFunction } from '../../../Utils'; +import { Utils, setupMoveUpEvents, emptyFunction, returnOne } from '../../../Utils'; import { Docs } from '../../documents/Documents'; import { KeyCodes } from '../../util/KeyCodes'; import { undoBatch } from '../../util/UndoManager'; @@ -31,6 +31,7 @@ const PdfDocument = makeInterface(documentSchema, panZoomSchema, pageSchema); @observer export class PDFBox extends ViewBoxAnnotatableComponent(PdfDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PDFBox, fieldKey); } + public static openSidebarWidth = 250; private _searchString: string = ""; private _initialScrollTarget: Opt; private _pdfViewer: PDFViewer | undefined; @@ -146,11 +147,17 @@ export class PDFBox extends ViewBoxAnnotatableComponent this.toggleSidebar()); } + @observable _previewNativeWidth: Opt = undefined; + @observable _previewWidth: Opt = undefined; toggleSidebar = action((preview: boolean = false) => { const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + "-nativeWidth"]); - const ratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? 250 : 0) + nativeWidth) / nativeWidth; + const ratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? PDFBox.openSidebarWidth : 0) + nativeWidth) / nativeWidth; const curNativeWidth = NumCast(this.layoutDoc.nativeWidth, nativeWidth); - if (preview) this._showSidebar = true; + if (preview) { + this._previewNativeWidth = nativeWidth * ratio; + this._previewWidth = this.layoutDoc[WidthSym]() * nativeWidth * ratio / curNativeWidth; + this._showSidebar = true; + } else { this.layoutDoc.nativeWidth = nativeWidth * ratio; this.layoutDoc._width = this.layoutDoc[WidthSym]() * nativeWidth * ratio / curNativeWidth; @@ -208,7 +215,9 @@ export class PDFBox extends ViewBoxAnnotatableComponent
; } - sidebarWidth = () => !this.SidebarShown ? 0 : (NumCast(this.layoutDoc.nativeWidth) - Doc.NativeWidth(this.dataDoc)) * this.props.PanelWidth() / NumCast(this.layoutDoc.nativeWidth); + sidebarWidth = () => !this.SidebarShown ? 0 : + this._previewWidth ? PDFBox.openSidebarWidth : + (NumCast(this.layoutDoc.nativeWidth) - Doc.NativeWidth(this.dataDoc)) * this.props.PanelWidth() / NumCast(this.layoutDoc.nativeWidth); specificContextMenu = (e: React.MouseEvent): void => { const funcs: ContextMenuProps[] = []; @@ -232,38 +241,51 @@ export class PDFBox extends ViewBoxAnnotatableComponent { + return 1; + } @computed get renderPdfView() { TraceMobx(); + const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1; + const scale = previewScale * (this.props.scaling?.() || 1); return
600) ? NumCast(this.Document._height) * this.props.PanelWidth() / NumCast(this.Document._width) : undefined }}>
- +
+ +
(WebDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(WebBox, fieldKey); } + public static openSidebarWidth = 250; private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean) => void); private _mainCont: React.RefObject = React.createRef(); private _outerRef: React.RefObject = React.createRef(); @@ -454,18 +455,27 @@ export class WebBox extends ViewBoxAnnotatableComponent this.toggleSidebar()); } + @observable _previewNativeWidth: Opt = undefined; + @observable _previewWidth: Opt = undefined; toggleSidebar = action((preview: boolean = false) => { const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + "-nativeWidth"]); - const ratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? 250 : 0) + nativeWidth) / nativeWidth; + const ratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? WebBox.openSidebarWidth : 0) + nativeWidth) / nativeWidth; const curNativeWidth = NumCast(this.layoutDoc.nativeWidth, nativeWidth); - if (preview) this._showSidebar; + if (preview) { + this._previewNativeWidth = nativeWidth * ratio; + this._previewWidth = this.layoutDoc[WidthSym]() * nativeWidth * ratio / curNativeWidth; + this._showSidebar = true; + } else { this.layoutDoc.nativeWidth = nativeWidth * ratio; this.layoutDoc._width = this.layoutDoc[WidthSym]() * nativeWidth * ratio / curNativeWidth; this.layoutDoc._showSidebar = nativeWidth !== this.layoutDoc._nativeWidth; } }); - sidebarWidth = () => !this.SidebarShown ? 0 : (NumCast(this.layoutDoc.nativeWidth) - Doc.NativeWidth(this.dataDoc)) * this.props.PanelWidth() / NumCast(this.layoutDoc.nativeWidth); + sidebarWidth = () => !this.SidebarShown ? 0 : + this._previewWidth ? WebBox.openSidebarWidth : + (NumCast(this.layoutDoc.nativeWidth) - Doc.NativeWidth(this.dataDoc)) * this.props.PanelWidth() / + NumCast(this.layoutDoc.nativeWidth); @computed get content() { return
this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._scrollTop)); anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick; render() { - const inactiveLayer = this.props.layerProvider?.(this.layoutDoc) === false; - const scale = this.props.scaling?.() || 1; + const pointerEvents = this.props.layerProvider?.(this.layoutDoc) === false ? "none" : undefined; + const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1; + const scale = previewScale * (this.props.scaling?.() || 1); return (
-
+
{ e.stopPropagation(); e.preventDefault(); }} // block wheel events from propagating since they're handled by the iframe onScroll={e => this.setDashScrollTop(this._outerRef.current?.scrollTop || 0)} onPointerDown={this.onMarqueeDown} > -
+
{this.content} void; setPdfViewer: (view: PDFViewer) => void; ContentScaling?: () => number; - sidebarWidth: () => number; anchorMenuClick?: () => undefined | ((anchor: Doc) => void); } @@ -550,7 +549,6 @@ export class PDFViewer extends React.Component { onScroll={this.onScroll} onWheel={this.onZoomWheel} onPointerDown={this.onPointerDown} onClick={this.onClick} style={{ overflowX: this._zoomed !== 1 ? "scroll" : undefined, - width: !this.props.Document._fitWidth && (window.screen.width > 600) ? Doc.NativeWidth(this.props.Document) - this.props.sidebarWidth() / this.contentScaling : `calc(${100 / this.contentScaling}% - ${this.props.sidebarWidth() / this.contentScaling}px)`, height: !this.props.Document._fitWidth && (window.screen.width > 600) ? Doc.NativeHeight(this.props.Document) : `${100 / this.contentScaling}%`, transform: `scale(${this.contentScaling})` }} > -- cgit v1.2.3-70-g09d2 From 576c74eb596d19a7dfbef832ad626f5fcc4b8c71 Mon Sep 17 00:00:00 2001 From: geireann Date: Thu, 5 Aug 2021 17:27:27 -0400 Subject: Update SearchBox.tsx --- src/client/views/search/SearchBox.tsx | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index 66012e3f4..9150b2e39 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -222,6 +222,7 @@ export class SearchBox extends ViewBoxBaseComponent { + console.log("submit search"); this.resetSearch(); let query = StrCast(this._searchString); @@ -229,6 +230,7 @@ export class SearchBox extends ViewBoxBaseComponent Date: Thu, 5 Aug 2021 18:40:49 -0400 Subject: fixed follow pushpin links that target documents in sidebars. --- src/client/util/DocumentManager.ts | 11 ++++++++--- src/client/util/LinkManager.ts | 3 ++- 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 9c6100249..27ae0447a 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -144,9 +144,11 @@ export class DocumentManager { originalTarget = originalTarget ?? targetDoc; const getFirstDocView = LightboxView.LightboxDoc ? DocumentManager.Instance.getLightboxDocumentView : DocumentManager.Instance.getFirstDocumentView; const docView = getFirstDocView(targetDoc, originatingDoc); + const wasHidden = targetDoc.hidden; // + if (wasHidden) runInAction(() => targetDoc.hidden = false); // if the target is hidden, un-hide it here. const focusAndFinish = (didFocus: boolean) => { if (originatingDoc?.isPushpin) { - if (!didFocus || targetDoc.hidden) { + if (!didFocus && !wasHidden) { // don't toggle the hidden state if the doc was already un-hidden as part of this document traversal targetDoc.hidden = !targetDoc.hidden; } } else { @@ -161,13 +163,13 @@ export class DocumentManager { const contextDocs = docContext ? await DocListCastAsync(docContext.data) : undefined; const contextDoc = contextDocs?.find(doc => Doc.AreProtosEqual(doc, targetDoc) || Doc.AreProtosEqual(doc, annotatedDoc)) ? docContext : undefined; const targetDocContext = contextDoc || annotatedDoc; - const targetDocContextView = targetDocContext && getFirstDocView(targetDocContext); + var targetDocContextView = targetDocContext && getFirstDocView(targetDocContext); const focusView = !docView && targetDoc.type === DocumentType.MARKER && annoContainerView ? annoContainerView : docView; if (!docView && annoContainerView) { annoContainerView.focus(targetDoc); // this allows something like a PDF view to remove its doc filters to expose the target so that it can be found in the retry code below } if (focusView) { - focusView && Doc.linkFollowHighlight(focusView.rootDoc); + Doc.linkFollowHighlight(focusView.rootDoc); focusView.focus(targetDoc, { originalTarget, willZoom, afterFocus: (didFocus: boolean) => new Promise(res => { @@ -179,6 +181,9 @@ export class DocumentManager { if (!targetDocContext) { // we don't have a view and there's no context specified ... create a new view of the target using the dockFunc or default createViewFunc(Doc.BrushDoc(targetDoc), finished); // bcz: should we use this?: Doc.MakeAlias(targetDoc))); } else { // otherwise try to get a view of the context of the target + if (annoContainerView && wasHidden) { // if we have an annotation container and the target was hidden, then try again because we just un-hid the document above + targetDocContextView = annoContainerView; + } if (targetDocContextView) { // we found a context view and aren't forced to create a new one ... focus on the context first.. targetDocContext._viewTransition = "transform 500ms"; targetDocContextView.props.focus(targetDocContextView.rootDoc, { diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts index 08f4ac9b7..8abfd740c 100644 --- a/src/client/util/LinkManager.ts +++ b/src/client/util/LinkManager.ts @@ -135,7 +135,8 @@ export class LinkManager { const where = LightboxView.LightboxDoc ? "lightbox" : StrCast(sourceDoc.followLinkLocation, followLoc); docViewProps.addDocTab(doc, where); setTimeout(() => { - const targDocView = DocumentManager.Instance.getFirstDocumentView(doc); + const getFirstDocView = LightboxView.LightboxDoc ? DocumentManager.Instance.getLightboxDocumentView : DocumentManager.Instance.getFirstDocumentView; + const targDocView = getFirstDocView(doc); // get first document view available within the lightbox if that's open, or anywhere otherwise. if (targDocView) { targDocView.props.focus(doc, { willZoom: BoolCast(sourceDoc.followLinkZoom, false), -- cgit v1.2.3-70-g09d2 From d7eedddcba42017c4609d81f3a47b2f35a48ecea Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 5 Aug 2021 23:30:55 -0400 Subject: fixed creating webpages from toolbar / :webpage to not use templates --- src/client/util/CurrentUserUtils.ts | 2 +- src/client/views/nodes/WebBox.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index e1cbaf125..1af6607a7 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -459,7 +459,7 @@ export class CurrentUserUtils { ((doc.emptyButton as Doc).proto as Doc)["dragFactory-count"] = 0; } if (doc.emptyWebpage === undefined) { - doc.emptyWebpage = Docs.Create.WebDocument("", { title: "webpage", _nativeWidth: 850, isTemplateDoc: true, _height: 512, _width: 400, useCors: true, system: true, cloneFieldFilter: new List(["system"]) }); + doc.emptyWebpage = Docs.Create.WebDocument("", { title: "webpage", _nativeWidth: 850, _height: 512, _width: 400, useCors: true, system: true, cloneFieldFilter: new List(["system"]) }); } if (doc.activeMobileMenu === undefined) { this.setupActiveMobileMenu(doc); diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index d2c806df6..7b2fafaa9 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -68,7 +68,7 @@ export class WebBox extends ViewBoxAnnotatableComponent Date: Fri, 6 Aug 2021 09:08:33 -0400 Subject: fixed linking to WebBox to save current web page as part of view spec. --- src/client/documents/Documents.ts | 13 +++++++++---- src/client/views/nodes/WebBox.tsx | 23 +++++++++++++++-------- 2 files changed, 24 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 142c37ea4..24f777e88 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -721,15 +721,20 @@ export namespace Docs { return InstanceFromProto(Prototypes.get(DocumentType.KVP), document, { title: document.title + ".kvp", ...options }); } - export function TextanchorDocument(options: DocumentOptions = {}, id?: string) { - return InstanceFromProto(Prototypes.get(DocumentType.MARKER), undefined, options, id); - } - export function FreeformDocument(documents: Array, options: DocumentOptions, id?: string) { const inst = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { ...options, _viewType: CollectionViewType.Freeform }, id); documents.map(d => d.context = inst); return inst; } + + export function WebanchorDocument(url?: string, options: DocumentOptions = {}, id?: string) { + return InstanceFromProto(Prototypes.get(DocumentType.MARKER), url, options, id); + } + + export function TextanchorDocument(options: DocumentOptions = {}, id?: string) { + return InstanceFromProto(Prototypes.get(DocumentType.MARKER), options?.data, options, id); + } + export function HTMLAnchorDocument(documents: Array, options: DocumentOptions, id?: string) { return InstanceFromProto(Prototypes.get(DocumentType.MARKER), new List(documents), options, id); } diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 7b2fafaa9..4498a7bf1 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -52,6 +52,7 @@ export class WebBox extends ViewBoxAnnotatableComponent(); private _initialScroll: Opt; private _sidebarRef = React.createRef(); + @observable private _urlHash: string = ""; @observable private _scrollTimer: any; @observable private _overlayAnnoInfo: Opt; @observable private _marqueeing: number[] | undefined; @@ -82,9 +83,11 @@ export class WebBox extends ViewBoxAnnotatableComponent { this._url = this.webField?.toString() || ""; - this._annotationKey = "annotations-" + WebBox.urlHash(this._url); + this._urlHash = WebBox.urlHash(this._url) + ""; + this._annotationKey = this._urlHash + "-annotations"; // bcz: need to make sure that doc.data-annotations points to the currently active web page's annotations (this could/should be when the doc is created) - this.dataDoc[this.fieldKey + "-annotations"] = ComputedField.MakeFunction(`copyField(this["${this.fieldKey}-annotations-"+urlHash(this["${this.fieldKey}"]?.url?.toString()))`); + this.dataDoc[this.fieldKey + "-annotations"] = ComputedField.MakeFunction(`copyField(this["${this.fieldKey}-"+urlHash(this["${this.fieldKey}"]?.url?.toString())+"-annotations"`); + this.dataDoc[this.fieldKey + "-sidebar"] = ComputedField.MakeFunction(`copyField(this["${this.fieldKey}-"+urlHash(this["${this.fieldKey}"]?.url?.toString())+"-sidebar"`); }); this._disposers.selection = reaction(() => this.props.isSelected(), @@ -161,6 +164,7 @@ export class WebBox extends ViewBoxAnnotatableComponent this.urlEditor; // controls to be added to the top bar when a document of this type is selected scrollFocus = (doc: Doc, smooth: boolean) => { + if (StrCast(doc.data)) this.submitURL(StrCast(doc.data)); if (DocListCast(this.props.Document[this.fieldKey + "-sidebar"]).includes(doc) && !this.SidebarShown) { this.toggleSidebar(!smooth); } @@ -182,10 +186,10 @@ export class WebBox extends ViewBoxAnnotatableComponent { const anchor = AnchorMenu.Instance?.GetAnchor(this._savedAnnotations) ?? - Docs.Create.TextanchorDocument({ + Docs.Create.WebanchorDocument(this._url, { title: StrCast(this.rootDoc.title + " " + this.layoutDoc._scrollTop), annotationOn: this.rootDoc, - y: NumCast(this.layoutDoc._scrollTop), + y: NumCast(this.layoutDoc._scrollTop) }); this.addDocument(anchor); return anchor; @@ -301,7 +305,8 @@ export class WebBox extends ViewBoxAnnotatableComponent([this._url]); else future.push(this._url); this.dataDoc[this.fieldKey] = new WebField(new URL(this._url = history.pop()!)); - this._annotationKey = "annotations-" + WebBox.urlHash(this._url); + this._urlHash = WebBox.urlHash(this._url) + ""; + this._annotationKey = this._urlHash + "-annotations"; return true; } return false; @@ -343,7 +349,8 @@ export class WebBox extends ViewBoxAnnotatableComponent Date: Fri, 6 Aug 2021 09:52:04 -0400 Subject: fixed webbox history to allow duplicate urls --- src/client/views/collections/TabDocView.tsx | 1 - src/client/views/nodes/DocumentView.tsx | 2 +- src/client/views/nodes/WebBox.tsx | 8 ++++---- 3 files changed, 5 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 623e0f58d..1f73793b6 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -171,7 +171,6 @@ export class TabDocView extends React.Component { //attach the selection doc buttons menu to the drag handle const stack: HTMLDivElement = tab.contentItem.parent; const header: HTMLDivElement = tab; - console.log("Stack: " + stack.id, stack.className) stack.onscroll = action((e: any) => { console.log('scrolling...') }) diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index bea219831..745d58656 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -420,7 +420,7 @@ export class DocumentViewInternal extends DocComponent { LightboxView.SetCookie(StrCast(anchor["cookies-set"])); - // copying over _VIEW fields immediately allows the view type to switch to create the right _componentView + // copying over VIEW fields immediately allows the view type to switch to create the right _componentView Array.from(Object.keys(Doc.GetProto(anchor))).filter(key => key.startsWith(ViewSpecPrefix)).forEach(spec => { this.layoutDoc[spec.replace(ViewSpecPrefix, "")] = ((field) => field instanceof ObjectField ? ObjectField.MakeCopy(field) : field)(anchor[spec]); }); diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 4498a7bf1..751d63711 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -164,7 +164,7 @@ export class WebBox extends ViewBoxAnnotatableComponent this.urlEditor; // controls to be added to the top bar when a document of this type is selected scrollFocus = (doc: Doc, smooth: boolean) => { - if (StrCast(doc.data)) this.submitURL(StrCast(doc.data)); + if (StrCast(doc.data) !== this._url) this.submitURL(StrCast(doc.data)); if (DocListCast(this.props.Document[this.fieldKey + "-sidebar"]).includes(doc) && !this.SidebarShown) { this.toggleSidebar(!smooth); } @@ -303,7 +303,7 @@ export class WebBox extends ViewBoxAnnotatableComponent([...history, this._url]); this.dataDoc[this.fieldKey] = new WebField(new URL(this._url = future.pop()!)); this._urlHash = WebBox.urlHash(this._url) + ""; this._annotationKey = this._urlHash + "-annotations"; @@ -318,7 +318,7 @@ export class WebBox extends ViewBoxAnnotatableComponent([this._url]); - else future.push(this._url); + else this.dataDoc[this.fieldKey + "-future"] = new List([...future, this._url]); this.dataDoc[this.fieldKey] = new WebField(new URL(this._url = history.pop()!)); this._urlHash = WebBox.urlHash(this._url) + ""; this._annotationKey = this._urlHash + "-annotations"; @@ -343,7 +343,7 @@ export class WebBox extends ViewBoxAnnotatableComponent([url]); } else { - history.push(url); + this.dataDoc[this.fieldKey + "-history"] = new List([...history, url]); } this.layoutDoc._scrollTop = 0; future && (future.length = 0); -- cgit v1.2.3-70-g09d2 From d756ffd3daa24270361648454062e98f190ae964 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 6 Aug 2021 10:34:57 -0400 Subject: fixed webboxes so that you can link to an annotation and it will restore the url as well. a bunch of warnings cleanup. --- src/client/util/DocumentManager.ts | 6 ++---- src/client/views/DocumentButtonBar.tsx | 2 +- src/client/views/InkStrokeProperties.ts | 2 +- src/client/views/collections/CollectionSubView.tsx | 2 +- src/client/views/collections/CollectionView.tsx | 2 +- src/client/views/collections/TabDocView.tsx | 4 ++-- src/client/views/linking/LinkPopup.tsx | 1 - src/client/views/nodes/DocumentLinksButton.tsx | 4 ++-- src/client/views/nodes/PDFBox.tsx | 2 +- src/client/views/nodes/WebBox.tsx | 15 ++++++++++----- src/client/views/nodes/formattedText/FormattedTextBox.tsx | 1 - src/fields/Doc.ts | 2 +- 12 files changed, 22 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 27ae0447a..cb0ee411c 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -163,7 +163,8 @@ export class DocumentManager { const contextDocs = docContext ? await DocListCastAsync(docContext.data) : undefined; const contextDoc = contextDocs?.find(doc => Doc.AreProtosEqual(doc, targetDoc) || Doc.AreProtosEqual(doc, annotatedDoc)) ? docContext : undefined; const targetDocContext = contextDoc || annotatedDoc; - var targetDocContextView = targetDocContext && getFirstDocView(targetDocContext); + const targetDocContextView = (targetDocContext && getFirstDocView(targetDocContext)) || + (wasHidden && annoContainerView);// if we have an annotation container and the target was hidden, then try again because we just un-hid the document above const focusView = !docView && targetDoc.type === DocumentType.MARKER && annoContainerView ? annoContainerView : docView; if (!docView && annoContainerView) { annoContainerView.focus(targetDoc); // this allows something like a PDF view to remove its doc filters to expose the target so that it can be found in the retry code below @@ -181,9 +182,6 @@ export class DocumentManager { if (!targetDocContext) { // we don't have a view and there's no context specified ... create a new view of the target using the dockFunc or default createViewFunc(Doc.BrushDoc(targetDoc), finished); // bcz: should we use this?: Doc.MakeAlias(targetDoc))); } else { // otherwise try to get a view of the context of the target - if (annoContainerView && wasHidden) { // if we have an annotation container and the target was hidden, then try again because we just un-hid the document above - targetDocContextView = annoContainerView; - } if (targetDocContextView) { // we found a context view and aren't forced to create a new one ... focus on the context first.. targetDocContext._viewTransition = "transform 500ms"; targetDocContextView.props.focus(targetDocContextView.rootDoc, { diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index df1e6899d..5f09a322c 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -355,7 +355,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
- {(DocumentLinksButton.StartLink || Doc.UserDoc()["documentLinksButton-fullMenu"]) && DocumentLinksButton.StartLink != doc ?
+ {(DocumentLinksButton.StartLink || Doc.UserDoc()["documentLinksButton-fullMenu"]) && DocumentLinksButton.StartLink !== doc ?
: (null)} {/*!Doc.UserDoc()["documentLinksButton-fullMenu"] ? (null) :
diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts index 76ca5b5ec..6444e4451 100644 --- a/src/client/views/InkStrokeProperties.ts +++ b/src/client/views/InkStrokeProperties.ts @@ -283,7 +283,7 @@ export class InkStrokeProperties { */ @action rotatePoint = (target: PointData, origin: PointData, angle: number) => { - let rotatedTarget = { X: target.X - origin.X, Y: target.Y - origin.Y }; + const rotatedTarget = { X: target.X - origin.X, Y: target.Y - origin.Y }; const newX = Math.cos(angle) * rotatedTarget.X - Math.sin(angle) * rotatedTarget.Y; const newY = Math.sin(angle) * rotatedTarget.X + Math.cos(angle) * rotatedTarget.Y; rotatedTarget.X = newX + origin.X; diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index a9b5ce465..227635c9b 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -93,7 +93,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: childDocFilters = () => [...this.props.docFilters(), ...this.collectionFilters()]; childDocRangeFilters = () => [...(this.props.docRangeFilters?.() || []), ...this.collectionRangeDocFilters()]; IsFiltered = () => this.collectionFilters().length || this.collectionRangeDocFilters().length ? "hasFilter" : - this.props.docFilters().length || this.props.docRangeFilters().length ? "inheritsFilter" : undefined; + this.props.docFilters().length || this.props.docRangeFilters().length ? "inheritsFilter" : undefined searchFilterDocs = () => this.props.searchFilterDocs?.() ?? DocListCast(this.props.Document._searchFilterDocs); @computed.struct get childDocs() { TraceMobx(); diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 2ae06d2f4..e65ebf075 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -236,7 +236,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent { const stack: HTMLDivElement = tab.contentItem.parent; const header: HTMLDivElement = tab; stack.onscroll = action((e: any) => { - console.log('scrolling...') - }) + console.log('scrolling...'); + }); const moreInfoDrag = document.createElement("div"); moreInfoDrag.className = "lm_iconWrap"; tab._disposers.buttonDisposer = reaction(() => this.view, view => diff --git a/src/client/views/linking/LinkPopup.tsx b/src/client/views/linking/LinkPopup.tsx index 2c4b718f4..df469c53b 100644 --- a/src/client/views/linking/LinkPopup.tsx +++ b/src/client/views/linking/LinkPopup.tsx @@ -54,7 +54,6 @@ export class LinkPopup extends React.Component { @action onLinkChange = (e: React.ChangeEvent) => { this.linkURL = e.target.value; - console.log(this.linkURL) } diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx index b63174e54..7648e866e 100644 --- a/src/client/views/nodes/DocumentLinksButton.tsx +++ b/src/client/views/nodes/DocumentLinksButton.tsx @@ -114,7 +114,7 @@ export class DocumentLinksButton extends React.Component - ) + ); } render() { diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index b1f2070f8..23236cf20 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -217,7 +217,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent !this.SidebarShown ? 0 : this._previewWidth ? PDFBox.openSidebarWidth : - (NumCast(this.layoutDoc.nativeWidth) - Doc.NativeWidth(this.dataDoc)) * this.props.PanelWidth() / NumCast(this.layoutDoc.nativeWidth); + (NumCast(this.layoutDoc.nativeWidth) - Doc.NativeWidth(this.dataDoc)) * this.props.PanelWidth() / NumCast(this.layoutDoc.nativeWidth) specificContextMenu = (e: React.MouseEvent): void => { const funcs: ContextMenuProps[] = []; diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 751d63711..ca281d68f 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -164,7 +164,7 @@ export class WebBox extends ViewBoxAnnotatableComponent this.urlEditor; // controls to be added to the top bar when a document of this type is selected scrollFocus = (doc: Doc, smooth: boolean) => { - if (StrCast(doc.data) !== this._url) this.submitURL(StrCast(doc.data)); + if (StrCast(doc.webUrl) !== this._url) this.submitURL(StrCast(doc.webUrl)); if (DocListCast(this.props.Document[this.fieldKey + "-sidebar"]).includes(doc) && !this.SidebarShown) { this.toggleSidebar(!smooth); } @@ -191,7 +191,7 @@ export class WebBox extends ViewBoxAnnotatableComponent { + (doc instanceof Doc ? [doc] : doc).forEach(doc => doc.webUrl = this._url); + return this.addDocument(doc, annotationKey); + } + sidebarAddDocument = (doc: Doc | Doc[], sidebarKey?: string) => { if (!this.layoutDoc._showSidebar) this.toggleSidebar(); - return this.addDocument(doc, sidebarKey); + return this.addDocumentWrapper(doc, sidebarKey); } sidebarBtnDown = (e: React.PointerEvent) => { setupMoveUpEvents(this, e, (e, down, delta) => { @@ -482,7 +487,7 @@ export class WebBox extends ViewBoxAnnotatableComponent !this.SidebarShown ? 0 : this._previewWidth ? WebBox.openSidebarWidth : (NumCast(this.layoutDoc.nativeWidth) - Doc.NativeWidth(this.dataDoc)) * this.props.PanelWidth() / - NumCast(this.layoutDoc.nativeWidth); + NumCast(this.layoutDoc.nativeWidth) @computed get content() { return
{ this._editorView?.state && RichTextMenu.Instance.insertHighlight(color, this._editorView.state, this._editorView?.dispatch); - console.log("highlight") return undefined; }); /** diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 6dcf34a3a..0cbfaf067 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -1214,7 +1214,7 @@ export namespace Doc { case DocumentType.RTF: return "sticky-note"; case DocumentType.COL: const folder: IconProp = isOpen ? "folder-open" : "folder"; - const chevron: IconProp = isOpen ? "chevron-down" : "chevron-right" + const chevron: IconProp = isOpen ? "chevron-down" : "chevron-right"; return !doc?.isFolder ? folder : chevron; case DocumentType.WEB: return "globe-asia"; case DocumentType.SCREENSHOT: return "photo-video"; -- cgit v1.2.3-70-g09d2 From 1986646c0a1b422d8c4b6138ab81694762062f68 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 6 Aug 2021 10:40:39 -0400 Subject: fixed previewing web page links to not change the webpage unless link is followed. --- src/client/views/nodes/WebBox.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index ca281d68f..920d5e506 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -164,7 +164,7 @@ export class WebBox extends ViewBoxAnnotatableComponent this.urlEditor; // controls to be added to the top bar when a document of this type is selected scrollFocus = (doc: Doc, smooth: boolean) => { - if (StrCast(doc.webUrl) !== this._url) this.submitURL(StrCast(doc.webUrl)); + if (StrCast(doc.webUrl) !== this._url) this.submitURL(StrCast(doc.webUrl), !smooth); if (DocListCast(this.props.Document[this.fieldKey + "-sidebar"]).includes(doc) && !this.SidebarShown) { this.toggleSidebar(!smooth); } @@ -332,14 +332,14 @@ export class WebBox extends ViewBoxAnnotatableComponent { + submitURL = (newUrl?: string, preview?: boolean) => { if (!newUrl) return; if (!newUrl.startsWith("http")) newUrl = "http://" + newUrl; try { const future = Cast(this.dataDoc[this.fieldKey + "-future"], listSpec("string")); const history = Cast(this.dataDoc[this.fieldKey + "-history"], listSpec("string")); const url = this.webField?.toString(); - if (url) { + if (url && !preview) { if (history === undefined) { this.dataDoc[this.fieldKey + "-history"] = new List([url]); } else { @@ -351,7 +351,7 @@ export class WebBox extends ViewBoxAnnotatableComponent Date: Fri, 6 Aug 2021 10:46:12 -0400 Subject: from last --- src/client/views/nodes/WebBox.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 920d5e506..f3a4a46de 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -429,7 +429,7 @@ export class WebBox extends ViewBoxAnnotatableComponent; } else if (field instanceof WebField) { - const url = this.layoutDoc.useCors ? Utils.CorsProxy(field.url.href) : field.url.href; + const url = this.layoutDoc.useCors ? Utils.CorsProxy(this._url) : this._url; view =