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/views/DocComponent.tsx | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
(limited to 'src/client/views')
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);
--
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/client/views')
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/client/views')
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/client/views')
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/client/views')
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 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/client/views')
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 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/client/views')
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/client/views')
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 b85e7819ae46558a659cac73817be0b812d6abbe Mon Sep 17 00:00:00 2001
From: usodhi <61431818+usodhi@users.noreply.github.com>
Date: Mon, 31 May 2021 20:18:19 -0400
Subject: sharing dashboard works? pending fixing remnant on screen tabs
---
src/client/documents/Documents.ts | 17 +++---------
src/client/util/CurrentUserUtils.ts | 30 +++++++++++++++++++---
.../views/collections/CollectionDockingView.tsx | 9 ++++++-
3 files changed, 38 insertions(+), 18 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 6fb6f70b3..70541b559 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -648,9 +648,8 @@ 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, layoutData?: boolean) {
+ function InstanceFromProto(proto: Doc, data: Field | undefined, options: DocumentOptions, delegId?: string, fieldKey: string = "data", protoId?: string) {
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, "^_");
@@ -662,16 +661,8 @@ export namespace Docs {
dataProps["acl-Override"] = "None";
dataProps["acl-Public"] = Doc.UserDoc()?.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Add;
- 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;
+ 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();
@@ -902,7 +893,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, undefined, undefined, 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);
}
export function DirectoryImportDocument(options: DocumentOptions = {}) {
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index e143887fa..90a2378fe 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -1187,6 +1187,22 @@ 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;
+
+ // switching the tabs from the datadoc to the regular doc
+ const dashboardTabs = dashboardDoc[DataSym].data;
+ dashboardDoc[DataSym].data = new List();
+ dashboardDoc.data = dashboardTabs;
+
+ // collating all docs on the dashboard to make a data-all field
+ const allDocs = new List();
+ const allDocs2 = new List(); // Array.from, spread, splice all cause so stack or acl issues for some reason
+ DocListCast(dashboardTabs).forEach(doc => {
+ const tabDocs = DocListCast(doc.data);
+ allDocs.push(...tabDocs);
+ allDocs2.push(...tabDocs);
+ });
+ dashboardDoc[DataSym]["data-all"] = allDocs;
+ dashboardDoc["data-all"] = allDocs2;
DocListCast(dashboardDoc.data).forEach(doc => doc.dashboard = dashboardDoc);
DocListCast(dashboardDoc.data)[1].data = ComputedField.MakeFunction(`dynamicOffScreenDocs(self.dashboard)`) as any;
@@ -1257,14 +1273,18 @@ Scripting.addGlobal(function shareDashboard(dashboard: Doc) {
"opens sharing dialog for Dashboard");
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"]);
+ // moves the data-all field from the datadoc to the layoutdoc, necessary for off screen docs tab to function properly
+ dashboard["data-all"] = new List(allDocs);
dashboardAlias["data-all"] = new List((allDocs || []).map(doc => Doc.MakeAlias(doc)));
+ const dockingConfig = JSON.parse(StrCast(dashboardAlias.dockingConfig));
+ dockingConfig.content = [];
+ dashboardAlias.dockingConfig = JSON.stringify(dockingConfig);
+
+
dashboardAlias.data = new List(DocListCast(dashboard.data).map(tabFolder => Doc.MakeAlias(tabFolder)));
DocListCast(dashboardAlias.data).forEach(doc => doc.dashboard = dashboardAlias);
DocListCast(dashboardAlias.data)[0].data = new List();
@@ -1274,10 +1294,12 @@ Scripting.addGlobal(async function addToDashboards(dashboard: Doc) {
},
"adds Dashboard to set of Dashboards");
+/**
+ * Dynamically computes which docs should be rendered in the off-screen tabs tree of a dashboard.
+ */
Scripting.addGlobal(function dynamicOffScreenDocs(dashboard: Doc) {
if (dashboard[DataSym] instanceof Doc) {
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) => {
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 235fe8950..2e44b65e6 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -163,8 +163,15 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) {
if (!instance) return false;
else {
const docList = DocListCast(instance.props.Document[DataSym]["data-all"]);
+ // adds the doc of the newly created tab to the data-all field if it doesn't already include that doc or one of its aliases
!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)));
+ // adds an alias of the doc to the data-all field of the layoutdocs of the aliases
+ DocListCast(instance.props.Document[DataSym].aliases).forEach(alias => {
+ const aliasDocList = DocListCast(alias["data-all"]);
+ // if aliasDocList contains the alias, don't do anything
+ // otherwise add the original or an alias depending on whether the doc you're looking at is the current doc or a different alias
+ !DocListCast(document.aliases).some(a => aliasDocList.includes(a)) && Doc.AddDocToList(alias, "data-all", alias !== instance.props.Document ? Doc.MakeAlias(document) : document);
+ });
}
const docContentConfig = CollectionDockingView.makeDocumentConfig(document, panelName);
--
cgit v1.2.3-70-g09d2
From 0a0a467df5f87adb1f9872c82cc58bbc6c1046d7 Mon Sep 17 00:00:00 2001
From: usodhi <61431818+usodhi@users.noreply.github.com>
Date: Sat, 5 Jun 2021 17:44:54 -0400
Subject: cleanup
---
src/client/views/collections/TreeView.tsx | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index fc4361935..a20d41a8d 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -511,9 +511,7 @@ export class TreeView extends React.Component {
}
onChildClick = () => this.props.onChildClick?.() ?? (this._editTitleScript?.() || ScriptCast(this.doc.treeChildClick));
- onChildDoubleClick = () => {
- return (!this.props.treeView.outlineMode && this._openScript?.()) || ScriptCast(this.doc.treeChildDoubleClick)
- };
+ onChildDoubleClick = () => (!this.props.treeView.outlineMode && this._openScript?.()) || ScriptCast(this.doc.treeChildDoubleClick);
refocus = () => this.props.treeView.props.focus(this.props.treeView.props.Document);
ignoreEvent = (e: any) => {
--
cgit v1.2.3-70-g09d2
From 0d07ddae31c5dae8364160801509e236c7e6e894 Mon Sep 17 00:00:00 2001
From: bobzel
Date: Thu, 10 Jun 2021 18:30:29 -0400
Subject: fixed link anchor to not render as a blue box when link trails are
turned on.
---
src/client/views/StyleProvider.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'src/client/views')
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 9e61351c4..47a4a192c 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -127,7 +127,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt
Date: Thu, 10 Jun 2021 18:40:28 -0400
Subject: fixed positioning of blue anchor dot when showing link anchor lines
---
src/client/views/nodes/DocumentView.tsx | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
(limited to 'src/client/views')
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index b861669f8..5646a9790 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -13,7 +13,7 @@ import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../fields/Ty
import { AudioField } from "../../../fields/URLField";
import { GetEffectiveAcl, SharingPermissions, TraceMobx } from '../../../fields/util';
import { MobileInterface } from '../../../mobile/MobileInterface';
-import { emptyFunction, hasDescendantTarget, OmitKeys, returnVal, Utils } from "../../../Utils";
+import { emptyFunction, hasDescendantTarget, OmitKeys, returnVal, Utils, returnTrue } from "../../../Utils";
import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils';
import { Docs, DocUtils } from "../../documents/Documents";
import { DocumentType } from '../../documents/DocumentTypes';
@@ -846,6 +846,7 @@ export class DocumentViewInternal extends DocComponent
Date: Thu, 17 Jun 2021 18:26:49 -0400
Subject: fixed drawing on images/videos/photos
---
src/client/views/GestureOverlay.tsx | 2 +-
src/client/views/nodes/ImageBox.tsx | 4 +++-
src/client/views/nodes/VideoBox.tsx | 2 +-
src/client/views/nodes/WebBox.tsx | 2 +-
src/client/views/nodes/formattedText/RichTextMenu.tsx | 2 +-
src/pen-gestures/GestureUtils.ts | 4 +---
6 files changed, 8 insertions(+), 8 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 491bf18b2..6a4f55bef 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -634,7 +634,7 @@ export class GestureOverlay extends Touchable {
} else {
this._points = [];
}
- CollectionFreeFormViewChrome.Instance.primCreated();
+ CollectionFreeFormViewChrome.Instance?.primCreated();
}
makePolygon = (shape: string, gesture: boolean) => {
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index e2e08a0e6..13dfad0fe 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -26,6 +26,8 @@ import { FaceRectangles } from './FaceRectangles';
import { FieldView, FieldViewProps } from './FieldView';
import "./ImageBox.scss";
import React = require("react");
+import { InkTool } from '../../../fields/InkField';
+import { CurrentUserUtils } from '../../util/CurrentUserUtils';
const path = require('path');
export const pageSchema = createSchema({
@@ -321,7 +323,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent {
- if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.isContentActive(true)) this._marqueeing = [e.clientX, e.clientY];
+ if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) this._marqueeing = [e.clientX, e.clientY];
}
@action
finishMarquee = () => {
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 263fd5a19..fc08a2302 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -543,7 +543,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent {
- if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.isContentActive(true)) this._marqueeing = [e.clientX, e.clientY];
+ if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) this._marqueeing = [e.clientX, e.clientY];
});
finishMarquee = action(() => {
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index cb7e58559..bd9e03856 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -395,7 +395,7 @@ export class WebBox extends ViewBoxAnnotatableComponent {
- if (!e.altKey && e.button === 0 && this.isContentActive(true)) {
+ if (!e.altKey && e.button === 0 && this.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) {
this._marqueeing = [e.clientX, e.clientY];
this.props.select(false);
}
diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx
index 071491463..59b2d3753 100644
--- a/src/client/views/nodes/formattedText/RichTextMenu.tsx
+++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx
@@ -352,7 +352,7 @@ export class RichTextMenu extends AntimodeMenu {
function onClick(e: React.PointerEvent) {
e.preventDefault();
e.stopPropagation();
- self.TextView.endUndoTypingBatch();
+ self.TextView?.endUndoTypingBatch();
UndoManager.RunInBatch(() => {
self.view && command && command(self.view.state, self.view.dispatch, self.view);
self.view && onclick && onclick(self.view.state, self.view.dispatch, self.view);
diff --git a/src/pen-gestures/GestureUtils.ts b/src/pen-gestures/GestureUtils.ts
index e7cc89697..65f2bf80c 100644
--- a/src/pen-gestures/GestureUtils.ts
+++ b/src/pen-gestures/GestureUtils.ts
@@ -20,9 +20,7 @@ export namespace GestureUtils {
): GestureEventDisposer {
const handler = (e: Event) => func(e, (e as CustomEvent).detail);
element.addEventListener("dashOnGesture", handler);
- return () => {
- element.removeEventListener("dashOnGesture", handler);
- };
+ return () => element.removeEventListener("dashOnGesture", handler);
}
export enum Gestures {
--
cgit v1.2.3-70-g09d2
From 383e98b01fbee9383f1bc738a87d4ebeab1dea0b Mon Sep 17 00:00:00 2001
From: bobzel
Date: Thu, 17 Jun 2021 19:42:28 -0400
Subject: from last
---
src/client/views/pdf/PDFViewer.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'src/client/views')
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 85cf5abd7..3c6cad42f 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -372,7 +372,7 @@ export class PDFViewer extends React.Component {
if ((e.button !== 0 || e.altKey) && this.props.isContentActive(true)) {
this._setPreviewCursor?.(e.clientX, e.clientY, true);
}
- if (!e.altKey && e.button === 0 && this.props.isContentActive(true)) {
+ if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) {
this.props.select(false);
this._marqueeing = [e.clientX, e.clientY];
if (e.target && ((e.target as any).className.includes("endOfContent") || ((e.target as any).parentElement.className !== "textLayer"))) {
--
cgit v1.2.3-70-g09d2
From 0c6269f2eda7a090ebd7d10298d55b7bc832297b Mon Sep 17 00:00:00 2001
From: usodhi <61431818+usodhi@users.noreply.github.com>
Date: Sat, 19 Jun 2021 19:41:12 -0400
Subject: trying to solve sidebar issues
---
src/client/views/DocComponent.tsx | 1 -
src/client/views/MainView.tsx | 6 +++---
src/fields/util.ts | 4 ++--
3 files changed, 5 insertions(+), 6 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index f1042de0f..2baf9fbda 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -205,7 +205,6 @@ export function ViewBoxAnnotatableComponent {
-
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;
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 4eeb1fc95..9d7999672 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -103,7 +103,7 @@ export class MainView extends React.Component {
}
new InkStrokeProperties();
this._sidebarContent.proto = undefined;
- DocServer.setPlaygroundFields(["x", "y", "dataTransition", "_autoHeight", "_showSidebar", "_sidebarWidthPercent", "_width", "_height", "_viewTransition", "_panX", "_panY", "_viewScale", "_scrollTop", "hidden", "_curPage", "_viewType", "_chromeHidden"]); // can play with these fields on someone else's
+ DocServer.setPlaygroundFields(["x", "y", "dataTransition", "_autoHeight", "_showSidebar", "showSidebar", "_sidebarWidthPercent", "_width", "_height", "width", "height", "_viewTransition", "_panX", "_panY", "_viewScale", "_scrollTop", "hidden", "_curPage", "_viewType", "_chromeHidden", "nativeWidth", "_nativeWidth"]); // can play with these fields on someone else's
DocServer.GetRefField("rtfProto").then(proto => (proto instanceof Doc) && reaction(() => StrCast(proto.BROADCAST_MESSAGE), msg => msg && alert(msg)));
@@ -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();
diff --git a/src/fields/util.ts b/src/fields/util.ts
index f0cc20d74..526e5af72 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -249,8 +249,8 @@ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc
layoutDocChanged = true;
if (isDashboard) {
- DocListCast(target[Doc.LayoutFieldKey(target)]).forEach(d => {
- distributeAcls(key, acl, d, inheritingFromCollection, visited);
+ DocListCastAsync(target[Doc.LayoutFieldKey(target)]).then(docs => {
+ docs?.forEach(d => distributeAcls(key, acl, d, inheritingFromCollection, visited));
});
}
}
--
cgit v1.2.3-70-g09d2
From db2864dfbe85f411e0a098447a7684e104a093ed Mon Sep 17 00:00:00 2001
From: bobzel
Date: Mon, 21 Jun 2021 13:48:23 -0400
Subject: null tests
---
src/client/views/nodes/ScreenshotBox.tsx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index 252c029e4..700f8a7d3 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -252,8 +252,8 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent
Date: Tue, 22 Jun 2021 13:39:34 -0400
Subject: added "live" flag to url parsing to override playground fields.
---
src/client/views/Main.tsx | 1 +
src/client/views/MainView.tsx | 10 ++++++----
2 files changed, 7 insertions(+), 4 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index 60327f1bf..7553c8118 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -12,6 +12,7 @@ import { LinkManager } from "../util/LinkManager";
AssignAllExtensions();
(async () => {
+ MainView.Live = window.location.search.includes("live");
window.location.search.includes("safe") && CollectionView.SetSafeMode(true);
const info = await CurrentUserUtils.loadCurrentUser();
if (info.id !== "__guest__") {
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 9d7999672..a064f7fe8 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -68,6 +68,7 @@ const _global = (window /* browser */ || global /* node */) as any;
@observer
export class MainView extends React.Component {
public static Instance: MainView;
+ public static Live: boolean = false;
private _docBtnRef = React.createRef();
@observable public LastButton: Opt;
@observable private _windowWidth: number = 0;
@@ -103,8 +104,9 @@ export class MainView extends React.Component {
}
new InkStrokeProperties();
this._sidebarContent.proto = undefined;
- DocServer.setPlaygroundFields(["x", "y", "dataTransition", "_autoHeight", "_showSidebar", "showSidebar", "_sidebarWidthPercent", "_width", "_height", "width", "height", "_viewTransition", "_panX", "_panY", "_viewScale", "_scrollTop", "hidden", "_curPage", "_viewType", "_chromeHidden", "nativeWidth", "_nativeWidth"]); // can play with these fields on someone else's
-
+ if (!MainView.Live) {
+ DocServer.setPlaygroundFields(["x", "y", "dataTransition", "_autoHeight", "_showSidebar", "showSidebar", "_sidebarWidthPercent", "_width", "_height", "width", "height", "_viewTransition", "_panX", "_panY", "_viewScale", "_scrollTop", "hidden", "_curPage", "_viewType", "_chromeHidden", "nativeWidth", "_nativeWidth"]); // can play with these fields on someone else's
+ }
DocServer.GetRefField("rtfProto").then(proto => (proto instanceof Doc) && reaction(() => StrCast(proto.BROADCAST_MESSAGE), msg => msg && alert(msg)));
const tag = document.createElement('script');
@@ -180,8 +182,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();
--
cgit v1.2.3-70-g09d2
From c76598b7105e31e24ae771a839e63c27d787d3ed Mon Sep 17 00:00:00 2001
From: dg314
Date: Thu, 24 Jun 2021 04:54:33 -0400
Subject: removed search db option
---
src/client/views/search/SearchBox.tsx | 44 ++++-------------------------------
1 file changed, 4 insertions(+), 40 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 5c168d8a9..b722868d6 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -63,7 +63,6 @@ export class SearchBox extends ViewBoxBaseComponent {
this.open = this._searchbarOpen = true;
this.resultsScrolled();
@@ -289,7 +287,7 @@ export class SearchBox extends ViewBoxBaseComponent `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
@@ -471,39 +469,6 @@ export class SearchBox extends ViewBoxBaseComponent NumCast(this.layoutDoc._height);
returnLength = () => Math.min(window.innerWidth, 51 + 205 * Cast(this.props.Document._schemaHeaders, listSpec(SchemaHeaderField), []).length);
- @action
- changeSearchScope = (scope: string) => {
- this.docsforfilter = undefined;
- this.setSearchFilter(this.currentSelectedCollection, undefined);
- this._searchFullDB = scope;
- this.dataDoc[this.fieldKey] = new List([]);
- this.submitSearch();
- }
-
- @computed get scopeButtons() {
- return ;
- }
-
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/client/views')
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/client/views')
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 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/client/views')
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/client/views')
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/client/views')
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: 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/client/views')
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) =>
)}
{controlPoints.map((control, i) =>
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/client/views')
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/client/views')
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/client/views')
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/client/views')
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/client/views')
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/client/views')
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/client/views')
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/client/views')
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/client/views')
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/client/views')
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/client/views')
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/client/views')
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/client/views')
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/client/views')
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/client/views')
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/client/views')
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/client/views')
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 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/client/views')
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/client/views')
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/client/views')
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/client/views')
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 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/client/views')
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/client/views')
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/client/views')
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/client/views')
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/client/views')
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/client/views')
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 =
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index fc36c7e43..99c695a4a 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -1,4 +1,4 @@
-import { Doc, Opt, DataSym, AclReadonly, AclAddonly, AclPrivate, AclEdit, AclSym, DocListCastAsync, DocListCast, AclAdmin } from '../../fields/Doc';
+import { Doc, Opt, DataSym, AclReadonly, AclAugment, AclPrivate, AclEdit, AclSym, DocListCast, AclAdmin, AclSelfEdit } from '../../fields/Doc';
import { Touchable } from './Touchable';
import { computed, action, observable } from 'mobx';
import { Cast, BoolCast, ScriptCast } from '../../fields/Types';
@@ -131,7 +131,7 @@ export function ViewBoxAnnotatableComponent effectiveAcl === AclEdit || effectiveAcl === AclAdmin || GetEffectiveAcl(doc) === AclAdmin);
+ const docs = indocs.filter(doc => [AclEdit, AclAdmin].includes(effectiveAcl) || GetEffectiveAcl(doc) === AclAdmin);
if (docs.length) {
setTimeout(() => docs.map(doc => { // this allows 'addDocument' to see the annotationOn field in order to create a pushin
Doc.SetInPlace(doc, "isPushpin", undefined, true);
@@ -199,7 +199,7 @@ export function ViewBoxAnnotatableComponent
{
if ([AclAdmin, AclEdit].includes(GetEffectiveAcl(doc))) inheritParentAcls(CurrentUserUtils.ActiveDashboard, doc);
doc.context = this.props.Document;
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 005e46836..8f37172a0 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -107,7 +107,7 @@ export class MainView extends React.Component {
new InkStrokeProperties();
this._sidebarContent.proto = undefined;
if (!MainView.Live) {
- DocServer.setPlaygroundFields(["x", "y", "dataTransition", "_autoHeight", "_showSidebar", "showSidebar", "_sidebarWidthPercent", "_width", "_height", "width", "height", "_viewTransition", "_panX", "_panY", "_viewScale", "_scrollTop", "hidden", "_curPage", "_viewType", "_chromeHidden", "nativeWidth", "_nativeWidth"]); // can play with these fields on someone else's
+ DocServer.setPlaygroundFields(["dataTransition", "autoHeight", "showSidebar", "sidebarWidthPercent", "viewTransition", "panX", "panY", "viewScale", "scrollTop", "hidden", "curPage", "viewType", "chromeHidden", "nativeWidth"]); // can play with these fields on someone else's
}
DocServer.GetRefField("rtfProto").then(proto => (proto instanceof Doc) && reaction(() => StrCast(proto.BROADCAST_MESSAGE), msg => msg && alert(msg)));
diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx
index 805cda95c..a3a3bce56 100644
--- a/src/client/views/MarqueeAnnotator.tsx
+++ b/src/client/views/MarqueeAnnotator.tsx
@@ -1,6 +1,6 @@
import { action, observable, ObservableMap, runInAction } from "mobx";
import { observer } from "mobx-react";
-import { AclAddonly, AclAdmin, AclEdit, DataSym, Doc, Opt } from "../../fields/Doc";
+import { AclAugment, AclAdmin, AclEdit, DataSym, Doc, Opt, AclSelfEdit } from "../../fields/Doc";
import { Id } from "../../fields/FieldSymbols";
import { List } from "../../fields/List";
import { NumCast } from "../../fields/Types";
@@ -156,7 +156,7 @@ export class MarqueeAnnotator extends React.Component {
highlight = (color: string, isLinkButton: boolean, savedAnnotations?: ObservableMap) => {
// creates annotation documents for current highlights
const effectiveAcl = GetEffectiveAcl(this.props.rootDoc[DataSym]);
- const annotationDoc = [AclAddonly, AclEdit, AclAdmin].includes(effectiveAcl) && this.makeAnnotationDocument(color, isLinkButton, savedAnnotations);
+ const annotationDoc = [AclAugment, AclSelfEdit, AclEdit, AclAdmin].includes(effectiveAcl) && this.makeAnnotationDocument(color, isLinkButton, savedAnnotations);
!savedAnnotations && annotationDoc && this.props.addDocument(annotationDoc);
return annotationDoc as Doc ?? undefined;
}
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 8136edf04..de437e1df 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -5,7 +5,7 @@ import { intersection } from "lodash";
import { action, autorun, computed, Lambda, observable, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
import { ColorState, SketchPicker } from "react-color";
-import { AclAddonly, AclAdmin, AclEdit, AclPrivate, AclReadonly, AclSym, AclUnset, DataSym, Doc, Field, HeightSym, Opt, WidthSym } from "../../fields/Doc";
+import { AclAugment, AclAdmin, AclEdit, AclPrivate, AclReadonly, AclSym, AclUnset, DataSym, Doc, Field, HeightSym, Opt, WidthSym, AclSelfEdit } from "../../fields/Doc";
import { Id } from "../../fields/FieldSymbols";
import { InkField } from "../../fields/InkField";
import { ComputedField } from "../../fields/ScriptField";
@@ -342,12 +342,9 @@ export class PropertiesView extends React.Component {
return ;
}
@@ -402,7 +399,8 @@ export class PropertiesView extends React.Component {
[AclUnset, "None"],
[AclPrivate, SharingPermissions.None],
[AclReadonly, SharingPermissions.View],
- [AclAddonly, SharingPermissions.Add],
+ [AclAugment, SharingPermissions.Augment],
+ [AclSelfEdit, SharingPermissions.SelfEdit],
[AclEdit, SharingPermissions.Edit],
[AclAdmin, SharingPermissions.Admin]
]);
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 846d28214..19da7ea00 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -1,6 +1,6 @@
import { action, computed, observable } from "mobx";
import { observer } from "mobx-react";
-import { AclAddonly, AclAdmin, AclEdit, DataSym, Doc, Opt } from "../../../../fields/Doc";
+import { AclAugment, AclAdmin, AclEdit, DataSym, Doc, Opt } from "../../../../fields/Doc";
import { Id } from "../../../../fields/FieldSymbols";
import { InkData, InkField, InkTool } from "../../../../fields/InkField";
import { List } from "../../../../fields/List";
@@ -298,7 +298,7 @@ export class MarqueeView extends React.Component json?.indexOf("\"storedMarks\"") === -1 ?
json?.replace(/"selection":.*/, "") : json?.replace(/"selection":"\"storedMarks\""/, "\"storedMarks\"");
- if (effectiveAcl === AclEdit || effectiveAcl === AclAdmin) {
+ if (effectiveAcl === AclEdit || effectiveAcl === AclAdmin || effectiveAcl === AclSelfEdit) {
const accumTags = [] as string[];
state.tr.doc.nodesBetween(0, state.doc.content.size, (node: any, pos: number, parent: any) => {
if (node.type === schema.nodes.dashField && node.attrs.fieldKey.startsWith("#")) {
@@ -1401,6 +1401,14 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
this._rules!.EnteringStyle = false;
}
e.stopPropagation();
+ for (var i = state.selection.from; i < state.selection.to; i++) {
+ const node = state.doc.resolve(i);
+ if (node?.marks?.().some(mark => mark.type === schema.marks.user_mark &&
+ mark.attrs.userid !== Doc.CurrentUserEmail) &&
+ [AclAugment, AclSelfEdit].includes(GetEffectiveAcl(this.rootDoc))) {
+ e.preventDefault();
+ }
+ }
switch (e.key) {
case "Escape":
this._editorView!.dispatch(state.tr.setSelection(TextSelection.create(state.doc, state.selection.from, state.selection.from)));
diff --git a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
index d5c77786c..1f78b2204 100644
--- a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
+++ b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
@@ -7,13 +7,14 @@ import { splitListItem, wrapInList, } from "prosemirror-schema-list";
import { EditorState, Transaction, TextSelection } from "prosemirror-state";
import { SelectionManager } from "../../../util/SelectionManager";
import { NumCast, BoolCast, Cast, StrCast } from "../../../../fields/Types";
-import { Doc, DataSym, DocListCast } from "../../../../fields/Doc";
+import { Doc, DataSym, DocListCast, AclAugment } from "../../../../fields/Doc";
import { FormattedTextBox } from "./FormattedTextBox";
import { Id } from "../../../../fields/FieldSymbols";
import { Docs } from "../../../documents/Documents";
import { Utils } from "../../../../Utils";
import { listSpec } from "../../../../fields/Schema";
import { List } from "../../../../fields/List";
+import { GetEffectiveAcl } from "../../../../fields/util";
const mac = typeof navigator !== "undefined" ? /Mac/.test(navigator.platform) : false;
@@ -70,25 +71,39 @@ export function buildKeymap>(schema: S, props: any, mapKey
return false;
};
+ const canEdit = (state: any) => {
+ for (var i = state.selection.from; i < state.selection.to; i++) {
+ const node = state.doc.resolve(i);
+ if (node?.marks?.().some((mark: any) => mark.type === schema.marks.user_mark &&
+ mark.attrs.userid !== Doc.CurrentUserEmail) &&
+ GetEffectiveAcl(props.Document) === AclAugment) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ const toggleEditableMark = (mark: any) => (state: EditorState, dispatch: (tx: Transaction) => void) => canEdit(state) && toggleMark(mark)(state, dispatch);
+
//History commands
bind("Mod-z", undo);
bind("Shift-Mod-z", redo);
!mac && bind("Mod-y", redo);
//Commands to modify Mark
- bind("Mod-b", toggleMark(schema.marks.strong));
- bind("Mod-B", toggleMark(schema.marks.strong));
+ bind("Mod-b", toggleEditableMark(schema.marks.strong));
+ bind("Mod-B", toggleEditableMark(schema.marks.strong));
- bind("Mod-e", toggleMark(schema.marks.em));
- bind("Mod-E", toggleMark(schema.marks.em));
+ bind("Mod-e", toggleEditableMark(schema.marks.em));
+ bind("Mod-E", toggleEditableMark(schema.marks.em));
- bind("Mod-*", toggleMark(schema.marks.code));
+ bind("Mod-*", toggleEditableMark(schema.marks.code));
- bind("Mod-u", toggleMark(schema.marks.underline));
- bind("Mod-U", toggleMark(schema.marks.underline));
+ bind("Mod-u", toggleEditableMark(schema.marks.underline));
+ bind("Mod-U", toggleEditableMark(schema.marks.underline));
//Commands for lists
- bind("Ctrl-i", wrapInList(schema.nodes.ordered_list));
+ bind("Ctrl-i", (state: EditorState, dispatch: (tx: Transaction) => void) => canEdit(state) && wrapInList(schema.nodes.ordered_list)(state, dispatch as any));
bind("Tab", (state: EditorState, dispatch: (tx: Transaction) => void) => {
/// bcz; Argh!! replace layotuTEmpalteString with a onTab prop conditionally handles Tab);
@@ -96,6 +111,7 @@ export function buildKeymap>(schema: S, props: any, mapKey
if (!props.LayoutTemplateString) return addTextBox(false, true);
return true;
}
+ if (!canEdit(state)) return true;
const ref = state.selection;
const range = ref.$from.blockRange(ref.$to);
const marks = state.storedMarks || (state.selection.$to.parentOffset && state.selection.$from.marks());
@@ -121,6 +137,7 @@ export function buildKeymap>(schema: S, props: any, mapKey
bind("Shift-Tab", (state: EditorState, dispatch: (tx: Transaction) => void) => {
/// bcz; Argh!! replace with a onShiftTab prop conditionally handles Tab);
if (props.Document._singleLine) return true;
+ if (!canEdit(state)) return true;
const marks = state.storedMarks || (state.selection.$to.parentOffset && state.selection.$from.marks());
if (!liftListItem(schema.nodes.list_item)(state.tr, (tx2: Transaction) => {
@@ -140,24 +157,19 @@ export function buildKeymap>(schema: S, props: any, mapKey
});
//Commands to modify BlockType
- bind("Ctrl->", wrapIn(schema.nodes.blockquote));
- bind("Alt-\\", setBlockType(schema.nodes.paragraph));
- bind("Shift-Ctrl-\\", setBlockType(schema.nodes.code_block));
+ bind("Ctrl->", (state: EditorState, dispatch: (tx: Transaction) => void) => canEdit((state) && wrapIn(schema.nodes.blockquote)(state, dispatch as any)));
+ bind("Alt-\\", (state: EditorState, dispatch: (tx: Transaction) => void) => canEdit(state) && setBlockType(schema.nodes.paragraph)(state, dispatch as any));
+ bind("Shift-Ctrl-\\", (state: EditorState, dispatch: (tx: Transaction) => void) => canEdit(state) && setBlockType(schema.nodes.code_block)(state, dispatch as any));
- bind("Ctrl-m", (state: EditorState, dispatch: (tx: Transaction) => void) => {
- dispatch(state.tr.replaceSelectionWith(schema.nodes.equation.create({ fieldKey: "math" + Utils.GenerateGuid() })));
- });
+ bind("Ctrl-m", (state: EditorState, dispatch: (tx: Transaction) => void) => canEdit(state) && dispatch(state.tr.replaceSelectionWith(schema.nodes.equation.create({ fieldKey: "math" + Utils.GenerateGuid() }))));
for (let i = 1; i <= 6; i++) {
- bind("Shift-Ctrl-" + i, setBlockType(schema.nodes.heading, { level: i }));
+ bind("Shift-Ctrl-" + i, (state: EditorState, dispatch: (tx: Transaction) => void) => canEdit(state) && setBlockType(schema.nodes.heading, { level: i })(state, dispatch as any));
}
//Command to create a horizontal break line
const hr = schema.nodes.horizontal_rule;
- bind("Mod-_", (state: EditorState, dispatch: (tx: Transaction) => void) => {
- dispatch(state.tr.replaceSelectionWith(hr.create()).scrollIntoView());
- return true;
- });
+ bind("Mod-_", (state: EditorState, dispatch: (tx: Transaction) => void) => canEdit(state) && dispatch(state.tr.replaceSelectionWith(hr.create()).scrollIntoView()));
//Command to unselect all
bind("Escape", (state: EditorState, dispatch: (tx: Transaction) => void) => {
@@ -173,13 +185,15 @@ export function buildKeymap>(schema: S, props: any, mapKey
};
//Command to create a text document to the right of the selected textbox
- bind("Alt-Enter", (state: EditorState, dispatch: (tx: Transaction>) => void) => addTextBox(false, true));
+ bind("Alt-Enter", () => addTextBox(false, true));
//Command to create a text document to the bottom of the selected textbox
- bind("Ctrl-Enter", (state: EditorState, dispatch: (tx: Transaction) => void) => addTextBox(true, true));
+ bind("Ctrl-Enter", () => addTextBox(true, true));
// backspace = chainCommands(deleteSelection, joinBackward, selectNodeBackward);
bind("Backspace", (state: EditorState, dispatch: (tx: Transaction>) => void) => {
+ if (!canEdit(state)) return true;
+
if (!deleteSelection(state, (tx: Transaction>) => {
dispatch(updateBullets(tx, schema));
})) {
@@ -200,6 +214,9 @@ export function buildKeymap>(schema: S, props: any, mapKey
//command to break line
bind("Enter", (state: EditorState, dispatch: (tx: Transaction>) => void) => {
if (addTextBox(true, false)) return true;
+
+ if (!canEdit(state)) return true;
+
const trange = state.selection.$from.blockRange(state.selection.$to);
const path = (state.selection.$from as any).path;
const depth = trange ? liftTarget(trange) : undefined;
@@ -238,18 +255,19 @@ export function buildKeymap>(schema: S, props: any, mapKey
//Command to create a blank space
bind("Space", (state: EditorState, dispatch: (tx: Transaction) => void) => {
+ if (!canEdit(state)) return true;
const marks = state.storedMarks || (state.selection.$to.parentOffset && state.selection.$from.marks());
dispatch(splitMetadata(marks, state.tr));
return false;
});
- bind("Alt-ArrowUp", joinUp);
- bind("Alt-ArrowDown", joinDown);
- bind("Mod-BracketLeft", lift);
+ bind("Alt-ArrowUp", (state: EditorState, dispatch: (tx: Transaction) => void) => canEdit(state) && joinUp(state, dispatch as any));
+ bind("Alt-ArrowDown", (state: EditorState, dispatch: (tx: Transaction) => void) => canEdit(state) && joinDown(state, dispatch as any));
+ bind("Mod-BracketLeft", (state: EditorState, dispatch: (tx: Transaction) => void) => canEdit(state) && lift(state, dispatch as any));
const cmd = chainCommands(exitCode, (state, dispatch) => {
if (dispatch) {
- dispatch(state.tr.replaceSelectionWith(schema.nodes.hard_break.create()).scrollIntoView());
+ canEdit(state) && dispatch(state.tr.replaceSelectionWith(schema.nodes.hard_break.create()).scrollIntoView());
return true;
}
return false;
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 0cbfaf067..85ea3cfa9 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -90,7 +90,8 @@ export const DirectLinksSym = Symbol("DirectLinks");
export const AclUnset = Symbol("AclUnset");
export const AclPrivate = Symbol("AclOwnerOnly");
export const AclReadonly = Symbol("AclReadOnly");
-export const AclAddonly = Symbol("AclAddonly");
+export const AclAugment = Symbol("AclAugment");
+export const AclSelfEdit = Symbol("AclSelfEdit");
export const AclEdit = Symbol("AclEdit");
export const AclAdmin = Symbol("AclAdmin");
export const UpdatingFromServer = Symbol("UpdatingFromServer");
@@ -102,7 +103,8 @@ const AclMap = new Map([
["None", AclUnset],
[SharingPermissions.None, AclPrivate],
[SharingPermissions.View, AclReadonly],
- [SharingPermissions.Add, AclAddonly],
+ [SharingPermissions.Augment, AclAugment],
+ [SharingPermissions.SelfEdit, AclSelfEdit],
[SharingPermissions.Edit, AclEdit],
[SharingPermissions.Admin, AclAdmin]
]);
diff --git a/src/fields/util.ts b/src/fields/util.ts
index 526e5af72..2bb6b45c2 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -1,5 +1,5 @@
import { UndoManager } from "../client/util/UndoManager";
-import { Doc, FieldResult, UpdatingFromServer, LayoutSym, AclPrivate, AclEdit, AclReadonly, AclAddonly, AclSym, DataSym, DocListCast, AclAdmin, HeightSym, WidthSym, updateCachedAcls, AclUnset, DocListCastAsync, ForceServerWrite, Initializing } from "./Doc";
+import { Doc, FieldResult, UpdatingFromServer, LayoutSym, AclPrivate, AclEdit, AclReadonly, AclAugment, AclSym, DataSym, DocListCast, AclAdmin, HeightSym, WidthSym, updateCachedAcls, AclUnset, DocListCastAsync, ForceServerWrite, Initializing, AclSelfEdit } from "./Doc";
import { SerializationHelper } from "../client/util/SerializationHelper";
import { ProxyField, PrefetchProxy } from "./Proxy";
import { RefField } from "./RefField";
@@ -14,6 +14,7 @@ import CursorField from "./CursorField";
import { List } from "./List";
import { SnappingManager } from "../client/util/SnappingManager";
import { computedFn } from "mobx-utils";
+import { RichTextField } from "./RichTextField";
function _readOnlySetter(): never {
throw new Error("Documents can't be modified in read-only mode");
@@ -77,7 +78,9 @@ const _setterImpl = action(function (target: any, prop: string | symbol | number
const fromServer = target[UpdatingFromServer];
const sameAuthor = fromServer || (receiver.author === Doc.CurrentUserEmail);
const writeToDoc = sameAuthor || effectiveAcl === AclEdit || effectiveAcl === AclAdmin || (writeMode !== DocServer.WriteMode.LiveReadonly);
- const writeToServer = (sameAuthor || effectiveAcl === AclEdit || effectiveAcl === AclAdmin || writeMode === DocServer.WriteMode.Default) && !DocServer.Control.isReadOnly();// && !playgroundMode;
+ const writeToServer =
+ (sameAuthor || effectiveAcl === AclEdit || effectiveAcl === AclAdmin || (effectiveAcl === AclSelfEdit && (value instanceof RichTextField))) &&
+ !DocServer.Control.isReadOnly();
if (writeToDoc) {
if (value === undefined) {
@@ -157,9 +160,10 @@ export function inheritParentAcls(parent: Doc, child: Doc) {
*/
export enum SharingPermissions {
Admin = "Admin",
- Edit = "Can Edit",
- Add = "Can Augment",
- View = "Can View",
+ Edit = "Edit",
+ SelfEdit = "Self Edit",
+ Augment = "Augment",
+ View = "View",
None = "Not Shared"
}
@@ -176,7 +180,7 @@ export function GetEffectiveAcl(target: any, user?: string): symbol {
function getPropAcl(target: any, prop: string | symbol | number) {
if (prop === UpdatingFromServer || prop === Initializing || target[UpdatingFromServer] || prop === AclSym) return AclAdmin; // requesting the UpdatingFromServer prop or AclSym must always go through to keep the local DB consistent
- if (prop && DocServer.PlaygroundFields?.includes(prop.toString())) return AclEdit; // playground props are always editable
+ if (prop && DocServer.IsPlaygroundField(prop.toString())) return AclEdit; // playground props are always editable
return GetEffectiveAcl(target);
}
@@ -192,7 +196,8 @@ function getEffectiveAcl(target: any, user?: string): symbol {
HierarchyMapping = HierarchyMapping || new Map([
[AclPrivate, 0],
[AclReadonly, 1],
- [AclAddonly, 2],
+ [AclAugment, 2],
+ [AclSelfEdit, 2.5],
[AclEdit, 3],
[AclAdmin, 4]
]);
@@ -235,6 +240,7 @@ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc
["Not Shared", 0],
["Can View", 1],
["Can Augment", 2],
+ ["Self Edit", 2.5],
["Can Edit", 3],
["Admin", 4]
]);
@@ -294,7 +300,7 @@ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc
export function setter(target: any, in_prop: string | symbol | number, value: any, receiver: any): boolean {
let prop = in_prop;
const effectiveAcl = getPropAcl(target, prop);
- if (effectiveAcl !== AclEdit && effectiveAcl !== AclAdmin) return true;
+ if (effectiveAcl !== AclEdit && effectiveAcl !== AclAdmin && !(effectiveAcl === AclSelfEdit && value instanceof RichTextField)) return true;
// if you're trying to change an acl but don't have Admin access / you're trying to change it to something that isn't an acceptable acl, you can't
if (typeof prop === "string" && prop.startsWith("acl") && (effectiveAcl !== AclAdmin || ![...Object.values(SharingPermissions), undefined, "None"].includes(value))) return true;
// if (typeof prop === "string" && prop.startsWith("acl") && !["Can Edit", "Can Augment", "Can View", "Not Shared", undefined].includes(value)) return true;
--
cgit v1.2.3-70-g09d2
From 8480bcbe9e5ddea4bac64273c2e6581d36bb49de Mon Sep 17 00:00:00 2001
From: bobzel
Date: Fri, 6 Aug 2021 18:25:55 -0400
Subject: switched back to Playground fields and included
width/height/natiive(w,h) to playgorund list
---
src/client/DocServer.ts | 2 +-
src/client/views/MainView.tsx | 4 +++-
2 files changed, 4 insertions(+), 2 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts
index d9ae7d64c..5712a1d64 100644
--- a/src/client/DocServer.ts
+++ b/src/client/DocServer.ts
@@ -59,7 +59,7 @@ export namespace DocServer {
export var PlaygroundFields: string[];
export function setPlaygroundFields(livePlaygroundFields: string[]) {
DocServer.PlaygroundFields = livePlaygroundFields;
- livePlaygroundFields.forEach(f => DocServer.setFieldWriteMode(f, DocServer.WriteMode.LivePlayground));
+ livePlaygroundFields.forEach(f => DocServer.setFieldWriteMode(f, DocServer.WriteMode.Playground));
}
export function IsPlaygroundField(field: string) {
return DocServer.PlaygroundFields?.includes(field.replace(/^_/, ""));
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 8f37172a0..2be3c3135 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -107,7 +107,9 @@ export class MainView extends React.Component {
new InkStrokeProperties();
this._sidebarContent.proto = undefined;
if (!MainView.Live) {
- DocServer.setPlaygroundFields(["dataTransition", "autoHeight", "showSidebar", "sidebarWidthPercent", "viewTransition", "panX", "panY", "viewScale", "scrollTop", "hidden", "curPage", "viewType", "chromeHidden", "nativeWidth"]); // can play with these fields on someone else's
+ DocServer.setPlaygroundFields(["dataTransition", "autoHeight", "showSidebar", "sidebarWidthPercent", "viewTransition",
+ "panX", "panY", "width", "height", "nativeWidth", "nativeHeight",
+ "viewScale", "scrollTop", "hidden", "curPage", "viewType", "chromeHidden", "nativeWidth"]); // can play with these fields on someone else's
}
DocServer.GetRefField("rtfProto").then(proto => (proto instanceof Doc) && reaction(() => StrCast(proto.BROADCAST_MESSAGE), msg => msg && alert(msg)));
--
cgit v1.2.3-70-g09d2
From 81ae5175aebf7e14a781a73d4a7cbaec0b8f3e4a Mon Sep 17 00:00:00 2001
From: bobzel
Date: Mon, 9 Aug 2021 14:26:14 -0400
Subject: fixed augment only text to resize correctly with autoheight. fixed
acls to cache correctly for new documents. fixed links to be shared across
users. fixed links to always default to public.
---
src/client/DocServer.ts | 2 +-
src/client/documents/Documents.ts | 8 ++-
src/client/util/CurrentUserUtils.ts | 16 +++---
src/client/util/LinkManager.ts | 67 ++++++++++++++--------
src/client/util/SettingsManager.tsx | 3 +-
src/client/util/SharingManager.tsx | 4 +-
src/client/views/MainView.tsx | 2 +-
.../views/nodes/formattedText/FormattedTextBox.tsx | 20 ++++---
src/fields/util.ts | 4 +-
9 files changed, 79 insertions(+), 47 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts
index 5712a1d64..f4e3a22cf 100644
--- a/src/client/DocServer.ts
+++ b/src/client/DocServer.ts
@@ -1,6 +1,6 @@
import * as io from 'socket.io-client';
import { MessageStore, YoutubeQueryTypes, GestureContent, MobileInkOverlayContent, UpdateMobileInkOverlayPositionContent, MobileDocumentUploadContent } from "./../server/Message";
-import { Opt, Doc, UpdatingFromServer } from '../fields/Doc';
+import { Opt, Doc, UpdatingFromServer, updateCachedAcls } from '../fields/Doc';
import { Utils, emptyFunction } from '../Utils';
import { SerializationHelper } from './util/SerializationHelper';
import { RefField } from '../fields/RefField';
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 93f0880a4..48886aa3b 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1,7 +1,7 @@
import { action, runInAction } from "mobx";
import { basename, extname } from "path";
import { DateField } from "../../fields/DateField";
-import { Doc, DocListCast, DocListCastAsync, Field, HeightSym, Opt, WidthSym, Initializing } from "../../fields/Doc";
+import { Doc, DocListCast, DocListCastAsync, Field, HeightSym, Opt, WidthSym, Initializing, updateCachedAcls } from "../../fields/Doc";
import { Id } from "../../fields/FieldSymbols";
import { HtmlField } from "../../fields/HtmlField";
import { InkField } from "../../fields/InkField";
@@ -577,7 +577,7 @@ export namespace Docs {
dataProps.creationDate = new DateField;
dataProps[`${fieldKey}-lastModified`] = new DateField;
dataProps["acl-Override"] = "None";
- dataProps["acl-Public"] = Doc.UserDoc()?.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment;
+ dataProps["acl-Public"] = options["acl-Public"] ? options["acl-Public"] : Doc.UserDoc()?.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment;
dataProps[fieldKey] = data;
@@ -588,13 +588,15 @@ export namespace Docs {
viewProps.author = Doc.CurrentUserEmail;
viewProps["acl-Override"] = "None";
- viewProps["acl-Public"] = Doc.UserDoc()?.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment;
+ viewProps["acl-Public"] = options["_acl-Public"] ? options["_acl-Public"] : Doc.UserDoc()?.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment;
const viewDoc = Doc.assign(Doc.MakeDelegate(dataDoc, delegId), viewProps, true, true);
![DocumentType.LINK, DocumentType.MARKER, DocumentType.LABEL].includes(viewDoc.type as any) && DocUtils.MakeLinkToActiveAudio(() => viewDoc);
!Doc.IsSystem(dataDoc) && ![DocumentType.MARKER, DocumentType.KVP, DocumentType.LINK, DocumentType.LINKANCHOR].includes(proto.type as any) &&
!dataDoc.isFolder && !dataProps.annotationOn && Doc.AddDocToList(Cast(Doc.UserDoc().myFileOrphans, Doc, null), "data", dataDoc);
+ updateCachedAcls(dataDoc);
+ updateCachedAcls(viewDoc);
return viewDoc;
}
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 14c43fb1c..34990e121 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -2,13 +2,14 @@ import { computed, observable, reaction } from "mobx";
import * as rp from 'request-promise';
import { DataSym, Doc, DocListCast, DocListCastAsync } from "../../fields/Doc";
import { Id } from "../../fields/FieldSymbols";
+import { InkTool } from "../../fields/InkField";
import { List } from "../../fields/List";
import { PrefetchProxy } from "../../fields/Proxy";
import { RichTextField } from "../../fields/RichTextField";
import { listSpec } from "../../fields/Schema";
import { SchemaHeaderField } from "../../fields/SchemaHeaderField";
import { ComputedField, ScriptField } from "../../fields/ScriptField";
-import { BoolCast, Cast, NumCast, PromiseValue, StrCast, DateCast } from "../../fields/Types";
+import { BoolCast, Cast, DateCast, NumCast, PromiseValue, StrCast } from "../../fields/Types";
import { nullAudio } from "../../fields/URLField";
import { SharingPermissions } from "../../fields/util";
import { Utils } from "../../Utils";
@@ -19,6 +20,7 @@ import { Networking } from "../Network";
import { CollectionDockingView } from "../views/collections/CollectionDockingView";
import { DimUnit } from "../views/collections/collectionMulticolumn/CollectionMulticolumnView";
import { CollectionView, CollectionViewType } from "../views/collections/CollectionView";
+import { Colors } from "../views/global/globalEnums";
import { MainView } from "../views/MainView";
import { FormattedTextBox } from "../views/nodes/formattedText/FormattedTextBox";
import { LabelBox } from "../views/nodes/LabelBox";
@@ -31,13 +33,10 @@ import { LinkManager } from "./LinkManager";
import { Scripting } from "./Scripting";
import { SearchUtil } from "./SearchUtil";
import { SelectionManager } from "./SelectionManager";
-import { UndoManager } from "./UndoManager";
-import { SnappingManager } from "./SnappingManager";
-import { InkTool } from "../../fields/InkField";
-import { SharingManager } from "./SharingManager";
-import { computedFn } from "mobx-utils";
import { ColorScheme } from "./SettingsManager";
-import { Colors } from "../views/global/globalEnums";
+import { SharingManager } from "./SharingManager";
+import { SnappingManager } from "./SnappingManager";
+import { UndoManager } from "./UndoManager";
export let resolvedPorts: { server: number, socket: number };
@@ -915,6 +914,7 @@ export class CurrentUserUtils {
let linkDocs = Docs.newAccount ? undefined : await DocServer.GetRefField(linkDatabaseId);
if (!linkDocs) {
linkDocs = new Doc(linkDatabaseId, true);
+ (linkDocs as Doc).title = "LINK DATABASE: " + Doc.CurrentUserEmail;
(linkDocs as Doc).author = Doc.CurrentUserEmail;
(linkDocs as Doc).data = new List([]);
(linkDocs as Doc)["acl-Public"] = SharingPermissions.Augment;
@@ -1029,7 +1029,7 @@ export class CurrentUserUtils {
doc.fontFamily = StrCast(doc.fontFamily, "Arial");
doc.fontColor = StrCast(doc.fontColor, "black");
doc.fontHighlight = StrCast(doc.fontHighlight, "");
- doc.defaultAclPrivate = BoolCast(doc.defaultAclPrivate, true);
+ doc.defaultAclPrivate = BoolCast(doc.defaultAclPrivate, false);
doc.activeCollectionBackground = StrCast(doc.activeCollectionBackground, "white");
doc.activeCollectionNestedBackground = Cast(doc.activeCollectionNestedBackground, "string", null);
doc.noviceMode = BoolCast(doc.noviceMode, true);
diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
index 8abfd740c..933b98a8c 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -1,4 +1,4 @@
-import { observable, observe, action } from "mobx";
+import { observable, observe, action, reaction, computed } from "mobx";
import { computedFn } from "mobx-utils";
import { DirectLinksSym, Doc, DocListCast, Field, Opt } from "../../fields/Doc";
import { List } from "../../fields/List";
@@ -26,36 +26,41 @@ type CreateViewFunc = (doc: Doc, followLinkLocation: string, finished?: () => vo
export class LinkManager {
@observable static _instance: LinkManager;
- @observable static userDocs: Doc[] = [];
+ @observable static userLinkDBs: Doc[] = [];
public static currentLink: Opt;
public static get Instance() { return LinkManager._instance; }
+ public static addLinkDB = (linkDb: any) => LinkManager.userLinkDBs.push(linkDb);
+ static links: Doc[] = [];
constructor() {
LinkManager._instance = this;
setTimeout(() => {
- LinkManager.userDocs = [Doc.LinkDBDoc().data as Doc, ...SharingManager.Instance.users.map(user => user.linkDatabase)];
- const addLinkToDoc = action((link: Doc): any => {
+ LinkManager.userLinkDBs = [];
+ const addLinkToDoc = (link: Doc) => {
const a1 = link?.anchor1;
const a2 = link?.anchor2;
- if (a1 instanceof Promise || a2 instanceof Promise) return PromiseValue(a1).then(a1 => PromiseValue(a2).then(a2 => addLinkToDoc(link)));
- if (a1 instanceof Doc && a2 instanceof Doc && ((a1.author !== undefined && a2.author !== undefined) || link.author === Doc.CurrentUserEmail)) {
- Doc.GetProto(a1)[DirectLinksSym].add(link);
- Doc.GetProto(a2)[DirectLinksSym].add(link);
- Doc.GetProto(link)[DirectLinksSym].add(link);
- }
- });
- const remLinkFromDoc = action((link: Doc): any => {
+ Promise.all([a1, a2]).then(action(() => {
+ if (a1 instanceof Doc && a2 instanceof Doc && ((a1.author !== undefined && a2.author !== undefined) || link.author === Doc.CurrentUserEmail)) {
+ Doc.GetProto(a1)[DirectLinksSym].add(link);
+ Doc.GetProto(a2)[DirectLinksSym].add(link);
+ Doc.GetProto(link)[DirectLinksSym].add(link);
+ }
+ }));
+ }
+ const remLinkFromDoc = (link: Doc) => {
const a1 = link?.anchor1;
const a2 = link?.anchor2;
- if (a1 instanceof Promise || a2 instanceof Promise) return PromiseValue(a1).then(a1 => PromiseValue(a2).then(a2 => remLinkFromDoc(link)));
- if (a1 instanceof Doc && a2 instanceof Doc && ((a1.author !== undefined && a2.author !== undefined) || link.author === Doc.CurrentUserEmail)) {
- Doc.GetProto(a1)[DirectLinksSym].delete(link);
- Doc.GetProto(a2)[DirectLinksSym].delete(link);
- Doc.GetProto(link)[DirectLinksSym].delete(link);
- }
- });
- const watchUserLinks = (userLinks: List) => {
+ Promise.all([a1, a2]).then(action(() => {
+ if (a1 instanceof Doc && a2 instanceof Doc && ((a1.author !== undefined && a2.author !== undefined) || link.author === Doc.CurrentUserEmail)) {
+ Doc.GetProto(a1)[DirectLinksSym].delete(link);
+ Doc.GetProto(a2)[DirectLinksSym].delete(link);
+ Doc.GetProto(link)[DirectLinksSym].delete(link);
+ }
+ }));
+ }
+ const watchUserLinkDB = (userLinkDBDoc: Doc) => {
+ LinkManager.links.push(...DocListCast(userLinkDBDoc.data));
const toRealField = (field: Field) => field instanceof ProxyField ? field.value() : field; // see List.ts. data structure is not a simple list of Docs, but a list of ProxyField/Fields
- observe(userLinks, change => {
+ observe(userLinkDBDoc.data as Doc, change => { // observe pushes/splices on a user link DB 'data' field (should only happen for local changes)
switch (change.type as any) {
case "splice":
(change as any).added.forEach((link: any) => addLinkToDoc(toRealField(link)));
@@ -64,13 +69,29 @@ export class LinkManager {
case "update": //let oldValue = change.oldValue;
}
}, true);
+ observe(userLinkDBDoc, "data", // obsever when a new array of links is assigned as the link DB 'data' field (should happen whenever a remote user adds/removes a link)
+ change => {
+ switch (change.type as any) {
+ case "update":
+ Promise.all([...(change.oldValue as any as Doc[] || []), ...(change.newValue as any as Doc[] || [])]).then(doclist => {
+ const oldDocs = doclist.slice(0, (change.oldValue as any as Doc[] || []).length);
+ const newDocs = doclist.slice((change.oldValue as any as Doc[] || []).length, doclist.length);
+
+ const added = newDocs?.filter(link => !(oldDocs || []).includes(link));
+ const removed = oldDocs?.filter(link => !(newDocs || []).includes(link));
+ added?.forEach((link: any) => addLinkToDoc(toRealField(link)));
+ removed?.forEach((link: any) => remLinkFromDoc(toRealField(link)));
+ });
+ }
+ }, true);
};
- observe(LinkManager.userDocs, change => {
+ observe(LinkManager.userLinkDBs, change => {
switch (change.type as any) {
- case "splice": (change as any).added.forEach(watchUserLinks); break;
+ case "splice": (change as any).added.forEach(watchUserLinkDB); break;
case "update": //let oldValue = change.oldValue;
}
}, true);
+ LinkManager.addLinkDB(Doc.LinkDBDoc());
});
}
diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx
index 3987497b8..bd91db779 100644
--- a/src/client/util/SettingsManager.tsx
+++ b/src/client/util/SettingsManager.tsx
@@ -268,7 +268,8 @@ export class SettingsManager extends React.Component<{}> {
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index a8972b988..6c4556250 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -23,6 +23,7 @@ import { GroupManager, UserOptions } from "./GroupManager";
import { GroupMemberView } from "./GroupMemberView";
import { SelectionManager } from "./SelectionManager";
import "./SharingManager.scss";
+import { LinkManager } from "./LinkManager";
export interface User {
email: string;
@@ -154,10 +155,11 @@ export class SharingManager extends React.Component<{}> {
}
});
return Promise.all(evaluating).then(() => {
- runInAction(() => {
+ runInAction(async () => {
for (const sharer of sharingDocs) {
if (!this.users.find(user => user.user.email === sharer.user.email)) {
this.users.push(sharer);
+ LinkManager.addLinkDB(sharer.linkDatabase);
}
}
});
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 2be3c3135..3d7446cbe 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -108,7 +108,7 @@ export class MainView extends React.Component {
this._sidebarContent.proto = undefined;
if (!MainView.Live) {
DocServer.setPlaygroundFields(["dataTransition", "autoHeight", "showSidebar", "sidebarWidthPercent", "viewTransition",
- "panX", "panY", "width", "height", "nativeWidth", "nativeHeight",
+ "panX", "panY", "width", "height", "nativeWidth", "nativeHeight", "text-scrollHeight", "text-height",
"viewScale", "scrollTop", "hidden", "curPage", "viewType", "chromeHidden", "nativeWidth"]); // can play with these fields on someone else's
}
DocServer.GetRefField("rtfProto").then(proto => (proto instanceof Doc) && reaction(() => StrCast(proto.BROADCAST_MESSAGE), msg => msg && alert(msg)));
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index f7bed2fa1..9bba15b28 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -431,6 +431,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
this.ProseRef = ele;
this._dropDisposer?.();
ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.layoutDoc));
+ // if (this.autoHeight) this.tryUpdateScrollHeight();
}
@undoBatch
@@ -1438,16 +1439,19 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
}
}
- tryUpdateScrollHeight() {
+ tryUpdateScrollHeight = () => {
if (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this.props.docViewPath())) {
const margins = 2 * NumCast(this.layoutDoc._yMargin, this.props.yPadding || 0);
- const proseHeight = !this.ProseRef ? 0 : Array.from(this.ProseRef.children[0].children).reduce((p, child) => p + Number(getComputedStyle(child).height.replace("px", "")), margins);
- const scrollHeight = this.ProseRef && Math.min(NumCast(this.layoutDoc.docMaxAutoHeight, proseHeight), proseHeight);
- if (scrollHeight && this.props.renderDepth && !this.props.dontRegisterView) { // if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation
- const setScrollHeight = () => this.rootDoc[this.fieldKey + "-scrollHeight"] = scrollHeight;
- if (this.rootDoc === this.layoutDoc.doc || this.layoutDoc.resolvedDataDoc) {
- setScrollHeight();
- } else setTimeout(setScrollHeight, 10); // if we have a template that hasn't been resolved yet, we can't set the height or we'd be setting it on the unresolved template. So set a timeout and hope its arrived...
+ const children = this.ProseRef?.children.length ? Array.from(this.ProseRef.children[0].children) : undefined;
+ if (children) {
+ const proseHeight = !this.ProseRef ? 0 : children.reduce((p, child) => p + Number(getComputedStyle(child).height.replace("px", "")), margins);
+ const scrollHeight = this.ProseRef && Math.min(NumCast(this.layoutDoc.docMaxAutoHeight, proseHeight), proseHeight);
+ if (scrollHeight && this.props.renderDepth && !this.props.dontRegisterView) { // if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation
+ const setScrollHeight = () => this.rootDoc[this.fieldKey + "-scrollHeight"] = scrollHeight;
+ if (this.rootDoc === this.layoutDoc.doc || this.layoutDoc.resolvedDataDoc) {
+ setScrollHeight();
+ } else setTimeout(setScrollHeight, 10); // if we have a template that hasn't been resolved yet, we can't set the height or we'd be setting it on the unresolved template. So set a timeout and hope its arrived...
+ }
}
}
}
diff --git a/src/fields/util.ts b/src/fields/util.ts
index 2bb6b45c2..439c4d333 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -141,7 +141,9 @@ export function denormalizeEmail(email: string) {
export function inheritParentAcls(parent: Doc, child: Doc) {
const dataDoc = parent[DataSym];
for (const key of Object.keys(dataDoc)) {
- key.startsWith("acl") && distributeAcls(key, dataDoc[key], child);
+ // if the default acl mode is private, then don't inherit the acl-Public permission, but set it to private.
+ const permission = (key === "acl-Public" && Doc.UserDoc().defaultAclPrivate) ? AclPrivate : dataDoc[key];
+ key.startsWith("acl") && distributeAcls(key, permission, child);
}
}
--
cgit v1.2.3-70-g09d2
From dbdcff75d76fb54a0e085cc0958a07ded32d0b45 Mon Sep 17 00:00:00 2001
From: bobzel
Date: Mon, 9 Aug 2021 18:14:00 -0400
Subject: fixed bug where shared list field items weren't being received as
Documents so they didn't update -- eg add a private item to a list, then try
to make it public
---
src/client/DocServer.ts | 2 +-
src/client/views/collections/CollectionSubView.tsx | 4 ++--
src/fields/List.ts | 19 +++++++------------
3 files changed, 10 insertions(+), 15 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts
index f4e3a22cf..e498a7cca 100644
--- a/src/client/DocServer.ts
+++ b/src/client/DocServer.ts
@@ -398,7 +398,7 @@ export namespace DocServer {
(_cache[field.id] as any).then((f: any) => fieldMap[field.id] = f);
} else if (field) {
proms.push(_cache[field.id] as any);
- fieldMap[field.id] = field;
+ fieldMap[field.id] = DocServer.GetCachedRefField(field.id) || field;
}
}
});
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 227635c9b..2f07c0241 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -80,8 +80,8 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?:
get childLayoutPairs(): { layout: Doc; data: Doc; }[] {
const { Document, DataDoc } = this.props;
const validPairs = this.childDocs.map(doc => Doc.GetLayoutDataDocPair(Document, !this.props.isAnnotationOverlay ? DataDoc : undefined, doc)).
- filter(pair => { // filter out any documents that have a proto that we don't have permissions to (which we determine by not having any keys
- return pair.layout && /*!pair.layout.hidden &&*/ (!pair.layout.proto || (pair.layout.proto instanceof Doc && GetEffectiveAcl(pair.layout.proto) !== AclPrivate));// Object.keys(pair.layout.proto).length));
+ filter(pair => { // filter out any documents that have a proto that we don't have permissions to
+ return pair.layout && (!pair.layout.proto || (pair.layout.proto instanceof Doc && GetEffectiveAcl(pair.layout.proto) !== AclPrivate));
});
return validPairs.map(({ data, layout }) => ({ data: data as Doc, layout: layout! })); // this mapping is a bit of a hack to coerce types
}
diff --git a/src/fields/List.ts b/src/fields/List.ts
index 215dff34b..93a8d1d60 100644
--- a/src/fields/List.ts
+++ b/src/fields/List.ts
@@ -1,4 +1,4 @@
-import { action, observable, runInAction } from "mobx";
+import { action, observable } from "mobx";
import { alias, list, serializable } from "serializr";
import { DocServer } from "../client/DocServer";
import { Scripting } from "../client/util/Scripting";
@@ -264,24 +264,19 @@ class ListImpl extends ObjectField {
// this requests all ProxyFields at the same time to avoid the overhead
// of separate network requests and separate updates to the React dom.
private __realFields() {
- const waiting = this.__fields.filter(f => f instanceof ProxyField && f.promisedValue());
- const promised = waiting.map(f => f instanceof ProxyField ? f.promisedValue() : "");
+ const promised = this.__fields.filter(f => f instanceof ProxyField && f.promisedValue()).map(f => ({ field: f as any, promisedFieldId: (f instanceof ProxyField) ? f.promisedValue() : "" }));
// if we find any ProxyFields that don't have a current value, then
// start the server request for all of them
if (promised.length) {
- const promise = DocServer.GetRefFields(promised);
+ const batchPromise = DocServer.GetRefFields(promised.map(p => p.promisedFieldId));
// as soon as we get the fields from the server, set all the list values in one
// action to generate one React dom update.
- promise.then(fields => runInAction(() => {
- waiting.map((w, i) => w instanceof ProxyField && w.setValue(fields[promised[i]]));
- }));
+ batchPromise.then(pfields => promised.forEach(p => p.field.setValue(pfields[p.promisedFieldId])));
// we also have to mark all lists items with this promise so that any calls to them
- // will await the batch request.
- // This counts on the handler for 'promise' in the call above being invoked before the
+ // will await the batch request and return the requested field value.
+ // This assumes the handler for 'promise' in the call above being invoked before the
// handler for 'promise' in the lines below.
- waiting.map((w, i) => {
- w instanceof ProxyField && w.setPromise(promise.then(fields => fields[promised[i]]));
- });
+ promised.forEach(p => p.field.setPromise(batchPromise.then(pfields => pfields[p.promisedFieldId])));
}
return this.__fields.map(toRealField);
}
--
cgit v1.2.3-70-g09d2
From 31aca178137cf100eeffa9f281dc07d28b44f046 Mon Sep 17 00:00:00 2001
From: bobzel
Date: Tue, 10 Aug 2021 10:40:10 -0400
Subject: fixed clicking on +new dashboard when window is narrow.
---
src/client/views/topbar/TopBar.scss | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'src/client/views')
diff --git a/src/client/views/topbar/TopBar.scss b/src/client/views/topbar/TopBar.scss
index 164cc29cd..2ecbb536b 100644
--- a/src/client/views/topbar/TopBar.scss
+++ b/src/client/views/topbar/TopBar.scss
@@ -91,7 +91,7 @@
font-family: 'Roboto';
position: relative;
display: flex;
- width: 450;
+ width: fit-content;
gap: 5px;
.topBar-icon:hover {
--
cgit v1.2.3-70-g09d2
From ed39e4080b79ceba5c358e1359c1a1a44490f0dc Mon Sep 17 00:00:00 2001
From: bobzel
Date: Tue, 10 Aug 2021 10:59:59 -0400
Subject: hideMInimap is playground field. added Open Alias to dashboard tab
menu. Allow duplicates in List fields (not sure if this is problematic but
caused problems with URL history)
---
src/client/views/MainView.tsx | 2 +-
src/client/views/collections/TreeView.tsx | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 3d7446cbe..b0b8d7f41 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -108,7 +108,7 @@ export class MainView extends React.Component {
this._sidebarContent.proto = undefined;
if (!MainView.Live) {
DocServer.setPlaygroundFields(["dataTransition", "autoHeight", "showSidebar", "sidebarWidthPercent", "viewTransition",
- "panX", "panY", "width", "height", "nativeWidth", "nativeHeight", "text-scrollHeight", "text-height",
+ "panX", "panY", "width", "height", "nativeWidth", "nativeHeight", "text-scrollHeight", "text-height", "hideMinimap",
"viewScale", "scrollTop", "hidden", "curPage", "viewType", "chromeHidden", "nativeWidth"]); // can play with these fields on someone else's
}
DocServer.GetRefField("rtfProto").then(proto => (proto instanceof Doc) && reaction(() => StrCast(proto.BROADCAST_MESSAGE), msg => msg && alert(msg)));
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index e33c39d20..206e48aac 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -511,7 +511,7 @@ export class TreeView extends React.Component {
Doc.IsSystem(this.doc) ? [] :
this.props.treeView.fileSysMode && this.doc === Doc.GetProto(this.doc) ?
[{ script: ScriptField.MakeFunction(`openOnRight(getAlias(self))`)!, label: "Open Alias" }, makeFolder] :
- [{ script: ScriptField.MakeFunction(`DocFocusOrOpen(self)`)!, label: "Focus or Open" }];
+ [{ script: ScriptField.MakeFunction(`openOnRight(getAlias(self))`)!, label: "Open Alias" }, { script: ScriptField.MakeFunction(`DocFocusOrOpen(self)`)!, label: "Focus or Open" }];
}
onChildClick = () => this.props.onChildClick?.() ?? (this._editTitleScript?.() || ScriptCast(this.doc.treeChildClick));
--
cgit v1.2.3-70-g09d2
From fe78892ad8dd477779e0746918be373b9b5c15c0 Mon Sep 17 00:00:00 2001
From: bobzel
Date: Tue, 10 Aug 2021 13:42:47 -0400
Subject: fixes for git-like to work with sidebar. added 'lastModified' field
for changes to x/y/width/height
---
src/client/documents/Gitlike.ts | 36 ++++++++++++++++------
src/client/views/DocumentDecorations.tsx | 2 ++
.../collectionFreeForm/CollectionFreeFormView.tsx | 2 ++
src/fields/Doc.ts | 12 +++++---
4 files changed, 38 insertions(+), 14 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/documents/Gitlike.ts b/src/client/documents/Gitlike.ts
index fddf317bc..575c984f5 100644
--- a/src/client/documents/Gitlike.ts
+++ b/src/client/documents/Gitlike.ts
@@ -1,7 +1,8 @@
-import { Doc, DocListCast, DocListCastAsync } from "../../fields/Doc";
+import { Doc, DocListCast, DocListCastAsync, Field } from "../../fields/Doc";
import { List } from "../../fields/List";
-import { ObjectField } from "../../fields/ObjectField";
import { Cast, DateCast } from "../../fields/Types";
+import { DateField } from "../../fields/DateField";
+import { Id } from "../../fields/FieldSymbols";
// synchs matching documents on the two branches that are being merged/pulled
// currently this just synchs the main 'fieldKey' component of the data since
@@ -10,11 +11,22 @@ function GitlikeSynchDocs(bd: Doc, md: Doc) {
const fieldKey = Doc.LayoutFieldKey(md);
const bdate = DateCast(bd[`${fieldKey}-lastModified`])?.date;
const mdate = DateCast(md[`${fieldKey}-lastModified`])?.date;
- if (bdate === mdate || bdate > mdate) return;
const bdproto = bd && Doc.GetProto(bd);
+ if (bdate !== mdate && bdate <= mdate) {
+ if (bdproto && md) {
+ bdproto[fieldKey] = Field.Copy(md[fieldKey]);
+ bdproto[`${fieldKey}-lastModified`] = new DateField();
+ }
+ }
+ const bldate = DateCast(bd._lastModified)?.date;
+ const mldate = DateCast(md._lastModified)?.date;
+ if (bldate === mldate || bldate > mldate) return;
if (bdproto && md) {
- bdproto[fieldKey] = ObjectField.MakeCopy(md[fieldKey] as ObjectField);
- bdproto[`${fieldKey}-lastModified`] = ObjectField.MakeCopy(md[`${fieldKey}-lastModified`] as ObjectField);
+ bd.x = Field.Copy(md.x);
+ bd.y = Field.Copy(md.y);
+ bd.width = Field.Copy(md.width);
+ bd.height = Field.Copy(md.height);
+ bdproto._lastModified = new DateField();
}
}
@@ -36,8 +48,9 @@ async function GitlikePullFromMaster(branch: Doc, suffix = "") {
const bd = branchMainDocs?.find(bd => (Cast(bd.branchOf, Doc, null) || bd) === md);
bd && GitlikeSynchDocs(bd, md);
});
+ const cloneMap = new Map(); cloneMap.set(masterMain[Id], branch);
// make branch clones of them, then add them to the branch
- const newlyBranchedDocs = await Promise.all(newDocsFromMaster?.map(async md => (await Doc.MakeClone(md, false, true)).clone) || []);
+ const newlyBranchedDocs = await Promise.all(newDocsFromMaster?.map(async md => (await Doc.MakeClone(md, false, true, cloneMap)).clone) || []);
newlyBranchedDocs.forEach(nd => {
Doc.AddDocToList(branch, Doc.LayoutFieldKey(branch) + suffix, nd);
nd.context = branch;
@@ -56,22 +69,26 @@ async function GitlikeMergeWithMaster(master: Doc, suffix = "") {
branches?.map(async branch => {
const branchChildren = await DocListCastAsync(branch[Doc.LayoutFieldKey(branch) + suffix]);
branchChildren && await Promise.all(branchChildren.map(async bd => {
+ const cloneMap = new Map(); cloneMap.set(master[Id], branch);
// see if the branch's child exists on master.
- const masterChild = Cast(bd.branchOf, Doc, null) || (await Doc.MakeClone(bd, false, true)).clone;
+ const masterChild = Cast(bd.branchOf, Doc, null) || (await Doc.MakeClone(bd, false, true, cloneMap)).clone;
// if the branch's child didn't exist on master, we make a branch clone of the child to add to master.
// however, since master is supposed to have the "main" clone, and branches, the "branch" clones, we have to reverse the fields
// on the branch child and master clone.
if (masterChild.branchOf) {
const branchDocProto = Doc.GetProto(bd);
const masterChildProto = Doc.GetProto(masterChild);
- masterChildProto.branchOf = undefined; // the master child should not be a branch of the branch child, so unset 'branchOf'
+ const branchTitle = bd.title;
+ branchDocProto.title = masterChildProto.title;
+ masterChildProto.title = branchTitle;
+ masterChildProto.branchOf = masterChild.branchOf = undefined; // the master child should not be a branch of the branch child, so unset 'branchOf'
masterChildProto.branches = new List([bd]); // the master child's branches needs to include the branch child
Doc.RemoveDocFromList(branchDocProto, "branches", masterChildProto); // the branch child should not have the master child in its branch list.
branchDocProto.branchOf = masterChild; // the branch child is now a branch of the master child
}
Doc.AddDocToList(master, Doc.LayoutFieldKey(master) + suffix, masterChild); // add the masterChild to master (if it's already there, this is a no-op)
masterChild.context = master;
- GitlikeSynchDocs(Doc.GetProto(masterChild), bd);
+ GitlikeSynchDocs(masterChild, bd);//Doc.GetProto(masterChild), bd);
}));
const masterChildren = await DocListCastAsync(master[Doc.LayoutFieldKey(master) + suffix]);
masterChildren?.forEach(mc => { // see if any master children
@@ -93,6 +110,7 @@ export async function BranchTask(target: Doc, action: "pull" | "merge") {
const func = action === "pull" ? GitlikePullFromMaster : GitlikeMergeWithMaster;
await func(target, "");
await DocListCast(target[Doc.LayoutFieldKey(target)]).forEach(async targetChild => func(targetChild, "-annotations"));
+ await DocListCast(target[Doc.LayoutFieldKey(target)]).forEach(async targetChild => func(targetChild, "-sidebar"));
}
export async function BranchCreate(target: Doc) {
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index d24ab974c..118d2e7c7 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -27,6 +27,7 @@ import { LightboxView } from './LightboxView';
import { DocumentView } from "./nodes/DocumentView";
import React = require("react");
import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
+import { DateField } from '../../fields/DateField';
@observer
export class DocumentDecorations extends React.Component<{ boundsLeft: number, boundsTop: number }, { value: string }> {
@@ -367,6 +368,7 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
dW && (doc._width = actualdW);
dH && (doc._autoHeight = false);
}
+ doc._lastModified = new DateField();
}
const val = this._dragHeights.get(docView.layoutDoc);
if (val) this._dragHeights.set(docView.layoutDoc, { start: val.start, lowest: Math.min(val.lowest, NumCast(docView.layoutDoc._height)) });
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index ba6222605..fa7e75202 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -49,6 +49,7 @@ import "./CollectionFreeFormView.scss";
import { MarqueeView } from "./MarqueeView";
import React = require("react");
import { DocumentType } from "../../../documents/DocumentTypes";
+import { DateField } from "../../../../fields/DateField";
export const panZoomSchema = createSchema({
_panX: "number",
@@ -257,6 +258,7 @@ export class CollectionFreeFormView extends CollectionSubView = T | undefined;
@@ -537,7 +540,7 @@ export namespace Doc {
const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key]));
const field = ProxyField.WithoutProxy(() => doc[key]);
const copyObjectField = async (field: ObjectField) => {
- const list = Cast(doc[key], listSpec(Doc));
+ const list = await Cast(doc[key], listSpec(Doc));
const docs = list && (await DocListCastAsync(list))?.filter(d => d instanceof Doc);
if (docs !== undefined && docs.length) {
const clones = await Promise.all(docs.map(async d => Doc.makeClone(d, cloneMap, linkMap, rtfs, exclusions, dontCreate, asBranch)));
@@ -589,11 +592,10 @@ export namespace Doc {
}
return copy;
}
- export async function MakeClone(doc: Doc, dontCreate: boolean = false, asBranch = false) {
- const cloneMap = new Map();
+ export async function MakeClone(doc: Doc, dontCreate: boolean = false, asBranch = false, cloneMap: Map = new Map()) {
const linkMap = new Map();
const rtfMap: { copy: Doc, key: string, field: RichTextField }[] = [];
- const copy = await Doc.makeClone(doc, cloneMap, linkMap, rtfMap, ["context", "annotationOn", "cloneOf", "branches", "branchOf"], dontCreate, asBranch);
+ const copy = await Doc.makeClone(doc, cloneMap, linkMap, rtfMap, ["cloneOf", "branches", "branchOf"], dontCreate, asBranch);
Array.from(linkMap.entries()).map((links: Doc[]) => LinkManager.Instance.addLink(links[1], true));
rtfMap.map(({ copy, key, field }) => {
const replacer = (match: any, attr: string, id: string, offset: any, string: any) => {
@@ -1385,7 +1387,7 @@ Scripting.addGlobal(function getAlias(doc: any) { return Doc.MakeAlias(doc); });
Scripting.addGlobal(function getCopy(doc: any, copyProto: any) { return doc.isTemplateDoc ? Doc.ApplyTemplate(doc) : Doc.MakeCopy(doc, copyProto); });
Scripting.addGlobal(function copyDragFactory(dragFactory: Doc) { return Doc.copyDragFactory(dragFactory); });
Scripting.addGlobal(function delegateDragFactory(dragFactory: Doc) { return Doc.delegateDragFactory(dragFactory); });
-Scripting.addGlobal(function copyField(field: any) { return field instanceof ObjectField ? ObjectField.MakeCopy(field) : field; });
+Scripting.addGlobal(function copyField(field: any) { return Field.Copy(field); });
Scripting.addGlobal(function docList(field: any) { return DocListCast(field); });
Scripting.addGlobal(function setInPlace(doc: any, field: any, value: any) { return Doc.SetInPlace(doc, field, value, false); });
Scripting.addGlobal(function sameDocs(doc1: any, doc2: any) { return Doc.AreProtosEqual(doc1, doc2); });
--
cgit v1.2.3-70-g09d2
From 88074b6b085b0b5542759cb41519de719ee61cee Mon Sep 17 00:00:00 2001
From: bobzel
Date: Tue, 10 Aug 2021 21:34:59 -0400
Subject: fixed error when adding to a collection that does not have a list as
its data
---
src/client/views/DocComponent.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'src/client/views')
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 99c695a4a..14d32ef12 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -219,7 +219,7 @@ export function ViewBoxAnnotatableComponent;
- if (annoDocs) annoDocs.push(...added);
+ if (annoDocs instanceof List) annoDocs.push(...added);
else targetDataDoc[annotationKey ?? this.annotationKey] = new List(added);
targetDataDoc[(annotationKey ?? this.annotationKey) + "-lastModified"] = new DateField(new Date(Date.now()));
}
--
cgit v1.2.3-70-g09d2
From 5d3c00c2b02758a644df687656097dad055d0fe1 Mon Sep 17 00:00:00 2001
From: bobzel
Date: Wed, 11 Aug 2021 16:04:00 -0400
Subject: fixed issues with screenshotbox flickering when brought up from top
menu, and generating errors when recording.
---
src/client/views/nodes/ScreenshotBox.tsx | 23 ++++++++++++++---------
1 file changed, 14 insertions(+), 9 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index 0e235a62d..68ab3193b 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -1,11 +1,11 @@
import React = require("react");
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
// import { Canvas } from '@react-three/fiber';
-import { action, computed, observable, reaction } from "mobx";
+import { action, computed, observable, reaction, trace, runInAction } from "mobx";
import { observer } from "mobx-react";
// import { BufferAttribute, Camera, Vector2, Vector3 } from 'three';
import { DateField } from "../../../fields/DateField";
-import { Doc, WidthSym } from "../../../fields/Doc";
+import { Doc, WidthSym, HeightSym } from "../../../fields/Doc";
import { documentSchema } from "../../../fields/documentSchemas";
import { Id } from "../../../fields/FieldSymbols";
import { InkTool } from "../../../fields/InkField";
@@ -218,9 +218,8 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent {
- this._screenCapture = !this._screenCapture;
- if (this._screenCapture) {
+ toggleRecording = async () => {
+ if (!this._screenCapture) {
this._audioRec = new MediaRecorder(await navigator.mediaDevices.getUserMedia({ audio: true }));
const aud_chunks: any = [];
this._audioRec.ondataavailable = (e: any) => aud_chunks.push(e.data);
@@ -249,18 +248,24 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent {
+ this._screenCapture = true;
+ this.dataDoc.mediaState = "recording";
+ });
DocUtils.ActiveRecordings.push(this);
} else {
this._audioRec?.stop();
this._videoRec?.stop();
- this.dataDoc.mediaState = "paused";
+ runInAction(() => {
+ this._screenCapture = false;
+ this.dataDoc.mediaState = "paused";
+ });
const ind = DocUtils.ActiveRecordings.indexOf(this);
ind !== -1 && (DocUtils.ActiveRecordings.splice(ind, 1));
CaptureManager.Instance.open(this.rootDoc);
}
- });
+ };
setupDictation = () => {
if (this.dataDoc[this.fieldKey + "-dictation"]) return;
@@ -275,7 +280,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent [this.threed, this.content];
- videoPanelHeight = () => NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"], 1) / NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"], 1) * this.props.PanelWidth();
+ videoPanelHeight = () => NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"], this.layoutDoc[HeightSym]()) / NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"], this.layoutDoc[WidthSym]()) * this.props.PanelWidth();
formattedPanelHeight = () => Math.max(0, this.props.PanelHeight() - this.videoPanelHeight());
render() {
TraceMobx();
--
cgit v1.2.3-70-g09d2
From f4da02dac8ea9d92443533b82bee2557cdd8957e Mon Sep 17 00:00:00 2001
From: vkalev
Date: Wed, 11 Aug 2021 20:02:23 -0400
Subject: added circle shape generation using only 4 Bézier curves
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/client/util/InteractionUtils.tsx | 4 ---
src/client/views/GestureOverlay.tsx | 54 +++++++++++++++------------------
src/client/views/InkControls.tsx | 24 ++++++++++++++-
src/client/views/InkStrokeProperties.ts | 9 ++++--
src/client/views/InkingStroke.tsx | 2 +-
5 files changed, 56 insertions(+), 37 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx
index ba935e3bf..cb6a53157 100644
--- a/src/client/util/InteractionUtils.tsx
+++ b/src/client/util/InteractionUtils.tsx
@@ -299,8 +299,6 @@ export namespace InteractionUtils {
return points;
case "circle":
-
-
const centerX = (Math.max(left, right) + Math.min(left, right)) / 2;
const centerY = (Math.max(top, bottom) + Math.min(top, bottom)) / 2;
const radius = Math.max(centerX - Math.min(left, right), centerY - Math.min(top, bottom));
@@ -315,7 +313,6 @@ export namespace InteractionUtils {
points.push({ X: newX, Y: y });
}
points.push({ X: Math.sqrt(Math.pow(radius, 2) - (Math.pow((Math.min(top, bottom) - centerY), 2))) + centerX, Y: Math.min(top, bottom) });
-
} else {
for (var x = Math.min(left, right); x < Math.max(left, right); x++) {
const y = Math.sqrt(Math.pow(radius, 2) - (Math.pow((x - centerX), 2))) + centerY;
@@ -327,7 +324,6 @@ export namespace InteractionUtils {
points.push({ X: x, Y: newY });
}
points.push({ X: Math.min(left, right), Y: Math.sqrt(Math.pow(radius, 2) - (Math.pow((Math.min(left, right) - centerX), 2))) + centerY });
-
}
return points;
// case "arrow":
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 6a4f55bef..f7b5cc030 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -726,39 +726,35 @@ export class GestureOverlay extends Touchable {
break;
case "circle":
-
+ // Approximation of a circle using Bézier curves in which the constant "c" reduces the maximum radial drift to 0.019608%,
+ // making the curves indistinguishable from a circle.
+ // Source: https://spencermortensen.com/articles/bezier-circle/
+ const c = 0.551915024494;
const centerX = (Math.max(left, right) + Math.min(left, right)) / 2;
const centerY = (Math.max(top, bottom) + Math.min(top, bottom)) / 2;
const radius = Math.max(centerX - Math.min(left, right), centerY - Math.min(top, bottom));
- if (centerX - Math.min(left, right) < centerY - Math.min(top, bottom)) {
- for (var y = Math.min(top, bottom); y < Math.max(top, bottom); y++) {
- const x = Math.sqrt(Math.pow(radius, 2) - (Math.pow((y - centerY), 2))) + centerX;
- this._points.push({ X: x, Y: y });
- }
- for (var y = Math.max(top, bottom); y > Math.min(top, bottom); y--) {
- const x = Math.sqrt(Math.pow(radius, 2) - (Math.pow((y - centerY), 2))) + centerX;
- const newX = centerX - (x - centerX);
- this._points.push({ X: newX, Y: y });
- }
- this._points.push({ X: Math.sqrt(Math.pow(radius, 2) - (Math.pow((Math.min(top, bottom) - centerY), 2))) + centerX, Y: Math.min(top, bottom) });
- this._points.push({ X: Math.sqrt(Math.pow(radius, 2) - (Math.pow((Math.min(top, bottom) - centerY), 2))) + centerX, Y: Math.min(top, bottom) - 1 });
-
-
- } else {
- for (var x = Math.min(left, right); x < Math.max(left, right); x++) {
- const y = Math.sqrt(Math.pow(radius, 2) - (Math.pow((x - centerX), 2))) + centerY;
- this._points.push({ X: x, Y: y });
- }
- for (var x = Math.max(left, right); x > Math.min(left, right); x--) {
- const y = Math.sqrt(Math.pow(radius, 2) - (Math.pow((x - centerX), 2))) + centerY;
- const newY = centerY - (y - centerY);
- this._points.push({ X: x, Y: newY });
- }
- this._points.push({ X: Math.min(left, right), Y: Math.sqrt(Math.pow(radius, 2) - (Math.pow((Math.min(left, right) - centerX), 2))) + centerY });
- this._points.push({ X: Math.min(left, right), Y: Math.sqrt(Math.pow(radius, 2) - (Math.pow((Math.min(left, right) - centerX), 2))) + centerY - 1 });
-
- }
+ // Dividing the circle into four equal sections, and fiting each section to a cubic Bézier curve.
+ this._points.push({ X: centerX - radius, Y: centerY });
+ this._points.push({ X: centerX - radius, Y: centerY + (c * radius) });
+ this._points.push({ X: centerX - (c * radius), Y: centerY + radius });
+ this._points.push({ X: centerX, Y: centerY + radius });
+
+ this._points.push({ X: centerX, Y: centerY + radius });
+ this._points.push({ X: centerX + (c * radius), Y: centerY + radius });
+ this._points.push({ X: centerX + radius, Y: centerY + (c * radius) });
+ this._points.push({ X: centerX + radius, Y: centerY });
+
+ this._points.push({ X: centerX + radius, Y: centerY });
+ this._points.push({ X: centerX + radius, Y: centerY - (c * radius) });
+ this._points.push({ X: centerX + (c * radius), Y: centerY - radius });
+ this._points.push({ X: centerX, Y: centerY - radius });
+
+ this._points.push({ X: centerX, Y: centerY - radius });
+ this._points.push({ X: centerX - (c * radius), Y: centerY - radius });
+ this._points.push({ X: centerX - radius, Y: centerY - (c * radius) });
+ this._points.push({ X: centerX - radius, Y: centerY });
break;
+
case "line":
if (Math.abs(firstx - lastx) < 20) {
lastx = firstx;
diff --git a/src/client/views/InkControls.tsx b/src/client/views/InkControls.tsx
index 6213a4075..55a70ccd2 100644
--- a/src/client/views/InkControls.tsx
+++ b/src/client/views/InkControls.tsx
@@ -87,16 +87,38 @@ export class InkControls extends React.Component {
if (!formatInstance) return (null);
// Accessing the current ink's data and extracting all control points.
+ // Separate case for circle shape (?)
const data = this.props.data;
+ const [left, right, top, bottom, scaleX, scaleY, strokeWidth] = this.props.format;
+ const centerX = (Math.max(left, right) + Math.min(left, right)) / 2;
+ const centerY = (Math.max(top, bottom) + Math.min(top, bottom)) / 2;
+ const radius = Math.max(centerX - Math.min(left, right), centerY - Math.min(top, bottom));
const controlPoints: ControlPoint[] = [];
if (data.length >= 4) {
+ // const distance = Math.sqrt((Math.pow(data[0].X - centerX, 2)) + (Math.pow(data[0].Y - centerY, 2)));
+ // if (Math.abs(distance - radius) <= 2.5) {
+ // controlPoints.push({ X: data[0].X, Y: data[0].Y, I: 0 });
+ // const topPoint = formatInstance.rotatePoint(data[0], { X: centerX, Y: centerY }, Math.PI / 2);
+ // const rightPoint = formatInstance.rotatePoint(data[0], { X: centerX, Y: centerY }, Math.PI);
+ // const bottomPoint = formatInstance.rotatePoint(data[0], { X: centerX, Y: centerY }, Math.PI * 1.5);
+ // for (let i = 0; i <= data.length - 4; i += 4) {
+ // const currPoint = data[i];
+ // const isTopPoint = Math.sqrt((Math.pow(currPoint.X - topPoint.X, 2)) + (Math.pow(currPoint.Y - topPoint.Y, 2))) <= 2.5;
+ // const isRightPoint = Math.sqrt((Math.pow(currPoint.X - rightPoint.X, 2)) + (Math.pow(currPoint.Y - rightPoint.Y, 2))) <= 2.5;
+ // const isBottomPoint = Math.sqrt((Math.pow(currPoint.X - bottomPoint.X, 2)) + (Math.pow(currPoint.Y - bottomPoint.Y, 2))) <= 2.5;
+ // if (isTopPoint || isRightPoint || isBottomPoint) {
+ // controlPoints.push({ X: data[i].X, Y: data[i].Y, I: i });
+ // }
+ // }
+ // controlPoints.push({ X: data[0].X, Y: data[0].Y, I: 0 });
+ // } else {
for (let i = 0; i <= data.length - 4; i += 4) {
controlPoints.push({ X: data[i].X, Y: data[i].Y, I: i });
controlPoints.push({ X: data[i + 3].X, Y: data[i + 3].Y, I: i + 3 });
}
+ // }
}
const addedPoints = this.props.addedPoints;
- const [left, top, scaleX, scaleY, strokeWidth] = this.props.format;
return (
<>
diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts
index 76ca5b5ec..7ef6606c4 100644
--- a/src/client/views/InkStrokeProperties.ts
+++ b/src/client/views/InkStrokeProperties.ts
@@ -266,8 +266,13 @@ export class InkStrokeProperties {
this.applyFunction((doc: Doc, ink: InkData) => {
const brokenIndices = Cast(doc.brokenInkIndices, listSpec("number"));
if (brokenIndices) {
- brokenIndices.splice(brokenIndices.indexOf(controlIndex), 1);
- doc.brokenInkIndices = brokenIndices;
+ let newBrokenIndices = new List;
+ for (let i = 0; i < brokenIndices.length; i++) {
+ if (brokenIndices[i] !== controlIndex) {
+ newBrokenIndices.push(brokenIndices[i]);
+ }
+ }
+ doc.brokenInkIndices = newBrokenIndices;
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);
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index 21059b330..d30244a8f 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -138,7 +138,7 @@ export class InkingStroke extends ViewBoxBaseComponent
Date: Thu, 12 Aug 2021 12:48:24 -0400
Subject: fixed positioning of selection line
---
src/client/util/InteractionUtils.tsx | 1 +
src/client/views/GestureOverlay.tsx | 10 ++++++++--
src/client/views/InkHandles.tsx | 3 +++
src/client/views/InkingStroke.tsx | 7 ++++++-
4 files changed, 18 insertions(+), 3 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx
index cb6a53157..32b70c4b4 100644
--- a/src/client/util/InteractionUtils.tsx
+++ b/src/client/util/InteractionUtils.tsx
@@ -210,6 +210,7 @@ export namespace InteractionUtils {
style={{
// filter: drawHalo ? "url(#inkSelectionHalo)" : undefined,
fill: fill ? fill : "none",
+ // opacity: 1.0,
opacity: strokeWidth !== width ? 0.5 : undefined,
pointerEvents: pevents as any,
stroke: color ?? "rgb(0, 0, 0)",
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index f7b5cc030..cf57ac7a1 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -726,7 +726,7 @@ export class GestureOverlay extends Touchable {
break;
case "circle":
- // Approximation of a circle using Bézier curves in which the constant "c" reduces the maximum radial drift to 0.019608%,
+ // Approximation of a circle using 4 Bézier curves in which the constant "c" reduces the maximum radial drift to 0.019608%,
// making the curves indistinguishable from a circle.
// Source: https://spencermortensen.com/articles/bezier-circle/
const c = 0.551915024494;
@@ -748,11 +748,17 @@ export class GestureOverlay extends Touchable {
this._points.push({ X: centerX + radius, Y: centerY - (c * radius) });
this._points.push({ X: centerX + (c * radius), Y: centerY - radius });
this._points.push({ X: centerX, Y: centerY - radius });
-
+
this._points.push({ X: centerX, Y: centerY - radius });
this._points.push({ X: centerX - (c * radius), Y: centerY - radius });
this._points.push({ X: centerX - radius, Y: centerY - (c * radius) });
this._points.push({ X: centerX - radius, Y: centerY });
+
+ // this._points.push({ X: centerX - radius, Y: centerY });
+ // this._points.push({ X: centerX - radius, Y: centerY - (c * radius) });
+ // this._points.push({ X: centerX - (c * radius), Y: centerY - radius });
+ // this._points.push({ X: centerX, Y: centerY - radius });
+
break;
case "line":
diff --git a/src/client/views/InkHandles.tsx b/src/client/views/InkHandles.tsx
index f1eb4b9db..0b24c3c32 100644
--- a/src/client/views/InkHandles.tsx
+++ b/src/client/views/InkHandles.tsx
@@ -11,10 +11,12 @@ import { listSpec } from "../../fields/Schema";
import { List } from "../../fields/List";
import { Cast } from "../../fields/Types";
import { Colors } from "./global/globalEnums";
+import { GestureOverlay } from "./GestureOverlay";
export interface InkHandlesProps {
inkDoc: Doc;
data: InkData;
+ shape?: string;
format: number[];
ScreenToLocalTransform: () => Transform;
}
@@ -68,6 +70,7 @@ export class InkHandles extends React.Component {
// Accessing the current ink's data and extracting all handle points and handle lines.
const data = this.props.data;
+ const shape = this.props.shape;
const handlePoints: HandlePoint[] = [];
const handleLines: HandleLine[] = [];
if (data.length >= 4) {
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index d30244a8f..4beab6a62 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -20,6 +20,7 @@ import { CurrentUserUtils } from "../util/CurrentUserUtils";
import { InkControls } from "./InkControls";
import { InkHandles } from "./InkHandles";
import { Colors } from "./global/globalEnums";
+import { GestureOverlay } from "./GestureOverlay";
type InkDocument = makeInterface<[typeof documentSchema]>;
const InkDocument = makeInterface(documentSchema);
@@ -28,6 +29,7 @@ const InkDocument = makeInterface(documentSchema);
export class InkingStroke extends ViewBoxBaseComponent(InkDocument) {
static readonly MaskDim = 50000;
@observable private _properties?: InkStrokeProperties;
+ // static InkShape = GestureOverlay.Instance.InkShape;
constructor(props: FieldViewProps & InkDocument) {
super(props);
@@ -79,6 +81,8 @@ export class InkingStroke extends ViewBoxBaseComponent 1 && lineRight - lineLeft > 1, false);
// Thin blue line indicating that the current ink stroke is selected.
- 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"),
+ const selectedLine = InteractionUtils.CreatePolyline(data, left, top, Colors.MEDIUM_BLUE, strokeWidth, 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),
@@ -143,6 +147,7 @@ export class InkingStroke extends ViewBoxBaseComponent
> : ""}
--
cgit v1.2.3-70-g09d2
From 200585ebdc40b1c9710c8028e4e25965eaa73a9d Mon Sep 17 00:00:00 2001
From: vkalev
Date: Thu, 12 Aug 2021 13:02:26 -0400
Subject: increasing opacity (selected lines are no longer slightly
transparent)
---
src/client/util/InteractionUtils.tsx | 4 ++--
src/client/views/InkingStroke.tsx | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx
index 32b70c4b4..e009fb3a9 100644
--- a/src/client/util/InteractionUtils.tsx
+++ b/src/client/util/InteractionUtils.tsx
@@ -210,8 +210,8 @@ export namespace InteractionUtils {
style={{
// filter: drawHalo ? "url(#inkSelectionHalo)" : undefined,
fill: fill ? fill : "none",
- // opacity: 1.0,
- opacity: strokeWidth !== width ? 0.5 : undefined,
+ opacity: 1.0,
+ // opacity: strokeWidth !== width ? 0.5 : undefined,
pointerEvents: pevents as any,
stroke: color ?? "rgb(0, 0, 0)",
strokeWidth: strokeWidth,
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index 4beab6a62..affea61e3 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -108,7 +108,7 @@ export class InkingStroke extends ViewBoxBaseComponent 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),
+ const clickableLine = InteractionUtils.CreatePolyline(data, left, top, "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),
--
cgit v1.2.3-70-g09d2
From 136b900ed0b939c2a10b601470f764dcb50809ad Mon Sep 17 00:00:00 2001
From: bobzel
Date: Thu, 12 Aug 2021 17:07:41 -0400
Subject: fixed textboxes which were generally a line too short when opened in
contentfitting view (e.g. stackingView or pivotView)
---
src/client/views/nodes/formattedText/FormattedTextBox.tsx | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 9bba15b28..1058070f8 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1444,12 +1444,17 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
const margins = 2 * NumCast(this.layoutDoc._yMargin, this.props.yPadding || 0);
const children = this.ProseRef?.children.length ? Array.from(this.ProseRef.children[0].children) : undefined;
if (children) {
- const proseHeight = !this.ProseRef ? 0 : children.reduce((p, child) => p + Number(getComputedStyle(child).height.replace("px", "")), margins);
- const scrollHeight = this.ProseRef && Math.min(NumCast(this.layoutDoc.docMaxAutoHeight, proseHeight), proseHeight);
+ var proseHeight = !this.ProseRef ? 0 : children.reduce((p, child) => p + Number(getComputedStyle(child).height.replace("px", "")), margins);
+ var scrollHeight = this.ProseRef && Math.min(NumCast(this.layoutDoc.docMaxAutoHeight, proseHeight), proseHeight);
if (scrollHeight && this.props.renderDepth && !this.props.dontRegisterView) { // if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation
const setScrollHeight = () => this.rootDoc[this.fieldKey + "-scrollHeight"] = scrollHeight;
if (this.rootDoc === this.layoutDoc.doc || this.layoutDoc.resolvedDataDoc) {
setScrollHeight();
+ setTimeout(() => {
+ proseHeight = !this.ProseRef ? 0 : children.reduce((p, child) => p + Number(getComputedStyle(child).height.replace("px", "")), margins);
+ scrollHeight = this.ProseRef && Math.min(NumCast(this.layoutDoc.docMaxAutoHeight, proseHeight), proseHeight);
+ setScrollHeight();
+ }, 10);
} else setTimeout(setScrollHeight, 10); // if we have a template that hasn't been resolved yet, we can't set the height or we'd be setting it on the unresolved template. So set a timeout and hope its arrived...
}
}
--
cgit v1.2.3-70-g09d2
From b69fe78eadeb2bfa1f284e3e0333734b03b718a9 Mon Sep 17 00:00:00 2001
From: vkalev
Date: Fri, 13 Aug 2021 10:15:31 -0400
Subject: cleaning up
---
src/client/views/GestureOverlay.tsx | 7 +------
src/client/views/InkControls.tsx | 24 +-----------------------
src/client/views/InkStrokeProperties.ts | 12 ++++++------
src/client/views/InkingStroke.tsx | 3 +--
4 files changed, 9 insertions(+), 37 deletions(-)
(limited to 'src/client/views')
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index cf57ac7a1..bbf21f22c 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -733,7 +733,7 @@ export class GestureOverlay extends Touchable {
const centerX = (Math.max(left, right) + Math.min(left, right)) / 2;
const centerY = (Math.max(top, bottom) + Math.min(top, bottom)) / 2;
const radius = Math.max(centerX - Math.min(left, right), centerY - Math.min(top, bottom));
- // Dividing the circle into four equal sections, and fiting each section to a cubic Bézier curve.
+ // Dividing the circle into four equal sections, and fitting each section to a cubic Bézier curve.
this._points.push({ X: centerX - radius, Y: centerY });
this._points.push({ X: centerX - radius, Y: centerY + (c * radius) });
this._points.push({ X: centerX - (c * radius), Y: centerY + radius });
@@ -754,11 +754,6 @@ export class GestureOverlay extends Touchable {
this._points.push({ X: centerX - radius, Y: centerY - (c * radius) });
this._points.push({ X: centerX - radius, Y: centerY });
- // this._points.push({ X: centerX - radius, Y: centerY });
- // this._points.push({ X: centerX - radius, Y: centerY - (c * radius) });
- // this._points.push({ X: centerX - (c * radius), Y: centerY - radius });
- // this._points.push({ X: centerX, Y: centerY - radius });
-
break;
case "line":
diff --git a/src/client/views/InkControls.tsx b/src/client/views/InkControls.tsx
index 55a70ccd2..6213a4075 100644
--- a/src/client/views/InkControls.tsx
+++ b/src/client/views/InkControls.tsx
@@ -87,38 +87,16 @@ export class InkControls extends React.Component {
if (!formatInstance) return (null);
// Accessing the current ink's data and extracting all control points.
- // Separate case for circle shape (?)
const data = this.props.data;
- const [left, right, top, bottom, scaleX, scaleY, strokeWidth] = this.props.format;
- const centerX = (Math.max(left, right) + Math.min(left, right)) / 2;
- const centerY = (Math.max(top, bottom) + Math.min(top, bottom)) / 2;
- const radius = Math.max(centerX - Math.min(left, right), centerY - Math.min(top, bottom));
const controlPoints: ControlPoint[] = [];
if (data.length >= 4) {
- // const distance = Math.sqrt((Math.pow(data[0].X - centerX, 2)) + (Math.pow(data[0].Y - centerY, 2)));
- // if (Math.abs(distance - radius) <= 2.5) {
- // controlPoints.push({ X: data[0].X, Y: data[0].Y, I: 0 });
- // const topPoint = formatInstance.rotatePoint(data[0], { X: centerX, Y: centerY }, Math.PI / 2);
- // const rightPoint = formatInstance.rotatePoint(data[0], { X: centerX, Y: centerY }, Math.PI);
- // const bottomPoint = formatInstance.rotatePoint(data[0], { X: centerX, Y: centerY }, Math.PI * 1.5);
- // for (let i = 0; i <= data.length - 4; i += 4) {
- // const currPoint = data[i];
- // const isTopPoint = Math.sqrt((Math.pow(currPoint.X - topPoint.X, 2)) + (Math.pow(currPoint.Y - topPoint.Y, 2))) <= 2.5;
- // const isRightPoint = Math.sqrt((Math.pow(currPoint.X - rightPoint.X, 2)) + (Math.pow(currPoint.Y - rightPoint.Y, 2))) <= 2.5;
- // const isBottomPoint = Math.sqrt((Math.pow(currPoint.X - bottomPoint.X, 2)) + (Math.pow(currPoint.Y - bottomPoint.Y, 2))) <= 2.5;
- // if (isTopPoint || isRightPoint || isBottomPoint) {
- // controlPoints.push({ X: data[i].X, Y: data[i].Y, I: i });
- // }
- // }
- // controlPoints.push({ X: data[0].X, Y: data[0].Y, I: 0 });
- // } else {
for (let i = 0; i <= data.length - 4; i += 4) {
controlPoints.push({ X: data[i].X, Y: data[i].Y, I: i });
controlPoints.push({ X: data[i + 3].X, Y: data[i + 3].Y, I: i + 3 });
}
- // }
}
const addedPoints = this.props.addedPoints;
+ const [left, top, scaleX, scaleY, strokeWidth] = this.props.format;
return (
<>
diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts
index 7ef6606c4..d527b2a05 100644
--- a/src/client/views/InkStrokeProperties.ts
+++ b/src/client/views/InkStrokeProperties.ts
@@ -266,12 +266,12 @@ export class InkStrokeProperties {
this.applyFunction((doc: Doc, ink: InkData) => {
const brokenIndices = Cast(doc.brokenInkIndices, listSpec("number"));
if (brokenIndices) {
- let newBrokenIndices = new List;
- for (let i = 0; i < brokenIndices.length; i++) {
- if (brokenIndices[i] !== controlIndex) {
- newBrokenIndices.push(brokenIndices[i]);
+ const newBrokenIndices = new List;
+ brokenIndices.forEach(brokenIndex => {
+ if (brokenIndex !== controlIndex) {
+ newBrokenIndices.push(brokenIndex);
}
- }
+ });
doc.brokenInkIndices = newBrokenIndices;
const [controlPoint, handleA, handleB] = [ink[controlIndex], ink[handleIndexA], ink[handleIndexB]];
const oppositeHandleA = this.rotatePoint(handleA, controlPoint, Math.PI);
@@ -288,7 +288,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/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index affea61e3..834c3b745 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -29,7 +29,6 @@ const InkDocument = makeInterface(documentSchema);
export class InkingStroke extends ViewBoxBaseComponent(InkDocument) {
static readonly MaskDim = 50000;
@observable private _properties?: InkStrokeProperties;
- // static InkShape = GestureOverlay.Instance.InkShape;
constructor(props: FieldViewProps & InkDocument) {
super(props);
@@ -142,7 +141,7 @@ export class InkingStroke extends ViewBoxBaseComponent
Date: Sat, 14 Aug 2021 13:29:46 -0400
Subject: code reorganising and updates
---
package-lock.json | 5 +-
src/client/documents/Documents.ts | 15 +-
src/client/util/CurrentUserUtils.ts | 171 ++-
src/client/util/tempCurrentUserUtils.ts | 1389 ++++++++++++++++++++
.../views/collections/CollectionLinearView.scss | 139 --
.../views/collections/CollectionLinearView.tsx | 193 ---
.../views/collections/collectionFreeForm/index.ts | 7 +
.../views/collections/collectionGrid/index.ts | 2 +
.../collectionLinearView/CollectionLinearView.scss | 139 ++
.../collectionLinearView/CollectionLinearView.tsx | 192 +++
.../collections/collectionLinearView/index.ts | 1 +
src/client/views/nodes/DocumentContentsView.tsx | 2 +-
src/client/views/nodes/FontIconBox.scss | 103 --
src/client/views/nodes/FontIconBox.tsx | 96 --
src/client/views/nodes/button/FontIconBadge.tsx | 37 +
src/client/views/nodes/button/FontIconBox.scss | 103 ++
src/client/views/nodes/button/FontIconBox.tsx | 295 +++++
17 files changed, 2328 insertions(+), 561 deletions(-)
create mode 100644 src/client/util/tempCurrentUserUtils.ts
delete mode 100644 src/client/views/collections/CollectionLinearView.scss
delete mode 100644 src/client/views/collections/CollectionLinearView.tsx
create mode 100644 src/client/views/collections/collectionFreeForm/index.ts
create mode 100644 src/client/views/collections/collectionGrid/index.ts
create mode 100644 src/client/views/collections/collectionLinearView/CollectionLinearView.scss
create mode 100644 src/client/views/collections/collectionLinearView/CollectionLinearView.tsx
create mode 100644 src/client/views/collections/collectionLinearView/index.ts
delete mode 100644 src/client/views/nodes/FontIconBox.scss
delete mode 100644 src/client/views/nodes/FontIconBox.tsx
create mode 100644 src/client/views/nodes/button/FontIconBadge.tsx
create mode 100644 src/client/views/nodes/button/FontIconBox.scss
create mode 100644 src/client/views/nodes/button/FontIconBox.tsx
(limited to 'src/client/views')
diff --git a/package-lock.json b/package-lock.json
index 58cdf8805..59ae898bf 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -7694,14 +7694,13 @@
"resolved": "https://registry.npmjs.org/image-size-stream/-/image-size-stream-1.1.0.tgz",
"integrity": "sha1-Ivou2mbG31AQh0bacUkmSy0l+Gs=",
"requires": {
- "image-size": "image-size@github:netroy/image-size#da2c863807a3e9602617bdd357b0de3ab4a064c1",
"readable-stream": "^1.0.33",
"tryit": "^1.0.1"
},
"dependencies": {
"image-size": {
- "version": "git+ssh://git@github.com/netroy/image-size.git#da2c863807a3e9602617bdd357b0de3ab4a064c1",
- "from": "image-size@github:netroy/image-size#da2c863807a3e9602617bdd357b0de3ab4a064c1"
+ "version": "git+https://github.com/netroy/image-size.git#da2c863807a3e9602617bdd357b0de3ab4a064c1",
+ "from": "git+https://github.com/netroy/image-size.git#da2c863807a3e9602617bdd357b0de3ab4a064c1"
},
"isarray": {
"version": "0.0.1",
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 142c37ea4..a15b017bd 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -37,7 +37,7 @@ import { ColorBox } from "../views/nodes/ColorBox";
import { ComparisonBox } from "../views/nodes/ComparisonBox";
import { DocFocusOptions } from "../views/nodes/DocumentView";
import { FilterBox } from "../views/nodes/FilterBox";
-import { FontIconBox } from "../views/nodes/FontIconBox";
+import { FontIconBox } from "../views/nodes/button/FontIconBox";
import { FormattedTextBox } from "../views/nodes/formattedText/FormattedTextBox";
import { ImageBox } from "../views/nodes/ImageBox";
import { KeyValueBox } from "../views/nodes/KeyValueBox";
@@ -215,7 +215,19 @@ export class DocumentOptions {
annotationOn?: Doc;
isPushpin?: boolean;
_removeDropProperties?: List; // list of properties that should be removed from a document when it is dropped. e.g., a creator button may be forceActive to allow it be dragged, but the forceActive property can be removed from the dropped document
+
+ //BUTTONS
iconShape?: string; // shapes of the fonticon border
+ btnType?: string;
+ btnList?: List;
+ docColorBtn?: string;
+ userColorBtn?: string;
+ canClick?: string;
+
+ //LINEAR VIEW
+ linearViewIsExpanded?: boolean; // is linear view expanded
+ linearViewExpandable?: boolean; // can linear view be expanded
+
layout_linkView?: Doc; // view template for a link document
layout_keyValue?: string; // view tempalte for key value docs
linkRelationship?: string; // type of relatinoship a link represents
@@ -266,7 +278,6 @@ export class DocumentOptions {
selectedIndex?: number; // which item in a linear view has been selected using the "thumb doc" ui
clipboard?: Doc;
searchQuery?: string; // for quersyBox
- linearViewIsExpanded?: boolean; // is linear view expanded
useLinkSmallAnchor?: boolean; // whether links to this document should use a miniature linkAnchorBox
border?: string; //for searchbox
hoverBackgroundColor?: string; // background color of a label when hovered
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 66f9d060f..ecce573a1 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -2,13 +2,14 @@ import { computed, observable, reaction } from "mobx";
import * as rp from 'request-promise';
import { DataSym, Doc, DocListCast, DocListCastAsync } from "../../fields/Doc";
import { Id } from "../../fields/FieldSymbols";
+import { InkTool } from "../../fields/InkField";
import { List } from "../../fields/List";
import { PrefetchProxy } from "../../fields/Proxy";
import { RichTextField } from "../../fields/RichTextField";
import { listSpec } from "../../fields/Schema";
import { SchemaHeaderField } from "../../fields/SchemaHeaderField";
import { ComputedField, ScriptField } from "../../fields/ScriptField";
-import { BoolCast, Cast, NumCast, PromiseValue, StrCast, DateCast } from "../../fields/Types";
+import { BoolCast, Cast, DateCast, NumCast, PromiseValue, StrCast } from "../../fields/Types";
import { nullAudio } from "../../fields/URLField";
import { SharingPermissions } from "../../fields/util";
import { Utils } from "../../Utils";
@@ -19,6 +20,7 @@ import { Networking } from "../Network";
import { CollectionDockingView } from "../views/collections/CollectionDockingView";
import { DimUnit } from "../views/collections/collectionMulticolumn/CollectionMulticolumnView";
import { CollectionView, CollectionViewType } from "../views/collections/CollectionView";
+import { Colors } from "../views/global/globalEnums";
import { MainView } from "../views/MainView";
import { FormattedTextBox } from "../views/nodes/formattedText/FormattedTextBox";
import { LabelBox } from "../views/nodes/LabelBox";
@@ -31,13 +33,11 @@ import { LinkManager } from "./LinkManager";
import { Scripting } from "./Scripting";
import { SearchUtil } from "./SearchUtil";
import { SelectionManager } from "./SelectionManager";
-import { UndoManager } from "./UndoManager";
-import { SnappingManager } from "./SnappingManager";
-import { InkTool } from "../../fields/InkField";
-import { SharingManager } from "./SharingManager";
-import { computedFn } from "mobx-utils";
import { ColorScheme } from "./SettingsManager";
-import { Colors } from "../views/global/globalEnums";
+import { SharingManager } from "./SharingManager";
+import { SnappingManager } from "./SnappingManager";
+import { UndoManager } from "./UndoManager";
+import { ButtonType } from "../views/nodes/button/FontIconBox";
export let resolvedPorts: { server: number, socket: number };
@@ -68,13 +68,14 @@ export class CurrentUserUtils {
[this.ficon({
ignoreClick: true,
icon: "mobile",
+ btnType: ButtonType.ClickButton,
backgroundColor: "transparent"
}),
this.mobileTextContainer({},
[this.mobileButtonText({}, "NEW MOBILE BUTTON"), this.mobileButtonInfo({}, "You can customize this button and make it your own.")])]);
doc["template-mobile-button"] = CurrentUserUtils.ficon({
onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'),
- dragFactory: new PrefetchProxy(queryTemplate) as any as Doc, title: "mobile button", icon: "mobile"
+ dragFactory: new PrefetchProxy(queryTemplate) as any as Doc, title: "mobile button", icon: "mobile", btnType: ButtonType.ClickButton,
});
}
@@ -89,7 +90,8 @@ export class CurrentUserUtils {
slideTemplate.isTemplateDoc = makeTemplate(slideTemplate);
doc["template-button-slides"] = CurrentUserUtils.ficon({
onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'),
- dragFactory: new PrefetchProxy(slideTemplate) as any as Doc, title: "presentation slide", icon: "address-card"
+ dragFactory: new PrefetchProxy(slideTemplate) as any as Doc, title: "presentation slide", icon: "address-card",
+ btnType: ButtonType.ClickButton
});
}
@@ -135,7 +137,8 @@ export class CurrentUserUtils {
doc["template-button-link"] = CurrentUserUtils.ficon({
onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'),
- dragFactory: new PrefetchProxy(linkTemplate) as any as Doc, title: "link view", icon: "window-maximize", system: true
+ dragFactory: new PrefetchProxy(linkTemplate) as any as Doc, title: "link view", icon: "window-maximize", system: true,
+ btnType: ButtonType.ClickButton
});
}
@@ -166,7 +169,8 @@ export class CurrentUserUtils {
doc["template-button-switch"] = CurrentUserUtils.ficon({
onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'),
- dragFactory: new PrefetchProxy(box) as any as Doc, title: "data switch", icon: "toggle-on", system: true
+ dragFactory: new PrefetchProxy(box) as any as Doc, title: "data switch", icon: "toggle-on", system: true,
+ btnType: ButtonType.ClickButton
});
}
@@ -215,7 +219,11 @@ export class CurrentUserUtils {
doc["template-button-detail"] = CurrentUserUtils.ficon({
onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'),
- dragFactory: new PrefetchProxy(detailView) as any as Doc, title: "detailView", icon: "window-maximize", system: true
+ dragFactory: new PrefetchProxy(detailView) as any as Doc,
+ title: "detailView",
+ icon: "window-maximize",
+ system: true,
+ btnType: ButtonType.ClickButton,
});
}
@@ -501,6 +509,7 @@ export class CurrentUserUtils {
icon,
title,
toolTip,
+ btnType: ButtonType.ClickButton,
ignoreClick,
_dropAction: "alias",
onDragStart: drag ? ScriptField.MakeFunction(drag) : undefined,
@@ -556,7 +565,7 @@ export class CurrentUserUtils {
const menuBtns = (await CurrentUserUtils.menuBtnDescriptions(doc)).map(({ title, target, icon, click, watchedDocuments }) =>
Docs.Create.FontIconDocument({
icon,
- iconShape: "square",
+ btnType: ButtonType.MenuButton,
_stayInCollection: true,
_hideContextMenu: true,
system: true,
@@ -577,7 +586,6 @@ export class CurrentUserUtils {
title: "menuItemPanel",
childDropAction: "alias",
_chromeHidden: true,
- backgroundColor: Colors.DARK_GRAY,
boxShadow: "rgba(0,0,0,0)",
dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }),
ignoreClick: true,
@@ -637,7 +645,7 @@ export class CurrentUserUtils {
onClick: data.click ? ScriptField.MakeScript(data.click) : undefined,
backgroundColor: data.backgroundColor, system: true
},
- [this.ficon({ ignoreClick: true, icon: data.icon, backgroundColor: "rgba(0,0,0,0)", system: true }), this.mobileTextContainer({}, [this.mobileButtonText({}, data.title), this.mobileButtonInfo({}, data.info)])])
+ [this.ficon({ ignoreClick: true, icon: data.icon, backgroundColor: "rgba(0,0,0,0)", system: true, btnType: ButtonType.ClickButton, }), this.mobileTextContainer({}, [this.mobileButtonText({}, data.title), this.mobileButtonInfo({}, data.info)])])
);
}
@@ -747,8 +755,8 @@ 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,
+ title: "My Tools", _showTitle: "title", _width: 500, _yMargin: 20, ignoreClick: true, _lockedPosition: true, _forceActive: true,
+ system: true, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, boxShadow: "0 0",
})) as any as Doc;
doc.myTools = toolsStack;
@@ -869,9 +877,9 @@ export class CurrentUserUtils {
}
static blist = (opts: DocumentOptions, docs: Doc[]) => new PrefetchProxy(Docs.Create.LinearDocument(docs, {
- ...opts, _gridGap: 5, _xMargin: 5, _yMargin: 5, _height: 42, _width: 100, boxShadow: "0 0", _forceActive: true,
+ ...opts, _gridGap: 5, _xMargin: 5, _yMargin: 5, _width: 100, boxShadow: "0 0", _forceActive: true,
dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }),
- backgroundColor: "black", _lockedPosition: true, linearViewIsExpanded: true, system: true
+ _lockedPosition: true, linearViewIsExpanded: true, system: true
})) as any as Doc
static ficon = (opts: DocumentOptions) => new PrefetchProxy(Docs.Create.FontIconDocument({
@@ -881,18 +889,133 @@ export class CurrentUserUtils {
/// sets up the default list of buttons to be shown in the expanding button menu at the bottom of the Dash window
static setupDockedButtons(doc: Doc) {
if (doc["dockedBtn-undo"] === undefined) {
- doc["dockedBtn-undo"] = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("undo()"), dontUndo: true, _stayInCollection: true, _dropAction: "alias", _hideContextMenu: true, _removeDropProperties: new List(["dropAction", "_hideContextMenu", "stayInCollection"]), toolTip: "click to undo", title: "undo", icon: "undo-alt", system: true });
+ doc["dockedBtn-undo"] = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("undo()"), dontUndo: true, _stayInCollection: true, _dropAction: "alias", _hideContextMenu: true, _removeDropProperties: new List(["dropAction", "_hideContextMenu", "stayInCollection"]), toolTip: "Click to undo", title: "undo", icon: "undo-alt", system: true });
}
if (doc["dockedBtn-redo"] === undefined) {
- doc["dockedBtn-redo"] = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("redo()"), dontUndo: true, _stayInCollection: true, _dropAction: "alias", _hideContextMenu: true, _removeDropProperties: new List(["dropAction", "_hideContextMenu", "stayInCollection"]), toolTip: "click to redo", title: "redo", icon: "redo-alt", system: true });
+ doc["dockedBtn-redo"] = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("redo()"), dontUndo: true, _stayInCollection: true, _dropAction: "alias", _hideContextMenu: true, _removeDropProperties: new List(["dropAction", "_hideContextMenu", "stayInCollection"]), toolTip: "Click to redo", title: "redo", icon: "redo-alt", system: true });
}
if (doc.dockedBtns === undefined) {
- doc.dockedBtns = CurrentUserUtils.blist({ title: "docked buttons", ignoreClick: true }, [doc["dockedBtn-undo"] as Doc, doc["dockedBtn-redo"] as Doc]);
+ doc.dockedBtns = CurrentUserUtils.blist({ title: "docked buttons", linearViewExpandable: true, ignoreClick: true }, [doc["dockedBtn-undo"] as Doc, doc["dockedBtn-redo"] as Doc]);
}
(doc["dockedBtn-undo"] as Doc).dontUndo = true;
(doc["dockedBtn-redo"] as Doc).dontUndo = true;
}
+ static textTools(doc: Doc) {
+ return [
+ {
+ title: "Font", toolTip: "Font", width: 100, btnType: ButtonType.DropdownList, ignoreClick: true,
+ list: ["Roboto", "Roboto Mono", "Nunito", "Times New Roman", "Arial", "Georgia",
+ "Comic Sans MS", "Tahoma", "Impact", "Crimson Text"],
+ scriptDoc: Doc.UserDoc(), toggle: 'userDoc._fontFamily'
+ },
+ {
+ title: "Bold", toolTip: "Bold (Ctrl+B)", btnType: ButtonType.ToggleButton, icon: "bold", click: 'toggleBold()',
+ scriptDoc: Doc.UserDoc(),
+ toggle: 'userDoc._boldActive'
+ },
+ { title: "Italic", toolTip: "Italic (Ctrl+I)", btnType: ButtonType.ToggleButton, icon: "italic", click: 'toggleItalic()', scriptDoc: Doc.UserDoc(), toggle: 'userDoc._italicsActive' },
+ { title: "Underline", toolTip: "Underline (Ctrl+U)", btnType: ButtonType.ToggleButton, icon: "underline", click: 'toggleUnderline()', scriptDoc: Doc.UserDoc(), toggle: 'userDoc._underlineActive' },
+ // { title: "Strikethrough", tooltip: "Strikethrough", btnType: ButtonType.ToggleButton, icon: "strikethrough", click: 'toggleStrikethrough()', toggle: 'userDoc._underlineActive' },
+ // { title: "Superscript", tooltip: "Superscript", btnType: ButtonType.ToggleButton, icon: "superscript", click: 'toggleSuperscript()', toggle: 'userDoc._underlineActive' },
+ // { title: "Subscript", tooltip: "Subscript", btnType: ButtonType.ToggleButton, icon: "subscript", click: 'toggleSubscript()', toggle: 'userDoc._underlineActive' },
+ { title: "Highlight", toolTip: "Highlight", btnType: ButtonType.ColorButton, icon: "highlighter", ignoreClick: true, scriptDoc: Doc.UserDoc(), userColorBtn: 'userDoc._highlightColor' },
+ { title: "Text color", toolTip: "Text color", btnType: ButtonType.ColorButton, icon: "fill-drip", ignoreClick: true, scriptDoc: Doc.UserDoc(), userColorBtn: 'userDoc._textColor' },
+ // { title: "Link", tooltip: "Link", btnType: ButtonType.DropdownButton, icon: "link", click: '', ignoreClick: true },
+ ];
+ }
+
+ static async contextMenuBtnDescriptions(doc: Doc) {
+ return [
+ // { title: "Perspective", tooltip: "Change document's perspective", type: "btn", btnType: ButtonType.DropdownButton, ignoreClick: true, icon: "desktop", click: '' },
+ {
+ title: "Perspective", toolTip: "Perspective", width: 100, btnType: ButtonType.DropdownList, ignoreClick: true,
+ list: [CollectionViewType.Freeform, CollectionViewType.Schema, CollectionViewType.Tree,
+ CollectionViewType.Stacking, CollectionViewType.Masonry, CollectionViewType.Multicolumn,
+ CollectionViewType.Multirow, CollectionViewType.Time, CollectionViewType.Carousel,
+ CollectionViewType.Carousel3D, CollectionViewType.Linear, CollectionViewType.Map,
+ CollectionViewType.Grid],
+ scriptDoc: 'selectedDoc',
+ toggle: 'selectedDoc._viewType'
+ },
+ {
+ title: "Background", toolTip: "Background", btnType: ButtonType.ColorButton, scriptDoc: 'selectedDoc',
+ docColorBtn: 'selectedDoc.backgroundColor', width: 60, ignoreClick: true, icon: "fill-drip",
+ canClick: 'numSelected > 0'
+ },
+ { title: "Overlay", toolTip: "Overlay", btnType: ButtonType.ToggleButton, icon: "layer-group", click: 'toggleOverlay()', toggle: 'selectedDoc.z', canClick: 'numSelected > 0' },
+ { title: "Text Tools", type: "TextMenu", icon: "font" },
+ // { title: "Ink Tools", type: "LinearMenu", icon: "pen-nib" },
+ // { title: "GFX Tools", type: "LinearMenu", icon: "shapes" },
+ // { title: "Alias", btnType: ButtonType.ClickButton, icon: "copy" },
+ ];
+ }
+
+ // Default context menu buttons
+ static async setupContextMenuButtons(doc: Doc) {
+ const docList: Doc[] = [];
+
+ const contextMenuBtns = (await CurrentUserUtils.contextMenuBtnDescriptions(doc)).map(({ title, width, toolTip, ignoreClick, icon, type, btnType, click, toggle, scriptDoc, canClick, docColorBtn }) => {
+ const textDocList: Doc[] = [];
+ if (type === "TextMenu") {
+ const textBtns = (CurrentUserUtils.textTools(doc)).map(({ title, width, list, toolTip, ignoreClick, icon, btnType, click, toggle, scriptDoc, userColorBtn }) => {
+ textDocList.push(Docs.Create.FontIconDocument({
+ _nativeWidth: width ? width : 25,
+ _nativeHeight: 25,
+ _width: width ? width : 25,
+ _height: 25,
+ icon,
+ toolTip,
+ userColorBtn,
+
+ // testToggle: toggle ? ScriptField.MakeScript(toggle, { this: scriptDoc, scriptContext: "any" }) : undefined,
+ // toggle: toggle,
+ btnType: btnType,
+ btnList: new List(list),
+ ignoreClick: ignoreClick,
+ _stayInCollection: true,
+ _hideContextMenu: true,
+ system: true,
+ dontUndo: true,
+ title,
+ backgroundColor: "black",
+ _dropAction: "alias",
+ _removeDropProperties: new List(["dropAction", "_stayInCollection"]),
+ onClick: click ? ScriptField.MakeScript(click, { scriptContext: "any" }) : undefined
+ }));
+ });
+ docList.push(CurrentUserUtils.blist({ ignoreClick: true, linearViewExpandable: true, _height: 30, backgroundColor: "transparent" }, textDocList));
+ } else {
+ docList.push(Docs.Create.FontIconDocument({
+ _nativeWidth: width ? width : 30,
+ _nativeHeight: 30,
+ _width: width ? width : 30,
+ _height: 30,
+ icon,
+ toolTip,
+ // testToggle: toggle ? ScriptField.MakeScript(toggle, { scriptContext: "any" }) : undefined,
+ // toggle: toggle,
+ docColorBtn,
+ canClick: canClick,
+ btnType: btnType,
+ ignoreClick: ignoreClick,
+ _stayInCollection: true,
+ _hideContextMenu: true,
+ system: true,
+ dontUndo: true,
+ title,
+ backgroundColor: "black",
+ _dropAction: "alias",
+ _removeDropProperties: new List(["dropAction", "_stayInCollection"]),
+ onClick: click ? ScriptField.MakeScript(click, { scriptContext: "any" }) : undefined
+ }));
+ }
+ });
+
+ if (doc.contextMenuBtns === undefined) {
+ doc.contextMenuBtns = CurrentUserUtils.blist({ title: "menu buttons", ignoreClick: true, linearViewExpandable: false, _height: 35 }, docList);
+ }
+ }
// sets up the default set of documents to be shown in the Overlay layer
static setupOverlays(doc: Doc) {
if (doc.myOverlayDocs === undefined) {
@@ -1052,8 +1175,8 @@ export class CurrentUserUtils {
setTimeout(() => this.setupDefaultPresentation(doc), 0); // presentation that's initially triggered
// setup reactions to change the highlights on the undo/redo buttons -- would be better to encode this in the undo/redo buttons, but the undo/redo stacks are not wired up that way yet
- doc["dockedBtn-undo"] && reaction(() => UndoManager.undoStack.slice(), () => Doc.GetProto(doc["dockedBtn-undo"] as Doc).opacity = UndoManager.CanUndo() ? 1 : 0.4, { fireImmediately: true });
- doc["dockedBtn-redo"] && reaction(() => UndoManager.redoStack.slice(), () => Doc.GetProto(doc["dockedBtn-redo"] as Doc).opacity = UndoManager.CanRedo() ? 1 : 0.4, { fireImmediately: true });
+ // doc["dockedBtn-undo"] && reaction(() => UndoManager.undoStack.slice(), () => Doc.GetProto(doc["dockedBtn-undo"] as Doc).opacity = UndoManager.CanUndo() ? 1 : 0.4, { fireImmediately: true });
+ // doc["dockedBtn-redo"] && reaction(() => UndoManager.redoStack.slice(), () => Doc.GetProto(doc["dockedBtn-redo"] as Doc).opacity = UndoManager.CanRedo() ? 1 : 0.4, { fireImmediately: true });
// uncomment this to setup a default note style that uses the custom header layout
// PromiseValue(doc.emptyHeader).then(factory => {
diff --git a/src/client/util/tempCurrentUserUtils.ts b/src/client/util/tempCurrentUserUtils.ts
new file mode 100644
index 000000000..3fba672e6
--- /dev/null
+++ b/src/client/util/tempCurrentUserUtils.ts
@@ -0,0 +1,1389 @@
+import { computed, observable, reaction, action } from "mobx";
+import * as rp from 'request-promise';
+import { DataSym, Doc, DocListCast, DocListCastAsync, AclReadonly } from "../../fields/Doc";
+import { Id } from "../../fields/FieldSymbols";
+import { List } from "../../fields/List";
+import { PrefetchProxy } from "../../fields/Proxy";
+import { RichTextField } from "../../fields/RichTextField";
+import { listSpec } from "../../fields/Schema";
+import { SchemaHeaderField } from "../../fields/SchemaHeaderField";
+import { ComputedField, ScriptField } from "../../fields/ScriptField";
+import { BoolCast, Cast, NumCast, PromiseValue, StrCast, DateCast } from "../../fields/Types";
+import { nullAudio } from "../../fields/URLField";
+import { SharingPermissions } from "../../fields/util";
+import { Utils } from "../../Utils";
+import { DocServer } from "../DocServer";
+import { Docs, DocumentOptions, DocUtils } from "../documents/Documents";
+import { DocumentType } from "../documents/DocumentTypes";
+import { Networking } from "../Network";
+import { CollectionDockingView } from "../views/collections/collectionDocking/CollectionDockingView";
+import { DimUnit } from "../views/collections/collectionMulticolumn/CollectionMulticolumnView";
+import { CollectionView, CollectionViewType } from "../views/collections/CollectionView";
+import { MainView } from "../views/MainView";
+import { FormattedTextBox } from "../views/nodes/formattedText/FormattedTextBox";
+import { LabelBox } from "../views/nodes/LabelBox";
+import { OverlayView } from "../views/OverlayView";
+import { DocumentManager } from "./DocumentManager";
+import { DragManager } from "./DragManager";
+import { makeTemplate } from "./DropConverter";
+import { HistoryUtil } from "./History";
+import { LinkManager } from "./LinkManager";
+import { Scripting } from "./Scripting";
+import { SearchUtil } from "./SearchUtil";
+import { SelectionManager } from "./SelectionManager";
+import { SnappingManager } from "./SnappingManager";
+import { InkTool } from "../../fields/InkField";
+import { ButtonType } from "../views/nodes/FontIconBox";
+
+
+export let resolvedPorts: { server: number, socket: number };
+const headerViewVersion = "0.1";
+export class CurrentUserUtils {
+ private static curr_id: string;
+ //TODO tfs: these should be temporary...
+ private static mainDocId: string | undefined;
+
+ 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; }
+ @computed public static get UserDocument() { return Doc.UserDoc(); }
+
+ @observable public static GuestTarget: Doc | undefined;
+ @observable public static GuestDashboard: Doc | undefined;
+ @observable public static GuestMobile: Doc | undefined;
+ @observable public static propertiesWidth: number = 0;
+
+ // sets up the default User Templates - slideView, headerView
+ static setupUserTemplateButtons(doc: Doc) {
+ // Prototype for mobile button (not sure if 'Advanced Item Prototypes' is ideal location)
+ if (doc["template-mobile-button"] === undefined) {
+ const queryTemplate = this.mobileButton({
+ title: "NEW MOBILE BUTTON",
+ onClick: undefined,
+ },
+ [this.ficon({
+ ignoreClick: true,
+ icon: "mobile",
+ btnType: ButtonType.ClickButton,
+ backgroundColor: "transparent"
+ }),
+ this.mobileTextContainer({},
+ [this.mobileButtonText({}, "NEW MOBILE BUTTON"), this.mobileButtonInfo({}, "You can customize this button and make it your own.")])]);
+ doc["template-mobile-button"] = CurrentUserUtils.ficon({
+ onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'),
+ dragFactory: new PrefetchProxy(queryTemplate) as any as Doc, title: "mobile button",
+ btnType: ButtonType.ClickButton,
+ icon: "mobile"
+ });
+ }
+
+ if (doc["template-button-slides"] === undefined) {
+ const slideTemplate = Docs.Create.MultirowDocument(
+ [
+ Docs.Create.MulticolumnDocument([], { title: "data", _height: 200, system: true }),
+ Docs.Create.TextDocument("", { title: "text", _height: 100, system: true })
+ ],
+ { _width: 400, _height: 300, title: "slideView", _xMargin: 3, _yMargin: 3, system: true }
+ );
+ slideTemplate.isTemplateDoc = makeTemplate(slideTemplate);
+ doc["template-button-slides"] = CurrentUserUtils.ficon({
+ onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'),
+ dragFactory: new PrefetchProxy(slideTemplate) as any as Doc, title: "presentation slide",
+ icon: "address-card",
+ btnType: ButtonType.ClickButton
+ });
+ }
+
+ if (doc["template-button-link"] === undefined) { // set _backgroundColor to transparent to prevent link dot from obscuring document it's attached to.
+ const linkTemplate = Doc.MakeDelegate(Docs.Create.TextDocument(" ", { title: "header", _autoHeight: true, system: true }, "header")); // text needs to be a space to allow templateText to be created
+ linkTemplate.system = true;
+ Doc.GetProto(linkTemplate).layout =
+ "" +
+ " " +
+ " " +
+ "
";
+ (linkTemplate.proto as Doc).isTemplateDoc = makeTemplate(linkTemplate.proto as Doc, true, "linkView");
+
+ const rtf2 = {
+ doc: {
+ type: "doc", content: [
+ {
+ type: "paragraph",
+ content: [{
+ type: "dashField",
+ attrs: {
+ fieldKey: "src",
+ hideKey: false
+ }
+ }]
+ },
+ { type: "paragraph" },
+ {
+ type: "paragraph",
+ content: [{
+ type: "dashField",
+ attrs: {
+ fieldKey: "dst",
+ hideKey: false
+ }
+ }]
+ }]
+ },
+ selection: { type: "text", anchor: 1, head: 1 },
+ storedMarks: []
+ };
+ linkTemplate.header = new RichTextField(JSON.stringify(rtf2), "");
+
+ doc["template-button-link"] = CurrentUserUtils.ficon({
+ onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'),
+ dragFactory: new PrefetchProxy(linkTemplate) as any as Doc, title: "link view",
+ btnType: ButtonType.ClickButton,
+ icon: "window-maximize", system: true
+ });
+ }
+
+ if (doc["template-button-switch"] === undefined) {
+ const { FreeformDocument, MulticolumnDocument, TextDocument } = Docs.Create;
+
+ const yes = FreeformDocument([], { title: "yes", _height: 35, _width: 50, _dimUnit: DimUnit.Pixel, _dimMagnitude: 40, system: true });
+ const name = TextDocument("name", { title: "name", _height: 35, _width: 70, _dimMagnitude: 1, system: true });
+ const no = FreeformDocument([], { title: "no", _height: 100, _width: 100, system: true });
+ const labelTemplate = {
+ doc: {
+ type: "doc", content: [{
+ type: "paragraph",
+ content: [{ type: "dashField", attrs: { fieldKey: "PARAMS", hideKey: true } }]
+ }]
+ },
+ selection: { type: "text", anchor: 1, head: 1 },
+ storedMarks: []
+ };
+ Doc.GetProto(name).text = new RichTextField(JSON.stringify(labelTemplate), "PARAMS");
+ Doc.GetProto(yes).backgroundColor = ComputedField.MakeFunction("self[this.PARAMS] ? 'green':'red'");
+ // Doc.GetProto(no).backgroundColor = ComputedField.MakeFunction("!self[this.PARAMS] ? 'red':'white'");
+ // Doc.GetProto(yes).onClick = ScriptField.MakeScript("self[this.PARAMS] = true");
+ Doc.GetProto(yes).onClick = ScriptField.MakeScript("self[this.PARAMS] = !self[this.PARAMS]");
+ // Doc.GetProto(no).onClick = ScriptField.MakeScript("self[this.PARAMS] = false");
+ const box = MulticolumnDocument([/*no, */ yes, name], { title: "value", _width: 120, _height: 35, system: true });
+ box.isTemplateDoc = makeTemplate(box, true, "switch");
+
+ doc["template-button-switch"] = CurrentUserUtils.ficon({
+ onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'),
+ dragFactory: new PrefetchProxy(box) as any as Doc, title: "data switch",
+ btnType: ButtonType.ClickButton,
+ icon: "toggle-on", system: true
+ });
+ }
+
+ if (doc["template-button-detail"] === undefined) {
+ const { TextDocument, MasonryDocument, CarouselDocument } = Docs.Create;
+
+ const openInTarget = ScriptField.MakeScript("openOnRight(self.doubleClickView)");
+ const carousel = CarouselDocument([], {
+ title: "data", _height: 350, _itemIndex: 0, "_carousel-caption-xMargin": 10, "_carousel-caption-yMargin": 10,
+ onChildDoubleClick: openInTarget, backgroundColor: "#9b9b9b3F", system: true
+ });
+
+ const details = TextDocument("", { title: "details", _height: 200, _autoHeight: true, system: true });
+ const short = TextDocument("", { title: "shortDescription", treeViewOpen: true, treeViewExpandedView: "layout", _height: 75, _autoHeight: true, system: true });
+ const long = TextDocument("", { title: "longDescription", treeViewOpen: false, treeViewExpandedView: "layout", _height: 150, _autoHeight: true, system: true });
+
+ const buxtonFieldKeys = ["year", "originalPrice", "degreesOfFreedom", "company", "attribute", "primaryKey", "secondaryKey", "dimensions"];
+ const detailedTemplate = {
+ doc: {
+ type: "doc", content: buxtonFieldKeys.map(fieldKey => ({
+ type: "paragraph",
+ content: [{ type: "dashField", attrs: { fieldKey } }]
+ }))
+ },
+ selection: { type: "text", anchor: 1, head: 1 },
+ storedMarks: []
+ };
+ details.text = new RichTextField(JSON.stringify(detailedTemplate), buxtonFieldKeys.join(" "));
+
+ const shared = { _autoHeight: true, _xMargin: 0 };
+ const detailViewOpts = { title: "detailView", _width: 300, _fontFamily: "Arial", _fontSize: "12px" };
+ const descriptionWrapperOpts = { title: "descriptions", _height: 300, _columnWidth: -1, treeViewHideTitle: true, _pivotField: "title", system: true };
+
+ const descriptionWrapper = MasonryDocument([details, short, long], { ...shared, ...descriptionWrapperOpts });
+ descriptionWrapper._columnHeaders = new List([
+ new SchemaHeaderField("[A Short Description]", "dimGray", undefined, undefined, undefined, false),
+ new SchemaHeaderField("[Long Description]", "dimGray", undefined, undefined, undefined, true),
+ new SchemaHeaderField("[Details]", "dimGray", undefined, undefined, undefined, true),
+ ]);
+ const detailView = Docs.Create.StackingDocument([carousel, descriptionWrapper], { ...shared, ...detailViewOpts, _chromeHidden: true, system: true });
+ detailView.isTemplateDoc = makeTemplate(detailView);
+
+ details.title = "Details";
+ short.title = "A Short Description";
+ long.title = "Long Description";
+
+ doc["template-button-detail"] = CurrentUserUtils.ficon({
+ onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'),
+ dragFactory: new PrefetchProxy(detailView) as any as Doc, title: "detailView",
+ btnType: ButtonType.ClickButton,
+ icon: "window-maximize", system: true
+ });
+ }
+
+ const requiredTypes = [
+ doc["template-button-slides"] as Doc,
+ doc["template-mobile-button"] as Doc,
+ doc["template-button-detail"] as Doc,
+ doc["template-button-link"] as Doc,
+ //doc["template-button-switch"] as Doc]
+ ];
+ if (doc["template-buttons"] === undefined) {
+ doc["template-buttons"] = new PrefetchProxy(Docs.Create.MasonryDocument(requiredTypes, {
+ title: "Advanced Item Prototypes", _xMargin: 0, _showTitle: "title", _chromeHidden: true,
+ hidden: ComputedField.MakeFunction("IsNoviceMode()") as any,
+ _stayInCollection: true, _hideContextMenu: true,
+ _autoHeight: true, _width: 500, _height: 300, _fitWidth: true, _columnWidth: 35, ignoreClick: true, _lockedPosition: true,
+ dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), system: true
+ }));
+ } else {
+ const curButnTypes = Cast(doc["template-buttons"], Doc, null);
+ DocListCastAsync(curButnTypes.data).then(async curBtns => {
+ curBtns && await Promise.all(curBtns);
+ requiredTypes.map(btype => Doc.AddDocToList(curButnTypes, "data", btype));
+ });
+ }
+ return doc["template-buttons"] as Doc;
+ }
+
+ // setup the different note type skins
+ static setupNoteTemplates(doc: Doc) {
+ if (doc["template-note-Note"] === undefined) {
+ const noteView = Docs.Create.TextDocument("", { title: "text", isTemplateDoc: true, backgroundColor: "yellow", system: true });
+ noteView.isTemplateDoc = makeTemplate(noteView, true, "Note");
+ doc["template-note-Note"] = new PrefetchProxy(noteView);
+ }
+ if (doc["template-note-Idea"] === undefined) {
+ const noteView = Docs.Create.TextDocument("", { title: "text", backgroundColor: "pink", system: true });
+ noteView.isTemplateDoc = makeTemplate(noteView, true, "Idea");
+ doc["template-note-Idea"] = new PrefetchProxy(noteView);
+ }
+ if (doc["template-note-Topic"] === undefined) {
+ const noteView = Docs.Create.TextDocument("", { title: "text", backgroundColor: "lightblue", system: true });
+ noteView.isTemplateDoc = makeTemplate(noteView, true, "Topic");
+ doc["template-note-Topic"] = new PrefetchProxy(noteView);
+ }
+ if (doc["template-note-Todo"] === undefined) {
+ const noteView = Docs.Create.TextDocument("", {
+ title: "text", backgroundColor: "orange", _autoHeight: false, _height: 100, _showCaption: "caption",
+ layout: FormattedTextBox.LayoutString("Todo"), caption: RichTextField.DashField("taskStatus"), system: true
+ });
+ noteView.isTemplateDoc = makeTemplate(noteView, true, "Todo");
+ doc["template-note-Todo"] = new PrefetchProxy(noteView);
+ }
+ const taskStatusValues = [
+ { title: "todo", _backgroundColor: "blue", color: "white", system: true },
+ { title: "in progress", _backgroundColor: "yellow", color: "black", system: true },
+ { title: "completed", _backgroundColor: "green", color: "white", system: true }
+ ];
+ if (doc.fieldTypes === undefined) {
+ doc.fieldTypes = Docs.Create.TreeDocument([], { title: "field enumerations", system: true });
+ DocUtils.addFieldEnumerations(Doc.GetProto(doc["template-note-Todo"] as any as Doc), "taskStatus", taskStatusValues);
+ }
+
+ if (doc["template-notes"] === undefined) {
+ doc["template-notes"] = new PrefetchProxy(Docs.Create.TreeDocument([doc["template-note-Note"] as any as Doc, doc["template-note-Idea"] as any as Doc, doc["template-note-Topic"] as any as Doc], // doc["template-note-Todo"] as any as Doc],
+ { title: "Note Layouts", _height: 75, system: true }));
+ } else {
+ const curNoteTypes = Cast(doc["template-notes"], Doc, null);
+ const requiredTypes = [doc["template-note-Note"] as any as Doc, doc["template-note-Idea"] as any as Doc, doc["template-note-Topic"] as any as Doc];//, doc["template-note-Todo"] as any as Doc];
+ DocListCastAsync(curNoteTypes.data).then(async curNotes => {
+ curNotes && await Promise.all(curNotes);
+ requiredTypes.map(ntype => Doc.AddDocToList(curNoteTypes, "data", ntype));
+ });
+ }
+
+ return doc["template-notes"] as Doc;
+ }
+
+ // creates Note templates, and initial "user" templates
+ static setupDocTemplates(doc: Doc) {
+ const noteTemplates = CurrentUserUtils.setupNoteTemplates(doc);
+ const userTemplateBtns = CurrentUserUtils.setupUserTemplateButtons(doc);
+ const clickTemplates = CurrentUserUtils.setupClickEditorTemplates(doc);
+ if (doc.templateDocs === undefined) {
+ doc.templateDocs = new PrefetchProxy(Docs.Create.TreeDocument([noteTemplates, userTemplateBtns, clickTemplates], {
+ title: "template layouts", _xPadding: 0, system: true,
+ dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name })
+ }));
+ }
+ }
+
+ // setup templates for different document types when they are iconified from Document Decorations
+ static setupDefaultIconTemplates(doc: Doc) {
+ if (doc["template-icon-view"] === undefined) {
+ const iconView = Docs.Create.LabelDocument({
+ title: "icon", textTransform: "unset", letterSpacing: "unset", layout: LabelBox.LayoutString("title"), _backgroundColor: "dimGray",
+ _width: 150, _height: 70, _xPadding: 10, _yPadding: 10, isTemplateDoc: true, onDoubleClick: ScriptField.MakeScript("deiconifyView(self)"), system: true
+ });
+ // Docs.Create.TextDocument("", {
+ // title: "icon", _width: 150, _height: 30, isTemplateDoc: true, onDoubleClick: ScriptField.MakeScript("deiconifyView(self)")
+ // });
+ // Doc.GetProto(iconView).icon = new RichTextField('{"doc":{"type":"doc","content":[{"type":"paragraph","attrs":{"align":null,"color":null,"id":null,"indent":null,"inset":null,"lineSpacing":null,"paddingBottom":null,"paddingTop":null},"content":[{"type":"dashField","attrs":{"fieldKey":"title","docid":""}}]}]},"selection":{"type":"text","anchor":2,"head":2},"storedMarks":[]}', "");
+ iconView.isTemplateDoc = makeTemplate(iconView);
+ doc["template-icon-view"] = new PrefetchProxy(iconView);
+ }
+ if (doc["template-icon-view-rtf"] === undefined) {
+ const iconRtfView = Docs.Create.LabelDocument({
+ title: "icon_" + DocumentType.RTF, textTransform: "unset", letterSpacing: "unset", layout: LabelBox.LayoutString("text"),
+ _width: 150, _height: 70, _xPadding: 10, _yPadding: 10, isTemplateDoc: true, onDoubleClick: ScriptField.MakeScript("deiconifyView(self)"), system: true
+ });
+ iconRtfView.isTemplateDoc = makeTemplate(iconRtfView, true, "icon_" + DocumentType.RTF);
+ doc["template-icon-view-rtf"] = new PrefetchProxy(iconRtfView);
+ }
+ if (doc["template-icon-view-button"] === undefined) {
+ const iconBtnView = Docs.Create.FontIconDocument({
+ title: "icon_" + DocumentType.BUTTON, _nativeHeight: 30, _nativeWidth: 30,
+ _width: 30, _height: 30, isTemplateDoc: true, onDoubleClick: ScriptField.MakeScript("deiconifyView(self)"), system: true
+ });
+ iconBtnView.isTemplateDoc = makeTemplate(iconBtnView, true, "icon_" + DocumentType.BUTTON);
+ doc["template-icon-view-button"] = new PrefetchProxy(iconBtnView);
+ }
+ if (doc["template-icon-view-img"] === undefined) {
+ const iconImageView = Docs.Create.ImageDocument("http://www.cs.brown.edu/~bcz/face.gif", {
+ title: "data", _width: 50, isTemplateDoc: true, onDoubleClick: ScriptField.MakeScript("deiconifyView(self)"), system: true
+ });
+ iconImageView.isTemplateDoc = makeTemplate(iconImageView, true, "icon_" + DocumentType.IMG);
+ doc["template-icon-view-img"] = new PrefetchProxy(iconImageView);
+ }
+ if (doc["template-icon-view-col"] === undefined) {
+ const iconColView = Docs.Create.TreeDocument([], { title: "data", _width: 180, _height: 80, onDoubleClick: ScriptField.MakeScript("deiconifyView(self)"), system: true });
+ iconColView.isTemplateDoc = makeTemplate(iconColView, true, "icon_" + DocumentType.COL);
+ doc["template-icon-view-col"] = new PrefetchProxy(iconColView);
+ }
+ if (doc["template-icons"] === undefined) {
+ doc["template-icons"] = new PrefetchProxy(Docs.Create.TreeDocument([doc["template-icon-view"] as Doc, doc["template-icon-view-img"] as Doc, doc["template-icon-view-button"] as Doc,
+ doc["template-icon-view-col"] as Doc, doc["template-icon-view-rtf"] as Doc, doc["template-icon-view-pdf"] as Doc], { title: "icon templates", _height: 75, system: true }));
+ } else {
+ const templateIconsDoc = Cast(doc["template-icons"], Doc, null);
+ const requiredTypes = [doc["template-icon-view"] as Doc, doc["template-icon-view-img"] as Doc, doc["template-icon-view-button"] as Doc,
+ doc["template-icon-view-col"] as Doc, doc["template-icon-view-rtf"] as Doc];
+ DocListCastAsync(templateIconsDoc.data).then(async curIcons => {
+ curIcons && await Promise.all(curIcons);
+ requiredTypes.map(ntype => Doc.AddDocToList(templateIconsDoc, "data", ntype));
+ });
+ }
+ return doc["template-icons"] as Doc;
+ }
+
+ static creatorBtnDescriptors(doc: Doc): {
+ title: string, toolTip: string, icon: string, drag?: string, ignoreClick?: boolean,
+ click?: string, backgroundColor?: string, dragFactory?: Doc, noviceMode?: boolean, clickFactory?: Doc
+ }[] {
+ if (doc.emptyPresentation === undefined) {
+ doc.emptyPresentation = Docs.Create.PresDocument(new List(),
+ { title: "Untitled Presentation", _viewType: CollectionViewType.Stacking, _fitWidth: true, _width: 400, _height: 500, targetDropAction: "alias", _chromeHidden: true, boxShadow: "0 0", system: true, cloneFieldFilter: new List(["system"]) });
+ ((doc.emptyPresentation as Doc).proto as Doc)["dragFactory-count"] = 0;
+ }
+ if (doc.emptyCollection === undefined) {
+ doc.emptyCollection = Docs.Create.FreeformDocument([],
+ { _nativeWidth: undefined, _nativeHeight: undefined, _fitWidth: true, _width: 150, _height: 100, title: "freeform", system: true, cloneFieldFilter: new List(["system"]) });
+ ((doc.emptyCollection as Doc).proto as Doc)["dragFactory-count"] = 0;
+ }
+ if (doc.emptyPane === undefined) {
+ doc.emptyPane = Docs.Create.FreeformDocument([], { _nativeWidth: undefined, _nativeHeight: undefined, _width: 500, _height: 800, title: "Untitled Tab", system: true, cloneFieldFilter: new List(["system"]) });
+ ((doc.emptyPane as Doc).proto as Doc)["dragFactory-count"] = 0;
+ }
+ if (doc.emptySlide === undefined) {
+ const textDoc = Docs.Create.TreeDocument([], { title: "Slide", _viewType: CollectionViewType.Tree, _fontSize: "20px", treeViewType: "outline", _xMargin: 0, _yMargin: 0, _width: 300, _height: 200, _singleLine: true, backgroundColor: "transparent", system: true, cloneFieldFilter: new List(["system"]) });
+ Doc.GetProto(textDoc).title = ComputedField.MakeFunction('self.text?.Text');
+ FormattedTextBox.SelectOnLoad = textDoc[Id];
+ doc.emptySlide = textDoc;
+ }
+ if ((doc.emptyHeader as Doc)?.version !== headerViewVersion) {
+ const json = {
+ doc: {
+ type: "doc",
+ content: [
+ {
+ type: "paragraph", attrs: {}, content: [{
+ type: "dashField",
+ attrs: { fieldKey: "author", docid: "", hideKey: false },
+ marks: [{ type: "strong" }]
+ }, {
+ type: "dashField",
+ attrs: { fieldKey: "creationDate", docid: "", hideKey: false },
+ marks: [{ type: "strong" }]
+ }]
+ }]
+ },
+ selection: { type: "text", anchor: 1, head: 1 },
+ storedMarks: []
+ };
+ const headerTemplate = Docs.Create.RTFDocument(new RichTextField(JSON.stringify(json), ""), {
+ title: "text", version: headerViewVersion, target: doc, _height: 70, _headerPointerEvents: "all",
+ _headerHeight: 12, _headerFontSize: 9, _autoHeight: true, system: true, _fitWidth: true,
+ cloneFieldFilter: new List(["system"])
+ }, "header");
+ const headerBtnHgt = 10;
+ headerTemplate[DataSym].layout =
+ "" +
+ ` ` +
+ " " +
+ ` Metadata` +
+ "";
+
+ // "" +
+ // " " +
+ // " " +
+ // "
";
+ (headerTemplate.proto as Doc).isTemplateDoc = makeTemplate(headerTemplate.proto as Doc, true, "headerView");
+ doc.emptyHeader = headerTemplate;
+ ((doc.emptyHeader as Doc).proto as Doc)["dragFactory-count"] = 0;
+ }
+ if (doc.emptyComparison === undefined) {
+ doc.emptyComparison = Docs.Create.ComparisonDocument({ title: "compare", _width: 300, _height: 300, system: true, cloneFieldFilter: new List(["system"]) });
+ }
+ if (doc.emptyScript === undefined) {
+ doc.emptyScript = Docs.Create.ScriptingDocument(undefined, { _width: 200, _height: 250, title: "script", system: true, cloneFieldFilter: new List(["system"]) });
+ ((doc.emptyScript as Doc).proto as Doc)["dragFactory-count"] = 0;
+ }
+ if (doc.emptyScreenshot === undefined) {
+ doc.emptyScreenshot = Docs.Create.ScreenshotDocument("empty screenshot", { _fitWidth: true, _width: 400, _height: 200, system: true, cloneFieldFilter: new List(["system"]) });
+ }
+ if (doc.emptyWall === undefined) {
+ doc.emptyWall = Docs.Create.ScreenshotDocument("", { _fitWidth: true, _width: 400, _height: 200, title: "screen snapshot", system: true, cloneFieldFilter: new List(["system"]) });
+ (doc.emptyWall as Doc).videoWall = true;
+ }
+ if (doc.emptyAudio === undefined) {
+ doc.emptyAudio = Docs.Create.AudioDocument(nullAudio, { _width: 200, title: "audio recording", system: true, cloneFieldFilter: new List(["system"]) });
+ ((doc.emptyAudio as Doc).proto as Doc)["dragFactory-count"] = 0;
+ }
+ if (doc.emptyNote === undefined) {
+ doc.emptyNote = Docs.Create.TextDocument("", { _width: 200, title: "text note", _autoHeight: true, system: true, cloneFieldFilter: new List(["system"]) });
+ ((doc.emptyNote as Doc).proto as Doc)["dragFactory-count"] = 0;
+ }
+ if (doc.emptyImage === undefined) {
+ doc.emptyImage = Docs.Create.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { _width: 250, _nativeWidth: 250, title: "an image of a cat", system: true });
+ }
+ if (doc.emptyButton === undefined) {
+ doc.emptyButton = Docs.Create.ButtonDocument({ _width: 150, _height: 50, _xPadding: 10, _yPadding: 10, title: "Button", system: true, cloneFieldFilter: new List(["system"]) });
+ ((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"]) });
+ }
+ if (doc.activeMobileMenu === undefined) {
+ this.setupActiveMobileMenu(doc);
+ }
+ return [
+ { toolTip: "Tap to create a note in a new pane, drag for a note", title: "Note", icon: "sticky-note", click: 'openOnRight(copyDragFactory(this.clickFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyNote as Doc, noviceMode: true, clickFactory: doc.emptyNote as Doc, },
+ { toolTip: "Tap to create a collection in a new pane, drag for a collection", title: "Col", icon: "folder", click: 'openOnRight(copyDragFactory(this.clickFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyCollection as Doc, noviceMode: true, clickFactory: doc.emptyPane as Doc, },
+ { toolTip: "Tap to create a webpage in a new pane, drag for a webpage", title: "Web", icon: "globe-asia", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyWebpage as Doc, noviceMode: true },
+ { toolTip: "Tap to create a progressive slide", title: "Slide", icon: "file", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptySlide as Doc, noviceMode: true },
+ { toolTip: "Tap to create a cat image in a new pane, drag for a cat image", title: "Image", icon: "cat", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyImage as Doc },
+ { toolTip: "Tap to create a comparison box in a new pane, drag for a comparison box", title: "Compare", icon: "columns", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyComparison as Doc, noviceMode: true },
+ { toolTip: "Tap to create a screen grabber in a new pane, drag for a screen grabber", title: "Grab", icon: "photo-video", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyScreenshot as Doc, noviceMode: true },
+ { toolTip: "Tap to create a videoWall", title: "Wall", icon: "photo-video", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyWall as Doc },
+ { toolTip: "Tap to create an audio recorder in a new pane, drag for an audio recorder", title: "Audio", icon: "microphone", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyAudio as Doc, noviceMode: true },
+ { toolTip: "Tap to create a button in a new pane, drag for a button", title: "Button", icon: "bolt", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyButton as Doc },
+ // { toolTip: "Tap to create a presentation in a new pane, drag for a presentation", title: "Trails", icon: "pres-trail", click: 'openOnRight(Doc.UserDoc().activePresentation = copyDragFactory(this.dragFactory))', drag: `Doc.UserDoc().activePresentation = copyDragFactory(this.dragFactory)`, dragFactory: doc.emptyPresentation as Doc, noviceMode: true },
+ { toolTip: "Tap to create a scripting box in a new pane, drag for a scripting box", title: "Script", icon: "terminal", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyScript as Doc },
+ { toolTip: "Tap to create a mobile view in a new pane, drag for a mobile view", title: "Phone", icon: "mobile", click: 'openOnRight(Doc.UserDoc().activeMobileMenu)', drag: 'this.dragFactory', dragFactory: doc.activeMobileMenu as Doc },
+ { toolTip: "Tap to create a custom header note document, drag for a custom header note", title: "Custom", icon: "window-maximize", click: 'openOnRight(delegateDragFactory(this.dragFactory))', drag: 'delegateDragFactory(this.dragFactory)', dragFactory: doc.emptyHeader as Doc },
+ { toolTip: "Toggle a Calculator REPL", title: "repl", icon: "calculator", click: 'addOverlayWindow("ScriptingRepl", { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" })' },
+ ];
+
+ }
+
+ // setup the "creator" buttons for the sidebar-- eg. the default set of draggable document creation tools
+ static async setupCreatorButtons(doc: Doc) {
+ let alreadyCreatedButtons: string[] = [];
+ const dragCreatorSet = await Cast(doc.myItemCreators, Doc, null);
+ if (dragCreatorSet) {
+ const dragCreators = await Cast(dragCreatorSet.data, listSpec(Doc));
+ if (dragCreators) {
+ const dragDocs = await Promise.all(dragCreators);
+ alreadyCreatedButtons = dragDocs.map(d => StrCast(d.title));
+ }
+ }
+ const buttons = CurrentUserUtils.creatorBtnDescriptors(doc).filter(d => !alreadyCreatedButtons?.includes(d.title));
+ const creatorBtns = buttons.map(({ title, toolTip, icon, ignoreClick, drag, click, backgroundColor, dragFactory, noviceMode, clickFactory }) => Docs.Create.FontIconDocument({
+ _nativeWidth: 50, _nativeHeight: 50, _width: 30, _height: 25,
+ icon,
+ title,
+ toolTip,
+ btnType: ButtonType.ClickButton,
+ ignoreClick,
+ _dropAction: "alias",
+ onDragStart: drag ? ScriptField.MakeFunction(drag) : undefined,
+ onClick: click ? ScriptField.MakeScript(click) : undefined,
+ backgroundColor,
+ _hideContextMenu: true,
+ _removeDropProperties: new List(["_stayInCollection"]),
+ _stayInCollection: true,
+ dragFactory,
+ clickFactory,
+ hidden: !noviceMode ? ComputedField.MakeFunction("IsNoviceMode()") as any : undefined,
+ system: true,
+ }));
+
+ if (dragCreatorSet === undefined) {
+ doc.myItemCreators = new PrefetchProxy(Docs.Create.MasonryDocument(creatorBtns, {
+ title: "Basic Item Creators", _showTitle: "title", _xMargin: 0, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true,
+ _autoHeight: true, _width: 500, _height: 300, _fitWidth: true, _columnWidth: 35, ignoreClick: true, _lockedPosition: true,
+ dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), system: true
+ }));
+ } else {
+ creatorBtns.forEach(nb => Doc.AddDocToList(doc.myItemCreators as Doc, "data", nb));
+ }
+ return doc.myItemCreators as Doc;
+ }
+
+ static async menuBtnDescriptions(doc: Doc) {
+ return [
+ { title: "Dashboards", target: Cast(doc.myDashboards, Doc, null), icon: "desktop", 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)' },
+ { 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)' },
+ { title: "User Doc", target: Cast(doc.myUserDoc, Doc, null), icon: "address-card", click: 'selectMainMenu(self)' },
+ ];
+ }
+
+ 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
+ const menuBtns = (await CurrentUserUtils.menuBtnDescriptions(doc)).map(({ title, target, icon, click, watchedDocuments }) =>
+ Docs.Create.FontIconDocument({
+ icon,
+ btnType: ButtonType.MenuButton,
+ _stayInCollection: true,
+ _hideContextMenu: true,
+ system: true,
+ dontUndo: true,
+ title,
+ target,
+ _dropAction: "alias",
+ _removeDropProperties: new List(["dropAction", "_stayInCollection"]),
+ _width: 60,
+ _height: 60,
+ watchedDocuments,
+ onClick: ScriptField.MakeScript(click, { scriptContext: "any" })
+ }));
+ // hack -- last button is assumed to be the userDoc
+ menuBtns[menuBtns.length - 1].hidden = ComputedField.MakeFunction("IsNoviceMode()");
+
+ doc.menuStack = new PrefetchProxy(Docs.Create.StackingDocument(menuBtns, {
+ title: "menuItemPanel",
+ childDropAction: "alias",
+ _chromeHidden: true,
+ dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }),
+ ignoreClick: true,
+ _gridGap: 0,
+ _yMargin: 0,
+ _yPadding: 0, _xMargin: 0, _autoHeight: false, _width: 60, _columnWidth: 60, _lockedPosition: true, system: true
+ }));
+ }
+ // this resets all sidebar buttons to being deactivated
+ PromiseValue(Cast(doc.menuStack, Doc)).then(stack => {
+ stack && PromiseValue(stack.data).then(btns => {
+ DocListCastAsync(btns).then(bts => bts?.forEach(btn => {
+ btn.dontUndo = true;
+ btn.system = true;
+ if (btn.title === "Catalog" || btn.title === "My Files") { // migration from Catalog to My Files
+ btn.target = Doc.UserDoc().myFilesystem;
+ btn.title = "My Files";
+ }
+ }));
+ });
+ });
+ return doc.menuStack as Doc;
+ }
+
+
+ // Sets up mobile menu if it is undefined creates a new one, otherwise returns existing menu
+ static setupActiveMobileMenu(doc: Doc) {
+ if (doc.activeMobileMenu === undefined) {
+ doc.activeMobileMenu = this.setupMobileMenu();
+ }
+ return doc.activeMobileMenu as Doc;
+ }
+
+ // Sets up mobileMenu stacking document
+ static setupMobileMenu() {
+ const menu = new PrefetchProxy(Docs.Create.StackingDocument(this.setupMobileButtons(), {
+ _width: 980, ignoreClick: true, _lockedPosition: false, title: "home", _yMargin: 100, system: true, _chromeHidden: true,
+ }));
+ return menu;
+ }
+
+ // SEts up mobile buttons for inside mobile menu
+ static setupMobileButtons(doc?: Doc, buttons?: string[]) {
+ const docProtoData: { title: string, icon: string, drag?: string, ignoreClick?: boolean, click?: string, activePen?: Doc, backgroundColor?: string, info: string, dragFactory?: Doc }[] = [
+ { title: "DASHBOARDS", icon: "bars", click: 'switchToMobileLibrary()', backgroundColor: "lightgrey", info: "Access your Dashboards from your mobile, and navigate through all of your documents. " },
+ { title: "UPLOAD", icon: "upload", click: 'openMobileUploads()', backgroundColor: "lightgrey", info: "Upload files from your mobile device so they can be accessed on Dash Web." },
+ { title: "MOBILE UPLOAD", icon: "mobile", click: 'switchToMobileUploadCollection()', backgroundColor: "lightgrey", info: "Access the collection of your mobile uploads." },
+ { title: "RECORD", icon: "microphone", click: 'openMobileAudio()', backgroundColor: "lightgrey", info: "Use your phone to record, dictate and then upload audio onto Dash Web." },
+ { title: "PRESENTATION", icon: "desktop", click: 'switchToMobilePresentation()', backgroundColor: "lightgrey", info: "Use your phone as a remote for you presentation." },
+ { title: "SETTINGS", icon: "cog", click: 'openMobileSettings()', backgroundColor: "lightgrey", info: "Change your password, log out, or manage your account security." }
+ ];
+ // returns a list of mobile buttons
+ return docProtoData.filter(d => !buttons || !buttons.includes(d.title)).map(data =>
+ this.mobileButton({
+ title: data.title,
+ _lockedPosition: true,
+ onClick: data.click ? ScriptField.MakeScript(data.click) : undefined,
+ backgroundColor: data.backgroundColor, system: true
+ },
+ [this.ficon({ ignoreClick: true, icon: data.icon, backgroundColor: "rgba(0,0,0,0)", btnType: ButtonType.ClickButton, system: true }), this.mobileTextContainer({}, [this.mobileButtonText({}, data.title), this.mobileButtonInfo({}, data.info)])])
+ );
+ }
+
+ // sets up the main document for the mobile button
+ static mobileButton = (opts: DocumentOptions, docs: Doc[]) => Docs.Create.MulticolumnDocument(docs, {
+ ...opts,
+ _removeDropProperties: new List(["dropAction"]), _nativeWidth: 900, _nativeHeight: 250, _width: 900, _height: 250, _yMargin: 15,
+ borderRounding: "5px", boxShadow: "0 0", system: true
+ }) as any as Doc
+
+ // sets up the text container for the information contained within the mobile button
+ static mobileTextContainer = (opts: DocumentOptions, docs: Doc[]) => Docs.Create.MultirowDocument(docs, {
+ ...opts,
+ _removeDropProperties: new List(["dropAction"]), _nativeWidth: 450, _nativeHeight: 250, _width: 450, _height: 250, _yMargin: 25,
+ backgroundColor: "rgba(0,0,0,0)", borderRounding: "0", boxShadow: "0 0", ignoreClick: true, system: true
+ }) as any as Doc
+
+ // Sets up the title of the button
+ static mobileButtonText = (opts: DocumentOptions, buttonTitle: string) => Docs.Create.TextDocument(buttonTitle, {
+ ...opts,
+ title: buttonTitle, _fontSize: "37px", _xMargin: 0, _yMargin: 0, ignoreClick: true, backgroundColor: "rgba(0,0,0,0)", system: true
+ }) as any as Doc
+
+ // Sets up the description of the button
+ static mobileButtonInfo = (opts: DocumentOptions, buttonInfo: string) => Docs.Create.TextDocument(buttonInfo, {
+ ...opts,
+ title: "info", _fontSize: "25px", _xMargin: 0, _yMargin: 0, ignoreClick: true, backgroundColor: "rgba(0,0,0,0)", _dimMagnitude: 2, system: true
+ }) as any as Doc
+
+
+ static setupThumbButtons(doc: Doc) {
+ const docProtoData: { title: string, icon: string, drag?: string, ignoreClick?: boolean, pointerDown?: string, pointerUp?: string, clipboard?: Doc, backgroundColor?: string, dragFactory?: Doc }[] = [
+ { title: "use pen", icon: "pen-nib", pointerUp: "resetPen()", pointerDown: 'setPen(2, this.backgroundColor)', backgroundColor: "blue" },
+ { title: "use highlighter", icon: "highlighter", pointerUp: "resetPen()", pointerDown: 'setPen(20, this.backgroundColor)', backgroundColor: "yellow" },
+ { title: "notepad", icon: "clipboard", pointerUp: "GestureOverlay.Instance.closeFloatingDoc()", pointerDown: 'GestureOverlay.Instance.openFloatingDoc(this.clipboard)', clipboard: Docs.Create.FreeformDocument([], { _width: 300, _height: 300, system: true }), backgroundColor: "orange" },
+ { title: "interpret text", icon: "font", pointerUp: "setToolglass('none')", pointerDown: "setToolglass('inktotext')", backgroundColor: "orange" },
+ { title: "ignore gestures", icon: "signature", pointerUp: "setToolglass('none')", pointerDown: "setToolglass('ignoregesture')", backgroundColor: "green" },
+ ];
+ return docProtoData.map(data => Docs.Create.FontIconDocument({
+ _nativeWidth: 10, _nativeHeight: 10, _width: 10, _height: 10, title: data.title, icon: data.icon,
+ _dropAction: data.pointerDown ? "copy" : undefined, ignoreClick: data.ignoreClick,
+ onDragStart: data.drag ? ScriptField.MakeFunction(data.drag) : undefined,
+ clipboard: data.clipboard,
+ onPointerUp: data.pointerUp ? ScriptField.MakeScript(data.pointerUp) : undefined, onPointerDown: data.pointerDown ? ScriptField.MakeScript(data.pointerDown) : undefined,
+ backgroundColor: data.backgroundColor,
+ _removeDropProperties: new List