From 4590467260a783e7d83adb20631c3b575d7e4cd3 Mon Sep 17 00:00:00 2001 From: usodhi <61431818+usodhi@users.noreply.github.com> Date: Tue, 30 Jun 2020 15:25:08 +0530 Subject: beginning sharing interface ui rework --- src/client/util/SharingManager.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx index 127ee33ce..903f6e23e 100644 --- a/src/client/util/SharingManager.tsx +++ b/src/client/util/SharingManager.tsx @@ -296,7 +296,7 @@ export default class SharingManager extends React.Component<{}> { onCloseButtonClick={action(() => this.groupToView = undefined)} /> : null} -

Manage the public link to {this.focusOn("this document...")}

+ {/*

Manage the public link to {this.focusOn("this document...")}

{!this.linkVisible ? (null) :
{this.sharingUrl}
@@ -325,10 +325,10 @@ export default class SharingManager extends React.Component<{}> { {this.sharingOptions}
-
+
*/}
-

Privately share {this.focusOn("this document")} with an individual...

+

Privately share {this.focusOn(StrCast(this.targetDoc?.title, "this document"))} with an individual...

{/*200*/} {!existOtherUsers ? "There are no other users in your database." : this.users.map(({ user, notificationDoc }) => { // can't use async here @@ -366,7 +366,7 @@ export default class SharingManager extends React.Component<{}> {
-

Privately share {this.focusOn("this document")} with a group...

+

Privately share {this.focusOn(StrCast(this.targetDoc?.title, "this document"))} with a group...

{/*200*/} {!existGroups ? "There are no groups in your database." : this.groups.map(group => { -- cgit v1.2.3-70-g09d2 From 467afe6346bf3188461721fa78eed0f9ac214da7 Mon Sep 17 00:00:00 2001 From: usodhi <61431818+usodhi@users.noreply.github.com> Date: Wed, 1 Jul 2020 16:55:51 +0530 Subject: ui changes + related functionality changes --- package-lock.json | 44 +++++-- src/client/util/GroupManager.tsx | 91 ++++++------- src/client/util/GroupMemberView.tsx | 4 +- src/client/util/SharingManager.scss | 122 +++++++++++------ src/client/util/SharingManager.tsx | 252 +++++++++++++++++++++++------------- 5 files changed, 321 insertions(+), 192 deletions(-) (limited to 'src/client/util') diff --git a/package-lock.json b/package-lock.json index f03a39df0..c4c623994 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2966,7 +2966,8 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true + "bundled": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -2984,11 +2985,13 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true + "bundled": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3001,15 +3004,18 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "concat-map": { "version": "0.0.1", - "bundled": true + "bundled": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -3112,7 +3118,8 @@ }, "inherits": { "version": "2.0.4", - "bundled": true + "bundled": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -3122,6 +3129,7 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -3134,17 +3142,20 @@ "minimatch": { "version": "3.0.4", "bundled": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "1.2.5", - "bundled": true + "bundled": true, + "optional": true }, "minipass": { "version": "2.9.0", "bundled": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -3161,6 +3172,7 @@ "mkdirp": { "version": "0.5.3", "bundled": true, + "optional": true, "requires": { "minimist": "^1.2.5" } @@ -3216,7 +3228,8 @@ }, "npm-normalize-package-bin": { "version": "1.0.1", - "bundled": true + "bundled": true, + "optional": true }, "npm-packlist": { "version": "1.4.8", @@ -3241,7 +3254,8 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true + "bundled": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -3251,6 +3265,7 @@ "once": { "version": "1.4.0", "bundled": true, + "optional": true, "requires": { "wrappy": "1" } @@ -3319,7 +3334,8 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true + "bundled": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -3349,6 +3365,7 @@ "string-width": { "version": "1.0.2", "bundled": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -3366,6 +3383,7 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -3404,11 +3422,13 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true + "bundled": true, + "optional": true }, "yallist": { "version": "3.1.1", - "bundled": true + "bundled": true, + "optional": true } } } diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx index 7c68fc2a0..e352d46a8 100644 --- a/src/client/util/GroupManager.tsx +++ b/src/client/util/GroupManager.tsx @@ -89,7 +89,8 @@ export default class GroupManager extends React.Component<{}> { /** * @returns a list of all group documents. */ - private getAllGroups(): Doc[] { + // private ? + getAllGroups(): Doc[] { const groupDoc = this.GroupManagerDoc; return groupDoc ? DocListCast(groupDoc.data) : []; } @@ -98,7 +99,8 @@ export default class GroupManager extends React.Component<{}> { * @returns a group document based on the group name. * @param groupName */ - private getGroup(groupName: string): Doc | undefined { + // private? + getGroup(groupName: string): Doc | undefined { const groupDoc = this.getAllGroups().find(group => group.groupName === groupName); return groupDoc; } @@ -172,8 +174,9 @@ export default class GroupManager extends React.Component<{}> { deleteGroup(group: Doc): boolean { if (group) { if (this.GroupManagerDoc && this.hasEditAccess(group)) { + // TODO look at this later + // SharingManager.Instance.setInternalGroupSharing(group, "Not Shared"); Doc.RemoveDocFromList(this.GroupManagerDoc, "data", group); - SharingManager.Instance.setInternalGroupSharing(group, "Not Shared"); if (group === this.currentGroup) { runInAction(() => this.currentGroup = undefined); } @@ -248,48 +251,48 @@ export default class GroupManager extends React.Component<{}> { /** * A getter that @returns the interface rendered to view an individual group. */ - private get editingInterface() { - const members: string[] = this.currentGroup ? JSON.parse(StrCast(this.currentGroup.members)) : []; - const options: UserOptions[] = this.currentGroup ? this.options.filter(option => !(JSON.parse(StrCast(this.currentGroup!.members)) as string[]).includes(option.value)) : []; - return (!this.currentGroup ? null : -
-
- {this.currentGroup.groupName} -
this.currentGroup = undefined)}> - -
+ // private get editingInterface() { + // const members: string[] = this.currentGroup ? JSON.parse(StrCast(this.currentGroup.members)) : []; + // const options: UserOptions[] = this.currentGroup ? this.options.filter(option => !(JSON.parse(StrCast(this.currentGroup!.members)) as string[]).includes(option.value)) : []; + // return (!this.currentGroup ? null : + //
+ //
+ // {this.currentGroup.groupName} + //
this.currentGroup = undefined)}> + // + //
- {this.hasEditAccess(this.currentGroup) ? -
-
- this.addMemberToGroup(this.currentGroup!, (selectedOption as UserOptions).value)} + // placeholder={"Add members"} + // value={null} + // closeMenuOnSelect={true} + // /> + //
+ // + //
: + // null} + //
+ //
+ // {members.map(member => ( + //
+ //
+ // {member} + //
+ // {this.hasEditAccess(this.currentGroup!) ? : null} + //
+ // ))} + //
+ //
+ // ); - } + // } /** * A getter that @returns the main interface for the GroupManager. @@ -307,7 +310,7 @@ export default class GroupManager extends React.Component<{}> { {this.currentGroup ? this.currentGroup = undefined} + onCloseButtonClick={action(() => this.currentGroup = undefined)} /> : null}
diff --git a/src/client/util/GroupMemberView.tsx b/src/client/util/GroupMemberView.tsx index b2d75158e..c844892b1 100644 --- a/src/client/util/GroupMemberView.tsx +++ b/src/client/util/GroupMemberView.tsx @@ -8,7 +8,7 @@ import { action } from "mobx"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import * as fa from '@fortawesome/free-solid-svg-icons'; import Select from "react-select"; -import { Doc, Opt } from "../../fields/Doc"; +import { Doc } from "../../fields/Doc"; import "./GroupMemberView.scss"; library.add(fa.faWindowClose); @@ -44,7 +44,7 @@ export default class GroupMemberView extends React.Component
- +
: null}
diff --git a/src/client/util/SharingManager.scss b/src/client/util/SharingManager.scss index fcbc05f8a..209c41651 100644 --- a/src/client/util/SharingManager.scss +++ b/src/client/util/SharingManager.scss @@ -1,9 +1,9 @@ @import "../views/globalCssVariables"; .sharing-interface { - display: flex; - flex-direction: column; - width: 730px; + // display: flex; + // flex-direction: column; + width: 600px; .dialogue-box { width: 450; @@ -16,6 +16,66 @@ .sharing-contents { display: flex; + flex-direction: column; + + .share-setup { + display: flex; + margin-bottom: 20px; + align-items: center; + height: 36; + + .user-search { + width: 90%; + } + + .permissions-select { + z-index: 1; + margin-left: -100; + border: none; + outline: none; + } + + .share-button { + height: 100%; + margin-left: 3%; + } + } + + .main-container { + display: flex; + + + .individual-container, + .group-container { + width: 50%; + + .share-title { + margin-top: 20px; + margin-bottom: 20px; + } + + .groups-list, + .users-list { + font-style: italic; + background: white; + border: 1px solid black; + padding-left: 10px; + padding-right: 10px; + overflow-y: scroll; + overflow-x: hidden; + text-align: left; + display: flex; + align-content: center; + align-items: center; + text-align: center; + justify-content: center; + // color: red; + color: black; + height: 150px; + margin: 0 2; + } + } + } button { background: $darker-alt-accent; @@ -31,37 +91,6 @@ transition: transform 0.2s; height: 25; } - - .individual-container, - .group-container { - width: 50%; - - .share-groups, - .share-individual { - margin-top: 20px; - margin-bottom: 20px; - } - - .groups-list, - .users-list { - font-style: italic; - background: white; - border: 1px solid black; - padding-left: 10px; - padding-right: 10px; - overflow-y: scroll; - overflow-x: hidden; - text-align: left; - display: flex; - align-content: center; - align-items: center; - text-align: center; - justify-content: center; - color: red; - height: 150px; - margin: 0 2; - } - } } .focus-span { @@ -69,11 +98,12 @@ } p { - font-size: 15px; + font-size: 20px; text-align: left; - font-style: italic; - padding: 0; + // font-style: italic; + // padding: 0; margin: 0 0 20px 0; + color: black; } .hr-substitute { @@ -108,9 +138,9 @@ -moz-user-select: none; -ms-user-select: none; user-select: none; - width: 700px; - min-width: 700px; - max-width: 700px; + width: 100%; + // min-width: 700px; + // max-width: 700px; text-align: left; font-style: normal; font-size: 14; @@ -118,20 +148,28 @@ padding: 0; align-items: baseline; + &:hover .padding { + white-space: unset; + } + .padding { padding: 0 10px 0 0; color: black; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + max-width: 48%; } .permissions-dropdown { - outline: none; + border: none; height: 25; } .edit-actions { display: flex; position: absolute; - right: 51.5%; + right: -10; } } diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx index 903f6e23e..491abe1dc 100644 --- a/src/client/util/SharingManager.tsx +++ b/src/client/util/SharingManager.tsx @@ -9,7 +9,6 @@ import { Utils } from "../../Utils"; import "./SharingManager.scss"; import { Id } from "../../fields/FieldSymbols"; import { observer } from "mobx-react"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { library } from '@fortawesome/fontawesome-svg-core'; import * as fa from '@fortawesome/free-solid-svg-icons'; import { DocumentView } from "../views/nodes/DocumentView"; @@ -17,8 +16,9 @@ import { SelectionManager } from "./SelectionManager"; import { DocumentManager } from "./DocumentManager"; import { CollectionView } from "../views/collections/CollectionView"; import { DictationOverlay } from "../views/DictationOverlay"; -import GroupManager from "./GroupManager"; +import GroupManager, { UserOptions } from "./GroupManager"; import GroupMemberView from "./GroupMemberView"; +import Select from "react-select"; library.add(fa.faCopy); @@ -28,18 +28,18 @@ export interface User { } export enum SharingPermissions { - None = "Not Shared", - View = "Can View", + Edit = "Can Edit", Add = "Can Add", - Edit = "Can Edit" + View = "Can View", + None = "Not Shared" } -const ColorMapping = new Map([ - [SharingPermissions.None, "red"], - [SharingPermissions.View, "maroon"], - [SharingPermissions.Add, "blue"], - [SharingPermissions.Edit, "green"] -]); +// const ColorMapping = new Map([ +// [SharingPermissions.None, "red"], +// [SharingPermissions.View, "maroon"], +// [SharingPermissions.Add, "blue"], +// [SharingPermissions.Edit, "green"] +// ]); const HierarchyMapping = new Map([ [SharingPermissions.None, "0"], @@ -54,10 +54,18 @@ const HierarchyMapping = new Map([ ]); +interface GroupOptions { + label: string; + options: UserOptions[]; +} + const SharingKey = "sharingPermissions"; const PublicKey = "publicLinkPermissions"; const DefaultColor = "black"; +const groupType = "!groupType/"; +const indType = "!indType/"; + interface ValidatedUser { user: User; notificationDoc: Doc; @@ -70,17 +78,18 @@ export default class SharingManager extends React.Component<{}> { public static Instance: SharingManager; @observable private isOpen = false; @observable private users: ValidatedUser[] = []; - @observable private groups: Doc[] = []; + // @observable private groups: Doc[] = []; @observable private targetDoc: Doc | undefined; @observable private targetDocView: DocumentView | undefined; @observable private copied = false; @observable private dialogueBoxOpacity = 1; @observable private overlayOpacity = 0.4; - @observable private groupToView: Opt; + @observable private selectedUsers: UserOptions[] | null = null; + @observable private permissions: SharingPermissions = SharingPermissions.None; - private get linkVisible() { - return this.sharingDoc ? this.sharingDoc[PublicKey] !== SharingPermissions.None : false; - } + // private get linkVisible() { + // return this.sharingDoc ? this.sharingDoc[PublicKey] !== SharingPermissions.None : false; + // } public open = (target: DocumentView) => { SelectionManager.DeselectAll(); @@ -94,7 +103,7 @@ export default class SharingManager extends React.Component<{}> { } })); - runInAction(() => this.groups = GroupManager.Instance.getAllGroupsCopy()); + // runInAction(() => this.groups = GroupManager.Instance.getAllGroups()); } public close = action(() => { @@ -145,6 +154,7 @@ export default class SharingManager extends React.Component<{}> { const users: ValidatedUser[] = this.users.filter(user => members.includes(user.user.email)); const sharingDoc = this.sharingDoc!; + console.log(sharingDoc) if (permission === SharingPermissions.None) { const metadata = sharingDoc[StrCast(group.groupName)]; if (metadata) sharingDoc[StrCast(group.groupName)] = undefined; @@ -158,7 +168,7 @@ export default class SharingManager extends React.Component<{}> { }); } - setInternalSharing = async (recipient: ValidatedUser, state: string, group: Opt) => { + setInternalSharing = async (recipient: ValidatedUser, state: string, group?: Doc) => { const { user, notificationDoc } = recipient; const target = this.targetDoc!; const manager = this.sharingDoc!; @@ -207,13 +217,13 @@ export default class SharingManager extends React.Component<{}> { if (metadata) metadata.maxPermission = HierarchyMapping.get(`${max}`); } - private setExternalSharing = (state: string) => { - const sharingDoc = this.sharingDoc; - if (!sharingDoc) { - return; - } - sharingDoc[PublicKey] = state; - } + // private setExternalSharing = (state: string) => { + // const sharingDoc = this.sharingDoc; + // if (!sharingDoc) { + // return; + // } + // sharingDoc[PublicKey] = state; + // } private get sharingUrl() { if (!this.targetDoc) { @@ -282,18 +292,57 @@ export default class SharingManager extends React.Component<{}> { return StrCast(metadata instanceof Doc ? metadata.maxPermission : metadata, SharingPermissions.None); } + @action + handleUsersChange = (selectedOptions: any) => { + this.selectedUsers = selectedOptions as UserOptions[]; + } + + @action + handlePermissionsChange = (event: React.ChangeEvent) => { + this.permissions = event.currentTarget.value as SharingPermissions; + } + + @action + share = () => { + this.selectedUsers?.forEach(user => { + if (user.value.includes(indType)) { + console.log(user); + console.log(this.users.find(u => u.user.email === user.label)); + this.setInternalSharing(this.users.find(u => u.user.email === user.label)!, this.permissions); + } + else { + this.setInternalGroupSharing(GroupManager.Instance.getGroup(user.label)!, this.permissions); + } + }); + + this.selectedUsers = null; + } + private get sharingInterface() { const existOtherUsers = this.users.length > 0; - const existGroups = this.groups.length > 0; + const existGroups = GroupManager.Instance?.getAllGroups().length > 0; // const manager = this.sharingDoc!; + const options: GroupOptions[] = GroupManager.Instance ? + [ + { + label: 'Individuals', + options: GroupManager.Instance.options.map(({ label, value }) => ({ label, value: "!indType/" + value })) + }, + { + label: 'Groups', + options: GroupManager.Instance.getAllGroups().map(({ groupName }) => ({ label: StrCast(groupName), value: "!groupType/" + StrCast(groupName) })) + } + ] + : []; + return (
- {this.groupToView ? + {GroupManager.Instance?.currentGroup ? this.groupToView = undefined)} + group={GroupManager.Instance.currentGroup} + onCloseButtonClick={action(() => GroupManager.Instance.currentGroup = undefined)} /> : null} {/*

Manage the public link to {this.focusOn("this document...")}

@@ -327,76 +376,95 @@ export default class SharingManager extends React.Component<{}> {
*/}
-
-

Privately share {this.focusOn(StrCast(this.targetDoc?.title, "this document"))} with an individual...

-
{/*200*/} - {!existOtherUsers ? "There are no other users in your database." : - this.users.map(({ user, notificationDoc }) => { // can't use async here - const userKey = user.userDocumentId; - const permissions = this.computePermissions(userKey); - const color = ColorMapping.get(permissions); - - // console.log(manager); - // const metadata = manager[userKey] as Doc; - // const usersShared = StrCast(metadata?.usersShared, ""); - // console.log(usersShared) - - - return ( -
- {user.email} - {/*
{usersShared}
*/} -
- +

Share {this.focusOn(StrCast(this.targetDoc?.title, "this document"))}

+
+ + {this.sharingOptions} + + +
+
+
+
{/*200*/} + {!existOtherUsers ? "There are no other users in your database." : + this.users.map(({ user, notificationDoc }) => { // can't use async here + const userKey = user.userDocumentId; + const permissions = this.computePermissions(userKey); + // const color = ColorMapping.get(permissions); + + // console.log(manager); + // const metadata = manager[userKey] as Doc; + // const usersShared = StrCast(metadata?.usersShared, ""); + // console.log(usersShared) + + + return permissions === SharingPermissions.None ? null : ( +
+ {user.email} + {/*
{usersShared}
*/} +
+ +
-
- ); - }) - } + ); + }) + } +
-
-
-

Privately share {this.focusOn(StrCast(this.targetDoc?.title, "this document"))} with a group...

-
{/*200*/} - {!existGroups ? "There are no groups in your database." : - this.groups.map(group => { - const permissions = this.computePermissions(StrCast(group.groupName)); - const color = ColorMapping.get(permissions); - return ( -
- {group.groupName} -
- - +
+
{/*200*/} + {!existGroups ? "There are no groups in your database." : + GroupManager.Instance.getAllGroups().map(group => { + const permissions = this.computePermissions(StrCast(group.groupName)); + // const color = ColorMapping.get(permissions); + return permissions === SharingPermissions.None ? null : ( +
+ {group.groupName} +
+ + +
-
- ); - }) + ); + }) - } + } +
+
Done
-- cgit v1.2.3-70-g09d2 From d7f2f6994ce6f2a450dff67b3595a692be9cb977 Mon Sep 17 00:00:00 2001 From: usodhi <61431818+usodhi@users.noreply.github.com> Date: Thu, 2 Jul 2020 17:23:31 +0530 Subject: restructuring and simplifying group implementation --- src/client/util/GroupManager.tsx | 34 +++++- src/client/util/SharingManager.tsx | 199 +++++++++++++++++--------------- src/client/views/nodes/DocumentView.tsx | 3 +- src/fields/Doc.ts | 8 +- src/fields/util.ts | 2 +- 5 files changed, 141 insertions(+), 105 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx index e352d46a8..c8d3be49b 100644 --- a/src/client/util/GroupManager.tsx +++ b/src/client/util/GroupManager.tsx @@ -3,11 +3,11 @@ import { observable, action, runInAction, computed } from "mobx"; import { SelectionManager } from "./SelectionManager"; import MainViewModal from "../views/MainViewModal"; import { observer } from "mobx-react"; -import { Doc, DocListCast, Opt } from "../../fields/Doc"; +import { Doc, DocListCast, Opt, DocListCastAsync } from "../../fields/Doc"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import * as fa from '@fortawesome/free-solid-svg-icons'; import { library } from "@fortawesome/fontawesome-svg-core"; -import SharingManager, { User } from "./SharingManager"; +import { User } from "./SharingManager"; import { Utils } from "../../Utils"; import * as RequestPromise from "request-promise"; import Select from 'react-select'; @@ -33,6 +33,7 @@ export default class GroupManager extends React.Component<{}> { @observable private selectedUsers: UserOptions[] | null = null; // list of users selected in the "Select users" dropdown. @observable currentGroup: Opt; // the currently selected group. private inputRef: React.RefObject = React.createRef(); // the ref for the input box. + private currentUserGroups: Doc[] = []; constructor(props: Readonly<{}>) { super(props); @@ -42,6 +43,26 @@ export default class GroupManager extends React.Component<{}> { // sets up the list of users componentDidMount() { this.populateUsers().then(resolved => runInAction(() => this.users = resolved)); + + // this.getAllGroups().forEach(group => { + // const members: string[] = JSON.parse(StrCast(group.members)); + // if (members.includes(Doc.CurrentUserEmail)) this.currentUserGroups.push(group); + // }); + DocListCastAsync(this.GroupManagerDoc?.data).then(groups => { + groups?.forEach(group => { + const members: string[] = JSON.parse(StrCast(group.members)); + if (members.includes(Doc.CurrentUserEmail)) this.currentUserGroups.push(group); + }); + }) + .finally(() => console.log(this.currentUserGroups)); + + // (this.GroupManagerDoc?.data as List).forEach(group => { + // Promise.resolve(group).then(resolvedGroup => { + // const members: string[] = JSON.parse(StrCast(resolvedGroup.members)); + // if (members.includes(Doc.CurrentUserEmail)) this.currentUserGroups.push(resolvedGroup); + // }); + // }); + } /** @@ -49,8 +70,8 @@ export default class GroupManager extends React.Component<{}> { */ populateUsers = async () => { const userList: User[] = JSON.parse(await RequestPromise.get(Utils.prepend("/getUsers"))); - const currentUserIndex = userList.findIndex(user => user.email === Doc.CurrentUserEmail); - currentUserIndex !== -1 && userList.splice(currentUserIndex, 1); + // const currentUserIndex = userList.findIndex(user => user.email === Doc.CurrentUserEmail); + // currentUserIndex !== -1 && userList.splice(currentUserIndex, 1); return userList.map(user => user.email); } @@ -61,6 +82,11 @@ export default class GroupManager extends React.Component<{}> { return this.users.map(user => ({ label: user, value: user })); } + + get groupMemberships() { + return this.currentUserGroups; + } + /** * Makes the GroupManager visible. */ diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx index 491abe1dc..b4977f8ea 100644 --- a/src/client/util/SharingManager.tsx +++ b/src/client/util/SharingManager.tsx @@ -85,7 +85,7 @@ export default class SharingManager extends React.Component<{}> { @observable private dialogueBoxOpacity = 1; @observable private overlayOpacity = 0.4; @observable private selectedUsers: UserOptions[] | null = null; - @observable private permissions: SharingPermissions = SharingPermissions.None; + @observable private permissions: SharingPermissions = SharingPermissions.Edit; // private get linkVisible() { // return this.sharingDoc ? this.sharingDoc[PublicKey] !== SharingPermissions.None : false; @@ -98,9 +98,9 @@ export default class SharingManager extends React.Component<{}> { this.targetDoc = target.props.Document; DictationOverlay.Instance.hasActiveModal = true; this.isOpen = true; - if (!this.sharingDoc) { - this.sharingDoc = new Doc; - } + // if (!this.sharingDoc) { + // this.sharingDoc = new Doc; + // } })); // runInAction(() => this.groups = GroupManager.Instance.getAllGroups()); @@ -116,13 +116,13 @@ export default class SharingManager extends React.Component<{}> { }), 500); }); - private get sharingDoc() { - return this.targetDoc ? Cast(this.targetDoc[SharingKey], Doc) as Doc : undefined; - } + // private get sharingDoc() { + // return this.targetDoc ? Cast(this.targetDoc[SharingKey], Doc) as Doc : undefined; + // } - private set sharingDoc(value: Doc | undefined) { - this.targetDoc && (this.targetDoc[SharingKey] = value); - } + // private set sharingDoc(value: Doc | undefined) { + // this.targetDoc && (this.targetDoc[SharingKey] = value); + // } constructor(props: {}) { super(props); @@ -153,76 +153,79 @@ export default class SharingManager extends React.Component<{}> { const members: string[] = JSON.parse(StrCast(group.members)); const users: ValidatedUser[] = this.users.filter(user => members.includes(user.user.email)); - const sharingDoc = this.sharingDoc!; - console.log(sharingDoc) - if (permission === SharingPermissions.None) { - const metadata = sharingDoc[StrCast(group.groupName)]; - if (metadata) sharingDoc[StrCast(group.groupName)] = undefined; - } - else { - sharingDoc[StrCast(group.groupName)] = permission; - } + const target = this.targetDoc!; + const ACL = `ACL-${StrCast(group.groupName)}`; + + target[ACL] = permission; + // const sharingDoc = this.sharingDoc!; + // if (permission === SharingPermissions.None) { + // const metadata = sharingDoc[StrCast(group.groupName)]; + // if (metadata) sharingDoc[StrCast(group.groupName)] = undefined; + // } + // else { + // sharingDoc[StrCast(group.groupName)] = permission; + // } - users.forEach(user => { - this.setInternalSharing(user, permission, group); + users.forEach(({ notificationDoc }) => { + Doc.AddDocToList(notificationDoc, storage, target); }); } - setInternalSharing = async (recipient: ValidatedUser, state: string, group?: Doc) => { + setInternalSharing = (recipient: ValidatedUser, permission: string, group?: Doc) => { const { user, notificationDoc } = recipient; const target = this.targetDoc!; - const manager = this.sharingDoc!; + // const manager = this.sharingDoc!; const key = user.userDocumentId; - let metadata = await DocCastAsync(manager[key]); - const permissions: { [key: string]: number } = metadata?.permissions ? JSON.parse(StrCast(metadata.permissions)) : {}; - permissions[StrCast(group ? group.groupName : Doc.CurrentUserEmail)] = parseInt(HierarchyMapping.get(state)!); - const max = Math.max(...Object.values(permissions)); - - // let max = 0; - // const keys: string[] = []; - // for (const [key, value] of Object.entries(permissions)) { - // if (value === max && max !== 0) { - // keys.push(key); - // } - // else if (value > max) { - // keys.splice(0, keys.length); - // keys.push(key); - // max = value; - // } - // } + const ACL = `ACL-${key}`; - switch (max) { - case 0: - if (metadata) { - const sharedAlias = (await DocCastAsync(metadata.sharedAlias))!; - Doc.RemoveDocFromList(notificationDoc, storage, sharedAlias); - manager[key] = undefined; - } - break; - - case 1: case 2: case 3: - if (!metadata) { - metadata = new Doc; - const sharedAlias = Doc.MakeAlias(target); - Doc.AddDocToList(notificationDoc, storage, sharedAlias); - metadata.sharedAlias = sharedAlias; - manager[key] = metadata; - } - metadata.permissions = JSON.stringify(permissions); - // metadata.usersShared = JSON.stringify(keys); - break; - } + // const permissions: { [key: string]: number } = target[ACL] ? JSON.parse(StrCast(target[ACL])) : {}; + + target[ACL] = permission; + + Doc.AddDocToList(notificationDoc, storage, target); - if (metadata) metadata.maxPermission = HierarchyMapping.get(`${max}`); + + // let metadata = await DocCastAsync(manager[key]); + // const permissions: { [key: string]: number } = metadata?.permissions ? JSON.parse(StrCast(metadata.permissions)) : {}; + // permissions[StrCast(group ? group.groupName : Doc.CurrentUserEmail)] = parseInt(HierarchyMapping.get(permission)!); + // const max = Math.max(...Object.values(permissions)); + + // switch (max) { + // case 0: + // // if (metadata) { + // // const sharedAlias = (await DocCastAsync(metadata.sharedAlias))!; + // // Doc.RemoveDocFromList(notificationDoc, storage, sharedAlias); + // // manager[key] = undefined; + // // } + // Doc.RemoveDocFromList(notificationDoc, storage, target); + // break; + + // case 1: case 2: case 3: + + // Doc.AddDocToList(notificationDoc, storage, target); + + // if (!metadata) { + // metadata = new Doc; + // const sharedAlias = Doc.MakeAlias(target); + // Doc.AddDocToList(notificationDoc, storage, target); + // metadata.sharedAlias = sharedAlias; + // manager[key] = metadata; + // } + // metadata.permissions = JSON.stringify(permissions); + // // metadata.usersShared = JSON.stringify(keys); + // break; + // } + + // if (metadata) metadata.maxPermission = HierarchyMapping.get(`${max}`); } - // private setExternalSharing = (state: string) => { + // private setExternalSharing = (permission: string) => { // const sharingDoc = this.sharingDoc; // if (!sharingDoc) { // return; // } - // sharingDoc[PublicKey] = state; + // sharingDoc[PublicKey] = permission; // } private get sharingUrl() { @@ -281,15 +284,21 @@ export default class SharingManager extends React.Component<{}> { } private computePermissions = (userKey: string) => { - const sharingDoc = this.sharingDoc; - if (!sharingDoc) { - return SharingPermissions.None; - } - const metadata = sharingDoc[userKey] as Doc | string; - if (!metadata) { - return SharingPermissions.None; - } - return StrCast(metadata instanceof Doc ? metadata.maxPermission : metadata, SharingPermissions.None); + // const sharingDoc = this.sharingDoc; + // if (!sharingDoc) { + // return SharingPermissions.None; + // } + // const metadata = sharingDoc[userKey] as Doc | string; + + if (!this.targetDoc) return SharingPermissions.None; + + const ACL = `ACL-${userKey}`; + const permission = StrCast(this.targetDoc[ACL]); + + // if (!metadata) { + // return SharingPermissions.None; + // } + return StrCast(this.targetDoc[ACL], SharingPermissions.None); } @action @@ -314,7 +323,6 @@ export default class SharingManager extends React.Component<{}> { this.setInternalGroupSharing(GroupManager.Instance.getGroup(user.label)!, this.permissions); } }); - this.selectedUsers = null; } @@ -377,27 +385,30 @@ export default class SharingManager extends React.Component<{}> {
*/}

Share {this.focusOn(StrCast(this.targetDoc?.title, "this document"))}

-
- - {this.sharingOptions} - - -
+ {this.targetDoc?.author !== Doc.CurrentUserEmail ? null + : +
+ + {this.sharingOptions} + + +
+ }
{/*200*/} - {!existOtherUsers ? "There are no other users in your database." : + { this.users.map(({ user, notificationDoc }) => { // can't use async here const userKey = user.userDocumentId; const permissions = this.computePermissions(userKey); @@ -434,8 +445,8 @@ export default class SharingManager extends React.Component<{}> {
{/*200*/} - {!existGroups ? "There are no groups in your database." : - GroupManager.Instance.getAllGroups().map(group => { + { + GroupManager.Instance?.getAllGroups().map(group => { const permissions = this.computePermissions(StrCast(group.groupName)); // const color = ColorMapping.get(permissions); return permissions === SharingPermissions.None ? null : ( diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 09eeaee36..21b6d8310 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1169,9 +1169,8 @@ export class DocumentView extends DocComponent(Docu } render() { - if (!(this.props.Document instanceof Doc)) return (null); if (this.props.Document[AclSym] && this.props.Document[AclSym] === AclPrivate) return (null); - if (this.props.Document.hidden) return (null); + if (!(this.props.Document instanceof Doc)) return (null); const backgroundColor = Doc.UserDoc().renderStyle === "comic" ? undefined : this.props.forcedBackgroundColor?.(this.Document) || StrCast(this.layoutDoc._backgroundColor) || StrCast(this.layoutDoc.backgroundColor) || StrCast(this.Document.backgroundColor) || this.props.backgroundColor?.(this.Document); const opacity = Cast(this.layoutDoc._opacity, "number", Cast(this.layoutDoc.opacity, "number", Cast(this.Document.opacity, "number", null))); const finalOpacity = this.props.opacity ? this.props.opacity() : opacity; diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index e4d11dd4d..7b1db1042 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -96,13 +96,13 @@ export const AclSym = Symbol("Acl"); export const AclPrivate = Symbol("AclOwnerOnly"); export const AclReadonly = Symbol("AclReadOnly"); export const AclAddonly = Symbol("AclAddonly"); -export const AclReadWrite = Symbol("AclReadWrite"); +export const AclEdit = Symbol("AclEdit"); export const UpdatingFromServer = Symbol("UpdatingFromServer"); const CachedUpdates = Symbol("Cached updates"); export function fetchProto(doc: Doc) { - if (doc.author !== Doc.CurrentUserEmail) { + if (doc.author !== Doc.CurrentUserEmail) { // storing acls for groups needs to be extended here - AclSym should store a datastructure that stores information about permissions const acl = Doc.Get(doc, "ACL", true); switch (acl) { case "ownerOnly": @@ -114,8 +114,8 @@ export function fetchProto(doc: Doc) { case "addOnly": doc[AclSym] = AclAddonly; break; - case "write": - doc[AclSym] = AclReadWrite; + case "edit": + doc[AclSym] = AclEdit; } } diff --git a/src/fields/util.ts b/src/fields/util.ts index 2dc21c987..7bb090a93 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -111,7 +111,7 @@ const layoutProps = ["panX", "panY", "width", "height", "nativeWidth", "nativeHe "chromeStatus", "viewType", "gridGap", "xMargin", "yMargin", "autoHeight"]; export function setter(target: any, in_prop: string | symbol | number, value: any, receiver: any): boolean { let prop = in_prop; - if (target[AclSym] && !_overrideAcl && !DocServer.PlaygroundFields.includes(in_prop.toString())) return true; + if (target[AclSym] && !_overrideAcl && !DocServer.PlaygroundFields.includes(in_prop.toString())) return true; // generalise to a testpermission function if (typeof prop === "string" && prop !== "__id" && prop !== "__fields" && (prop.startsWith("_") || layoutProps.includes(prop))) { if (!prop.startsWith("_")) { console.log(prop + " is deprecated - switch to _" + prop); -- cgit v1.2.3-70-g09d2 From 293c62ea3eccbeb2565960abb5ab02fabb5e20a0 Mon Sep 17 00:00:00 2001 From: usodhi <61431818+usodhi@users.noreply.github.com> Date: Fri, 3 Jul 2020 16:16:36 +0530 Subject: many changes related to adding and removing document from the notificationDoc of a user --- src/client/DocServer.ts | 2 +- src/client/util/GroupManager.tsx | 11 +- src/client/util/SharingManager.scss | 62 ++++++--- src/client/util/SharingManager.tsx | 258 +++++++++++++++++++++++------------- src/client/views/MainViewModal.scss | 5 +- src/client/views/MainViewModal.tsx | 1 - 6 files changed, 218 insertions(+), 121 deletions(-) (limited to 'src/client/util') diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index 2a7a7c59a..eac53bb02 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -31,7 +31,7 @@ export namespace DocServer { export enum WriteMode { Default = 0, //Anything goes - Playground = 1, //Playground (write own/no read) + Playground = 1, //Playground (write own/no read other updates) LiveReadonly = 2,//Live Readonly (no write/read others) LivePlayground = 3,//Live Playground (write own/read others) } diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx index c8d3be49b..220916ba7 100644 --- a/src/client/util/GroupManager.tsx +++ b/src/client/util/GroupManager.tsx @@ -7,7 +7,7 @@ import { Doc, DocListCast, Opt, DocListCastAsync } from "../../fields/Doc"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import * as fa from '@fortawesome/free-solid-svg-icons'; import { library } from "@fortawesome/fontawesome-svg-core"; -import { User } from "./SharingManager"; +import SharingManager, { User } from "./SharingManager"; import { Utils } from "../../Utils"; import * as RequestPromise from "request-promise"; import Select from 'react-select'; @@ -203,6 +203,7 @@ export default class GroupManager extends React.Component<{}> { // TODO look at this later // SharingManager.Instance.setInternalGroupSharing(group, "Not Shared"); Doc.RemoveDocFromList(this.GroupManagerDoc, "data", group); + SharingManager.Instance.removeGroup(group); if (group === this.currentGroup) { runInAction(() => this.currentGroup = undefined); } @@ -222,6 +223,7 @@ export default class GroupManager extends React.Component<{}> { const memberList: string[] = JSON.parse(StrCast(groupDoc.members)); !memberList.includes(email) && memberList.push(email); groupDoc.members = JSON.stringify(memberList); + SharingManager.Instance.shareWithAddedMember(groupDoc, email); } } @@ -234,8 +236,11 @@ export default class GroupManager extends React.Component<{}> { if (this.hasEditAccess(groupDoc)) { const memberList: string[] = JSON.parse(StrCast(groupDoc.members)); const index = memberList.indexOf(email); - index !== -1 && memberList.splice(index, 1); - groupDoc.members = JSON.stringify(memberList); + if (index !== -1) { + const user = memberList.splice(index, 1)[0]; + groupDoc.members = JSON.stringify(memberList); + SharingManager.Instance.removeMember(groupDoc, email); + } } } diff --git a/src/client/util/SharingManager.scss b/src/client/util/SharingManager.scss index 209c41651..2708876a3 100644 --- a/src/client/util/SharingManager.scss +++ b/src/client/util/SharingManager.scss @@ -4,6 +4,7 @@ // display: flex; // flex-direction: column; width: 600px; + height: 360px; .dialogue-box { width: 450; @@ -14,10 +15,23 @@ transform: translate(-20px, -20px); } + select { + text-align: justify; + text-align-last: end + } + .sharing-contents { display: flex; flex-direction: column; + .close-button { + position: absolute; + right: 1em; + top: 1em; + cursor: pointer; + z-index: 999; + } + .share-setup { display: flex; margin-bottom: 20px; @@ -33,11 +47,14 @@ margin-left: -100; border: none; outline: none; + text-align: justify; // for Edge + text-align-last: end; } .share-button { - height: 100%; - margin-left: 3%; + height: 105%; + margin-left: 2%; + background-color: #979797; } } @@ -57,8 +74,8 @@ .groups-list, .users-list { font-style: italic; - background: white; - border: 1px solid black; + background: gainsboro; + // border: 1px solid black; padding-left: 10px; padding-right: 10px; overflow-y: scroll; @@ -71,8 +88,14 @@ justify-content: center; // color: red; color: black; - height: 150px; + height: 255px; margin: 0 2; + + + .none { + font-style: italic; + + } } } } @@ -146,7 +169,7 @@ font-size: 14; font-weight: normal; padding: 0; - align-items: baseline; + align-items: center; &:hover .padding { white-space: unset; @@ -164,6 +187,7 @@ .permissions-dropdown { border: none; height: 25; + background: gainsboro; } .edit-actions { @@ -210,17 +234,17 @@ } } - .close-button { - border-radius: 5px; - margin-top: 20px; - padding: 10px 0; - background: aliceblue; - transition: 0.5s ease all; - border: 1px solid; - border-color: aliceblue; - } - - .close-button:hover { - border-color: black; - } + // .close-button { + // border-radius: 5px; + // margin-top: 20px; + // padding: 10px 0; + // background: aliceblue; + // transition: 0.5s ease all; + // border: 1px solid; + // border-color: aliceblue; + // } + + // .close-button:hover { + // border-color: black; + // } } \ No newline at end of file diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx index b4977f8ea..372b6172d 100644 --- a/src/client/util/SharingManager.tsx +++ b/src/client/util/SharingManager.tsx @@ -1,7 +1,7 @@ import { observable, runInAction, action } from "mobx"; import * as React from "react"; import MainViewModal from "../views/MainViewModal"; -import { Doc, Opt, DocCastAsync } from "../../fields/Doc"; +import { Doc, Opt, DocCastAsync, DocListCast } from "../../fields/Doc"; import { DocServer } from "../DocServer"; import { Cast, StrCast } from "../../fields/Types"; import * as RequestPromise from "request-promise"; @@ -19,6 +19,8 @@ import { DictationOverlay } from "../views/DictationOverlay"; import GroupManager, { UserOptions } from "./GroupManager"; import GroupMemberView from "./GroupMemberView"; import Select from "react-select"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { List } from "../../fields/List"; library.add(fa.faCopy); @@ -86,6 +88,8 @@ export default class SharingManager extends React.Component<{}> { @observable private overlayOpacity = 0.4; @observable private selectedUsers: UserOptions[] | null = null; @observable private permissions: SharingPermissions = SharingPermissions.Edit; + @observable private sharedUsers: ValidatedUser[] = []; + @observable private sharedGroups: Doc[] = []; // private get linkVisible() { // return this.sharingDoc ? this.sharingDoc[PublicKey] !== SharingPermissions.None : false; @@ -166,16 +170,52 @@ export default class SharingManager extends React.Component<{}> { // sharingDoc[StrCast(group.groupName)] = permission; // } + group.docsShared ? Doc.IndexOf(target, DocListCast(group.docsShared)) === -1 && (group.docsShared as List).push(target) : group.docsShared = new List([target]); + users.forEach(({ notificationDoc }) => { - Doc.AddDocToList(notificationDoc, storage, target); + + if (permission !== SharingPermissions.None) Doc.IndexOf(target, DocListCast(notificationDoc[storage])) === -1 && Doc.AddDocToList(notificationDoc, storage, target); + else Doc.IndexOf(target, DocListCast(notificationDoc[storage])) !== -1 && Doc.RemoveDocFromList(notificationDoc, storage, target); + }); } - setInternalSharing = (recipient: ValidatedUser, permission: string, group?: Doc) => { + shareWithAddedMember = (group: Doc, email: string) => { + const user: ValidatedUser = this.users.find(user => user.user.email === email)!; + + if (group.docsShared) { + DocListCast(group.docsShared).forEach(doc => Doc.IndexOf(doc, DocListCast(user.notificationDoc[storage])) === -1 && Doc.AddDocToList(user.notificationDoc, storage, doc)); + } + } + + removeMember = (group: Doc, email: string) => { + const user: ValidatedUser = this.users.find(user => user.user.email === email)!; + + if (group.docsShared) { + DocListCast(group.docsShared).forEach(doc => Doc.IndexOf(doc, DocListCast(user.notificationDoc[storage])) !== -1 && Doc.RemoveDocFromList(user.notificationDoc, storage, doc)); + } + } + + removeGroup = (group: Doc) => { + if (group.docsShared) { + DocListCast(group.docsShared).forEach(doc => { + const ACL = `ACL-${StrCast(group.groupName)}`; + doc[ACL] = "Not Shared"; + + const members: string[] = JSON.parse(StrCast(group.members)); + const users: ValidatedUser[] = this.users.filter(user => members.includes(user.user.email)); + + users.forEach(user => Doc.RemoveDocFromList(user.notificationDoc, storage, doc)); + }) + } + } + + setInternalSharing = (recipient: ValidatedUser, permission: string) => { const { user, notificationDoc } = recipient; const target = this.targetDoc!; // const manager = this.sharingDoc!; - const key = user.userDocumentId; + const key = user.email.replace('.', '_'); + // const key = user.userDocumentId; const ACL = `ACL-${key}`; @@ -183,43 +223,47 @@ export default class SharingManager extends React.Component<{}> { target[ACL] = permission; - Doc.AddDocToList(notificationDoc, storage, target); - - - // let metadata = await DocCastAsync(manager[key]); - // const permissions: { [key: string]: number } = metadata?.permissions ? JSON.parse(StrCast(metadata.permissions)) : {}; - // permissions[StrCast(group ? group.groupName : Doc.CurrentUserEmail)] = parseInt(HierarchyMapping.get(permission)!); - // const max = Math.max(...Object.values(permissions)); - - // switch (max) { - // case 0: - // // if (metadata) { - // // const sharedAlias = (await DocCastAsync(metadata.sharedAlias))!; - // // Doc.RemoveDocFromList(notificationDoc, storage, sharedAlias); - // // manager[key] = undefined; - // // } - // Doc.RemoveDocFromList(notificationDoc, storage, target); - // break; - - // case 1: case 2: case 3: - - // Doc.AddDocToList(notificationDoc, storage, target); - - // if (!metadata) { - // metadata = new Doc; - // const sharedAlias = Doc.MakeAlias(target); - // Doc.AddDocToList(notificationDoc, storage, target); - // metadata.sharedAlias = sharedAlias; - // manager[key] = metadata; - // } - // metadata.permissions = JSON.stringify(permissions); - // // metadata.usersShared = JSON.stringify(keys); - // break; - // } - // if (metadata) metadata.maxPermission = HierarchyMapping.get(`${max}`); + if (permission !== SharingPermissions.None) Doc.IndexOf(target, DocListCast(notificationDoc[storage])) === -1 && Doc.AddDocToList(notificationDoc, storage, target); + else Doc.IndexOf(target, DocListCast(notificationDoc[storage])) !== -1 && Doc.RemoveDocFromList(notificationDoc, storage, target); + } + + // let metadata = await DocCastAsync(manager[key]); + // const permissions: { [key: string]: number } = metadata?.permissions ? JSON.parse(StrCast(metadata.permissions)) : {}; + // permissions[StrCast(group ? group.groupName : Doc.CurrentUserEmail)] = parseInt(HierarchyMapping.get(permission)!); + // const max = Math.max(...Object.values(permissions)); + + // switch (max) { + // case 0: + // // if (metadata) { + // // const sharedAlias = (await DocCastAsync(metadata.sharedAlias))!; + // // Doc.RemoveDocFromList(notificationDoc, storage, sharedAlias); + // // manager[key] = undefined; + // // } + // Doc.RemoveDocFromList(notificationDoc, storage, target); + // break; + + // case 1: case 2: case 3: + + // Doc.AddDocToList(notificationDoc, storage, target); + + // if (!metadata) { + // metadata = new Doc; + // const sharedAlias = Doc.MakeAlias(target); + // Doc.AddDocToList(notificationDoc, storage, target); + // metadata.sharedAlias = sharedAlias; + // manager[key] = metadata; + // } + // metadata.permissions = JSON.stringify(permissions); + // // metadata.usersShared = JSON.stringify(keys); + // break; + // } + + // if (metadata) metadata.maxPermission = HierarchyMapping.get(`${max}`); + + // private setExternalSharing = (permission: string) => { // const sharingDoc = this.sharingDoc; // if (!sharingDoc) { @@ -345,6 +389,67 @@ export default class SharingManager extends React.Component<{}> { ] : []; + const userListContents: (JSX.Element | null)[] = this.users.map(({ user, notificationDoc }) => { // can't use async here + const userKey = user.email.replace('.', '_'); + // const userKey = user.userDocumentId; + const permissions = this.computePermissions(userKey); + // const color = ColorMapping.get(permissions); + + // console.log(manager); + // const metadata = manager[userKey] as Doc; + // const usersShared = StrCast(metadata?.usersShared, ""); + // console.log(usersShared) + + return permissions === SharingPermissions.None ? null : ( +
+ {user.email} + {/*
{usersShared}
*/} +
+ +
+
+ ); + }); + + + const groupListContents = GroupManager.Instance?.getAllGroups().map(group => { + const permissions = this.computePermissions(StrCast(group.groupName)); + // const color = ColorMapping.get(permissions); + + return permissions === SharingPermissions.None ? null : ( +
+ {group.groupName} +
+ + +
+
+ ); + }); + + const displayUserList = userListContents?.every(user => user === null); + const displayGroupList = groupListContents?.every(group => group === null); + return (
{GroupManager.Instance?.currentGroup ? @@ -385,6 +490,9 @@ export default class SharingManager extends React.Component<{}> {
*/}

Share {this.focusOn(StrCast(this.targetDoc?.title, "this document"))}

+
+ +
{this.targetDoc?.author !== Doc.CurrentUserEmail ? null :
@@ -407,69 +515,30 @@ export default class SharingManager extends React.Component<{}> { }
-
{/*200*/} +
{/*200*/} { - this.users.map(({ user, notificationDoc }) => { // can't use async here - const userKey = user.userDocumentId; - const permissions = this.computePermissions(userKey); - // const color = ColorMapping.get(permissions); - - // console.log(manager); - // const metadata = manager[userKey] as Doc; - // const usersShared = StrCast(metadata?.usersShared, ""); - // console.log(usersShared) - - - return permissions === SharingPermissions.None ? null : ( -
- {user.email} - {/*
{usersShared}
*/} -
- -
-
- ); - }) + displayUserList ? +
+ There are no users this document has been shared with. +
+ : + userListContents }
-
{/*200*/} +
{/*200*/} { - GroupManager.Instance?.getAllGroups().map(group => { - const permissions = this.computePermissions(StrCast(group.groupName)); - // const color = ColorMapping.get(permissions); - return permissions === SharingPermissions.None ? null : ( -
- {group.groupName} -
- - -
+ displayGroupList ? +
+ There are no groups this document has been shared with.
- ); - }) - + : + groupListContents }
@@ -477,7 +546,6 @@ export default class SharingManager extends React.Component<{}> {
-
Done
); } diff --git a/src/client/views/MainViewModal.scss b/src/client/views/MainViewModal.scss index f5a9ee76c..812fe540b 100644 --- a/src/client/views/MainViewModal.scss +++ b/src/client/views/MainViewModal.scss @@ -6,9 +6,10 @@ align-self: center; align-content: center; padding: 20px; - background: gainsboro; + // background: gainsboro; + background: white; border-radius: 10px; - border: 3px solid black; + border: 0.5px solid black; box-shadow: #00000044 5px 5px 10px; transform: translate(-50%, -50%); top: 50%; diff --git a/src/client/views/MainViewModal.tsx b/src/client/views/MainViewModal.tsx index a7bd5882d..c6b3532e8 100644 --- a/src/client/views/MainViewModal.tsx +++ b/src/client/views/MainViewModal.tsx @@ -22,7 +22,6 @@ export default class MainViewModal extends React.Component
Date: Fri, 3 Jul 2020 21:50:56 +0530 Subject: can now exit modal by clicking outside it --- src/client/apis/GoogleAuthenticationManager.tsx | 1 + src/client/util/GroupManager.tsx | 1 + src/client/util/GroupMemberView.tsx | 1 + src/client/util/SettingsManager.tsx | 1 + src/client/util/SharingManager.tsx | 1 + src/client/views/DictationOverlay.tsx | 1 + src/client/views/MainViewModal.tsx | 35 +++++++++++++++++++++++++ src/mobile/AudioUpload.tsx | 1 + src/mobile/ImageUpload.tsx | 1 + 9 files changed, 43 insertions(+) (limited to 'src/client/util') diff --git a/src/client/apis/GoogleAuthenticationManager.tsx b/src/client/apis/GoogleAuthenticationManager.tsx index bf4469aeb..5a2bdb13b 100644 --- a/src/client/apis/GoogleAuthenticationManager.tsx +++ b/src/client/apis/GoogleAuthenticationManager.tsx @@ -157,6 +157,7 @@ export default class GoogleAuthenticationManager extends React.Component<{}> { contents={this.renderPrompt} overlayDisplayedOpacity={0.9} dialogueBoxStyle={this.dialogueBoxStyle} + closeOnExternalClick={() => this.isOpen = false} /> ); } diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx index 220916ba7..0e710457e 100644 --- a/src/client/util/GroupManager.tsx +++ b/src/client/util/GroupManager.tsx @@ -387,6 +387,7 @@ export default class GroupManager extends React.Component<{}> { interactive={true} dialogueBoxDisplayedOpacity={this.dialogueBoxOpacity} overlayDisplayedOpacity={this.overlayOpacity} + closeOnExternalClick={this.close} /> ); } diff --git a/src/client/util/GroupMemberView.tsx b/src/client/util/GroupMemberView.tsx index c844892b1..4377a1428 100644 --- a/src/client/util/GroupMemberView.tsx +++ b/src/client/util/GroupMemberView.tsx @@ -68,6 +68,7 @@ export default class GroupMemberView extends React.Component; } diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx index 9888cce48..fa2b20095 100644 --- a/src/client/util/SettingsManager.tsx +++ b/src/client/util/SettingsManager.tsx @@ -134,6 +134,7 @@ export default class SettingsManager extends React.Component<{}> { interactive={true} dialogueBoxDisplayedOpacity={this.dialogueBoxOpacity} overlayDisplayedOpacity={this.overlayOpacity} + closeOnExternalClick={this.close} /> ); } diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx index 372b6172d..e74824581 100644 --- a/src/client/util/SharingManager.tsx +++ b/src/client/util/SharingManager.tsx @@ -559,6 +559,7 @@ export default class SharingManager extends React.Component<{}> { interactive={true} dialogueBoxDisplayedOpacity={this.dialogueBoxOpacity} overlayDisplayedOpacity={this.overlayOpacity} + closeOnExternalClick={this.close} /> ); } diff --git a/src/client/views/DictationOverlay.tsx b/src/client/views/DictationOverlay.tsx index 65770c0bb..9ed14509f 100644 --- a/src/client/views/DictationOverlay.tsx +++ b/src/client/views/DictationOverlay.tsx @@ -66,6 +66,7 @@ export class DictationOverlay extends React.Component { interactive={false} dialogueBoxStyle={dialogueBoxStyle} overlayStyle={overlayStyle} + closeOnExternalClick={this.initiateDictationFade} />); } } \ No newline at end of file diff --git a/src/client/views/MainViewModal.tsx b/src/client/views/MainViewModal.tsx index c6b3532e8..6041593b8 100644 --- a/src/client/views/MainViewModal.tsx +++ b/src/client/views/MainViewModal.tsx @@ -1,5 +1,8 @@ import * as React from 'react'; import "./MainViewModal.scss"; +import { Opt } from '../../fields/Doc'; +import { Lambda, reaction } from 'mobx'; +import { observer } from 'mobx-react'; export interface MainViewOverlayProps { isDisplayed: boolean; @@ -9,10 +12,41 @@ export interface MainViewOverlayProps { overlayStyle?: React.CSSProperties; dialogueBoxDisplayedOpacity?: number; overlayDisplayedOpacity?: number; + closeOnExternalClick?: () => void; } +@observer export default class MainViewModal extends React.Component { + private ref: React.RefObject = React.createRef(); + private displayedListenerDisposer: Opt; + + componentDidMount() { + + document.removeEventListener("click", this.close); + + this.displayedListenerDisposer = reaction(() => this.props.isDisplayed, (isDisplayed) => { + if (isDisplayed) document.addEventListener("click", this.close); + else document.removeEventListener("click", this.close); + }); + } + + componentWillUnmount() { + this.displayedListenerDisposer?.(); + document.removeEventListener("click", this.close); + } + + close = (e: MouseEvent) => { + + const { left, right, top, bottom } = this.ref.current!.getBoundingClientRect(); + + if (e.clientX === 0 && e.clientY === 0) return; // why does this happen? + if (e.clientX < left || e.clientX > right || e.clientY > bottom || e.clientY < top) { + this.props.closeOnExternalClick?.(); + } + + } + render() { const p = this.props; const dialogueOpacity = p.dialogueBoxDisplayedOpacity || 1; @@ -26,6 +60,7 @@ export default class MainViewModal extends React.Component ...(p.dialogueBoxStyle || {}), opacity: p.isDisplayed ? dialogueOpacity : 0 }} + ref={this.ref} >{p.contents}
); } diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx index 5ea626d52..6a5834f52 100644 --- a/src/mobile/ImageUpload.tsx +++ b/src/mobile/ImageUpload.tsx @@ -172,6 +172,7 @@ export class Uploader extends React.Component { interactive={true} dialogueBoxDisplayedOpacity={this.dialogueBoxOpacity} overlayDisplayedOpacity={this.overlayOpacity} + closeOnExternalClick={this.closeUpload} /> ); } -- cgit v1.2.3-70-g09d2 From 9cc98267457b0d69d4699b27d881430c169c2c2a Mon Sep 17 00:00:00 2001 From: usodhi <61431818+usodhi@users.noreply.github.com> Date: Sun, 5 Jul 2020 23:35:00 +0530 Subject: simplified exit on outside click + rotating arrow in dropdown menu --- src/client/util/GroupManager.tsx | 7 +++++++ src/client/util/GroupMemberView.tsx | 7 +++++++ src/client/views/MainViewModal.tsx | 33 +-------------------------------- 3 files changed, 15 insertions(+), 32 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx index 0e710457e..b14dcf55b 100644 --- a/src/client/util/GroupManager.tsx +++ b/src/client/util/GroupManager.tsx @@ -362,6 +362,13 @@ export default class GroupManager extends React.Component<{}> { placeholder={"Select users"} value={this.selectedUsers} closeMenuOnSelect={false} + styles={{ + dropdownIndicator: (base, state) => ({ + ...base, + transition: '0.5s all ease', + transform: state.selectProps.menuIsOpen ? 'rotate(180deg)' : undefined + }) + }} />
diff --git a/src/client/util/GroupMemberView.tsx b/src/client/util/GroupMemberView.tsx index 4377a1428..cc279b6b2 100644 --- a/src/client/util/GroupMemberView.tsx +++ b/src/client/util/GroupMemberView.tsx @@ -42,6 +42,13 @@ export default class GroupMemberView extends React.Component ({ + ...base, + transition: '0.5s all ease', + transform: state.selectProps.menuIsOpen ? 'rotate(180deg)' : undefined + }) + }} />
diff --git a/src/client/views/MainViewModal.tsx b/src/client/views/MainViewModal.tsx index 2bdd159c9..0b73a6ad7 100644 --- a/src/client/views/MainViewModal.tsx +++ b/src/client/views/MainViewModal.tsx @@ -1,7 +1,5 @@ import * as React from 'react'; import "./MainViewModal.scss"; -import { Opt } from '../../fields/Doc'; -import { Lambda, reaction } from 'mobx'; import { observer } from 'mobx-react'; export interface MainViewOverlayProps { @@ -18,35 +16,6 @@ export interface MainViewOverlayProps { @observer export default class MainViewModal extends React.Component { - private ref: React.RefObject = React.createRef(); - private displayedListenerDisposer: Opt; - - componentDidMount() { - - document.removeEventListener("pointerdown", this.close); - - this.displayedListenerDisposer = reaction(() => this.props.isDisplayed, (isDisplayed) => { - if (isDisplayed) document.addEventListener("pointerdown", this.close); - else document.removeEventListener("pointerdown", this.close); - }); - } - - componentWillUnmount() { - this.displayedListenerDisposer?.(); - document.removeEventListener("pointerdown", this.close); - } - - close = (e: PointerEvent) => { - - const { left, right, top, bottom } = this.ref.current!.getBoundingClientRect(); - - if (e.clientX === 0 && e.clientY === 0) return; // why does this happen? - if (e.clientX < left || e.clientX > right || e.clientY > bottom || e.clientY < top) { - this.props.closeOnExternalClick?.(); - } - - } - render() { const p = this.props; const dialogueOpacity = p.dialogueBoxDisplayedOpacity || 1; @@ -60,10 +29,10 @@ export default class MainViewModal extends React.Component ...(p.dialogueBoxStyle || {}), opacity: p.isDisplayed ? dialogueOpacity : 0 }} - ref={this.ref} >{p.contents}
Date: Mon, 6 Jul 2020 18:18:17 +0530 Subject: trying first implementation of storing acls --- src/client/DocServer.ts | 7 ++- src/client/util/GroupManager.tsx | 60 +++---------------- src/client/util/SharingManager.tsx | 42 +++++++------- src/client/views/DocComponent.tsx | 7 ++- src/client/views/collections/CollectionView.tsx | 8 ++- src/client/views/nodes/DocumentContentsView.tsx | 6 +- src/client/views/nodes/DocumentView.tsx | 5 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 8 ++- src/fields/Doc.ts | 67 ++++++++++++++-------- src/fields/util.ts | 60 +++++++++++++++++-- 10 files changed, 151 insertions(+), 119 deletions(-) (limited to 'src/client/util') diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index eac53bb02..860a8fd92 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -39,9 +39,10 @@ export namespace DocServer { const docsWithUpdates: { [field: string]: Set } = {}; export var PlaygroundFields: string[]; - export function setPlaygroundFields(livePlayougroundFields: string[]) { - DocServer.PlaygroundFields = livePlayougroundFields; - livePlayougroundFields.forEach(f => DocServer.setFieldWriteMode(f, DocServer.WriteMode.LivePlayground)); + export function setPlaygroundFields(livePlaygroundFields: string[]) { + console.log("here"); + DocServer.PlaygroundFields = livePlaygroundFields; + livePlaygroundFields.forEach(f => DocServer.setFieldWriteMode(f, DocServer.WriteMode.LivePlayground)); } export function setFieldWriteMode(field: string, writeMode: WriteMode) { diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx index b14dcf55b..83b206f94 100644 --- a/src/client/util/GroupManager.tsx +++ b/src/client/util/GroupManager.tsx @@ -33,7 +33,7 @@ export default class GroupManager extends React.Component<{}> { @observable private selectedUsers: UserOptions[] | null = null; // list of users selected in the "Select users" dropdown. @observable currentGroup: Opt; // the currently selected group. private inputRef: React.RefObject = React.createRef(); // the ref for the input box. - private currentUserGroups: Doc[] = []; + currentUserGroups: string[] = []; constructor(props: Readonly<{}>) { super(props); @@ -51,7 +51,7 @@ export default class GroupManager extends React.Component<{}> { DocListCastAsync(this.GroupManagerDoc?.data).then(groups => { groups?.forEach(group => { const members: string[] = JSON.parse(StrCast(group.members)); - if (members.includes(Doc.CurrentUserEmail)) this.currentUserGroups.push(group); + if (members.includes(Doc.CurrentUserEmail)) this.currentUserGroups.push(StrCast(group.groupName)); }); }) .finally(() => console.log(this.currentUserGroups)); @@ -82,11 +82,6 @@ export default class GroupManager extends React.Component<{}> { return this.users.map(user => ({ label: user, value: user })); } - - get groupMemberships() { - return this.currentUserGroups; - } - /** * Makes the GroupManager visible. */ @@ -151,6 +146,11 @@ export default class GroupManager extends React.Component<{}> { ); } + getGroupMembers(group: string | Doc): string[] { + if (group instanceof Doc) return JSON.parse(StrCast(group.members)) as string[]; + else return JSON.parse(StrCast(this.getGroup(group)!.members)) as string[]; + } + /** * @returns the members of the admin group. */ @@ -279,52 +279,6 @@ export default class GroupManager extends React.Component<{}> { this.inputRef.current.value = ""; } - /** - * A getter that @returns the interface rendered to view an individual group. - */ - // private get editingInterface() { - // const members: string[] = this.currentGroup ? JSON.parse(StrCast(this.currentGroup.members)) : []; - // const options: UserOptions[] = this.currentGroup ? this.options.filter(option => !(JSON.parse(StrCast(this.currentGroup!.members)) as string[]).includes(option.value)) : []; - // return (!this.currentGroup ? null : - //
- //
- // {this.currentGroup.groupName} - //
this.currentGroup = undefined)}> - // - //
- - // {this.hasEditAccess(this.currentGroup) ? - //
- //
- // this.buttonColour = this.inputRef.current?.value ? "black" : "#979797")} /> + - this.props.group.groupName = e.currentTarget.value} + > +
- +
- {GroupManager.Instance.hasEditAccess(this.props.group) ?
@@ -55,13 +60,18 @@ export default class GroupMemberView extends React.Component : null}
+
{members.map(member => (
{member}
- {GroupManager.Instance.hasEditAccess(this.props.group) ? : null} + {GroupManager.Instance.hasEditAccess(this.props.group) ? +
GroupManager.Instance.removeMemberFromGroup(this.props.group, member)}> + +
+ : null}
))}
@@ -75,6 +85,7 @@ export default class GroupMemberView extends React.Component; } diff --git a/src/client/util/SharingManager.scss b/src/client/util/SharingManager.scss index 2708876a3..ce23ce413 100644 --- a/src/client/util/SharingManager.scss +++ b/src/client/util/SharingManager.scss @@ -6,10 +6,10 @@ width: 600px; height: 360px; - .dialogue-box { - width: 450; - height: 300; - } + // .dialogue-box { + // width: 450; + // height: 300; + // } .overlay { transform: translate(-20px, -20px); @@ -60,11 +60,13 @@ .main-container { display: flex; - + margin-top: -10px; .individual-container, .group-container { width: 50%; + display: flex; + flex-direction: column; .share-title { margin-top: 20px; @@ -74,7 +76,7 @@ .groups-list, .users-list { font-style: italic; - background: gainsboro; + background: #e8e8e8; // border: 1px solid black; padding-left: 10px; padding-right: 10px; @@ -88,7 +90,7 @@ justify-content: center; // color: red; color: black; - height: 255px; + height: 250px; margin: 0 2; @@ -187,7 +189,6 @@ .permissions-dropdown { border: none; height: 25; - background: gainsboro; } .edit-actions { diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx index af68edab6..6c7c634eb 100644 --- a/src/client/util/SharingManager.tsx +++ b/src/client/util/SharingManager.tsx @@ -22,7 +22,7 @@ import Select from "react-select"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { List } from "../../fields/List"; -library.add(fa.faCopy); +library.add(fa.faCopy, fa.faTimes); export interface User { email: string; @@ -140,7 +140,7 @@ export default class SharingManager extends React.Component<{}> { setInternalGroupSharing = (group: Doc, permission: string) => { const members: string[] = JSON.parse(StrCast(group.members)); - const users: ValidatedUser[] = this.users.filter(user => members.includes(user.user.email)); + const users: ValidatedUser[] = this.users.filter(({ user: { email } }) => members.includes(email)); const target = this.targetDoc!; const ACL = `ACL-${StrCast(group.groupName)}`; @@ -160,8 +160,8 @@ export default class SharingManager extends React.Component<{}> { }); } - shareWithAddedMember = (group: Doc, email: string) => { - const user: ValidatedUser = this.users.find(user => user.user.email === email)!; + shareWithAddedMember = (group: Doc, emailId: string) => { + const user: ValidatedUser = this.users.find(({ user: { email } }) => email === emailId)!; if (group.docsShared) { DocListCastAsync(group.docsShared).then(docsShared => { @@ -173,8 +173,8 @@ export default class SharingManager extends React.Component<{}> { } } - removeMember = (group: Doc, email: string) => { - const user: ValidatedUser = this.users.find(user => user.user.email === email)!; + removeMember = (group: Doc, emailId: string) => { + const user: ValidatedUser = this.users.find(({ user: { email } }) => email === emailId)!; if (group.docsShared) { DocListCastAsync(group.docsShared).then(docsShared => { @@ -194,9 +194,9 @@ export default class SharingManager extends React.Component<{}> { doc[ACL] = "Not Shared"; const members: string[] = JSON.parse(StrCast(group.members)); - const users: ValidatedUser[] = this.users.filter(user => members.includes(user.user.email)); + const users: ValidatedUser[] = this.users.filter(({ user: { email } }) => members.includes(email)); - users.forEach(user => Doc.RemoveDocFromList(user.notificationDoc, storage, doc)); + users.forEach(({ notificationDoc }) => Doc.RemoveDocFromList(notificationDoc, storage, doc)); }); }); @@ -330,24 +330,6 @@ export default class SharingManager extends React.Component<{}> { ); } - private computePermissions = (userKey: string) => { - // const sharingDoc = this.sharingDoc; - // if (!sharingDoc) { - // return SharingPermissions.None; - // } - // const metadata = sharingDoc[userKey] as Doc | string; - - if (!this.targetDoc) return SharingPermissions.None; - - const ACL = `ACL-${userKey}`; - const permission = StrCast(this.targetDoc[ACL]); - - // if (!metadata) { - // return SharingPermissions.None; - // } - return StrCast(this.targetDoc[ACL], SharingPermissions.None); - } - @action handleUsersChange = (selectedOptions: any) => { this.selectedUsers = selectedOptions as UserOptions[]; @@ -381,7 +363,7 @@ export default class SharingManager extends React.Component<{}> { [ { label: 'Individuals', - options: GroupManager.Instance.options.map(({ label, value }) => ({ label, value: "!indType/" + value })) + options: this.users.map(({ user: { email } }) => ({ label: email, value: "!indType/" + email })) }, { label: 'Groups', @@ -390,10 +372,12 @@ export default class SharingManager extends React.Component<{}> { ] : []; + console.log(this.users); + const userListContents: (JSX.Element | null)[] = this.users.map(({ user, notificationDoc }) => { // can't use async here const userKey = user.email.replace('.', '_'); // const userKey = user.userDocumentId; - const permissions = this.computePermissions(userKey); + const permissions = StrCast(this.targetDoc?.[`ACL-${userKey}`], SharingPermissions.None); // const color = ColorMapping.get(permissions); // console.log(manager); @@ -401,7 +385,7 @@ export default class SharingManager extends React.Component<{}> { // const usersShared = StrCast(metadata?.usersShared, ""); // console.log(usersShared) - return permissions === SharingPermissions.None ? null : ( + return permissions === SharingPermissions.None || user.email === this.targetDoc?.author ? null : (
{ ); }); + userListContents.unshift( + ( +
+ {this.targetDoc?.author} +
+
+ Owner +
+
+
+ ) + ); const groupListContents = GroupManager.Instance?.getAllGroups().map(group => { - const permissions = this.computePermissions(StrCast(group.groupName)); + const permissions = StrCast(this.targetDoc?.[`ACL-${StrCast(group.groupName)}`], SharingPermissions.None); // const color = ColorMapping.get(permissions); return permissions === SharingPermissions.None ? null : ( @@ -492,7 +491,7 @@ export default class SharingManager extends React.Component<{}> {

Share {this.focusOn(StrCast(this.targetDoc?.title, "this document"))}

- +
{this.targetDoc?.author !== Doc.CurrentUserEmail ? null : @@ -516,6 +515,7 @@ export default class SharingManager extends React.Component<{}> { }
+
Individuals
{/*200*/} { displayUserList ? @@ -530,6 +530,7 @@ export default class SharingManager extends React.Component<{}> {
+
Groups
{/*200*/} { displayGroupList ? diff --git a/src/client/views/MainViewModal.tsx b/src/client/views/MainViewModal.tsx index 0b73a6ad7..249715511 100644 --- a/src/client/views/MainViewModal.tsx +++ b/src/client/views/MainViewModal.tsx @@ -21,7 +21,7 @@ export default class MainViewModal extends React.Component const dialogueOpacity = p.dialogueBoxDisplayedOpacity || 1; const overlayOpacity = p.overlayDisplayedOpacity || 0.4; return !p.isDisplayed ? (null) : ( -
+
Date: Tue, 14 Jul 2020 14:20:53 -0400 Subject: fixed issues with creating & using scripting boxes by making scriptFields be a function, not value, prop --- src/client/documents/Documents.ts | 2 ++ src/client/util/CurrentUserUtils.ts | 26 ++++++++++++------ src/client/views/OverlayView.scss | 2 ++ src/client/views/TemplateMenu.tsx | 7 +++-- .../views/collections/CollectionCarousel3DView.tsx | 10 +++---- .../views/collections/CollectionCarouselView.tsx | 7 +++-- .../views/collections/CollectionStackingView.tsx | 4 +-- .../views/collections/CollectionTreeView.tsx | 30 +++++++++++--------- src/client/views/collections/CollectionView.tsx | 11 +++++--- .../collectionFreeForm/CollectionFreeFormView.tsx | 9 +++--- .../collectionGrid/CollectionGridView.tsx | 2 +- .../CollectionMulticolumnView.tsx | 4 +-- .../CollectionMultirowView.tsx | 4 +-- src/client/views/nodes/DocumentView.tsx | 32 +++++++++++----------- src/fields/documentSchemas.ts | 1 - 15 files changed, 87 insertions(+), 64 deletions(-) (limited to 'src/client/util') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index a415e17c8..90cef31d9 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -136,6 +136,8 @@ export interface DocumentOptions { dontRegisterChildViews?: boolean; lookupField?: ScriptField; // script that returns the value of a field. This script is passed the rootDoc, layoutDoc, field, and container of the document. see PresBox. "onDoubleClick-rawScript"?: string; // onDoubleClick script in raw text form + "onChildDoubleClick-rawScript"?: string; // onChildDoubleClick script in raw text form + "onChildClick-rawScript"?: string // on ChildClick script in raw text form "onClick-rawScript"?: string; // onClick script in raw text form "onCheckedClick-rawScript"?: string; // onChecked script in raw text form "onCheckedClick-params"?: List; // parameter list for onChecked treeview functions diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 7a06e1bc1..ad8336e8a 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -413,7 +413,7 @@ export class CurrentUserUtils { { title: "Drag a presentation view", label: "Prezi", icon: "tv", click: 'openOnRight(Doc.UserDoc().activePresentation = getCopy(this.dragFactory, true))', drag: `Doc.UserDoc().activePresentation = getCopy(this.dragFactory,true)`, dragFactory: doc.emptyPresentation as Doc }, { title: "Drag a search box", label: "Query", icon: "search", ignoreClick: true, drag: 'Docs.Create.QueryDocument({ _width: 200, title: "an image of a cat" })' }, { title: "Drag a scripting box", label: "Script", icon: "terminal", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyScript as Doc }, - // { title: "Drag an import folder", label: "Load", icon: "cloud-upload-alt", ignoreClick: true, drag: 'Docs.Create.DirectoryImportDocument({ title: "Directory Import", _width: 400, _height: 400 })' }, + { title: "Drag an import folder", label: "Load", icon: "cloud-upload-alt", ignoreClick: true, drag: 'Docs.Create.DirectoryImportDocument({ title: "Directory Import", _width: 400, _height: 400 })' }, { title: "Drag a mobile view", label: "Phone", icon: "mobile", click: 'openOnRight(Doc.UserDoc().activeMobileMenu)', drag: 'this.dragFactory', dragFactory: doc.activeMobileMenu as Doc }, // { title: "Drag an instance of the device collection", label: "Buxton", icon: "globe-asia", ignoreClick: true, drag: 'Docs.Create.Buxton()' }, // { title: "use pen", icon: "pen-nib", click: 'activatePen(this.activeInkPen = sameDocs(this.activeInkPen, this) ? undefined : this)', backgroundColor: "blue", ischecked: `sameDocs(this.activeInkPen, this)`, activeInkPen: doc }, @@ -775,17 +775,17 @@ export class CurrentUserUtils { 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 const openInTarget = Docs.Create.ScriptingDocument(ScriptField.MakeScript( - "docCast(thisContainer.target).then((target) => {" + - " target && docCast(this.source).then((source) => { " + - " target.proto.data = new List([source || this]); " + - " }); " + - "})", - { target: Doc.name }), { title: "Click to open in target", _width: 300, _height: 200, targetScriptKey: "onChildClick" }); + "docCast(thisContainer.target).then((target) => target && (target.proto.data = new List([self]))) ", + { thisContainer: Doc.name }), { + title: "Click to open in target", _width: 300, _height: 200, + targetScriptKey: "onChildClick", + }); const openDetail = Docs.Create.ScriptingDocument(ScriptField.MakeScript( "openOnRight(self.doubleClickView)", - { target: Doc.name }), { title: "Double click to open doubleClickView", _width: 300, _height: 200, targetScriptKey: "onChildDoubleClick" }); + {}), { title: "Double click to open doubleClickView", _width: 300, _height: 200, targetScriptKey: "onChildDoubleClick" }); doc["clickFuncs-child"] = Docs.Create.TreeDocument([openInTarget, openDetail], { title: "on Child Click function templates" }); } @@ -797,14 +797,22 @@ export class CurrentUserUtils { title: "onClick", "onClick-rawScript": "console.log('click')", isTemplateDoc: true, isTemplateForField: "onClick", _width: 300, _height: 200 }, "onClick"); + const onChildClick = Docs.Create.ScriptingDocument(undefined, { + title: "onChildClick", "onChildClick-rawScript": "console.log('child click')", + isTemplateDoc: true, isTemplateForField: "onChildClick", _width: 300, _height: 200 + }, "onChildClick"); const onDoubleClick = Docs.Create.ScriptingDocument(undefined, { title: "onDoubleClick", "onDoubleClick-rawScript": "console.log('double click')", isTemplateDoc: true, isTemplateForField: "onDoubleClick", _width: 300, _height: 200 }, "onDoubleClick"); + const onChildDoubleClick = Docs.Create.ScriptingDocument(undefined, { + title: "onChildDoubleClick", "onChildDoubleClick-rawScript": "console.log('child double click')", + isTemplateDoc: true, isTemplateForField: "onChildDoubleClick", _width: 300, _height: 200 + }, "onChildDoubleClick"); const onCheckedClick = Docs.Create.ScriptingDocument(undefined, { title: "onCheckedClick", "onCheckedClick-rawScript": "console.log(heading + checked + containingTreeView)", "onCheckedClick-params": new List(["heading", "checked", "containingTreeView"]), isTemplateDoc: true, isTemplateForField: "onCheckedClick", _width: 300, _height: 200 }, "onCheckedClick"); - doc.clickFuncs = Docs.Create.TreeDocument([onClick, onDoubleClick, onCheckedClick], { title: "onClick funcs" }); + doc.clickFuncs = Docs.Create.TreeDocument([onClick, onChildClick, onDoubleClick, onCheckedClick], { title: "onClick funcs" }); } PromiseValue(Cast(doc.clickFuncs, Doc)).then(func => func && PromiseValue(func.data).then(DocListCast)); diff --git a/src/client/views/OverlayView.scss b/src/client/views/OverlayView.scss index 26c2e0e1e..09a349012 100644 --- a/src/client/views/OverlayView.scss +++ b/src/client/views/OverlayView.scss @@ -3,6 +3,8 @@ overflow: hidden; display: flex; flex-direction: column; + top: 0; + left: 0; } .overlayWindow-outerDiv, diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index 916e631d0..9fb8a227e 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -108,8 +108,9 @@ export class TemplateMenu extends React.Component { return100 = () => 100; @computed get scriptField() { - return ScriptField.MakeScript("docs.map(d => switchView(d, this))", { this: Doc.name, heading: "string", checked: "string", containingTreeView: Doc.name, firstDoc: Doc.name }, + const script = ScriptField.MakeScript("docs.map(d => switchView(d, this))", { this: Doc.name, heading: "string", checked: "string", containingTreeView: Doc.name, firstDoc: Doc.name }, { docs: new List(this.props.docViews.map(dv => dv.props.Document)) }); + return script ? () => script : undefined; } templateIsUsed = (selDoc: Doc, templateDoc: Doc) => { const template = StrCast(templateDoc.dragFactory ? Cast(templateDoc.dragFactory, Doc, null)?.title : templateDoc.title); @@ -142,8 +143,8 @@ export class TemplateMenu extends React.Component { ContainingCollectionView={undefined} docFilters={returnEmptyFilter} rootSelected={returnFalse} - onCheckedClick={this.scriptField!} - onChildClick={this.scriptField!} + onCheckedClick={this.scriptField} + onChildClick={this.scriptField} LibraryPath={emptyPath} dropAction={undefined} active={returnTrue} diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx index 8f1cd5311..8e9970ada 100644 --- a/src/client/views/collections/CollectionCarousel3DView.tsx +++ b/src/client/views/collections/CollectionCarousel3DView.tsx @@ -38,15 +38,15 @@ export class CollectionCarousel3DView extends CollectionSubView(Carousel3DDocume panelWidth = () => this.props.PanelWidth() / 3; panelHeight = () => this.props.PanelHeight() * 0.6; + onChildDoubleClick = () => ScriptCast(this.layoutDoc.onChildDoubleClick); @computed get content() { const currentIndex = NumCast(this.layoutDoc._itemIndex); const displayDoc = (childPair: { layout: Doc, data: Doc }) => { + const script = ScriptField.MakeScript("child._showCaption = 'caption'", { child: Doc.name }, { child: childPair.layout }); + const onChildClick = script && (() => script); return ; const CarouselDocument = makeInterface(documentSchema, collectionSchema); @@ -40,14 +41,16 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument) this.layoutDoc._itemIndex = (NumCast(this.layoutDoc._itemIndex) - 1 + this.childLayoutPairs.length) % this.childLayoutPairs.length; } panelHeight = () => this.props.PanelHeight() - 50; + onContentDoubleClick = () => ScriptCast(this.layoutDoc.onChildDoubleClick); + onContentClick = () => ScriptCast(this.layoutDoc.onChildClick); @computed get content() { const index = NumCast(this.layoutDoc._itemIndex); return !(this.childLayoutPairs?.[index]?.layout instanceof Doc) ? (null) : <>
this.props.childClickScript || ScriptCast(this.Document.onChildClick); } + @computed get onChildDoubleClickHandler() { return () => this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick); } addDocTab = (doc: Doc, where: string) => { if (where === "inPlace" && this.layoutDoc.isInPlaceContainer) { diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index dbd39d8df..8438248ad 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -61,8 +61,8 @@ export interface TreeViewProps { treeViewHideHeaderFields: () => boolean; treeViewPreventOpen: boolean; renderedIds: string[]; // list of document ids rendered used to avoid unending expansion of items in a cycle - onCheckedClick?: ScriptField; - onChildClick?: ScriptField; + onCheckedClick?: () => ScriptField; + onChildClick?: () => ScriptField; ignoreFields?: string[]; } @@ -76,7 +76,7 @@ export interface TreeViewProps { * treeViewExpandedView : name of field whose contents are being displayed as the document's subtree */ class TreeView extends React.Component { - private _editTitleScript: ScriptField | undefined; + private _editTitleScript: (() => ScriptField) | undefined; private _header?: React.RefObject = React.createRef(); private _treedropDisposer?: DragManager.DragDropDisposer; private _dref = React.createRef(); @@ -124,7 +124,8 @@ class TreeView extends React.Component { constructor(props: any) { super(props); - this._editTitleScript = ScriptField.MakeScript(`{setInPlace(self, 'editTitle', '${this._uniqueId}'); selectDoc(self);} `); + const script = ScriptField.MakeScript(`{setInPlace(self, 'editTitle', '${this._uniqueId}'); selectDoc(self);} `); + this._editTitleScript = script && (() => script); if (Doc.GetT(this.doc, "editTitle", "string", true) === "*") Doc.SetInPlace(this.doc, "editTitle", this._uniqueId, false); } @@ -368,13 +369,13 @@ class TreeView extends React.Component { } } - get onCheckedClick() { return this.props.onCheckedClick || ScriptCast(this.doc.onCheckedClick); } + get onCheckedClick() { return this.props.onCheckedClick || (() => ScriptCast(this.doc.onCheckedClick)); } @action bulletClick = (e: React.MouseEvent) => { - if (this.onCheckedClick && this.doc.type !== DocumentType.COL) { + if (this.onCheckedClick() && this.doc.type !== DocumentType.COL) { // this.props.document.treeViewChecked = this.props.document.treeViewChecked === "check" ? "x" : this.props.document.treeViewChecked === "x" ? undefined : "check"; - this.onCheckedClick.script.run({ + this.onCheckedClick()?.script.run({ this: this.doc.isTemplateForField && this.props.dataDoc ? this.props.dataDoc : this.doc, heading: this.props.containingCollection.title, checked: this.doc.treeViewChecked === "check" ? "x" : this.doc.treeViewChecked === "x" ? undefined : "check", @@ -388,7 +389,7 @@ class TreeView extends React.Component { @computed get renderBullet() { TraceMobx(); - const checked = this.doc.type === DocumentType.COL ? undefined : this.onCheckedClick ? (this.doc.treeViewChecked ?? "unchecked") : undefined; + const checked = this.doc.type === DocumentType.COL ? undefined : this.onCheckedClick() ? (this.doc.treeViewChecked ?? "unchecked") : undefined; return
{ treeViewPreventOpen: boolean, renderedIds: string[], libraryPath: Doc[] | undefined, - onCheckedClick: ScriptField | undefined, - onChildClick: ScriptField | undefined, + onCheckedClick?: () => ScriptField, + onChildClick?: () => ScriptField, ignoreFields: string[] | undefined ) { const viewSpecScript = Cast(containingCollection.viewSpecScript, ScriptField); @@ -658,8 +659,8 @@ class TreeView extends React.Component { export type collectionTreeViewProps = { treeViewHideTitle?: boolean; treeViewHideHeaderFields?: boolean; - onCheckedClick?: ScriptField; - onChildClick?: ScriptField; + onCheckedClick?: () => ScriptField; + onChildClick?: () => ScriptField; }; @observer @@ -797,6 +798,9 @@ export class CollectionTreeView extends CollectionSubView { console.log(e); } + onChildClick = () => { + return this.props.onChildClick?.() || ScriptCast(this.doc.onChildClick); + } render() { TraceMobx(); if (!(this.doc instanceof Doc)) return (null); @@ -839,7 +843,7 @@ export class CollectionTreeView extends CollectionSubView this.props.treeViewHideHeaderFields || BoolCast(this.doc.treeViewHideHeaderFields), BoolCast(this.doc.treeViewPreventOpen), [], this.props.LibraryPath, this.props.onCheckedClick, - this.props.onChildClick || ScriptCast(this.doc.onChildClick), this.props.ignoreFields) + this.onChildClick, this.props.ignoreFields) }
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index cbd1ac9af..5165a8f11 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -305,14 +305,16 @@ export class CollectionView extends Touchable onClicks.push({ description: `Edit ${func.name} script`, icon: "edit", event: (obj: any) => { - ScriptBox.EditButtonScript(func.name + "...", this.props.Document, func.key, obj.x, obj.y, { thisContainer: Doc.name }); + const alias = Doc.MakeAlias(this.props.Document); + DocUtils.makeCustomViewClicked(alias, undefined, func.key); + this.props.addDocTab(alias, "onRight"); } })); DocListCast(Cast(Doc.UserDoc()["clickFuncs-child"], Doc, null).data).forEach(childClick => onClicks.push({ description: `Set child ${childClick.title}`, icon: "edit", - event: () => this.props.Document[StrCast(childClick.targetScriptKey)] = ObjectField.MakeCopy(ScriptCast(childClick.data)), + event: () => Doc.GetProto(this.props.Document)[StrCast(childClick.targetScriptKey)] = ObjectField.MakeCopy(ScriptCast(childClick.data)), })); !existingOnClick && cm.addItem({ description: "OnClick...", noexpand: true, subitems: onClicks, icon: "hand-point-right" }); @@ -470,7 +472,8 @@ export class CollectionView extends Touchable script : undefined; } @computed get filterView() { TraceMobx(); @@ -523,7 +526,7 @@ export class CollectionView extends Touchable (this.props.childClickScript || ScriptCast(this.Document.onChildClick)); } + @computed get onChildDoubleClickHandler() { return () => (this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick)); } @computed get backgroundActive() { return this.layoutDoc.isBackground && (this.props.ContainingCollectionView?.active() || this.props.active()); } backgroundHalo = () => BoolCast(this.Document.useClusters); parentActive = (outsideReaction: boolean) => this.props.active(outsideReaction) || this.backgroundActive ? true : false; @@ -1151,7 +1152,7 @@ export class CollectionFreeFormView extends CollectionSubView this._layoutElements = elements || [], { fireImmediately: true, name: "doLayout" }); - const handler = (e: Event) => this.handleDragging(e, (e as CustomEvent).detail); + const handler = (e: any) => this.handleDragging(e, (e as CustomEvent).detail); document.addEventListener("dashDragging", handler); } @@ -1159,7 +1160,7 @@ export class CollectionFreeFormView extends CollectionSubView this.handleDragging(e, (e as CustomEvent).detail); + const handler = (e: any) => this.handleDragging(e, (e as CustomEvent).detail); document.removeEventListener("dashDragging", handler); } diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx index 188b88c41..b2e506dfa 100644 --- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx +++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx @@ -31,7 +31,7 @@ export class CollectionGridView extends CollectionSubView(GridSchema) { @observable private _rowHeight: Opt; // temporary store of row height to make change undoable @observable private _scroll: number = 0; // required to make sure the decorations box container updates on scroll - @computed get onChildClickHandler() { return ScriptCast(this.Document.onChildClick); } + @computed get onChildClickHandler() { return () => ScriptCast(this.Document.onChildClick); } @computed get numCols() { return NumCast(this.props.Document.gridNumCols, 10); } @computed get rowHeight() { return this._rowHeight === undefined ? NumCast(this.props.Document.gridRowHeight, 100) : this._rowHeight; } diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index cd25c21b4..402e7563d 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -202,8 +202,8 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu } - @computed get onChildClickHandler() { return ScriptCast(this.Document.onChildClick); } - @computed get onChildDoubleClickHandler() { return ScriptCast(this.Document.onChildDoubleClick); } + @computed get onChildClickHandler() { return () => ScriptCast(this.Document.onChildClick); } + @computed get onChildDoubleClickHandler() { return () => ScriptCast(this.Document.onChildDoubleClick); } addDocTab = (doc: Doc, where: string) => { diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx index 51dcdcfe6..e4ef9b436 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx @@ -202,8 +202,8 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument) } - @computed get onChildClickHandler() { return ScriptCast(this.Document.onChildClick); } - @computed get onChildDoubleClickHandler() { return ScriptCast(this.Document.onChildDoubleClick); } + @computed get onChildClickHandler() { return () => ScriptCast(this.Document.onChildClick); } + @computed get onChildDoubleClickHandler() { return () => ScriptCast(this.Document.onChildDoubleClick); } addDocTab = (doc: Doc, where: string) => { if (where === "inPlace" && this.layoutDoc.isInPlaceContainer) { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 11be4c2e7..e338d5203 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -11,7 +11,7 @@ import { InkTool } from '../../../fields/InkField'; import { listSpec } from "../../../fields/Schema"; import { SchemaHeaderField } from '../../../fields/SchemaHeaderField'; import { ScriptField } from '../../../fields/ScriptField'; -import { BoolCast, Cast, NumCast, StrCast } from "../../../fields/Types"; +import { BoolCast, Cast, NumCast, StrCast, ScriptCast } from "../../../fields/Types"; import { TraceMobx } from '../../../fields/util'; import { GestureUtils } from '../../../pen-gestures/GestureUtils'; import { emptyFunction, OmitKeys, returnOne, returnTransparent, Utils, emptyPath } from "../../../Utils"; @@ -68,10 +68,10 @@ export interface DocumentViewProps { ignoreAutoHeight?: boolean; contextMenuItems?: () => { script: ScriptField, label: string }[]; rootSelected: (outsideReaction?: boolean) => boolean; // whether the root of a template has been selected - onClick?: ScriptField; - onDoubleClick?: ScriptField; - onPointerDown?: ScriptField; - onPointerUp?: ScriptField; + onClick?: () => ScriptField; + onDoubleClick?: () => ScriptField; + onPointerDown?: () => ScriptField; + onPointerUp?: () => ScriptField; treeViewDoc?: Doc; dropAction?: dropActionType; dragDivName?: string; @@ -127,10 +127,10 @@ export class DocumentView extends DocComponent(Docu @computed get freezeDimensions() { return this.props.FreezeDimensions; } @computed get nativeWidth() { return NumCast(this.layoutDoc._nativeWidth, this.props.NativeWidth() || (this.freezeDimensions ? this.layoutDoc[WidthSym]() : 0)); } @computed get nativeHeight() { return NumCast(this.layoutDoc._nativeHeight, this.props.NativeHeight() || (this.freezeDimensions ? this.layoutDoc[HeightSym]() : 0)); } - @computed get onClickHandler() { return this.props.onClick || Cast(this.Document.onClick, ScriptField, Cast(this.layoutDoc.onClick, ScriptField, null)); } - @computed get onDoubleClickHandler() { return this.props.onDoubleClick || Cast(this.layoutDoc.onDoubleClick, ScriptField, null) || this.Document.onDoubleClick; } - @computed get onPointerDownHandler() { return this.props.onPointerDown ? this.props.onPointerDown : this.Document.onPointerDown; } - @computed get onPointerUpHandler() { return this.props.onPointerUp ? this.props.onPointerUp : this.Document.onPointerUp; } + @computed get onClickHandler() { return this.props.onClick?.() ? this.props.onClick : (() => Cast(this.Document.onClick, ScriptField, Cast(this.layoutDoc.onClick, ScriptField, null))); } + @computed get onDoubleClickHandler() { return this.props.onDoubleClick?.() ? this.props.onDoubleClick : () => (Cast(this.layoutDoc.onDoubleClick, ScriptField, null) || this.Document.onDoubleClick); } + @computed get onPointerDownHandler() { return this.props.onPointerDown?.() ? this.props.onPointerDown : () => ScriptCast(this.Document.onPointerDown) } + @computed get onPointerUpHandler() { return this.props.onPointerUp ?? (() => ScriptCast(this.Document.onPointerUp)); } NativeWidth = () => this.nativeWidth; NativeHeight = () => this.nativeHeight; @@ -293,10 +293,10 @@ export class DocumentView extends DocComponent(Docu let stopPropagate = true; let preventDefault = true; !this.props.Document.isBackground && this.props.bringToFront(this.props.Document); - if (this._doubleTap && this.props.renderDepth && !this.onClickHandler?.script) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click + if (this._doubleTap && this.props.renderDepth && !this.onClickHandler()?.script) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click if (!(e.nativeEvent as any).formattedHandled) { - if (this.onDoubleClickHandler?.script && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes("ScriptingBox")) { // bcz: hack? don't execute script if you're clicking on a scripting box itself - const func = () => this.onDoubleClickHandler.script.run({ + if (this.onDoubleClickHandler()?.script && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes("ScriptingBox")) { // bcz: hack? don't execute script if you're clicking on a scripting box itself + const func = () => this.onDoubleClickHandler()?.script.run({ this: this.layoutDoc, self: this.rootDoc, thisContainer: this.props.ContainingCollectionDoc, shiftKey: e.shiftKey @@ -316,9 +316,9 @@ export class DocumentView extends DocComponent(Docu Doc.UnBrushDoc(this.props.Document); } } - } else if (this.onClickHandler?.script && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes("ScriptingBox")) { // bcz: hack? don't execute script if you're clicking on a scripting box itself + } else if (this.onClickHandler()?.script && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes("ScriptingBox")) { // bcz: hack? don't execute script if you're clicking on a scripting box itself //SelectionManager.DeselectAll(); - const func = () => this.onClickHandler.script.run({ + const func = () => this.onClickHandler()?.script.run({ this: this.layoutDoc, self: this.rootDoc, thisContainer: this.props.ContainingCollectionDoc, shiftKey: e.shiftKey @@ -553,8 +553,8 @@ export class DocumentView extends DocComponent(Docu onPointerUp = (e: PointerEvent): void => { this.cleanUpInteractions(); - if (this.onPointerUpHandler?.script && !InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) { - this.onPointerUpHandler.script.run({ self: this.rootDoc, this: this.layoutDoc }, console.log); + if (this.onPointerUpHandler()?.script && !InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) { + this.onPointerUpHandler()?.script.run({ self: this.rootDoc, this: this.layoutDoc }, console.log); document.removeEventListener("pointerup", this.onPointerUp); return; } diff --git a/src/fields/documentSchemas.ts b/src/fields/documentSchemas.ts index 61a37ef8a..9dda644f3 100644 --- a/src/fields/documentSchemas.ts +++ b/src/fields/documentSchemas.ts @@ -3,7 +3,6 @@ import { ScriptField } from "./ScriptField"; import { Doc } from "./Doc"; import { DateField } from "./DateField"; import { SchemaHeaderField } from "./SchemaHeaderField"; -import { Schema } from "prosemirror-model"; export const documentSchema = createSchema({ // content properties -- cgit v1.2.3-70-g09d2 From d97a4f470456a89597017d643bf5139a2f8ef3e0 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 14 Jul 2020 15:00:54 -0400 Subject: possible fix for dragging icons problem caused by setisdragging invalidating the dragged element --- src/client/util/DragManager.ts | 2 +- src/client/views/collections/CollectionTreeView.tsx | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 5f34509a1..40467abaf 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -330,7 +330,6 @@ export namespace DragManager { DragManager.Root().appendChild(dragDiv); } dragLabel.style.display = ""; - SnappingManager.SetIsDragging(true); const scaleXs: number[] = []; const scaleYs: number[] = []; const xs: number[] = []; @@ -394,6 +393,7 @@ export namespace DragManager { set[i].hasAttribute("style") && ((set[i] as any).style.pointerEvents = "none"); } + SnappingManager.SetIsDragging(true); dragDiv.appendChild(dragElement); return dragElement; }); diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 8438248ad..eb355fa2b 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -405,6 +405,7 @@ class TreeView extends React.Component { contextMenuItems = () => [{ script: ScriptField.MakeFunction(`DocFocus(self)`)!, label: "Focus" }]; truncateTitleWidth = () => NumCast(this.props.treeViewDoc.treeViewTruncateTitleWidth, 0); showTitleEdit = () => ["*", this._uniqueId].includes(Doc.GetT(this.doc, "editTitle", "string", true) || ""); + onChildClick = () => this.props.onChildClick?.() ?? (this._editTitleScript?.() || ScriptCast(this.doc.editTitleScript)); /** * Renders the EditableView title element for placement into the tree. */ @@ -438,7 +439,7 @@ class TreeView extends React.Component { addDocTab={this.props.addDocTab} rootSelected={returnTrue} pinToPres={emptyFunction} - onClick={this.props.onChildClick || this._editTitleScript} + onClick={this.onChildClick} dropAction={this.props.dropAction} moveDocument={this.move} removeDocument={this.removeDoc} -- cgit v1.2.3-70-g09d2 From a88c5f551347c934686327bdfa4070084ccfc1ef Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 14 Jul 2020 15:35:16 -0400 Subject: proper fix for onClickHandlers so they don't invalidate things when they haven't changed. --- src/client/util/DragManager.ts | 2 +- src/client/views/nodes/DocumentView.tsx | 46 +++++++++++++++++---------------- 2 files changed, 25 insertions(+), 23 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 40467abaf..5f34509a1 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -330,6 +330,7 @@ export namespace DragManager { DragManager.Root().appendChild(dragDiv); } dragLabel.style.display = ""; + SnappingManager.SetIsDragging(true); const scaleXs: number[] = []; const scaleYs: number[] = []; const xs: number[] = []; @@ -393,7 +394,6 @@ export namespace DragManager { set[i].hasAttribute("style") && ((set[i] as any).style.pointerEvents = "none"); } - SnappingManager.SetIsDragging(true); dragDiv.appendChild(dragElement); return dragElement; }); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index b118ec243..7d9c4da87 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -127,12 +127,14 @@ export class DocumentView extends DocComponent(Docu @computed get freezeDimensions() { return this.props.FreezeDimensions; } @computed get nativeWidth() { return NumCast(this.layoutDoc._nativeWidth, this.props.NativeWidth() || (this.freezeDimensions ? this.layoutDoc[WidthSym]() : 0)); } @computed get nativeHeight() { return NumCast(this.layoutDoc._nativeHeight, this.props.NativeHeight() || (this.freezeDimensions ? this.layoutDoc[HeightSym]() : 0)); } - @computed get onClickHandler() { return this.props.onClick?.() ? this.props.onClick : (() => Cast(this.Document.onClick, ScriptField, Cast(this.layoutDoc.onClick, ScriptField, null))); } - @computed get onDoubleClickHandler() { return this.props.onDoubleClick?.() ? this.props.onDoubleClick : () => (Cast(this.layoutDoc.onDoubleClick, ScriptField, null) || this.Document.onDoubleClick); } - @computed get onPointerDownHandler() { return this.props.onPointerDown?.() ? this.props.onPointerDown : () => ScriptCast(this.Document.onPointerDown) } - @computed get onPointerUpHandler() { return this.props.onPointerUp ?? (() => ScriptCast(this.Document.onPointerUp)); } + @computed get onClickHandler() { return this.props.onClick?.() ?? Cast(this.Document.onClick, ScriptField, Cast(this.layoutDoc.onClick, ScriptField, null)); } + @computed get onDoubleClickHandler() { return this.props.onDoubleClick?.() || (Cast(this.layoutDoc.onDoubleClick, ScriptField, null) || this.Document.onDoubleClick); } + @computed get onPointerDownHandler() { return this.props.onPointerDown?.() || ScriptCast(this.Document.onPointerDown) } + @computed get onPointerUpHandler() { return this.props.onPointerUp?.() || ScriptCast(this.Document.onPointerUp); } NativeWidth = () => this.nativeWidth; NativeHeight = () => this.nativeHeight; + onClickFunc = () => this.onClickHandler; + onDoubleClickFunc = () => this.onDoubleClickHandler; private _firstX: number = -1; private _firstY: number = -1; @@ -293,10 +295,10 @@ export class DocumentView extends DocComponent(Docu let stopPropagate = true; let preventDefault = true; !this.props.Document.isBackground && this.props.bringToFront(this.props.Document); - if (this._doubleTap && this.props.renderDepth && !this.onClickHandler()?.script) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click + if (this._doubleTap && this.props.renderDepth && !this.onClickHandler?.script) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click if (!(e.nativeEvent as any).formattedHandled) { - if (this.onDoubleClickHandler()?.script && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes("ScriptingBox")) { // bcz: hack? don't execute script if you're clicking on a scripting box itself - const func = () => this.onDoubleClickHandler()?.script.run({ + if (this.onDoubleClickHandler?.script && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes("ScriptingBox")) { // bcz: hack? don't execute script if you're clicking on a scripting box itself + const func = () => this.onDoubleClickHandler?.script.run({ this: this.layoutDoc, self: this.rootDoc, thisContainer: this.props.ContainingCollectionDoc, shiftKey: e.shiftKey @@ -316,9 +318,9 @@ export class DocumentView extends DocComponent(Docu Doc.UnBrushDoc(this.props.Document); } } - } else if (this.onClickHandler()?.script && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes("ScriptingBox")) { // bcz: hack? don't execute script if you're clicking on a scripting box itself + } else if (this.onClickHandler?.script && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes("ScriptingBox")) { // bcz: hack? don't execute script if you're clicking on a scripting box itself //SelectionManager.DeselectAll(); - const func = () => this.onClickHandler()?.script.run({ + const func = () => this.onClickHandler?.script.run({ this: this.layoutDoc, self: this.rootDoc, thisContainer: this.props.ContainingCollectionDoc, shiftKey: e.shiftKey @@ -379,7 +381,7 @@ export class DocumentView extends DocComponent(Docu this._downX = touch.clientX; this._downY = touch.clientY; if (!e.nativeEvent.cancelBubble) { - if ((this.active || this.layoutDoc.onDragStart || this.onClickHandler()) && !e.ctrlKey && !this.layoutDoc.lockedPosition && !this.layoutDoc.inOverlay) e.stopPropagation(); + if ((this.active || this.layoutDoc.onDragStart || this.onClickHandler) && !e.ctrlKey && !this.layoutDoc.lockedPosition && !this.layoutDoc.inOverlay) e.stopPropagation(); this.removeMoveListeners(); this.addMoveListeners(); this.removeEndListeners(); @@ -394,11 +396,11 @@ export class DocumentView extends DocComponent(Docu if (e.cancelBubble && this.active) { this.removeMoveListeners(); } - else if (!e.cancelBubble && (SelectionManager.IsSelected(this, true) || this.props.parentActive(true) || this.layoutDoc.onDragStart || this.onClickHandler()) && !this.layoutDoc.lockedPosition && !this.layoutDoc.inOverlay) { + else if (!e.cancelBubble && (SelectionManager.IsSelected(this, true) || this.props.parentActive(true) || this.layoutDoc.onDragStart || this.onClickHandler) && !this.layoutDoc.lockedPosition && !this.layoutDoc.inOverlay) { const touch = me.touchEvent.changedTouches.item(0); if (touch && (Math.abs(this._downX - touch.clientX) > 3 || Math.abs(this._downY - touch.clientY) > 3)) { - if (!e.altKey && (!this.topMost || this.layoutDoc.onDragStart || this.onClickHandler())) { + if (!e.altKey && (!this.topMost || this.layoutDoc.onDragStart || this.onClickHandler)) { this.cleanUpInteractions(); this.startDragging(this._downX, this._downY, this.Document.dropAction ? this.Document.dropAction as any : e.ctrlKey || e.altKey ? "alias" : undefined); } @@ -511,7 +513,7 @@ export class DocumentView extends DocComponent(Docu } this._downX = e.clientX; this._downY = e.clientY; - if ((!e.nativeEvent.cancelBubble || this.onClickHandler() || this.layoutDoc.onDragStart) && + if ((!e.nativeEvent.cancelBubble || this.onClickHandler || this.layoutDoc.onDragStart) && // if this is part of a template, let the event go up to the tempalte root unless right/ctrl clicking !((this.props.Document.rootDocument) && !(e.ctrlKey || e.button > 0))) { if ((this.active || this.layoutDoc.onDragStart) && @@ -539,7 +541,7 @@ export class DocumentView extends DocComponent(Docu } else if (!e.cancelBubble && (SelectionManager.IsSelected(this, true) || this.props.parentActive(true) || this.layoutDoc.onDragStart) && !this.layoutDoc.lockedPosition && !this.layoutDoc.inOverlay) { if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3) { - if (!e.altKey && (!this.topMost || this.layoutDoc.onDragStart || this.onClickHandler()) && (e.buttons === 1 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE))) { + if (!e.altKey && (!this.topMost || this.layoutDoc.onDragStart || this.onClickHandler) && (e.buttons === 1 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE))) { document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); this.startDragging(this._downX, this._downY, ((e.ctrlKey || e.altKey) && "alias") || (this.props.dropAction || this.Document.dropAction || undefined) as dropActionType); @@ -553,8 +555,8 @@ export class DocumentView extends DocComponent(Docu onPointerUp = (e: PointerEvent): void => { this.cleanUpInteractions(); - if (this.onPointerUpHandler()?.script && !InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) { - this.onPointerUpHandler()?.script.run({ self: this.rootDoc, this: this.layoutDoc }, console.log); + if (this.onPointerUpHandler?.script && !InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) { + this.onPointerUpHandler?.script.run({ self: this.rootDoc, this: this.layoutDoc }, console.log); document.removeEventListener("pointerup", this.onPointerUp); return; } @@ -587,7 +589,7 @@ export class DocumentView extends DocComponent(Docu @undoBatch toggleLinkButtonBehavior = (): void => { - if (this.Document.isLinkButton || this.onClickHandler() || this.Document.ignoreClick) { + if (this.Document.isLinkButton || this.onClickHandler || this.Document.ignoreClick) { this.Document.isLinkButton = false; const first = DocListCast(this.Document.links).find(d => d instanceof Doc); first && (first.hidden = false); @@ -782,7 +784,7 @@ export class DocumentView extends DocComponent(Docu onClicks.push({ description: this.Document.ignoreClick ? "Select" : "Do Nothing", event: () => this.Document.ignoreClick = !this.Document.ignoreClick, icon: this.Document.ignoreClick ? "unlock" : "lock" }); onClicks.push({ description: this.Document.isLinkButton ? "Remove Follow Behavior" : "Follow Link in Place", event: this.toggleFollowInPlace, icon: "concierge-bell" }); onClicks.push({ description: this.Document.isLinkButton ? "Remove Follow Behavior" : "Follow Link on Right", event: this.toggleFollowOnRight, icon: "concierge-bell" }); - onClicks.push({ description: this.Document.isLinkButton || this.onClickHandler() ? "Remove Click Behavior" : "Follow Link", event: this.toggleLinkButtonBehavior, icon: "concierge-bell" }); + onClicks.push({ description: this.Document.isLinkButton || this.onClickHandler ? "Remove Click Behavior" : "Follow Link", event: this.toggleLinkButtonBehavior, icon: "concierge-bell" }); onClicks.push({ description: "Edit onClick Script", event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this.props.Document, undefined, "onClick"), "edit onClick"), icon: "edit" }); !existingOnClick && cm.addItem({ description: "OnClick...", noexpand: true, subitems: onClicks, icon: "hand-point-right" }); @@ -1070,7 +1072,7 @@ export class DocumentView extends DocComponent(Docu ChromeHeight={this.chromeHeight} isSelected={this.isSelected} select={this.select} - onClick={this.onClickHandler} + onClick={this.onClickFunc} layoutKey={this.finalLayoutKey} /> {this.layoutDoc.hideAllLinks ? (null) : this.allAnchors} {/* {this.allAnchors} */} @@ -1141,13 +1143,13 @@ export class DocumentView extends DocComponent(Docu ChromeHeight={this.chromeHeight} isSelected={this.isSelected} select={this.select} - onClick={this.onClickHandler} + onClick={this.onClickFunc} layoutKey={this.finalLayoutKey} />
); const titleView = (!showTitle ? (null) :
(Docu fontFamily: StrCast(this.Document._fontFamily, "inherit"), fontSize: Cast(this.Document._fontSize, "string", null) }}> - {this.onClickHandler() && this.props.ContainingCollectionView?.props.Document._viewType === CollectionViewType.Time ? <> + {this.onClickHandler && this.props.ContainingCollectionView?.props.Document._viewType === CollectionViewType.Time ? <> {this.innards}
: -- cgit v1.2.3-70-g09d2 From 9fae8d59b6dfaa0641941cd59aaa21ed271d6586 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 14 Jul 2020 15:36:06 -0400 Subject: from last --- src/client/util/CurrentUserUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client/util') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index ad8336e8a..e0cb90b46 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -413,7 +413,7 @@ export class CurrentUserUtils { { title: "Drag a presentation view", label: "Prezi", icon: "tv", click: 'openOnRight(Doc.UserDoc().activePresentation = getCopy(this.dragFactory, true))', drag: `Doc.UserDoc().activePresentation = getCopy(this.dragFactory,true)`, dragFactory: doc.emptyPresentation as Doc }, { title: "Drag a search box", label: "Query", icon: "search", ignoreClick: true, drag: 'Docs.Create.QueryDocument({ _width: 200, title: "an image of a cat" })' }, { title: "Drag a scripting box", label: "Script", icon: "terminal", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyScript as Doc }, - { title: "Drag an import folder", label: "Load", icon: "cloud-upload-alt", ignoreClick: true, drag: 'Docs.Create.DirectoryImportDocument({ title: "Directory Import", _width: 400, _height: 400 })' }, + // { title: "Drag an import folder", label: "Load", icon: "cloud-upload-alt", ignoreClick: true, drag: 'Docs.Create.DirectoryImportDocument({ title: "Directory Import", _width: 400, _height: 400 })' }, { title: "Drag a mobile view", label: "Phone", icon: "mobile", click: 'openOnRight(Doc.UserDoc().activeMobileMenu)', drag: 'this.dragFactory', dragFactory: doc.activeMobileMenu as Doc }, // { title: "Drag an instance of the device collection", label: "Buxton", icon: "globe-asia", ignoreClick: true, drag: 'Docs.Create.Buxton()' }, // { title: "use pen", icon: "pen-nib", click: 'activatePen(this.activeInkPen = sameDocs(this.activeInkPen, this) ? undefined : this)', backgroundColor: "blue", ischecked: `sameDocs(this.activeInkPen, this)`, activeInkPen: doc }, -- cgit v1.2.3-70-g09d2 From 866561aa20aff0f570d31edf64eae36cd2d35279 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 14 Jul 2020 17:27:19 -0400 Subject: fixed onClickHandler stuff to use functions properly. fixed several linking to annotations/pushpins problems. --- src/client/documents/Documents.ts | 8 +- src/client/util/DocumentManager.ts | 4 +- src/client/util/LinkManager.ts | 11 ++- src/client/util/SettingsManager.tsx | 4 +- src/client/views/DocumentButtonBar.tsx | 2 +- src/client/views/MetadataEntryMenu.tsx | 96 ++++++---------------- src/client/views/collections/CollectionView.tsx | 7 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 10 +-- .../collectionFreeForm/FormatShapePane.tsx | 2 +- .../collectionFreeForm/InkOptionsMenu.tsx | 2 +- .../collectionGrid/CollectionGridView.tsx | 2 +- .../CollectionMulticolumnView.tsx | 5 +- .../CollectionMultirowView.tsx | 4 +- src/client/views/linking/LinkMenuGroup.tsx | 4 +- src/client/views/linking/LinkMenuItem.tsx | 5 +- src/client/views/nodes/DocumentLinksButton.tsx | 3 - src/client/views/nodes/DocumentView.tsx | 17 ++-- src/client/views/nodes/FieldView.tsx | 2 +- .../views/nodes/formattedText/RichTextMenu.tsx | 2 +- src/fields/documentSchemas.ts | 3 + 20 files changed, 78 insertions(+), 115 deletions(-) (limited to 'src/client/util') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 90cef31d9..1fd533b62 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -102,6 +102,8 @@ export interface DocumentOptions { childLayoutTemplate?: Doc; // template for collection to use to render its children (see PresBox or Buxton layout in tree view) childLayoutString?: string; // template string for collection to use to render its children hideFilterView?: boolean; // whether to hide the filter popout on collections + hideLinkButton?: boolean; // whether the blue link counter button should be hidden + hideAllLinks?: boolean; // whether all individual blue anchor dots should be hidden _columnsHideIfEmpty?: boolean; // whether stacking view column headings should be hidden isTemplateForField?: string; // the field key for which the containing document is a rendering template isTemplateDoc?: boolean; @@ -137,7 +139,7 @@ export interface DocumentOptions { lookupField?: ScriptField; // script that returns the value of a field. This script is passed the rootDoc, layoutDoc, field, and container of the document. see PresBox. "onDoubleClick-rawScript"?: string; // onDoubleClick script in raw text form "onChildDoubleClick-rawScript"?: string; // onChildDoubleClick script in raw text form - "onChildClick-rawScript"?: string // on ChildClick script in raw text form + "onChildClick-rawScript"?: string; // on ChildClick script in raw text form "onClick-rawScript"?: string; // onClick script in raw text form "onCheckedClick-rawScript"?: string; // onChecked script in raw text form "onCheckedClick-params"?: List; // parameter list for onChecked treeview functions @@ -779,7 +781,7 @@ export namespace Docs { export function FontIconDocument(options?: DocumentOptions) { - return InstanceFromProto(Prototypes.get(DocumentType.FONTICON), undefined, { ...(options || {}) }); + return InstanceFromProto(Prototypes.get(DocumentType.FONTICON), undefined, { hideLinkButton: true, ...(options || {}) }); } export function PresElementBoxDocument(options?: DocumentOptions) { @@ -912,6 +914,8 @@ export namespace DocUtils { if (target.doc === Doc.UserDoc()) return undefined; const linkDoc = Docs.Create.LinkDocument(source, target, { linkRelationship, layoutKey: "layout_linkView", description }, id); + linkDoc.linkDisplay = true; + linkDoc.hideAnhors = true; linkDoc.layout_linkView = Cast(Cast(Doc.UserDoc()["template-button-link"], Doc, null).dragFactory, Doc, null); Doc.GetProto(linkDoc).title = ComputedField.MakeFunction('self.anchor1?.title +" (" + (self.linkRelationship||"to") +") " + self.anchor2?.title'); diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 1fa5faeb3..b66e7fdc4 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -146,7 +146,7 @@ export class DocumentManager { }; const docView = getFirstDocView(targetDoc, originatingDoc); let annotatedDoc = await Cast(targetDoc.annotationOn, Doc); - if (annotatedDoc && !linkDoc?.isPushpin) { + if (annotatedDoc && !targetDoc?.isPushpin) { const first = getFirstDocView(annotatedDoc); if (first) { annotatedDoc = first.props.Document; @@ -156,7 +156,7 @@ export class DocumentManager { } } if (docView) { // we have a docView already and aren't forced to create a new one ... just focus on the document. TODO move into view if necessary otherwise just highlight? - if (linkDoc?.isPushpin) docView.props.Document.hidden = !docView.props.Document.hidden; + if (originatingDoc?.isPushpin) docView.props.Document.hidden = !docView.props.Document.hidden; else { docView.props.Document.hidden && (docView.props.Document.hidden = undefined); docView.props.focus(docView.props.Document, willZoom, undefined, focusAndFinish); diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts index 50f3fc1d6..974744344 100644 --- a/src/client/util/LinkManager.ts +++ b/src/client/util/LinkManager.ts @@ -63,12 +63,17 @@ export class LinkManager { } // finds all links that contain the given anchor - public getAllRelatedLinks(anchor: Doc): Doc[] { + public getAllDirectLinks(anchor: Doc): Doc[] { const related = LinkManager.Instance.getAllLinks().filter(link => { const protomatch1 = Doc.AreProtosEqual(anchor, Cast(link.anchor1, Doc, null)); const protomatch2 = Doc.AreProtosEqual(anchor, Cast(link.anchor2, Doc, null)); return protomatch1 || protomatch2 || Doc.AreProtosEqual(link, anchor); }); + return related; + } + // finds all links that contain the given anchor + public getAllRelatedLinks(anchor: Doc): Doc[] { + const related = LinkManager.Instance.getAllDirectLinks(anchor); DocListCast(anchor[Doc.LayoutFieldKey(anchor) + "-annotations"]).map(anno => { related.push(...LinkManager.Instance.getAllRelatedLinks(anno)); }); @@ -208,4 +213,6 @@ export class LinkManager { } Scripting.addGlobal(function links(doc: any) { return new List(LinkManager.Instance.getAllRelatedLinks(doc)); }, - "creates a link to inputted document", "(doc: any)"); \ No newline at end of file + "returns all the links to the document or its annotations", "(doc: any)"); +Scripting.addGlobal(function directLinks(doc: any) { return new List(LinkManager.Instance.getAllDirectLinks(doc)); }, + "returns all the links directly to the document", "(doc: any)"); \ No newline at end of file diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx index f7ca3942b..981ee698d 100644 --- a/src/client/util/SettingsManager.tsx +++ b/src/client/util/SettingsManager.tsx @@ -87,11 +87,11 @@ export default class SettingsManager extends React.Component<{}> { } @action googleAuthorize = (event: any) => { - GoogleAuthenticationManager.Instance.fetchOrGenerateAccessToken(true) + GoogleAuthenticationManager.Instance.fetchOrGenerateAccessToken(true); } @action hypothesisAuthorize = (event: any) => { - HypothesisAuthenticationManager.Instance.fetchAccessToken(true) + HypothesisAuthenticationManager.Instance.fetchAccessToken(true); } private get settingsInterface() { diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index c188618f4..927c192cd 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -208,7 +208,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV const view0 = this.view0; return !view0 ? (null) :
this.props.views().filter(dv => dv).map(dv => dv!.props.Document)} suggestWithFunction /> /* tfs: @bcz This might need to be the data document? */}> + content={ dv).map(dv => dv!.props.Document)} suggestWithFunction /> /* tfs: @bcz This might need to be the data document? */}>
e.stopPropagation()} > {}
diff --git a/src/client/views/MetadataEntryMenu.tsx b/src/client/views/MetadataEntryMenu.tsx index b0752ffb2..ca8a6e1d7 100644 --- a/src/client/views/MetadataEntryMenu.tsx +++ b/src/client/views/MetadataEntryMenu.tsx @@ -3,14 +3,14 @@ import "./MetadataEntryMenu.scss"; import { observer } from 'mobx-react'; import { observable, action, runInAction, trace, computed, IReactionDisposer, reaction } from 'mobx'; import { KeyValueBox } from './nodes/KeyValueBox'; -import { Doc, Field, DocListCastAsync } from '../../fields/Doc'; +import { Doc, Field, DocListCastAsync, DocListCast } from '../../fields/Doc'; import * as Autosuggest from 'react-autosuggest'; -import { undoBatch } from '../util/UndoManager'; +import { undoBatch, UndoManager } from '../util/UndoManager'; import { emptyFunction, emptyPath } from '../../Utils'; export type DocLike = Doc | Doc[] | Promise | Promise; export interface MetadataEntryProps { - docs: DocLike | (() => DocLike); + docs: Doc[]; onError?: () => boolean; suggestWithFunction?: boolean; } @@ -39,26 +39,13 @@ export class MetadataEntryMenu extends React.Component{ let onProto: boolean = false; let value: string | undefined = undefined; let docs = this.props.docs; - if (typeof docs === "function") { - if (this.props.suggestWithFunction) { - docs = docs(); - } else { - return; - } - } - docs = await docs; - if (docs instanceof Doc) { - await docs[this._currentKey]; - value = Field.toKeyValueString(docs, this._currentKey); - } else { - for (const doc of docs) { - const v = await doc[this._currentKey]; - onProto = onProto || !Object.keys(doc).includes(this._currentKey); - if (field === null) { - field = v; - } else if (v !== field) { - value = "multiple values"; - } + for (const doc of docs) { + const v = await doc[this._currentKey]; + onProto = onProto || !Object.keys(doc).includes(this._currentKey); + if (field === null) { + field = v; + } else if (v !== field) { + value = "multiple values"; } } if (value === undefined) { @@ -86,27 +73,16 @@ export class MetadataEntryMenu extends React.Component{ const script = KeyValueBox.CompileKVPScript(this._currentValue); if (!script) return; - let doc = this.props.docs; - if (typeof doc === "function") { - doc = doc(); - } - doc = await doc; - - let success: boolean; - if (doc instanceof Doc) { - success = KeyValueBox.ApplyKVPScript(doc, this._currentKey, script); - } else { - let childSuccess = true; - if (this._addChildren) { - for (const document of doc) { - const collectionChildren = await DocListCastAsync(document.data); - if (collectionChildren) { - childSuccess = collectionChildren.every(c => KeyValueBox.ApplyKVPScript(c, this._currentKey, script)); - } + let childSuccess = true; + if (this._addChildren) { + for (const document of this.props.docs) { + const collectionChildren = DocListCast(document.data); + if (collectionChildren) { + childSuccess = collectionChildren.every(c => KeyValueBox.ApplyKVPScript(c, this._currentKey, script)); } } - success = doc.every(d => KeyValueBox.ApplyKVPScript(d, this._currentKey, script)) && childSuccess; } + const success = this.props.docs.every(d => KeyValueBox.ApplyKVPScript(d, this._currentKey, script)) && childSuccess; if (!success) { if (this.props.onError) { if (this.props.onError()) { @@ -132,24 +108,12 @@ export class MetadataEntryMenu extends React.Component{ } } - getKeySuggestions = async (value: string): Promise => { + getKeySuggestions = (value: string) => { value = value.toLowerCase(); let docs = this.props.docs; - if (typeof docs === "function") { - if (this.props.suggestWithFunction) { - docs = docs(); - } else { - return []; - } - } - docs = await docs; - if (docs instanceof Doc) { - return Object.keys(docs).filter(key => key.toLowerCase().startsWith(value)); - } else { - const keys = new Set(); - docs.forEach(doc => Doc.allKeys(doc).forEach(key => keys.add(key))); - return Array.from(keys).filter(key => key.toLowerCase().startsWith(value)); - } + const keys = new Set(); + docs.forEach(doc => Doc.allKeys(doc).forEach(key => keys.add(key))); + return Array.from(keys).filter(key => key.toLowerCase().startsWith(value)); } getSuggestionValue = (suggestion: string) => suggestion; @@ -157,9 +121,8 @@ export class MetadataEntryMenu extends React.Component{ return (null); } componentDidMount() { - this._suggestionDispser = reaction(() => this._currentKey, - () => this.getKeySuggestions(this._currentKey).then(action((s: string[]) => this._allSuggestions = s)), + () => this._allSuggestions = this.getKeySuggestions(this._currentKey), { fireImmediately: true }); } componentWillUnmount() { @@ -171,19 +134,8 @@ export class MetadataEntryMenu extends React.Component{ } private get considerChildOptions() { - let docSource = this.props.docs; - if (typeof docSource === "function") { - docSource = docSource(); - } - docSource = docSource as Doc[] | Doc; - if (docSource instanceof Doc) { - if (docSource._viewType === undefined) { - return (null); - } - } else if (Array.isArray(docSource)) { - if (!docSource.every(doc => doc._viewType !== undefined)) { - return null; - } + if (!this.props.docs.every(doc => doc._viewType !== undefined)) { + return null; } return (
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 5165a8f11..6ab4645ea 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -140,17 +140,18 @@ export class CollectionView extends Touchable { const context = Cast(doc.context, Doc, null); - if (context && (context.type === DocumentType.VID || context.type === DocumentType.WEB || context.type === DocumentType.PDF || context.type === DocumentType.IMG) && - !DocListCast(doc.links).some(d => d.isPushpin)) { + if (context && (context.type === DocumentType.VID || context.type === DocumentType.WEB || context.type === DocumentType.PDF || context.type === DocumentType.IMG)) { const pushpin = Docs.Create.FontIconDocument({ icon: "map-pin", x: Cast(doc.x, "number", null), y: Cast(doc.y, "number", null), _backgroundColor: "#0000003d", color: "#ACCEF7", _width: 15, _height: 15, _xPadding: 0, isLinkButton: true, displayTimecode: Cast(doc.displayTimecode, "number", null) }); + pushpin.isPushpin = true; + Doc.GetProto(pushpin).annotationOn = doc.annotationOn; + Doc.SetInPlace(doc, "annotationOn", undefined, true); Doc.AddDocToList(context, Doc.LayoutFieldKey(context) + "-annotations", pushpin); const pushpinLink = DocUtils.MakeLink({ doc: pushpin }, { doc: doc }, "pushpin", ""); const first = DocListCast(pushpin.links).find(d => d instanceof Doc); first && (first.hidden = true); - pushpinLink && (Doc.GetProto(pushpinLink).isPushpin = true); doc.displayTimecode = undefined; } doc.context = this.props.Document; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index f33b5371f..994f4ce6e 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -939,9 +939,9 @@ export class CollectionFreeFormView extends CollectionSubView (this.props.childClickScript || ScriptCast(this.Document.onChildClick)); } - @computed get onChildDoubleClickHandler() { return () => (this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick)); } @computed get backgroundActive() { return this.layoutDoc.isBackground && (this.props.ContainingCollectionView?.active() || this.props.active()); } + onChildClickHandler = () => this.props.childClickScript || ScriptCast(this.Document.onChildClick); + onChildDoubleClickHandler = () => this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick); backgroundHalo = () => BoolCast(this.Document.useClusters); parentActive = (outsideReaction: boolean) => this.props.active(outsideReaction) || this.backgroundActive ? true : false; getChildDocumentViewProps(childLayout: Doc, childData?: Doc): DocumentViewProps { @@ -1186,8 +1186,8 @@ export class CollectionFreeFormView extends CollectionSubView - (p === undefined || (p && p === i.rootDoc[key])) && i.rootDoc[key] !== "0" ? Field.toString(i.rootDoc[key] as Field) : "", undefined as Opt) + (p === undefined || (p && p === i.rootDoc[key])) && i.rootDoc[key] !== "0" ? Field.toString(i.rootDoc[key] as Field) : "", undefined as Opt); } @computed get selectedInk() { diff --git a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx index 15707ad9e..5d115df69 100644 --- a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx +++ b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx @@ -128,7 +128,7 @@ export default class InkOptionsMenu extends AntimodeMenu { // doc.strokeBezier === 300 ? doc.strokeBezier = 0 : doc.strokeBezier = 300; break; case "dash": - doc.strokeDash = Number(value); + doc.strokeDash = value; default: break; } diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx index b2e506dfa..73d0ae374 100644 --- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx +++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx @@ -31,7 +31,7 @@ export class CollectionGridView extends CollectionSubView(GridSchema) { @observable private _rowHeight: Opt; // temporary store of row height to make change undoable @observable private _scroll: number = 0; // required to make sure the decorations box container updates on scroll - @computed get onChildClickHandler() { return () => ScriptCast(this.Document.onChildClick); } + onChildClickHandler = () => ScriptCast(this.Document.onChildClick); @computed get numCols() { return NumCast(this.props.Document.gridNumCols, 10); } @computed get rowHeight() { return this._rowHeight === undefined ? NumCast(this.props.Document.gridRowHeight, 100) : this._rowHeight; } diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index 402e7563d..21d283547 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -202,9 +202,8 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu } - @computed get onChildClickHandler() { return () => ScriptCast(this.Document.onChildClick); } - @computed get onChildDoubleClickHandler() { return () => ScriptCast(this.Document.onChildDoubleClick); } - + onChildClickHandler = () => ScriptCast(this.Document.onChildClick); + onChildDoubleClickHandler = () => ScriptCast(this.Document.onChildDoubleClick); addDocTab = (doc: Doc, where: string) => { if (where === "inPlace" && this.layoutDoc.isInPlaceContainer) { diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx index e4ef9b436..d02088a6c 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx @@ -202,8 +202,8 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument) } - @computed get onChildClickHandler() { return () => ScriptCast(this.Document.onChildClick); } - @computed get onChildDoubleClickHandler() { return () => ScriptCast(this.Document.onChildDoubleClick); } + onChildClickHandler = () => ScriptCast(this.Document.onChildClick); + onChildDoubleClickHandler = () => ScriptCast(this.Document.onChildDoubleClick); addDocTab = (doc: Doc, where: string) => { if (where === "inPlace" && this.layoutDoc.isInPlaceContainer) { diff --git a/src/client/views/linking/LinkMenuGroup.tsx b/src/client/views/linking/LinkMenuGroup.tsx index 2f6b75437..2ae87ac13 100644 --- a/src/client/views/linking/LinkMenuGroup.tsx +++ b/src/client/views/linking/LinkMenuGroup.tsx @@ -11,6 +11,7 @@ import { DocumentView } from "../nodes/DocumentView"; import './LinkMenu.scss'; import { LinkMenuItem, StartLinkTargetsDrag } from "./LinkMenuItem"; import React = require("react"); +import { Cast } from "../../../fields/Types"; interface LinkMenuGroupProps { sourceDoc: Doc; @@ -66,7 +67,8 @@ export class LinkMenuGroup extends React.Component { render() { const groupItems = this.props.group.map(linkDoc => { - const destination = LinkManager.Instance.getOppositeAnchor(linkDoc, this.props.sourceDoc); + const destination = LinkManager.Instance.getOppositeAnchor(linkDoc, this.props.sourceDoc) || + LinkManager.Instance.getOppositeAnchor(linkDoc, Cast(linkDoc.anchor2, Doc, null).annotationOn === this.props.sourceDoc ? Cast(linkDoc.anchor2, Doc, null) : Cast(linkDoc.anchor1, Doc, null)); if (destination && this.props.sourceDoc) { return { const eyeIcon = this.props.linkDoc.hidden ? "eye-slash" : "eye"; - let destinationIcon: string = "";; + let destinationIcon: FontAwesomeIconProps["icon"] = "question"; switch (this.props.destinationDoc.type) { case DocumentType.IMG: destinationIcon = "image"; break; case DocumentType.COMPARISON: destinationIcon = "columns"; break; @@ -205,7 +205,6 @@ export class LinkMenuItem extends React.Component { case DocumentType.SCRIPTING: destinationIcon = "terminal"; break; case DocumentType.IMPORT: destinationIcon = "cloud-upload-alt"; break; case DocumentType.DOCHOLDER: destinationIcon = "expand"; break; - default: "question"; } const title = StrCast(this.props.destinationDoc.title).length > 18 ? diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx index 83710cfbf..823e25471 100644 --- a/src/client/views/nodes/DocumentLinksButton.tsx +++ b/src/client/views/nodes/DocumentLinksButton.tsx @@ -101,8 +101,6 @@ export class DocumentLinksButton extends React.Component { if (linkDoc) { @@ -137,7 +135,6 @@ export class DocumentLinksButton extends React.Component { if (linkDoc) { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 7d9c4da87..a6771443a 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -128,9 +128,9 @@ export class DocumentView extends DocComponent(Docu @computed get nativeWidth() { return NumCast(this.layoutDoc._nativeWidth, this.props.NativeWidth() || (this.freezeDimensions ? this.layoutDoc[WidthSym]() : 0)); } @computed get nativeHeight() { return NumCast(this.layoutDoc._nativeHeight, this.props.NativeHeight() || (this.freezeDimensions ? this.layoutDoc[HeightSym]() : 0)); } @computed get onClickHandler() { return this.props.onClick?.() ?? Cast(this.Document.onClick, ScriptField, Cast(this.layoutDoc.onClick, ScriptField, null)); } - @computed get onDoubleClickHandler() { return this.props.onDoubleClick?.() || (Cast(this.layoutDoc.onDoubleClick, ScriptField, null) || this.Document.onDoubleClick); } - @computed get onPointerDownHandler() { return this.props.onPointerDown?.() || ScriptCast(this.Document.onPointerDown) } - @computed get onPointerUpHandler() { return this.props.onPointerUp?.() || ScriptCast(this.Document.onPointerUp); } + @computed get onDoubleClickHandler() { return this.props.onDoubleClick?.() ?? (Cast(this.layoutDoc.onDoubleClick, ScriptField, null) ?? this.Document.onDoubleClick); } + @computed get onPointerDownHandler() { return this.props.onPointerDown?.() ?? ScriptCast(this.Document.onPointerDown); } + @computed get onPointerUpHandler() { return this.props.onPointerUp?.() ?? ScriptCast(this.Document.onPointerUp); } NativeWidth = () => this.nativeWidth; NativeHeight = () => this.nativeHeight; onClickFunc = () => this.onClickHandler; @@ -298,7 +298,7 @@ export class DocumentView extends DocComponent(Docu if (this._doubleTap && this.props.renderDepth && !this.onClickHandler?.script) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click if (!(e.nativeEvent as any).formattedHandled) { if (this.onDoubleClickHandler?.script && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes("ScriptingBox")) { // bcz: hack? don't execute script if you're clicking on a scripting box itself - const func = () => this.onDoubleClickHandler?.script.run({ + const func = () => this.onDoubleClickHandler.script.run({ this: this.layoutDoc, self: this.rootDoc, thisContainer: this.props.ContainingCollectionDoc, shiftKey: e.shiftKey @@ -320,7 +320,7 @@ export class DocumentView extends DocComponent(Docu } } else if (this.onClickHandler?.script && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes("ScriptingBox")) { // bcz: hack? don't execute script if you're clicking on a scripting box itself //SelectionManager.DeselectAll(); - const func = () => this.onClickHandler?.script.run({ + const func = () => this.onClickHandler.script.run({ this: this.layoutDoc, self: this.rootDoc, thisContainer: this.props.ContainingCollectionDoc, shiftKey: e.shiftKey @@ -556,7 +556,7 @@ export class DocumentView extends DocComponent(Docu this.cleanUpInteractions(); if (this.onPointerUpHandler?.script && !InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) { - this.onPointerUpHandler?.script.run({ self: this.rootDoc, this: this.layoutDoc }, console.log); + this.onPointerUpHandler.script.run({ self: this.rootDoc, this: this.layoutDoc }, console.log); document.removeEventListener("pointerup", this.onPointerUp); return; } @@ -644,7 +644,6 @@ export class DocumentView extends DocComponent(Docu const makeLink = action((linkDoc: Doc) => { LinkManager.currentLink = linkDoc; linkDoc.hidden = true; - linkDoc.linkDisplay = true; LinkCreatedBox.popupX = de.x; LinkCreatedBox.popupY = de.y - 33; @@ -1076,7 +1075,7 @@ export class DocumentView extends DocComponent(Docu layoutKey={this.finalLayoutKey} /> {this.layoutDoc.hideAllLinks ? (null) : this.allAnchors} {/* {this.allAnchors} */} - {this.props.forcedBackgroundColor?.(this.Document) === "transparent" || this.props.dontRegisterView ? (null) : } + {this.props.forcedBackgroundColor?.(this.Document) === "transparent" || this.layoutDoc.hideLinkButton || this.props.dontRegisterView ? (null) : }
); } @@ -1105,7 +1104,7 @@ export class DocumentView extends DocComponent(Docu return (this.props.treeViewDoc && this.props.LayoutTemplateString) || // render nothing for: tree view anchor dots this.layoutDoc.presBox || // presentationbox nodes this.props.dontRegisterView ? (null) : // view that are not registered - DocUtils.FilterDocs(DocListCast(this.Document.links), this.props.docFilters(), []).filter(d => !d.hidden && this.isNonTemporalLink).map((d, i) => + DocUtils.FilterDocs(LinkManager.Instance.getAllDirectLinks(this.Document), this.props.docFilters(), []).filter(d => !d.hidden && this.isNonTemporalLink).map((d, i) => ScriptField; dropAction: dropActionType; backgroundHalo?: () => boolean; docFilters: () => string[]; diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index 8da1f99b5..c8798d757 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -431,7 +431,7 @@ export default class RichTextMenu extends AntimodeMenu { const nextIsOL = this.view.state.selection.$from.nodeAfter?.type === schema.nodes.ordered_list; let inList: any = undefined; let fromList = -1; - let path: any = Array.from((this.view.state.selection.$from as any).path); + const path: any = Array.from((this.view.state.selection.$from as any).path); for (let i = 0; i < path.length; i++) { if (path[i]?.type === schema.nodes.ordered_list) { inList = path[i]; diff --git a/src/fields/documentSchemas.ts b/src/fields/documentSchemas.ts index 9dda644f3..ddffb56c3 100644 --- a/src/fields/documentSchemas.ts +++ b/src/fields/documentSchemas.ts @@ -65,6 +65,7 @@ export const documentSchema = createSchema({ color: "string", // foreground color of document fitToBox: "boolean", // whether freeform view contents should be zoomed/panned to fill the area of the document view fontSize: "string", + hidden: "boolean", // whether a document should not be displayed isInkMask: "boolean", // is the document a mask (ie, sits on top of other documents, has an unbounded width/height that is dark, and content uses 'hard-light' mix-blend-mode to let other documents pop through) layout: "string", // this is the native layout string for the document. templates can be added using other fields and setting layoutKey below layoutKey: "string", // holds the field key for the field that actually holds the current lyoat @@ -87,6 +88,8 @@ export const documentSchema = createSchema({ onPointerUp: ScriptField, // script to run when document is clicked (can be overriden by an onClick prop) onDragStart: ScriptField, // script to run when document is dragged (without being selected). the script should return the Doc to be dropped. followLinkLocation: "string",// flag for where to place content when following a click interaction (e.g., onRight, inPlace, inTab, ) + hideLinkButton: "boolean", // whether the blue link counter button should be hidden + hideAllLinks: "boolean", // whether all individual blue anchor dots should be hidden isInPlaceContainer: "boolean",// whether the marked object will display addDocTab() calls that target "inPlace" destinations isLinkButton: "boolean", // whether document functions as a link follow button to follow the first link on the document when clicked isBackground: "boolean", // whether document is a background element and ignores input events (can only select with marquee) -- cgit v1.2.3-70-g09d2 From 9c2410571d08674477eced80419585ebd15faaf0 Mon Sep 17 00:00:00 2001 From: usodhi <61431818+usodhi@users.noreply.github.com> Date: Wed, 15 Jul 2020 16:49:56 +0530 Subject: ui + sorting --- src/client/util/GroupManager.scss | 99 ++++++++++++++++++++---------------- src/client/util/GroupManager.tsx | 74 +++++++++++++++++++-------- src/client/util/GroupMemberView.scss | 27 ++++++++-- src/client/util/GroupMemberView.tsx | 21 ++++++-- src/client/util/SharingManager.scss | 23 +++++++-- src/client/util/SharingManager.tsx | 68 +++++++++++++++++-------- 6 files changed, 215 insertions(+), 97 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/GroupManager.scss b/src/client/util/GroupManager.scss index 2da1f0d95..8a2c616b1 100644 --- a/src/client/util/GroupManager.scss +++ b/src/client/util/GroupManager.scss @@ -20,9 +20,10 @@ // border: none; padding: 8px; min-width: 100%; - margin: 4px 0 4px 0; + // margin: 4px 0 4px 0; border: 1px solid hsl(0, 0%, 80%); outline: none; + height: 30; &:focus { // border: unset; @@ -100,59 +101,69 @@ } } + .main-container { + display: flex; + flex-direction: column; - .group-body { - // display: flex; - justify-content: space-between; - // max-height: 80%; - height: 100%; - background-color: #e8e8e8; - // flex-direction: column; + .sort-groups { + text-align: left; + margin-left: 5; + cursor: pointer; + } - // padding-left: 1em; - padding-right: 1em; - justify-content: space-around; - text-align: left; + .group-body { + // display: flex; + justify-content: space-between; + // max-height: 80%; + height: 220; + background-color: #e8e8e8; + // flex-direction: column; + + // padding-left: 1em; + padding-right: 1em; + justify-content: space-around; + text-align: left; - overflow-y: auto; - width: 100%; + overflow-y: auto; + width: 100%; - .group-row { - display: flex; - // position: relative; - margin-bottom: 5px; - min-height: 30px; - // border: 1px solid; - // border-radius: 10px; - align-items: center; - - .group-name { + .group-row { + display: flex; // position: relative; - max-width: 65%; - // left: 10; - margin: 0 10; - color: black; - } + margin-bottom: 5px; + min-height: 30px; + // border: 1px solid; + // border-radius: 10px; + align-items: center; + + .group-name { + // position: relative; + max-width: 65%; + // left: 10; + margin: 0 10; + color: black; + } - .group-info { - cursor: pointer; + .group-info { + cursor: pointer; + } + + button { + position: absolute; + width: 30%; + right: 2; + margin-top: 0; + } } - button { - position: absolute; - width: 30%; - right: 2; - margin-top: 0; + input { + border-radius: 5px; + border: none; + padding: 4px; + min-width: 100%; + margin: 2px 0; } - } - input { - border-radius: 5px; - border: none; - padding: 4px; - min-width: 100%; - margin: 2px 0; } - } } \ No newline at end of file diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx index f2b502ae0..2d8930660 100644 --- a/src/client/util/GroupManager.tsx +++ b/src/client/util/GroupManager.tsx @@ -38,31 +38,38 @@ export default class GroupManager extends React.Component<{}> { private inputRef: React.RefObject = React.createRef(); // the ref for the input box. private currentUserGroups: string[] = []; @observable private buttonColour: "#979797" | "black" = "#979797"; + @observable private groupSort: "ascending" | "descending" | "none" = "none"; + constructor(props: Readonly<{}>) { super(props); GroupManager.Instance = this; } + componentDidMount() { + this.populateUsers(); + } + /** * Fetches the list of users stored on the database. */ populateUsers = async () => { + runInAction(() => this.users = []); const userList = await RequestPromise.get(Utils.prepend("/getUsers")); const raw = JSON.parse(userList) as User[]; const evaluating = raw.map(async user => { - const isCandidate = user.email !== Doc.CurrentUserEmail; - if (isCandidate) { - const userDocument = await DocServer.GetRefField(user.userDocumentId); - if (userDocument instanceof Doc) { - const notificationDoc = await Cast(userDocument.rightSidebarCollection, Doc); - runInAction(() => { - if (notificationDoc instanceof Doc) { - this.users.push(user.email); - } - }); - } + // const isCandidate = user.email !== Doc.CurrentUserEmail; + // if (isCandidate) { + const userDocument = await DocServer.GetRefField(user.userDocumentId); + if (userDocument instanceof Doc) { + const notificationDoc = await Cast(userDocument.rightSidebarCollection, Doc); + runInAction(() => { + if (notificationDoc instanceof Doc) { + this.users.push(user.email); + } + }); } + // } }); return Promise.all(evaluating); } @@ -99,7 +106,7 @@ export default class GroupManager extends React.Component<{}> { close = () => { this.isOpen = false; this.currentGroup = undefined; - this.users = []; + // this.users = []; this.createGroupModalOpen = false; } @@ -304,6 +311,7 @@ export default class GroupManager extends React.Component<{}> {
{ * A getter that @returns the main interface for the GroupManager. */ private get groupInterface() { + + const sortGroups = (d1: Doc, d2: Doc) => { + const g1 = StrCast(d1.groupName); + const g2 = StrCast(d2.groupName); + + return g1 < g2 ? -1 : g1 === g2 ? 0 : 1; + }; + + let groups = this.getAllGroups(); + groups = this.groupSort === "ascending" ? groups.sort(sortGroups) : this.groupSort === "descending" ? groups.sort(sortGroups).reverse() : groups; + return (
{this.groupCreationModal} @@ -375,19 +394,30 @@ export default class GroupManager extends React.Component<{}> {
-
- {this.getAllGroups().map(group => -
-
{group.groupName}
-
this.currentGroup = group)}> - -
- {/* */} -
- )} +
+ )} +
+
); } diff --git a/src/client/util/GroupMemberView.scss b/src/client/util/GroupMemberView.scss index 9bdf832e0..a34e5b989 100644 --- a/src/client/util/GroupMemberView.scss +++ b/src/client/util/GroupMemberView.scss @@ -8,7 +8,7 @@ // color: black; hr { - margin-top: 10; + margin-top: 20; } button { @@ -17,7 +17,7 @@ border-radius: 5px; border: 0px; color: #fcfbf7; - // text-transform: uppercase; + text-transform: none; letter-spacing: 2px; font-size: 75%; padding: 10px; @@ -45,15 +45,33 @@ outline: none; color: black; margin-top: -5; + height: 20; + text-overflow: ellipsis; + + &:hover { + text-overflow: visible; + overflow-x: auto; + } + } + + .sort-emails { + float: left; + margin: -18 0 0 5; + cursor: pointer; } .group-buttons { display: flex; margin-top: 5; + margin-bottom: 25; .add-member-dropdown { width: 65%; margin: 0 5; + + input { + height: 30; + } } } } @@ -61,7 +79,7 @@ .editing-contents { overflow-y: auto; // max-height: 67%; - height: 67%; + height: 65%; width: 100%; color: black; margin-top: -15px; @@ -70,6 +88,7 @@ display: flex; align-items: center; margin-bottom: 10px; + position: relative; // border: 1px solid; // border-radius: 10px; @@ -83,7 +102,7 @@ .remove-button { position: absolute; - right: 30; + right: 10; cursor: pointer; } } diff --git a/src/client/util/GroupMemberView.tsx b/src/client/util/GroupMemberView.tsx index 2462ee4d5..ebe9830ba 100644 --- a/src/client/util/GroupMemberView.tsx +++ b/src/client/util/GroupMemberView.tsx @@ -4,7 +4,7 @@ import { observer } from "mobx-react"; import GroupManager, { UserOptions } from "./GroupManager"; import { library } from "@fortawesome/fontawesome-svg-core"; import { StrCast } from "../../fields/Types"; -import { action } from "mobx"; +import { action, observable } from "mobx"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import * as fa from '@fortawesome/free-solid-svg-icons'; import Select from "react-select"; @@ -21,10 +21,17 @@ interface GroupMemberViewProps { @observer export default class GroupMemberView extends React.Component { + @observable private memberSort: "ascending" | "descending" | "none" = "none"; private get editingInterface() { - const members: string[] = this.props.group ? JSON.parse(StrCast(this.props.group.members)) : []; + let members: string[] = this.props.group ? JSON.parse(StrCast(this.props.group.members)) : []; + members = this.memberSort === "ascending" ? members.sort() : this.memberSort === "descending" ? members.sort().reverse() : members; + const options: UserOptions[] = this.props.group ? GroupManager.Instance.options.filter(option => !(JSON.parse(StrCast(this.props.group.members)) as string[]).includes(option.value)) : []; + console.log(this.props.group, options); + console.log(GroupManager.Instance.options); + + return (!this.props.group ? null :
@@ -59,11 +66,19 @@ export default class GroupMemberView extends React.Component GroupManager.Instance.deleteGroup(this.props.group)}>Delete group
: null} +
this.memberSort = this.memberSort === "ascending" ? "descending" : this.memberSort === "descending" ? "none" : "ascending")}> + Emails {this.memberSort === "ascending" ? "↑" : this.memberSort === "descending" ? "↓" : ""} {/* → */} +

{members.map(member => ( -
+
{member}
diff --git a/src/client/util/SharingManager.scss b/src/client/util/SharingManager.scss index ce23ce413..572b94ffb 100644 --- a/src/client/util/SharingManager.scss +++ b/src/client/util/SharingManager.scss @@ -1,4 +1,4 @@ -@import "../views/globalCssVariables"; +// @import "../views/globalCssVariables"; .sharing-interface { // display: flex; @@ -40,6 +40,10 @@ .user-search { width: 90%; + + input { + height: 30; + } } .permissions-select { @@ -68,6 +72,12 @@ display: flex; flex-direction: column; + .user-sort { + text-align: left; + margin-left: 10; + cursor: pointer; + } + .share-title { margin-top: 20px; margin-bottom: 20px; @@ -103,12 +113,12 @@ } button { - background: $darker-alt-accent; + // background: $darker-alt-accent; outline: none; border-radius: 5px; border: 0px; color: #fcfbf7; - text-transform: uppercase; + text-transform: none; letter-spacing: 2px; font-size: 75%; padding: 0 10; @@ -173,6 +183,10 @@ padding: 0; align-items: center; + .group-info { + cursor: pointer; + } + &:hover .padding { white-space: unset; } @@ -183,12 +197,13 @@ text-overflow: ellipsis; overflow: hidden; white-space: nowrap; - max-width: 48%; + max-width: 40%; } .permissions-dropdown { border: none; height: 25; + background-color: #e8e8e8; } .edit-actions { diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx index 6c7c634eb..817b7c6b8 100644 --- a/src/client/util/SharingManager.tsx +++ b/src/client/util/SharingManager.tsx @@ -75,6 +75,9 @@ export default class SharingManager extends React.Component<{}> { @observable private overlayOpacity = 0.4; @observable private selectedUsers: UserOptions[] | null = null; @observable private permissions: SharingPermissions = SharingPermissions.Edit; + @observable private individualSort: "ascending" | "descending" | "none" = "none"; + @observable private groupSort: "ascending" | "descending" | "none" = "none"; + // private get linkVisible() { // return this.sharingDoc ? this.sharingDoc[PublicKey] !== SharingPermissions.None : false; @@ -151,8 +154,6 @@ export default class SharingManager extends React.Component<{}> { // group.docsShared ? Doc.IndexOf(target, DocListCast(group.docsShared)) === -1 && (group.docsShared as List).push(target) : group.docsShared = new List([target]); users.forEach(({ notificationDoc }) => { - - DocListCastAsync(notificationDoc[storage]).then(res => console.log(res)); DocListCastAsync(notificationDoc[storage]).then(resolved => { if (permission !== SharingPermissions.None) Doc.IndexOf(target, resolved!) === -1 && Doc.AddDocToList(notificationDoc, storage, target); else Doc.IndexOf(target, resolved!) !== -1 && Doc.RemoveDocFromList(notificationDoc, storage, target); @@ -353,28 +354,44 @@ export default class SharingManager extends React.Component<{}> { this.selectedUsers = null; } + sortUsers = (u1: ValidatedUser, u2: ValidatedUser) => { + const { email: e1 } = u1.user; + const { email: e2 } = u2.user; + return e1 < e2 ? -1 : e1 === e2 ? 0 : 1; + } + + sortGroups = (group1: Doc, group2: Doc) => { + const g1 = StrCast(group1.groupName); + const g2 = StrCast(group2.groupName); + return g1 < g2 ? -1 : g1 === g2 ? 0 : 1; + } + private get sharingInterface() { - const existOtherUsers = this.users.length > 0; - const existGroups = GroupManager.Instance?.getAllGroups().length > 0; - // const manager = this.sharingDoc!; + const groupList = GroupManager.Instance?.getAllGroups() || []; + + const sortedUsers = this.users.sort(this.sortUsers) + .map(({ user: { email } }) => ({ label: email, value: "!indType/" + email })); + const sortedGroups = groupList.sort(this.sortGroups) + .map(({ groupName }) => ({ label: StrCast(groupName), value: "!groupType/" + StrCast(groupName) })); const options: GroupOptions[] = GroupManager.Instance ? [ { label: 'Individuals', - options: this.users.map(({ user: { email } }) => ({ label: email, value: "!indType/" + email })) + options: sortedUsers }, { label: 'Groups', - options: GroupManager.Instance.getAllGroups().map(({ groupName }) => ({ label: StrCast(groupName), value: "!groupType/" + StrCast(groupName) })) + options: sortedGroups } ] : []; - console.log(this.users); + const users = this.individualSort === "ascending" ? this.users.sort(this.sortUsers) : this.individualSort === "descending" ? this.users.sort(this.sortUsers).reverse() : this.users; + const groups = this.groupSort === "ascending" ? groupList.sort(this.sortGroups) : this.groupSort === "descending" ? groupList.sort(this.sortGroups).reverse() : groupList; - const userListContents: (JSX.Element | null)[] = this.users.map(({ user, notificationDoc }) => { // can't use async here + const userListContents: (JSX.Element | null)[] = users.map(({ user, notificationDoc }) => { // can't use async here const userKey = user.email.replace('.', '_'); // const userKey = user.userDocumentId; const permissions = StrCast(this.targetDoc?.[`ACL-${userKey}`], SharingPermissions.None); @@ -422,7 +439,7 @@ export default class SharingManager extends React.Component<{}> { ) ); - const groupListContents = GroupManager.Instance?.getAllGroups().map(group => { + const groupListContents = groups.map(group => { const permissions = StrCast(this.targetDoc?.[`ACL-${StrCast(group.groupName)}`], SharingPermissions.None); // const color = ColorMapping.get(permissions); @@ -431,7 +448,10 @@ export default class SharingManager extends React.Component<{}> { key={StrCast(group.groupName)} className={"container"} > - {group.groupName} +
{group.groupName}
+
GroupManager.Instance.currentGroup = group)}> + +
-
); }); - const displayUserList = userListContents?.every(user => user === null); - const displayGroupList = groupListContents?.every(group => group === null); + const displayUserList = !userListContents?.every(user => user === null); + const displayGroupList = !groupListContents?.every(group => group === null); return (
@@ -515,10 +534,14 @@ export default class SharingManager extends React.Component<{}> { }
-
Individuals
-
{/*200*/} +
this.individualSort = this.individualSort === "ascending" ? "descending" : this.individualSort === "descending" ? "none" : "ascending")}> + Individuals {this.individualSort === "ascending" ? "↑" : this.individualSort === "descending" ? "↓" : ""} {/* → */} +
+
{/*200*/} { - displayUserList ? + !displayUserList ?
@@ -530,10 +553,15 @@ export default class SharingManager extends React.Component<{}> {
-
Groups
-
{/*200*/} +
this.groupSort = this.groupSort === "ascending" ? "descending" : this.groupSort === "descending" ? "none" : "ascending")}> + Groups {this.groupSort === "ascending" ? "↑" : this.groupSort === "descending" ? "↓" : ""} {/* → */} + +
+
{/*200*/} { - displayGroupList ? + !displayGroupList ?
-- cgit v1.2.3-70-g09d2 From 3ad593cc8865d3fa1dc22bf403ad7cfaf1a751e6 Mon Sep 17 00:00:00 2001 From: usodhi <61431818+usodhi@users.noreply.github.com> Date: Wed, 15 Jul 2020 21:52:23 +0530 Subject: bugfix + cleanup --- src/client/util/GroupManager.scss | 25 -------- src/client/util/GroupManager.tsx | 4 -- src/client/util/GroupMemberView.scss | 10 --- src/client/util/GroupMemberView.tsx | 3 - src/client/util/SharingManager.scss | 30 --------- src/client/util/SharingManager.tsx | 106 +++++--------------------------- src/client/views/nodes/DocumentView.tsx | 22 +++---- src/fields/Doc.ts | 2 +- 8 files changed, 28 insertions(+), 174 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/GroupManager.scss b/src/client/util/GroupManager.scss index 8a2c616b1..34d4f40f8 100644 --- a/src/client/util/GroupManager.scss +++ b/src/client/util/GroupManager.scss @@ -1,8 +1,4 @@ -// @import "../views/globalCssVariables"; - .group-interface { - // background-color: whitesmoke !important; - // color: grey; width: 550px; height: 300px; @@ -12,21 +8,17 @@ flex-direction: column; height: 90%; justify-content: space-between; - // flex-basis: 30%; margin-left: 5px; input { border-radius: 5px; - // border: none; padding: 8px; min-width: 100%; - // margin: 4px 0 4px 0; border: 1px solid hsl(0, 0%, 80%); outline: none; height: 30; &:focus { - // border: unset; border: 2.5px solid #2684FF; } } @@ -43,18 +35,12 @@ } } - // .dialogue-box { - // width: 450; - // height: 300; - // } button { - // background: $lighter-alt-accent; align-self: center; outline: none; border-radius: 5px; border: 0px; - // color: #fcfbf7; text-transform: none; letter-spacing: 2px; font-size: 75%; @@ -94,10 +80,8 @@ p { font-size: 20px; text-align: left; - // margin: 0 0 20px 0; margin-right: 15px; color: black; - // width: 60%; } } @@ -112,14 +96,10 @@ } .group-body { - // display: flex; justify-content: space-between; - // max-height: 80%; height: 220; background-color: #e8e8e8; - // flex-direction: column; - // padding-left: 1em; padding-right: 1em; justify-content: space-around; text-align: left; @@ -129,17 +109,12 @@ .group-row { display: flex; - // position: relative; margin-bottom: 5px; min-height: 30px; - // border: 1px solid; - // border-radius: 10px; align-items: center; .group-name { - // position: relative; max-width: 65%; - // left: 10; margin: 0 10; color: black; } diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx index 2d8930660..12951f2ab 100644 --- a/src/client/util/GroupManager.tsx +++ b/src/client/util/GroupManager.tsx @@ -286,7 +286,6 @@ export default class GroupManager extends React.Component<{}> { */ @action createGroup = () => { - // this.createGroupModalOpen = true; if (!this.inputRef.current?.value) { alert("Please enter a group name"); return; @@ -410,9 +409,6 @@ export default class GroupManager extends React.Component<{}> {
this.currentGroup = group)}>
- {/* */}
)}
diff --git a/src/client/util/GroupMemberView.scss b/src/client/util/GroupMemberView.scss index a34e5b989..c609c5c7b 100644 --- a/src/client/util/GroupMemberView.scss +++ b/src/client/util/GroupMemberView.scss @@ -1,18 +1,12 @@ -// @import "../views/globalCssVariables"; - .editing-interface { - // background-color: whitesmoke !important; - // color: grey; width: 100%; height: 100%; - // color: black; hr { margin-top: 20; } button { - // background: $darker-alt-accent; outline: none; border-radius: 5px; border: 0px; @@ -78,7 +72,6 @@ .editing-contents { overflow-y: auto; - // max-height: 67%; height: 65%; width: 100%; color: black; @@ -89,11 +82,8 @@ align-items: center; margin-bottom: 10px; position: relative; - // border: 1px solid; - // border-radius: 10px; .user-email { - // position: relative; min-width: 65%; word-break: break-all; padding: 0 5; diff --git a/src/client/util/GroupMemberView.tsx b/src/client/util/GroupMemberView.tsx index ebe9830ba..f20670c4e 100644 --- a/src/client/util/GroupMemberView.tsx +++ b/src/client/util/GroupMemberView.tsx @@ -28,9 +28,6 @@ export default class GroupMemberView extends React.Component !(JSON.parse(StrCast(this.props.group.members)) as string[]).includes(option.value)) : []; - console.log(this.props.group, options); - console.log(GroupManager.Instance.options); - return (!this.props.group ? null :
diff --git a/src/client/util/SharingManager.scss b/src/client/util/SharingManager.scss index 572b94ffb..130785672 100644 --- a/src/client/util/SharingManager.scss +++ b/src/client/util/SharingManager.scss @@ -1,16 +1,7 @@ -// @import "../views/globalCssVariables"; - .sharing-interface { - // display: flex; - // flex-direction: column; width: 600px; height: 360px; - // .dialogue-box { - // width: 450; - // height: 300; - // } - .overlay { transform: translate(-20px, -20px); } @@ -87,7 +78,6 @@ .users-list { font-style: italic; background: #e8e8e8; - // border: 1px solid black; padding-left: 10px; padding-right: 10px; overflow-y: scroll; @@ -98,7 +88,6 @@ align-items: center; text-align: center; justify-content: center; - // color: red; color: black; height: 250px; margin: 0 2; @@ -113,7 +102,6 @@ } button { - // background: $darker-alt-accent; outline: none; border-radius: 5px; border: 0px; @@ -135,8 +123,6 @@ p { font-size: 20px; text-align: left; - // font-style: italic; - // padding: 0; margin: 0 0 20px 0; color: black; } @@ -174,8 +160,6 @@ -ms-user-select: none; user-select: none; width: 100%; - // min-width: 700px; - // max-width: 700px; text-align: left; font-style: normal; font-size: 14; @@ -249,18 +233,4 @@ padding-top: 12px; } } - - // .close-button { - // border-radius: 5px; - // margin-top: 20px; - // padding: 10px 0; - // background: aliceblue; - // transition: 0.5s ease all; - // border: 1px solid; - // border-color: aliceblue; - // } - - // .close-button:hover { - // border-color: black; - // } } \ No newline at end of file diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx index be86b183f..8d4e508ac 100644 --- a/src/client/util/SharingManager.tsx +++ b/src/client/util/SharingManager.tsx @@ -36,13 +36,6 @@ export enum SharingPermissions { None = "Not Shared" } -// const ColorMapping = new Map([ -// [SharingPermissions.None, "red"], -// [SharingPermissions.View, "maroon"], -// [SharingPermissions.Add, "blue"], -// [SharingPermissions.Edit, "green"] -// ]); - interface GroupOptions { label: string; options: UserOptions[]; @@ -67,10 +60,9 @@ export default class SharingManager extends React.Component<{}> { public static Instance: SharingManager; @observable private isOpen = false; @observable private users: ValidatedUser[] = []; - // @observable private groups: Doc[] = []; @observable private targetDoc: Doc | undefined; @observable private targetDocView: DocumentView | undefined; - @observable private copied = false; + // @observable private copied = false; @observable private dialogueBoxOpacity = 1; @observable private overlayOpacity = 0.4; @observable private selectedUsers: UserOptions[] | null = null; @@ -90,32 +82,20 @@ export default class SharingManager extends React.Component<{}> { this.targetDoc = target.props.Document; DictationOverlay.Instance.hasActiveModal = true; this.isOpen = true; - // if (!this.sharingDoc) { - // this.sharingDoc = new Doc; - // } })); - // runInAction(() => this.groups = GroupManager.Instance.getAllGroups()); } public close = action(() => { this.isOpen = false; this.users = []; setTimeout(action(() => { - this.copied = false; + // this.copied = false; DictationOverlay.Instance.hasActiveModal = false; this.targetDoc = undefined; }), 500); }); - // private get sharingDoc() { - // return this.targetDoc ? Cast(this.targetDoc[SharingKey], Doc) as Doc : undefined; - // } - - // private set sharingDoc(value: Doc | undefined) { - // this.targetDoc && (this.targetDoc[SharingKey] = value); - // } - constructor(props: {}) { super(props); SharingManager.Instance = this; @@ -152,7 +132,6 @@ export default class SharingManager extends React.Component<{}> { Doc.GetProto(target)[ACL] = permission; group.docsShared ? DocListCastAsync(group.docsShared).then(resolved => Doc.IndexOf(target, resolved!) === -1 && (group.docsShared as List).push(target)) : group.docsShared = new List([target]); - // group.docsShared ? Doc.IndexOf(target, DocListCast(group.docsShared)) === -1 && (group.docsShared as List).push(target) : group.docsShared = new List([target]); users.forEach(({ notificationDoc }) => { DocListCastAsync(notificationDoc[storage]).then(resolved => { @@ -171,7 +150,6 @@ export default class SharingManager extends React.Component<{}> { DocListCastAsync(user.notificationDoc[storage]).then(resolved => Doc.IndexOf(doc, resolved!) === -1 && Doc.AddDocToList(user.notificationDoc, storage, doc)); }); }); - // DocListCast(group.docsShared).forEach(doc => Doc.IndexOf(doc, DocListCast(user.notificationDoc[storage])) === -1 && Doc.AddDocToList(user.notificationDoc, storage, doc)); } } @@ -184,7 +162,6 @@ export default class SharingManager extends React.Component<{}> { DocListCastAsync(user.notificationDoc[storage]).then(resolved => Doc.IndexOf(doc, resolved!) !== -1 && Doc.RemoveDocFromList(user.notificationDoc, storage, doc)); }); }); - // DocListCast(group.docsShared).forEach(doc => Doc.IndexOf(doc, DocListCast(user.notificationDoc[storage])) === -1 && Doc.AddDocToList(user.notificationDoc, storage, doc)); } } @@ -208,14 +185,10 @@ export default class SharingManager extends React.Component<{}> { setInternalSharing = (recipient: ValidatedUser, permission: string) => { const { user, notificationDoc } = recipient; const target = this.targetDoc!; - // const manager = this.sharingDoc!; const key = user.email.replace('.', '_'); - // const key = user.userDocumentId; const ACL = `ACL-${key}`; - // const permissions: { [key: string]: number } = target[ACL] ? JSON.parse(StrCast(target[ACL])) : {}; - target[ACL] = permission; Doc.GetProto(target)[ACL] = permission; @@ -228,47 +201,12 @@ export default class SharingManager extends React.Component<{}> { } else { DocListCastAsync(notificationDoc[storage]).then(resolved => { - Doc.IndexOf(target, resolved!) === -1 && Doc.RemoveDocFromList(notificationDoc, storage, target); + Doc.IndexOf(target, resolved!) !== -1 && Doc.RemoveDocFromList(notificationDoc, storage, target); }); } } - - // let metadata = await DocCastAsync(manager[key]); - // const permissions: { [key: string]: number } = metadata?.permissions ? JSON.parse(StrCast(metadata.permissions)) : {}; - // permissions[StrCast(group ? group.groupName : Doc.CurrentUserEmail)] = parseInt(HierarchyMapping.get(permission)!); - // const max = Math.max(...Object.values(permissions)); - - // switch (max) { - // case 0: - // // if (metadata) { - // // const sharedAlias = (await DocCastAsync(metadata.sharedAlias))!; - // // Doc.RemoveDocFromList(notificationDoc, storage, sharedAlias); - // // manager[key] = undefined; - // // } - // Doc.RemoveDocFromList(notificationDoc, storage, target); - // break; - - // case 1: case 2: case 3: - - // Doc.AddDocToList(notificationDoc, storage, target); - - // if (!metadata) { - // metadata = new Doc; - // const sharedAlias = Doc.MakeAlias(target); - // Doc.AddDocToList(notificationDoc, storage, target); - // metadata.sharedAlias = sharedAlias; - // manager[key] = metadata; - // } - // metadata.permissions = JSON.stringify(permissions); - // // metadata.usersShared = JSON.stringify(keys); - // break; - // } - - // if (metadata) metadata.maxPermission = HierarchyMapping.get(`${max}`); - - // private setExternalSharing = (permission: string) => { // const sharingDoc = this.sharingDoc; // if (!sharingDoc) { @@ -277,20 +215,20 @@ export default class SharingManager extends React.Component<{}> { // sharingDoc[PublicKey] = permission; // } - private get sharingUrl() { - if (!this.targetDoc) { - return undefined; - } - const baseUrl = Utils.prepend("/doc/" + this.targetDoc[Id]); - return `${baseUrl}?sharing=true`; - } + // private get sharingUrl() { + // if (!this.targetDoc) { + // return undefined; + // } + // const baseUrl = Utils.prepend("/doc/" + this.targetDoc[Id]); + // return `${baseUrl}?sharing=true`; + // } - copy = action(() => { - if (this.sharingUrl) { - Utils.CopyText(this.sharingUrl); - this.copied = true; - } - }); + // copy = action(() => { + // if (this.sharingUrl) { + // Utils.CopyText(this.sharingUrl); + // this.copied = true; + // } + // }); private get sharingOptions() { return Object.values(SharingPermissions).map(permission => { @@ -394,14 +332,7 @@ export default class SharingManager extends React.Component<{}> { const userListContents: (JSX.Element | null)[] = users.map(({ user, notificationDoc }) => { // can't use async here const userKey = user.email.replace('.', '_'); - // const userKey = user.userDocumentId; const permissions = StrCast(this.targetDoc?.[`ACL-${userKey}`], SharingPermissions.None); - // const color = ColorMapping.get(permissions); - - // console.log(manager); - // const metadata = manager[userKey] as Doc; - // const usersShared = StrCast(metadata?.usersShared, ""); - // console.log(usersShared) return permissions === SharingPermissions.None || user.email === this.targetDoc?.author ? null : (
{ className={"container"} > {user.email} - {/*
{usersShared}
*/}
this.setInternalGroupSharing(group, e.currentTarget.value)} > {this.sharingOptions} @@ -582,7 +509,6 @@ export default class SharingManager extends React.Component<{}> { } render() { - // console.log(this.sharingDoc); return ( (Docu !Doc.UserDoc().novice && helpItems.push({ description: "Show Fields ", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "onRight"), icon: "layer-group" }); cm.addItem({ description: "Help...", noexpand: true, subitems: helpItems, icon: "question" }); - const existingAcls = cm.findByDescription("Privacy..."); - const aclItems: ContextMenuProps[] = existingAcls && "subitems" in existingAcls ? existingAcls.subitems : []; - aclItems.push({ description: "Make Add Only", event: () => this.setAcl("addOnly"), icon: "concierge-bell" }); - aclItems.push({ description: "Make Read Only", event: () => this.setAcl("readOnly"), icon: "concierge-bell" }); - aclItems.push({ description: "Make Private", event: () => this.setAcl("ownerOnly"), icon: "concierge-bell" }); - aclItems.push({ description: "Make Editable", event: () => this.setAcl("write"), icon: "concierge-bell" }); - aclItems.push({ description: "Test Private", event: () => this.testAcl("ownerOnly"), icon: "concierge-bell" }); - aclItems.push({ description: "Test Readonly", event: () => this.testAcl("readOnly"), icon: "concierge-bell" }); - !existingAcls && cm.addItem({ description: "Privacy...", subitems: aclItems, icon: "question" }); - - cm.addItem({ description: `${getPlaygroundMode() ? "Disable" : "Enable"} playground mode`, event: togglePlaygroundMode, icon: "concierge-bell" }); + // const existingAcls = cm.findByDescription("Privacy..."); + // const aclItems: ContextMenuProps[] = existingAcls && "subitems" in existingAcls ? existingAcls.subitems : []; + // aclItems.push({ description: "Make Add Only", event: () => this.setAcl(SharingPermissions.Add), icon: "concierge-bell" }); + // aclItems.push({ description: "Make Read Only", event: () => this.setAcl(SharingPermissions.View), icon: "concierge-bell" }); + // aclItems.push({ description: "Make Private", event: () => this.setAcl(SharingPermissions.None), icon: "concierge-bell" }); + // aclItems.push({ description: "Make Editable", event: () => this.setAcl(SharingPermissions.Edit), icon: "concierge-bell" }); + // aclItems.push({ description: "Test Private", event: () => this.testAcl(SharingPermissions.None), icon: "concierge-bell" }); + // aclItems.push({ description: "Test Readonly", event: () => this.testAcl(SharingPermissions.View), icon: "concierge-bell" }); + // !existingAcls && cm.addItem({ description: "Privacy...", subitems: aclItems, icon: "question" }); + + // cm.addItem({ description: `${getPlaygroundMode() ? "Disable" : "Enable"} playground mode`, event: togglePlaygroundMode, icon: "concierge-bell" }); // const recommender_subitems: ContextMenuProps[] = []; diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 8ab4735a7..5dfc14a4a 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -109,7 +109,7 @@ const AclMap = new Map([ ]); export function fetchProto(doc: Doc) { - if (doc.author !== Doc.CurrentUserEmail) { // storing acls for groups needs to be extended here - AclSym should store a datastructure that stores information about permissions + if (doc.author !== Doc.CurrentUserEmail) { untracked(() => { const permissions: { [key: string]: symbol } = {}; -- cgit v1.2.3-70-g09d2 From 7543ca061700fda8286e6dd3f4374a877ccf929c Mon Sep 17 00:00:00 2001 From: usodhi <61431818+usodhi@users.noreply.github.com> Date: Thu, 16 Jul 2020 13:00:12 +0530 Subject: can't change acl field to non-acl (through kvp) now + added playground mode button to settings --- src/client/util/SettingsManager.scss | 2 ++ src/client/util/SettingsManager.tsx | 13 +++++++++++-- src/client/util/SharingManager.tsx | 2 -- src/client/views/nodes/DocumentView.tsx | 2 +- src/fields/util.ts | 3 +++ 5 files changed, 17 insertions(+), 5 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/SettingsManager.scss b/src/client/util/SettingsManager.scss index 6d394a38d..c1627e69f 100644 --- a/src/client/util/SettingsManager.scss +++ b/src/client/util/SettingsManager.scss @@ -52,6 +52,7 @@ .settings-body { display: flex; justify-content: space-between; + margin-top: -10; .settings-type { display: flex; @@ -105,6 +106,7 @@ text-transform: uppercase; letter-spacing: 2px; font-size: 120%; + margin-top: 0; } .container { diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx index d54a39943..9d91568cf 100644 --- a/src/client/util/SettingsManager.tsx +++ b/src/client/util/SettingsManager.tsx @@ -14,8 +14,9 @@ import { Doc } from "../../fields/Doc"; import GroupManager from "./GroupManager"; import HypothesisAuthenticationManager from "../apis/HypothesisAuthenticationManager"; import GoogleAuthenticationManager from "../apis/GoogleAuthenticationManager"; +import { togglePlaygroundMode } from "../../fields/util"; -library.add(fa.faWindowClose); +library.add(fa.faTimes); @observer export default class SettingsManager extends React.Component<{}> { @@ -26,6 +27,7 @@ export default class SettingsManager extends React.Component<{}> { @observable private settingsContent = "password"; @observable private errorText = ""; @observable private successText = ""; + @observable private playgroundMode = false; private curr_password_ref = React.createRef(); private new_password_ref = React.createRef(); private new_confirm_ref = React.createRef(); @@ -95,19 +97,26 @@ export default class SettingsManager extends React.Component<{}> { HypothesisAuthenticationManager.Instance.fetchAccessToken(true) } + @action + togglePlaygroundMode = () => { + togglePlaygroundMode(); + this.playgroundMode = !this.playgroundMode; + } + private get settingsInterface() { return (

settings

- +
+ ; + return {StrCast(this.layoutDoc.toolTip)}
}> + + ; } } \ No newline at end of file diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index 9890ef2c1..3c7c58126 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -319,7 +319,7 @@ export default class RichTextMenu extends AntimodeMenu { } destroy() { - !this.TextView.props.isSelected(false) && this.fadeOut(true); + !this.TextView?.props.isSelected(false) && this.fadeOut(true); } @action @@ -657,7 +657,7 @@ export default class RichTextMenu extends AntimodeMenu { @action toggleColorDropdown() { this.showColorDropdown = !this.showColorDropdown; } @action setActiveColor(color: string) { this.activeFontColor = color; } - get TextView() { return (this.view as any).TextView as FormattedTextBox; } + get TextView() { return (this.view as any)?.TextView as FormattedTextBox; } createColorButton() { const self = this; diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 7aa1d528d..3ad9f4e41 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -899,9 +899,12 @@ export namespace Doc { } export function getDocTemplate(doc?: Doc) { - return doc?.isTemplateDoc ? doc : - Cast(doc?.dragFactory, Doc, null)?.isTemplateDoc ? doc?.dragFactory : - Cast(doc?.layout, Doc, null)?.isTemplateDoc ? doc?.layout : undefined; + return !doc ? undefined : + doc.isTemplateDoc ? doc : + Cast(doc.dragFactory, Doc, null)?.isTemplateDoc ? doc.dragFactory : + Cast(Doc.Layout(doc), Doc, null)?.isTemplateDoc ? + (Cast(Doc.Layout(doc), Doc, null).resolvedDataDoc ? Doc.Layout(doc).proto : Doc.Layout(doc)) : + undefined; } export function matchFieldValue(doc: Doc, key: string, value: any): boolean { -- cgit v1.2.3-70-g09d2 From 2df5e1fb9c249ab29c0d8fc56d0a2ce394ae6643 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 17 Jul 2020 17:10:43 -0400 Subject: got rid of InkOptionsMenu. Merged into CollectionFreeFormViewChrome. --- src/client/util/CurrentUserUtils.ts | 8 +- src/client/views/GestureOverlay.tsx | 10 +- src/client/views/GlobalKeyHandler.ts | 2 + src/client/views/MainView.tsx | 6 +- src/client/views/collections/CollectionMenu.scss | 61 +++++-- src/client/views/collections/CollectionMenu.tsx | 161 ++++++++++++++++- .../collectionFreeForm/InkOptionsMenu.scss | 83 --------- .../collectionFreeForm/InkOptionsMenu.tsx | 194 --------------------- src/mobile/MobileInterface.tsx | 4 +- 9 files changed, 213 insertions(+), 316 deletions(-) delete mode 100644 src/client/views/collections/collectionFreeForm/InkOptionsMenu.scss delete mode 100644 src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx (limited to 'src/client/util') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 892d0ca1d..58d3848a3 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -732,12 +732,6 @@ 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-pen"] === undefined) { - doc["dockedBtn-pen"] = CurrentUserUtils.ficon({ - onClick: ScriptField.MakeScript("activatePen(this.activeInkPen = sameDocs(this.activeInkPen, this) ? undefined : this)"), - author: "systemTemplates", toolTip: "open drawing tools", title: "draw", icon: "pen-nib", ischecked: ComputedField.MakeFunction(`sameDocs(this.activeInkPen, this)`), activeInkPen: doc - }); - } if (doc["dockedBtn-undo"] === undefined) { doc["dockedBtn-undo"] = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("undo()"), toolTip: "click to undo", title: "undo", icon: "undo-alt" }); } @@ -745,7 +739,7 @@ export class CurrentUserUtils { doc["dockedBtn-redo"] = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("redo()"), toolTip: "click to redo", title: "redo", icon: "redo-alt" }); } if (doc.dockedBtns === undefined) { - doc.dockedBtns = CurrentUserUtils.blist({ title: "docked buttons", ignoreClick: true }, [doc["dockedBtn-undo"] as Doc, doc["dockedBtn-redo"] as Doc, doc["dockedBtn-pen"] as Doc]); + doc.dockedBtns = CurrentUserUtils.blist({ title: "docked buttons", ignoreClick: true }, [doc["dockedBtn-undo"] as Doc, doc["dockedBtn-redo"] as Doc]); } } // sets up the default set of documents to be shown in the Overlay layer diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index 2f34cbc05..b0b0d72b1 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -22,7 +22,7 @@ import { RadialMenu } from "./nodes/RadialMenu"; import HorizontalPalette from "./Palette"; import { Touchable } from "./Touchable"; import TouchScrollableMenu, { TouchScrollableMenuItem } from "./TouchScrollableMenu"; -import InkOptionsMenu from "./collections/collectionFreeForm/InkOptionsMenu"; +import { CollectionFreeFormViewChrome } from "./collections/CollectionMenu"; @observer export default class GestureOverlay extends Touchable { @@ -603,12 +603,12 @@ export default class GestureOverlay extends Touchable { break; } } - //if any of the shape is activated in the InkOptionsMenu + //if any of the shape is activated in the CollectionFreeFormViewChrome else if (this.InkShape) { this.makePolygon(this.InkShape, false); this.dispatchGesture(GestureUtils.Gestures.Stroke); this._points = []; - if (!InkOptionsMenu.Instance._keepMode) { + if (!CollectionFreeFormViewChrome.Instance._keepMode) { this.InkShape = ""; } } @@ -639,9 +639,9 @@ export default class GestureOverlay extends Touchable { this._points = []; } //get out of ink mode after each stroke= - if (!InkOptionsMenu.Instance._keepMode) { + if (!CollectionFreeFormViewChrome.Instance._keepMode) { Doc.SetSelectedTool(InkTool.None); - InkOptionsMenu.Instance._selected = InkOptionsMenu.Instance._shapesNum; + CollectionFreeFormViewChrome.Instance._selected = CollectionFreeFormViewChrome.Instance._shapesNum; SetActiveArrowStart("none"); GestureOverlay.Instance.SavedArrowStart = ActiveArrowStart(); SetActiveArrowEnd("none"); diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index a3a023164..8c233489e 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -22,6 +22,7 @@ import { DocumentView } from "./nodes/DocumentView"; import { DocumentLinksButton } from "./nodes/DocumentLinksButton"; import PDFMenu from "./pdf/PDFMenu"; import { ContextMenu } from "./ContextMenu"; +import { CollectionFreeFormViewChrome } from "./collections/CollectionMenu"; const modifiers = ["control", "meta", "shift", "alt"]; type KeyHandler = (keycode: string, e: KeyboardEvent) => KeyControlInfo | Promise; @@ -107,6 +108,7 @@ export default class KeyManager { GoogleAuthenticationManager.Instance.cancel(); HypothesisAuthenticationManager.Instance.cancel(); SharingManager.Instance.close(); + CollectionFreeFormViewChrome.Instance.clearKeep(); break; case "delete": case "backspace": diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index e50ff342c..46eeac77a 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -38,7 +38,6 @@ import SharingManager from '../util/SharingManager'; import { Transform } from '../util/Transform'; import { CollectionDockingView } from './collections/CollectionDockingView'; import MarqueeOptionsMenu from './collections/collectionFreeForm/MarqueeOptionsMenu'; -import InkOptionsMenu from './collections/collectionFreeForm/InkOptionsMenu'; import { CollectionLinearView } from './collections/CollectionLinearView'; import { CollectionView, CollectionViewType } from './collections/CollectionView'; import { ContextMenu } from './ContextMenu'; @@ -392,7 +391,7 @@ export class MainView extends React.Component { doc.dockingConfig ? this.openWorkspace(doc) : CollectionDockingView.AddRightSplit(doc, libraryPath); } - sidebarScreenToLocal = () => new Transform(0, (RichTextMenu.Instance.Pinned ? -35 : 0) + (InkOptionsMenu.Instance.Pinned ? -35 : 0) + (CollectionMenu.Instance.Pinned ? -35 : 0), 1); + sidebarScreenToLocal = () => new Transform(0, (RichTextMenu.Instance.Pinned ? -35 : 0) + (CollectionMenu.Instance.Pinned ? -35 : 0), 1); mainContainerXf = () => this.sidebarScreenToLocal().translate(0, -this._buttonBarHeight); @computed get flyout() { @@ -469,7 +468,7 @@ export class MainView extends React.Component { @computed get mainContent() { const sidebar = this.userDoc?.["tabs-panelContainer"]; - const n = (RichTextMenu.Instance?.Pinned ? 1 : 0) + (InkOptionsMenu.Instance?.Pinned ? 1 : 0) + (CollectionMenu.Instance?.Pinned ? 1 : 0); + const n = (RichTextMenu.Instance?.Pinned ? 1 : 0) + (CollectionMenu.Instance?.Pinned ? 1 : 0); const height = `calc(100% - ${n * Number(ANTIMODEMENU_HEIGHT.replace("px", ""))}px)`; return !this.userDoc || !(sidebar instanceof Doc) ? (null) : (
- {LinkDescriptionPopup.descriptionPopup ? : null} diff --git a/src/client/views/collections/CollectionMenu.scss b/src/client/views/collections/CollectionMenu.scss index 0da78df9f..9da204787 100644 --- a/src/client/views/collections/CollectionMenu.scss +++ b/src/client/views/collections/CollectionMenu.scss @@ -8,15 +8,15 @@ opacity: 0.9; z-index: 9001; transition: top .5s; - background: #121721; + background: #323232; color: white; transform-origin: top left; top: 0; width:100%; .antimodeMenu-button { - padding:0; - width:30px; + padding: 0; + width: 30px; display: flex; svg { margin:auto; @@ -37,7 +37,7 @@ .collectionViewBaseChrome-viewPicker { font-size: 75%; - background: #121721; + background: #323232; outline-color: black; color: white; border: none; @@ -64,7 +64,7 @@ margin-left: 3px; margin-right: 0px; font-size: 75%; - background: #121721; + background: #323232; color: white; border: none; border-right: solid gray 1px; @@ -72,7 +72,7 @@ .commandEntry-outerDiv { pointer-events: all; - background-color: #121721; + background-color: #323232; display: flex; flex-direction: row; height: 30px; @@ -118,7 +118,7 @@ position: relative; display: flex; margin: auto; - background: #121721; + background: #323232; color: white; width: 30px; height: 30px; @@ -310,28 +310,54 @@ } .collectionFreeFormMenu-cont { - width: 60px; - display: flex; + display: inline-flex; position: relative; align-items: center; + .antimodeMenu-button { + text-align: center; + display: block; + } + .color-previewI { + width: 80%; + height: 20%; + bottom: 0; + position: absolute; + } + .color-previewII { + width: 80%; + height: 80%; + margin-left: 10%; + } + + .btn-group { + display: grid; + grid-template-columns: auto auto auto auto; + margin: auto; + /* Make the buttons appear below each other */ + } + + .btn-draw { + display: inline-flex; + margin: auto; + /* Make the buttons appear below each other */ + } + .fwdKeyframe, .numKeyframe, .backKeyframe { cursor: pointer; - position: absolute; + position: relative; width: 20; height: 30; bottom: 0; - background: #121721; - display: flex; + background: #323232; + display: inline-flex; align-items: center; color: white; } .backKeyframe { - left: 0; - svg { display: block; margin: auto; @@ -339,19 +365,16 @@ } .numKeyframe { - left: 20; - display: flex; flex-direction: column; - padding: 5px; + padding-top: 5px; } .fwdKeyframe { - left: 40; - svg { display: block; margin: auto; } + border-right: solid gray 1px; } } diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index f3ad21949..2be57b6d2 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -1,5 +1,5 @@ import React = require("react"); -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { FontAwesomeIcon, FontAwesomeIconProps } from "@fortawesome/react-fontawesome"; import { action, computed, observable, reaction, runInAction, Lambda } from "mobx"; import { observer } from "mobx-react"; import { Doc, DocListCast, Opt } from "../../../fields/Doc"; @@ -15,6 +15,15 @@ import { List } from "../../../fields/List"; import { EditableView } from "../EditableView"; import { Id } from "../../../fields/FieldSymbols"; import { listSpec } from "../../../fields/Schema"; +import FormatShapePane from "./collectionFreeForm/FormatShapePane"; +import { ActiveFillColor, SetActiveInkWidth, ActiveInkColor, SetActiveBezierApprox, SetActiveArrowEnd, SetActiveArrowStart, SetActiveFillColor, SetActiveInkColor } from "../InkingStroke"; +import GestureOverlay from "../GestureOverlay"; +import { InkTool } from "../../../fields/InkField"; +import { DocumentType } from "../../documents/DocumentTypes"; +import { Document } from "../../../fields/documentSchemas"; +import { SelectionManager } from "../../util/SelectionManager"; +import { DocumentView } from "../nodes/DocumentView"; +import { ColorState } from "react-color"; @observer export default class CollectionMenu extends AntimodeMenu { @@ -272,7 +281,11 @@ export class CollectionViewBaseChrome extends React.Component { - + public static Instance: CollectionFreeFormViewChrome; + constructor(props: any) { + super(props); + CollectionFreeFormViewChrome.Instance = this; + } get Document() { return this.props.CollectionView.props.Document; } @computed get dataField() { return this.props.CollectionView.props.Document[Doc.LayoutFieldKey(this.props.CollectionView.props.Document)]; @@ -303,6 +316,144 @@ export class CollectionFreeFormViewChrome extends React.Component { + const col: ColorState = { + hex: color, hsl: { a: 0, h: 0, s: 0, l: 0, source: "" }, hsv: { a: 0, h: 0, s: 0, v: 0, source: "" }, + rgb: { a: 0, r: 0, b: 0, g: 0, source: "" }, oldHue: 0, source: "", + }; + if (type === "color") { + SetActiveInkColor(Utils.colorString(col)); + } else if (type === "fill") { + SetActiveFillColor(Utils.colorString(col)); + } + } + + @action + editProperties = (value: any, field: string) => { + SelectionManager.SelectedDocuments().forEach(action((element: DocumentView) => { + const doc = Document(element.rootDoc); + if (doc.type === DocumentType.INK) { + switch (field) { + case "width": doc.strokeWidth = Number(value); break; + case "color": doc.color = String(value); break; + case "fill": doc.fillColor = String(value); break; + case "dash": doc.strokeDash = value; + } + } + })); + } + + @computed get drawButtons() { + const func = action((i: number, keep: boolean) => { + this._keepMode = keep; + if (this._selected !== i) { + this._selected = i; + Doc.SetSelectedTool(InkTool.Pen); + SetActiveArrowStart(this._head[i]); + SetActiveArrowEnd(this._end[i]); + SetActiveBezierApprox("300"); + + GestureOverlay.Instance.InkShape = this._shape[i]; + } else { + this._selected = this._shapesNum; + Doc.SetSelectedTool(InkTool.None); + SetActiveArrowStart(""); + SetActiveArrowEnd(""); + GestureOverlay.Instance.InkShape = ""; + SetActiveBezierApprox("0"); + } + }); + return
+ {this._draw.map((icon, i) => + )} +
; + } + + toggleButton = (key: string, value: boolean, setter: () => {}, icon: FontAwesomeIconProps["icon"], ele: JSX.Element | null) => { + return ; + } + + @computed get widthPicker() { + var widthPicker = this.toggleButton("stroke width", this._widthBtn, () => this._widthBtn = !this._widthBtn, "bars", null); + return !this._widthBtn ? widthPicker : +
+ {widthPicker} + {this._width.map(wid => + )} +
; + } + + @computed get colorPicker() { + var colorPicker = this.toggleButton("stroke color", this._colorBtn, () => this._colorBtn = !this._colorBtn, "pen-nib", +
); + return !this._colorBtn ? colorPicker : +
+ {colorPicker} + {this._palette.map(color => + )} +
; + } + @computed get fillPicker() { + var fillPicker = this.toggleButton("shape fill color", this._fillBtn, () => this._fillBtn = !this._fillBtn, "fill-drip", +
); + return !this._fillBtn ? fillPicker : +
+ {fillPicker} + {this._palette.map(color => + )} + +
; + } + + @computed get formatPane() { + return ; + } + render() { return this.Document.isAnnotationOverlay ? (null) :
@@ -316,6 +467,12 @@ export class CollectionFreeFormViewChrome extends React.Component
+ + {this.widthPicker} + {this.colorPicker} + {this.fillPicker} + {this.drawButtons} + {this.formatPane}
; } } diff --git a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.scss b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.scss deleted file mode 100644 index 03c6c97ab..000000000 --- a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.scss +++ /dev/null @@ -1,83 +0,0 @@ -.antimodeMenu-button { - .color-previewI { - width: 100%; - height: 40%; - } - - .color-previewII { - width: 100%; - height: 100%; - } - -} - -.sketch-picker { - background: #323232; - - .flexbox-fit { - background: #323232; - } -} - -.btn-group { - display: grid; - grid-template-columns: auto auto auto auto; - /* Make the buttons appear below each other */ -} - -.btn-draw { - display: inline; - /* Make the buttons appear below each other */ -} - -.btn2-group { - display: grid; - background: #323232; - grid-template-columns: auto; - - /* Make the buttons appear below each other */ - .antimodeMenu-button { - background: #323232; - display: block; - - } -} - -@media only screen and (max-device-width: 480px) { - .antimodeMenu-button { - font-size: 50%; - - .color-preview { - width: 100%; - height: 100%; - } - - } - - .sketch-picker { - background: #323232; - - .flexbox-fit { - background: #323232; - } - } - - .btn-group { - display: grid; - grid-template-columns: auto auto; - /* Make the buttons appear below each other */ - } - - .btn2-group { - display: block; - background: #323232; - grid-template-columns: auto; - - /* Make the buttons appear below each other */ - .antimodeMenu-button { - background: #323232; - display: block; - font-size: 50%; - } - } -} \ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx deleted file mode 100644 index 23e1c194a..000000000 --- a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx +++ /dev/null @@ -1,194 +0,0 @@ -import React = require("react"); -import AntimodeMenu from "../../AntimodeMenu"; -import { observer } from "mobx-react"; -import { observable, action, computed } from "mobx"; -import "./InkOptionsMenu.scss"; -import { ActiveInkColor, ActiveFillColor, SetActiveInkWidth, SetActiveInkColor, SetActiveBezierApprox, SetActiveFillColor, SetActiveArrowStart, SetActiveArrowEnd, ActiveDash, SetActiveDash } from "../../InkingStroke"; -import { Scripting } from "../../../util/Scripting"; -import { InkTool } from "../../../../fields/InkField"; -import { ColorState } from "react-color"; -import { Utils } from "../../../../Utils"; -import GestureOverlay from "../../GestureOverlay"; -import { Doc } from "../../../../fields/Doc"; -import { SelectionManager } from "../../../util/SelectionManager"; -import { DocumentView } from "../../../views/nodes/DocumentView"; -import { Document } from "../../../../fields/documentSchemas"; -import { DocumentType } from "../../../documents/DocumentTypes"; -import { FontAwesomeIcon, FontAwesomeIconProps } from "@fortawesome/react-fontawesome"; -import { BoolCast } from "../../../../fields/Types"; -import FormatShapePane from "./FormatShapePane"; - -@observer -export default class InkOptionsMenu extends AntimodeMenu { - static Instance: InkOptionsMenu; - - private _palette = ["#D0021B", "#F5A623", "#F8E71C", "#8B572A", "#7ED321", "#417505", "#9013FE", "#4A90E2", "#50E3C2", "#B8E986", "#000000", "#4A4A4A", "#9B9B9B", "#FFFFFF", ""]; - private _width = ["1", "5", "10", "100"]; - private _draw = ["⎯", "→", "↔︎", "∿", "↝", "↭", "ロ", "O", "∆"]; - private _head = ["", "", "arrow", "", "", "arrow", "", "", ""]; - private _end = ["", "arrow", "arrow", "", "arrow", "arrow", "", "", ""]; - private _shape = ["line", "line", "line", "", "", "", "rectangle", "circle", "triangle"]; - - @observable _shapesNum = this._shape.length; - @observable _selected = this._shapesNum; - - @observable _collapsed = false; - @observable _keepMode = false; - - @observable _colorBtn = false; - @observable _widthBtn = false; - @observable _fillBtn = false; - - constructor(props: Readonly<{}>) { - super(props); - InkOptionsMenu.Instance = this; - this._canFade = false; // don't let the inking menu fade away - this.Pinned = BoolCast(Doc.UserDoc()["menuInkOptions-pinned"]); - } - - @action - toggleMenuPin = (e: React.MouseEvent) => { - Doc.UserDoc()["menuInkOptions-pinned"] = this.Pinned = !this.Pinned; - } - - @action - changeColor = (color: string, type: string) => { - const col: ColorState = { - hex: color, hsl: { a: 0, h: 0, s: 0, l: 0, source: "" }, hsv: { a: 0, h: 0, s: 0, v: 0, source: "" }, - rgb: { a: 0, r: 0, b: 0, g: 0, source: "" }, oldHue: 0, source: "", - }; - if (type === "color") { - SetActiveInkColor(Utils.colorString(col)); - } else if (type === "fill") { - SetActiveFillColor(Utils.colorString(col)); - } - } - - @action - editProperties = (value: any, field: string) => { - SelectionManager.SelectedDocuments().forEach(action((element: DocumentView) => { - const doc = Document(element.rootDoc); - if (doc.type === DocumentType.INK) { - switch (field) { - case "width": doc.strokeWidth = Number(value); break; - case "color": doc.color = String(value); break; - case "fill": doc.fillColor = String(value); break; - case "dash": doc.strokeDash = value; - } - } - })); - } - - @computed get drawButtons() { - const func = action((i: number, keep: boolean) => { - this._keepMode = keep; - if (this._selected !== i) { - this._selected = i; - Doc.SetSelectedTool(InkTool.Pen); - SetActiveArrowStart(this._head[i]); - SetActiveArrowEnd(this._end[i]); - SetActiveBezierApprox("300"); - - GestureOverlay.Instance.InkShape = this._shape[i]; - } else { - this._selected = this._shapesNum; - Doc.SetSelectedTool(InkTool.None); - SetActiveArrowStart(""); - SetActiveArrowEnd(""); - GestureOverlay.Instance.InkShape = ""; - SetActiveBezierApprox("0"); - } - }); - return
- {this._draw.map((icon, i) => - )} -
; - } - - toggleButton = (key: string, value: boolean, setter: () => {}, icon: FontAwesomeIconProps["icon"], ele: JSX.Element | null) => { - return ; - } - - @computed get widthPicker() { - var widthPicker = this.toggleButton("stroke width", this._widthBtn, () => this._widthBtn = !this._widthBtn, "bars", null); - return !this._widthBtn ? widthPicker : -
- {widthPicker} - {this._width.map(wid => - )} -
; - } - - @computed get colorPicker() { - var colorPicker = this.toggleButton("stroke color", this._colorBtn, () => this._colorBtn = !this._colorBtn, "pen-nib", -
); - return !this._colorBtn ? colorPicker : -
- {colorPicker} - {this._palette.map(color => - )} -
; - } - @computed get fillPicker() { - var fillPicker = this.toggleButton("shape fill color", this._fillBtn, () => this._fillBtn = !this._fillBtn, "fill-drip", -
); - return !this._fillBtn ? fillPicker : -
- {fillPicker} - {this._palette.map(color => - )} - -
; - } - - @computed get formatPane() { - return ; - } - - render() { - return this.getElement([ - this.widthPicker, - this.colorPicker, - this.fillPicker, - this.drawButtons, - this.formatPane, - - ]); - } -} -Scripting.addGlobal(function activatePen(penBtn: any) { - if (penBtn) { - InkOptionsMenu.Instance.jumpTo(300, 300); - InkOptionsMenu.Instance.Pinned = true; - } else { - InkOptionsMenu.Instance.Pinned = false; - InkOptionsMenu.Instance.fadeOut(true); - } -}); diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index fafa94a11..3a889b0db 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -28,7 +28,6 @@ import { DockedFrameRenderer } from '../client/views/collections/CollectionDocki import { InkTool } from '../fields/InkField'; import GestureOverlay from "../client/views/GestureOverlay"; import { ScriptField } from "../fields/ScriptField"; -import InkOptionsMenu from "../client/views/collections/collectionFreeForm/InkOptionsMenu"; import { RadialMenu } from "../client/views/nodes/RadialMenu"; import { UndoManager } from "../client/util/UndoManager"; import { List } from "../fields/List"; @@ -38,6 +37,7 @@ import RichTextMenu from "../client/views/nodes/formattedText/RichTextMenu"; import { AudioBox } from "../client/views/nodes/AudioBox"; import { CollectionViewType } from "../client/views/collections/CollectionView"; import { DocumentType } from "../client/documents/DocumentTypes"; +import { CollectionFreeFormViewChrome } from "../client/views/collections/CollectionMenu"; library.add(faTasks, faReply, faQuoteLeft, faHandPointLeft, faFolderOpen, faAngleDoubleLeft, faExternalLinkSquareAlt, faMobile, faThLarge, faWindowClose, faEdit, faTrashAlt, faPalette, faAngleRight, faBell, faTrash, faCamera, faExpand, faCaretDown, faCaretLeft, faCaretRight, faCaretSquareDown, faCaretSquareRight, faArrowsAltH, faPlus, faMinus, faTerminal, faToggleOn, fileSolid, faExternalLinkAlt, faLocationArrow, faSearch, faFileDownload, faStop, faCalculator, faWindowMaximize, faAddressCard, @@ -429,7 +429,7 @@ export class MobileInterface extends React.Component { @computed get inkMenu() { return this._activeDoc._viewType !== CollectionViewType.Docking || !this._ink ? (null) :
- + {/* */}
; } -- cgit v1.2.3-70-g09d2 From d21ef189f2c160d3d80a5cf7d824c314262a59ac Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 19 Jul 2020 22:24:19 -0400 Subject: removed spurious point --- src/client/util/InteractionUtils.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/client/util') diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx index 07adbb8b1..473d4a263 100644 --- a/src/client/util/InteractionUtils.tsx +++ b/src/client/util/InteractionUtils.tsx @@ -112,7 +112,11 @@ export namespace InteractionUtils { } } } else { - pts = points; + pts = points.slice(); + // bcz: Ugh... this is ugly, but shapes apprently have an extra point added that is = (p[0].x,p[0].y+1) as some sort of flag. need to remove it here. + if (pts.length > 2 && pts[pts.length - 2].X === pts[0].X && pts[pts.length - 2].Y === pts[0].Y) { + pts.pop(); + } } const strpts = pts.reduce((acc: string, pt: { X: number, Y: number }) => acc + `${(pt.X - left - width / 2) * scalex + width / 2}, -- cgit v1.2.3-70-g09d2 From 7b7d83f6f7070334fdfc4dd7cca03699b8e21078 Mon Sep 17 00:00:00 2001 From: usodhi <61431818+usodhi@users.noreply.github.com> Date: Mon, 20 Jul 2020 19:21:54 +0530 Subject: fixed some addonly stuff + added annotations to playground fields + recursively distributes acls + some modal stuff --- src/client/apis/GoogleAuthenticationManager.tsx | 7 +-- .../apis/HypothesisAuthenticationManager.tsx | 6 ++- src/client/util/GroupManager.scss | 2 +- src/client/util/GroupManager.tsx | 6 +-- src/client/util/SettingsManager.tsx | 4 +- src/client/util/SharingManager.tsx | 58 ++++++++++++++++++---- src/client/views/DocComponent.tsx | 26 ++++++++-- src/client/views/MainView.tsx | 2 +- src/client/views/collections/CollectionView.tsx | 25 +++++++++- src/fields/Doc.ts | 14 +++--- src/fields/util.ts | 21 ++++---- 11 files changed, 128 insertions(+), 43 deletions(-) (limited to 'src/client/util') diff --git a/src/client/apis/GoogleAuthenticationManager.tsx b/src/client/apis/GoogleAuthenticationManager.tsx index 5a2bdb13b..117d1fa1e 100644 --- a/src/client/apis/GoogleAuthenticationManager.tsx +++ b/src/client/apis/GoogleAuthenticationManager.tsx @@ -146,7 +146,7 @@ export default class GoogleAuthenticationManager extends React.Component<{}> { private get dialogueBoxStyle() { const borderColor = this.success === undefined ? "black" : this.success ? "green" : "red"; - return { borderColor, transition: "0.2s borderColor ease" }; + return { borderColor, transition: "0.2s borderColor ease", zIndex: 1002 }; } render() { @@ -155,9 +155,10 @@ export default class GoogleAuthenticationManager extends React.Component<{}> { isDisplayed={this.openState} interactive={true} contents={this.renderPrompt} - overlayDisplayedOpacity={0.9} + // overlayDisplayedOpacity={0.9} dialogueBoxStyle={this.dialogueBoxStyle} - closeOnExternalClick={() => this.isOpen = false} + overlayStyle={{ zIndex: 1001 }} + closeOnExternalClick={action(() => this.isOpen = false)} /> ); } diff --git a/src/client/apis/HypothesisAuthenticationManager.tsx b/src/client/apis/HypothesisAuthenticationManager.tsx index a7fcf86a4..c3e8d2fff 100644 --- a/src/client/apis/HypothesisAuthenticationManager.tsx +++ b/src/client/apis/HypothesisAuthenticationManager.tsx @@ -138,7 +138,7 @@ export default class HypothesisAuthenticationManager extends React.Component<{}> private get dialogueBoxStyle() { const borderColor = this.success === undefined ? "black" : this.success ? "green" : "red"; - return { borderColor, transition: "0.2s borderColor ease" }; + return { borderColor, transition: "0.2s borderColor ease", zIndex: 1002 }; } render() { @@ -147,8 +147,10 @@ export default class HypothesisAuthenticationManager extends React.Component<{}> isDisplayed={this.openState} interactive={true} contents={this.renderPrompt} - overlayDisplayedOpacity={0.9} + // overlayDisplayedOpacity={0.9} dialogueBoxStyle={this.dialogueBoxStyle} + overlayStyle={{ zIndex: 1001 }} + closeOnExternalClick={action(() => this.isOpen = false)} /> ); } diff --git a/src/client/util/GroupManager.scss b/src/client/util/GroupManager.scss index 34d4f40f8..51e4fa9e2 100644 --- a/src/client/util/GroupManager.scss +++ b/src/client/util/GroupManager.scss @@ -1,5 +1,5 @@ .group-interface { - width: 550px; + width: 380px; height: 300px; .dialogue-box { diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx index 12951f2ab..2e5ecc543 100644 --- a/src/client/util/GroupManager.tsx +++ b/src/client/util/GroupManager.tsx @@ -354,7 +354,7 @@ export default class GroupManager extends React.Component<{}> { isDisplayed={this.createGroupModalOpen} interactive={true} contents={contents} - dialogueBoxStyle={{ width: "70%", height: "70%" }} + dialogueBoxStyle={{ width: "90%", height: "70%" }} closeOnExternalClick={action(() => this.createGroupModalOpen = false)} /> ); @@ -424,8 +424,8 @@ export default class GroupManager extends React.Component<{}> { contents={this.groupInterface} isDisplayed={this.isOpen} interactive={true} - dialogueBoxDisplayedOpacity={this.dialogueBoxOpacity} - overlayDisplayedOpacity={this.overlayOpacity} + dialogueBoxStyle={{ zIndex: 1002 }} + overlayStyle={{ zIndex: 1001 }} closeOnExternalClick={this.close} /> ); diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx index fc5fdd869..90d59aa51 100644 --- a/src/client/util/SettingsManager.tsx +++ b/src/client/util/SettingsManager.tsx @@ -119,10 +119,10 @@ export default class SettingsManager extends React.Component<{}> { + -
{this.settingsContent === "password" ?
@@ -155,8 +155,6 @@ export default class SettingsManager extends React.Component<{}> { contents={this.settingsInterface} isDisplayed={this.isOpen} interactive={true} - dialogueBoxDisplayedOpacity={this.dialogueBoxOpacity} - overlayDisplayedOpacity={this.overlayOpacity} closeOnExternalClick={this.close} /> ); diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx index fe7324d5c..8b3ac2613 100644 --- a/src/client/util/SharingManager.tsx +++ b/src/client/util/SharingManager.tsx @@ -1,13 +1,12 @@ import { observable, runInAction, action } from "mobx"; import * as React from "react"; import MainViewModal from "../views/MainViewModal"; -import { Doc, Opt, DocListCastAsync } from "../../fields/Doc"; +import { Doc, Opt, DocListCastAsync, DataSym, DocListCast } from "../../fields/Doc"; import { DocServer } from "../DocServer"; import { Cast, StrCast } from "../../fields/Types"; import * as RequestPromise from "request-promise"; import { Utils } from "../../Utils"; import "./SharingManager.scss"; -import { Id } from "../../fields/FieldSymbols"; import { observer } from "mobx-react"; import { library } from '@fortawesome/fontawesome-svg-core'; import * as fa from '@fortawesome/free-solid-svg-icons'; @@ -82,6 +81,7 @@ export default class SharingManager extends React.Component<{}> { this.targetDoc = target.props.Document; DictationOverlay.Instance.hasActiveModal = true; this.isOpen = true; + this.permissions = SharingPermissions.Edit; })); } @@ -127,9 +127,11 @@ export default class SharingManager extends React.Component<{}> { const target = this.targetDoc!; const ACL = `ACL-${StrCast(group.groupName)}`; + // fix this - not needed (here and setinternalsharing and removegroup) + // target[ACL] = permission; + // Doc.GetProto(target)[ACL] = permission; - target[ACL] = permission; - Doc.GetProto(target)[ACL] = permission; + this.distributeAcls(ACL, permission as SharingPermissions); group.docsShared ? DocListCastAsync(group.docsShared).then(resolved => Doc.IndexOf(target, resolved!) === -1 && (group.docsShared as List).push(target)) : group.docsShared = new List([target]); @@ -170,7 +172,9 @@ export default class SharingManager extends React.Component<{}> { DocListCastAsync(group.docsShared).then(resolved => { resolved?.forEach(doc => { const ACL = `ACL-${StrCast(group.groupName)}`; - doc[ACL] = "Not Shared"; + // doc[ACL] = doc[DataSym][ACL] = "Not Shared"; + + this.distributeAcls(ACL, SharingPermissions.None, doc); const members: string[] = JSON.parse(StrCast(group.members)); const users: ValidatedUser[] = this.users.filter(({ user: { email } }) => members.includes(email)); @@ -189,8 +193,10 @@ export default class SharingManager extends React.Component<{}> { const ACL = `ACL-${key}`; - target[ACL] = permission; - Doc.GetProto(target)[ACL] = permission; + // target[ACL] = permission; + // Doc.GetProto(target)[ACL] = permission; + + this.distributeAcls(ACL, permission as SharingPermissions); if (permission !== SharingPermissions.None) { DocListCastAsync(notificationDoc[storage]).then(resolved => { @@ -202,6 +208,40 @@ export default class SharingManager extends React.Component<{}> { Doc.IndexOf(target, resolved!) !== -1 && Doc.RemoveDocFromList(notificationDoc, storage, target); }); } + } + + @action + distributeAcls = (key: string, acl: SharingPermissions, doc?: Doc) => { + const target = doc ? doc : this.targetDoc!; + const dataDoc = target[DataSym]; + target[key] = acl; + if (dataDoc) dataDoc[key] = acl; + // dataDoc[key] = target[key] = acl; + // next line distributes the acl to all children of the target + DocListCast(dataDoc[Doc.LayoutFieldKey(dataDoc)]).map(d => { + if (d.author === Doc.CurrentUserEmail) { + this.distributeAcls(key, acl, d); + d[key] = acl; + } + const data = d[DataSym]; + if (data && data.author === Doc.CurrentUserEmail) { + this.distributeAcls(key, acl, data); + data[key] = acl; + } + }); + + DocListCast(dataDoc[Doc.LayoutFieldKey(dataDoc) + "-annotations"]).map(d => { + if (d.author === Doc.CurrentUserEmail) { + this.distributeAcls(key, acl, d); + d[key] = acl; + } + const data = d[DataSym]; + if (data && data.author === Doc.CurrentUserEmail) { + this.distributeAcls(key, acl, data); + data[key] = acl; + } + console.log(d, d[DataSym]); + }); } @@ -308,9 +348,9 @@ export default class SharingManager extends React.Component<{}> { const groupList = GroupManager.Instance?.getAllGroups() || []; const sortedUsers = this.users.sort(this.sortUsers) - .map(({ user: { email } }) => ({ label: email, value: "!indType/" + email })); + .map(({ user: { email } }) => ({ label: email, value: indType + email })); const sortedGroups = groupList.sort(this.sortGroups) - .map(({ groupName }) => ({ label: StrCast(groupName), value: "!groupType/" + StrCast(groupName) })); + .map(({ groupName }) => ({ label: StrCast(groupName), value: groupType + StrCast(groupName) })); const options: GroupOptions[] = GroupManager.Instance ? [ diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index eb58d8a3e..8740d17c2 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -1,4 +1,4 @@ -import { Doc, Opt, DataSym, DocListCast, AclReadonly, AclAddonly } from '../../fields/Doc'; +import { Doc, Opt, DataSym, DocListCast, AclReadonly, AclAddonly, AclPrivate, AclEdit, AclSym } from '../../fields/Doc'; import { Touchable } from './Touchable'; import { computed, action, observable } from 'mobx'; import { Cast, BoolCast, ScriptCast } from '../../fields/Types'; @@ -7,7 +7,8 @@ import { InteractionUtils } from '../util/InteractionUtils'; import { List } from '../../fields/List'; import { DateField } from '../../fields/DateField'; import { ScriptField } from '../../fields/ScriptField'; -import { GetEffectiveAcl } from '../../fields/util'; +import { GetEffectiveAcl, getPlaygroundMode } from '../../fields/util'; +import { SharingPermissions } from '../util/SharingManager'; /// DocComponent returns a generic React base class used by views that don't have 'fieldKey' props (e.g.,CollectionFreeFormDocumentView, DocumentView) @@ -92,6 +93,13 @@ export function ViewBoxAnnotatableComponent

([ + [AclPrivate, SharingPermissions.None], + [AclReadonly, SharingPermissions.View], + [AclAddonly, SharingPermissions.Add], + [AclEdit, SharingPermissions.Edit] + ]); + lookupField = (field: string) => ScriptCast((this.layoutDoc as any).lookupField)?.script.run({ self: this.layoutDoc, data: this.rootDoc, field: field }).result; styleFromLayoutString = (scale: number) => { @@ -139,11 +147,21 @@ export function ViewBoxAnnotatableComponent

!docList.includes(d)); const effectiveAcl = GetEffectiveAcl(this.dataDoc); + + if (this.props.Document[AclSym]) { + added.forEach(d => { + const dataDoc = d[DataSym]; + dataDoc[AclSym] = d[AclSym] = this.props.Document[AclSym]; + for (const [key, value] of Object.entries(this.props.Document[AclSym])) { + dataDoc[key] = d[key] = this.AclMap.get(value); + } + }); + } if (added.length) { - if (effectiveAcl === AclReadonly) { + if (effectiveAcl === AclReadonly && !getPlaygroundMode()) { return false; } else if (effectiveAcl === AclAddonly) { - added.map(doc => Doc.AddDocToList(targetDataDoc, this.annotationKey, doc)); + added.map(doc => console.log(Doc.AddDocToList(targetDataDoc, this.annotationKey, doc))); } else { added.map(doc => doc.context = this.props.Document); targetDataDoc[this.annotationKey] = new List([...docList, ...added]); diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 5c6781f4c..61d2246db 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -91,7 +91,7 @@ export class MainView extends React.Component { public isPointerDown = false; componentDidMount() { - DocServer.setPlaygroundFields(["dataTransition", "_viewTransition", "_panX", "_panY", "_viewScale", "_viewType", "_chromeStatus"]); // can play with these fields on someone else's + DocServer.setPlaygroundFields(["dataTransition", "_viewTransition", "_panX", "_panY", "_viewScale", "_viewType", "_chromeStatus", "data-annotations"]); // can play with these fields on someone else's const tag = document.createElement('script'); diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 50d66c567..17567ea73 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -8,7 +8,7 @@ import * as React from 'react'; import Lightbox from 'react-image-lightbox-with-rotate'; import 'react-image-lightbox-with-rotate/style.css'; // This only needs to be imported once in your app import { DateField } from '../../../fields/DateField'; -import { AclAddonly, AclReadonly, DataSym, Doc, DocListCast, Field, Opt, AclEdit } from '../../../fields/Doc'; +import { AclAddonly, AclReadonly, DataSym, Doc, DocListCast, Field, Opt, AclEdit, AclSym, AclPrivate } from '../../../fields/Doc'; import { Id } from '../../../fields/FieldSymbols'; import { List } from '../../../fields/List'; import { ObjectField } from '../../../fields/ObjectField'; @@ -48,6 +48,7 @@ import { CollectionTimeView } from './CollectionTimeView'; import { CollectionTreeView } from "./CollectionTreeView"; import './CollectionView.scss'; import CollectionMenu from './CollectionMenu'; +import { SharingPermissions } from '../../util/SharingManager'; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -106,6 +107,13 @@ export class CollectionView extends Touchable([ + [AclPrivate, SharingPermissions.None], + [AclReadonly, SharingPermissions.View], + [AclAddonly, SharingPermissions.Add], + [AclEdit, SharingPermissions.Edit] + ]); + get collectionViewType(): CollectionViewType | undefined { const viewField = StrCast(this.props.Document._viewType); if (CollectionView._safeMode) { @@ -128,11 +136,26 @@ export class CollectionView extends Touchable !docList.includes(d)); const effectiveAcl = GetEffectiveAcl(this.props.Document); + if (this.props.Document[AclSym]) { + // change so it only adds if more restrictive + added.forEach(d => { + console.log(d[Id]); + const dataDoc = d[DataSym]; + console.log(dataDoc[Id]); + for (const [key, value] of Object.entries(this.props.Document[AclSym])) { + dataDoc[key] = d[key] = this.AclMap.get(value); + } + dataDoc[AclSym] = d[AclSym] = this.props.Document[AclSym]; + + }); + } + if (added.length) { if (effectiveAcl === AclReadonly && !getPlaygroundMode()) { return false; diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 5dfc14a4a..ef57171bf 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -109,15 +109,15 @@ const AclMap = new Map([ ]); export function fetchProto(doc: Doc) { - if (doc.author !== Doc.CurrentUserEmail) { - untracked(() => { - const permissions: { [key: string]: symbol } = {}; + // if (doc.author !== Doc.CurrentUserEmail) { + untracked(() => { + const permissions: { [key: string]: symbol } = {}; - Object.keys(doc).filter(key => key.startsWith("ACL")).forEach(key => permissions[key] = AclMap.get(StrCast(doc[key]))!); + Object.keys(doc).filter(key => key.startsWith("ACL")).forEach(key => permissions[key] = AclMap.get(StrCast(doc[key]))!); - if (Object.keys(permissions).length) doc[AclSym] = permissions; - }); - } + if (Object.keys(permissions).length) doc[AclSym] = permissions; + }); + // } if (doc.proto instanceof Promise) { doc.proto.then(fetchProto); diff --git a/src/fields/util.ts b/src/fields/util.ts index 6d2d715bd..ee01f6213 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -129,28 +129,31 @@ export function setGroups(groups: string[]) { export function GetEffectiveAcl(target: any, in_prop?: string | symbol | number): symbol { if (in_prop === UpdatingFromServer || target[UpdatingFromServer]) return AclEdit; - const HierarchyMapping = new Map([ - [AclPrivate, 0], - [AclReadonly, 1], - [AclAddonly, 2], - [AclEdit, 3] - ]); - if (!target[AclSym] && target instanceof Doc) { fetchProto(target); } + if (target[AclSym] && Object.keys(target[AclSym]).length) { - if (target.author === Doc.CurrentUserEmail || currentUserGroups.includes("admin")) return AclEdit; + // console.log(target[AclSym]); + + if (target.__fields?.author === Doc.CurrentUserEmail || target.author === Doc.CurrentUserEmail || currentUserGroups.includes("admin")) return AclEdit; if (_overrideAcl || (in_prop && DocServer.PlaygroundFields?.includes(in_prop.toString()))) return AclEdit; - if (target[AclSym].ACL) return target[AclSym].ACL; + // if (target[AclSym].ACL) return target[AclSym].ACL; let effectiveAcl = AclPrivate; let aclPresent = false; + const HierarchyMapping = new Map([ + [AclPrivate, 0], + [AclReadonly, 1], + [AclAddonly, 2], + [AclEdit, 3] + ]); + for (const [key, value] of Object.entries(target[AclSym])) { if (currentUserGroups.includes(key.substring(4)) || Doc.CurrentUserEmail === key.substring(4).replace("_", ".")) { if (HierarchyMapping.get(value as symbol)! >= HierarchyMapping.get(effectiveAcl)!) { -- cgit v1.2.3-70-g09d2 From a8251abdaf57a3f02de46b434126caeb83df96ec Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 20 Jul 2020 10:35:33 -0400 Subject: added standard static ScriptFields to avoid extra compiles --- src/client/util/CurrentUserUtils.ts | 52 ++++++++++++++++++++++++------------- src/fields/ScriptField.ts | 23 +++++++++++++++- 2 files changed, 56 insertions(+), 19 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 58d3848a3..4b8c342f1 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -4,7 +4,7 @@ import { Utils } from "../../Utils"; import { DocServer } from "../DocServer"; import { Docs, DocumentOptions, DocUtils } from "../documents/Documents"; import { UndoManager } from "./UndoManager"; -import { Doc, DocListCast, DocListCastAsync } from "../../fields/Doc"; +import { Doc, DocListCast, DocListCastAsync, DataSym } from "../../fields/Doc"; import { List } from "../../fields/List"; import { listSpec } from "../../fields/Schema"; import { ScriptField, ComputedField } from "../../fields/ScriptField"; @@ -91,29 +91,29 @@ export class CurrentUserUtils { } if (doc["template-button-description"] === undefined) { - const descriptionTemplate = Docs.Create.TextDocument(" ", { title: "header", _height: 100 }, "header"); // text needs to be a space to allow templateText to be created - Doc.GetProto(descriptionTemplate).layout = + const descriptionTemplate = Doc.MakeDelegate(Docs.Create.TextDocument(" ", { title: "header", _height: 100 }, "header")); // text needs to be a space to allow templateText to be created + descriptionTemplate[DataSym].layout = "

" + " " + " " + "
"; - descriptionTemplate.isTemplateDoc = makeTemplate(descriptionTemplate, true, "descriptionView"); + (descriptionTemplate.proto as Doc).isTemplateDoc = makeTemplate(descriptionTemplate.proto as Doc, true, "descriptionView"); doc["template-button-description"] = CurrentUserUtils.ficon({ - onDragStart: ScriptField.MakeFunction('makeDelegate(this.dragFactory)'), + onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: new PrefetchProxy(descriptionTemplate) as any as Doc, removeDropProperties: new List(["dropAction"]), title: "description view", icon: "window-maximize" }); } if (doc["template-button-link"] === undefined) { // set _backgroundColor to transparent to prevent link dot from obscuring document it's attached to. - const linkTemplate = Docs.Create.TextDocument(" ", { title: "header", _height: 100 }, "header"); // text needs to be a space to allow templateText to be created + const linkTemplate = Doc.MakeDelegate(Docs.Create.TextDocument(" ", { title: "header", _height: 100 }, "header")); // text needs to be a space to allow templateText to be created Doc.GetProto(linkTemplate).layout = "
" + " " + " " + "
"; - linkTemplate.isTemplateDoc = makeTemplate(linkTemplate, true, "linkView"); + (linkTemplate.proto as Doc).isTemplateDoc = makeTemplate(linkTemplate.proto as Doc, true, "linkView"); const rtf2 = { doc: { @@ -146,7 +146,7 @@ export class CurrentUserUtils { linkTemplate.header = new RichTextField(JSON.stringify(rtf2), ""); doc["template-button-link"] = CurrentUserUtils.ficon({ - onDragStart: ScriptField.MakeFunction('makeDelegate(this.dragFactory)'), + onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: new PrefetchProxy(linkTemplate) as any as Doc, removeDropProperties: new List(["dropAction"]), title: "link view", icon: "window-maximize" }); @@ -390,6 +390,21 @@ export class CurrentUserUtils { if (doc.emptyScript === undefined) { doc.emptyScript = Docs.Create.ScriptingDocument(undefined, { _width: 200, _height: 250, title: "script" }); } + if (doc.emptyScreenshot === undefined) { + doc.emptyScreenshot = Docs.Create.ScreenshotDocument("", { _width: 400, _height: 200, title: "screen snapshot" }); + } + if (doc.emptyAudio === undefined) { + doc.emptyAudio = Docs.Create.AudioDocument(nullAudio, { _width: 200, title: "ready to record audio" }); + } + 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" }); + } + if (doc.emptyButton === undefined) { + doc.emptyButton = Docs.Create.ButtonDocument({ _width: 150, _height: 50, _xPadding: 10, _yPadding: 10, title: "Button" }); + } + if (doc.emptySearch === undefined) { + doc.emptySearch = Docs.Create.QueryDocument({ _width: 200, title: "empty search" }); + } if (doc.emptyDocHolder === undefined) { doc.emptyDocHolder = Docs.Create.DocumentDocument( ComputedField.MakeFunction("selectedDocs(this,this.excludeCollections,[_last_])?.[0]") as any, @@ -404,14 +419,15 @@ export class CurrentUserUtils { return [ { toolTip: "Drag a collection", title: "Col", icon: "folder", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyCollection as Doc }, { toolTip: "Drag a web page", title: "Web", icon: "globe-asia", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyWebpage as Doc }, - { toolTip: "Drag a cat image", title: "Image", icon: "cat", ignoreClick: true, drag: '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" })' }, + { toolTip: "Drag a cat image", title: "Image", icon: "cat", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyImage as Doc }, { toolTip: "Drag a comparison box", title: "Comp", icon: "columns", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyComparison as Doc }, - { toolTip: "Drag a screengrabber", title: "Grab", icon: "photo-video", ignoreClick: true, drag: 'Docs.Create.ScreenshotDocument("", { _width: 400, _height: 200, title: "screen snapshot" })' }, + { toolTip: "Drag a screengrabber", title: "Grab", icon: "photo-video", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyScreenshot as Doc }, // { title: "Drag a webcam", title: "Cam", icon: "video", ignoreClick: true, drag: 'Docs.Create.WebCamDocument("", { _width: 400, _height: 400, title: "a test cam" })' }, - { toolTip: "Drag a audio recorder", title: "Audio", icon: "microphone", ignoreClick: true, drag: `Docs.Create.AudioDocument("${nullAudio}", { _width: 200, title: "ready to record audio" })` }, - { toolTip: "Drag a button", title: "Button", icon: "bolt", ignoreClick: true, drag: 'Docs.Create.ButtonDocument({ _width: 150, _height: 50, _xPadding:10, _yPadding: 10, title: "Button" })' }, - { toolTip: "Drag a presentation view", title: "Prezi", icon: "tv", click: 'openOnRight(Doc.UserDoc().activePresentation = getCopy(this.dragFactory, true))', drag: `Doc.UserDoc().activePresentation = getCopy(this.dragFactory,true)`, dragFactory: doc.emptyPresentation as Doc }, - { toolTip: "Drag a search box", title: "Query", icon: "search", ignoreClick: true, drag: 'Docs.Create.QueryDocument({ _width: 200, title: "an image of a cat" })' }, + { toolTip: "Drag a audio recorder", title: "Audio", icon: "microphone", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyAudio as Doc }, + { toolTip: "Drag a button", title: "Button", icon: "bolt", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyButton as Doc }, + + { toolTip: "Drag a presentation view", title: "Prezi", icon: "tv", click: 'openOnRight(Doc.UserDoc().activePresentation = getCopy(this.dragFactory, true))', drag: `Doc.UserDoc().activePresentation = getCopy(this.dragFactory, true)`, dragFactory: doc.emptyPresentation as Doc }, + { toolTip: "Drag a search box", title: "Query", icon: "search", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptySearch as Doc }, { toolTip: "Drag a scripting box", title: "Script", icon: "terminal", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyScript as Doc }, // { title: "Drag an import folder", title: "Load", icon: "cloud-upload-alt", ignoreClick: true, drag: 'Docs.Create.DirectoryImportDocument({ title: "Directory Import", _width: 400, _height: 400 })' }, { toolTip: "Drag a mobile view", title: "Phone", icon: "mobile", click: 'openOnRight(Doc.UserDoc().activeMobileMenu)', drag: 'this.dragFactory', dragFactory: doc.activeMobileMenu as Doc }, @@ -421,7 +437,7 @@ export class CurrentUserUtils { // { title: "use stamp", icon: "stamp", click: 'activateStamp(this.activeInkPen = sameDocs(this.activeInkPen, this) ? undefined : this)', backgroundColor: "orange", ischecked: `sameDocs(this.activeInkPen, this)`, activeInkPen: doc }, // { title: "use eraser", icon: "eraser", click: 'activateEraser(this.activeInkPen = sameDocs(this.activeInkPen, this) ? undefined : this);', ischecked: `sameDocs(this.activeInkPen, this)`, backgroundColor: "pink", activeInkPen: doc }, // { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activeInkPen = this;', ischecked: `sameDocs(this.activeInkPen, this)`, backgroundColor: "white", activeInkPen: doc }, - { toolTip: "Drag a document previewer", title: "Prev", icon: "expand", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory,true)', dragFactory: doc.emptyDocHolder as Doc }, + { toolTip: "Drag a document previewer", title: "Prev", icon: "expand", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyDocHolder 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" })' }, ]; @@ -599,7 +615,7 @@ export class CurrentUserUtils { _width: 35, _height: 25, title: "Tools", _fontSize: "10pt", letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)", sourcePanel: toolsStack, - onDragStart: ScriptField.MakeFunction('getAlias(this.dragFactory, true)'), + onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: toolsStack, removeDropProperties: new List(["lockedPosition"]), stayInCollection: true, @@ -664,12 +680,12 @@ export class CurrentUserUtils { _width: 50, _height: 25, title: "Library", _fontSize: "10pt", targetDropAction: "same", letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)", sourcePanel: libraryStack, - onDragStart: ScriptField.MakeFunction('getAlias(this.dragFactory, true)'), + onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: libraryStack, removeDropProperties: new List(["lockedPosition"]), stayInCollection: true, targetContainer: new PrefetchProxy(sidebarContainer) as any as Doc, - onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel;") + onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel") })); } return doc["tabs-button-library"] as Doc; diff --git a/src/fields/ScriptField.ts b/src/fields/ScriptField.ts index 11b3b0524..ebca19430 100644 --- a/src/fields/ScriptField.ts +++ b/src/fields/ScriptField.ts @@ -3,7 +3,7 @@ import { CompiledScript, CompileScript, scriptingGlobal, ScriptOptions, CompileE import { Copy, ToScriptString, ToString, Parent, SelfProxy } from "./FieldSymbols"; import { serializable, createSimpleSchema, map, primitive, object, deserialize, PropSchema, custom, SKIP } from "serializr"; import { Deserializable, autoObject } from "../client/util/SerializationHelper"; -import { Doc, Field } from "./Doc"; +import { Doc, Field, Opt } from "./Doc"; import { Plugins, setter } from "./util"; import { computedFn } from "mobx-utils"; import { ProxyField } from "./Proxy"; @@ -38,6 +38,22 @@ const scriptSchema = createSimpleSchema({ }); async function deserializeScript(script: ScriptField) { + if (script.script.originalScript === 'getCopy(this.dragFactory, true)') { + return (script as any).script = (ScriptField.GetCopyOfDragFactory ?? (ScriptField.GetCopyOfDragFactory = ScriptField.MakeFunction('getCopy(this.dragFactory, true)')))?.script; + } + if (script.script.originalScript === 'links(self)') { + return (script as any).script = (ScriptField.LinksSelf ?? (ScriptField.LinksSelf = ComputedField.MakeFunction('links(self)')))?.script; + } + if (script.script.originalScript === 'openOnRight(getCopy(this.dragFactory, true))') { + return (script as any).script = (ScriptField.OpenOnRight ?? (ScriptField.OpenOnRight = ComputedField.MakeFunction('openOnRight(getCopy(this.dragFactory, true))')))?.script; + } + if (script.script.originalScript === 'deiconifyView(self)') { + return (script as any).script = (ScriptField.DeiconifyView ?? (ScriptField.DeiconifyView = ComputedField.MakeFunction('deiconifyView(self)')))?.script; + } + if (script.script.originalScript === 'convertToButtons(dragData)') { + return (script as any).script = (ScriptField.ConvertToButtons ?? (ScriptField.ConvertToButtons = ComputedField.MakeFunction('convertToButtons(dragData)')))?.script; + } + console.log(script.script.originalScript); const captures: ProxyField = (script as any).captures; if (captures) { const doc = (await captures.value())!; @@ -65,6 +81,11 @@ export class ScriptField extends ObjectField { @serializable(autoObject()) private captures?: ProxyField; + public static GetCopyOfDragFactory: Opt; + public static LinksSelf: Opt; + public static OpenOnRight: Opt; + public static DeiconifyView: Opt; + public static ConvertToButtons: Opt; constructor(script: CompiledScript, setterscript?: CompiledScript) { super(); -- cgit v1.2.3-70-g09d2 From 30b92fe6e39ffba2d55cc3f83e9d18d3d7bcf036 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 20 Jul 2020 15:36:46 -0400 Subject: fixed some performance issues with dragging invalidating stackingview documents unnecessarily --- src/client/util/DocumentManager.ts | 4 +- .../CollectionStackingViewFieldColumn.tsx | 68 +++++++++++++--------- 2 files changed, 43 insertions(+), 29 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index b66e7fdc4..51b50878d 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -9,6 +9,7 @@ import { LinkManager } from './LinkManager'; import { Scripting } from './Scripting'; import { SelectionManager } from './SelectionManager'; import { DocumentType } from '../documents/DocumentTypes'; +import { TraceMobx } from '../../fields/util'; export type CreateViewFunc = (doc: Doc, followLinkLocation: string, finished?: () => void) => void; @@ -104,8 +105,9 @@ export class DocumentManager { @computed public get LinkedDocumentViews() { + TraceMobx(); const pairs = DocumentManager.Instance.DocumentViews.reduce((pairs, dv) => { - const linksList = LinkManager.Instance.getAllRelatedLinks(dv.props.Document); + const linksList = DocListCast(dv.props.Document.links); pairs.push(...linksList.reduce((pairs, link) => { const linkToDoc = link && LinkManager.Instance.getOppositeAnchor(link, dv.props.Document); linkToDoc && DocumentManager.Instance.getDocumentViews(linkToDoc).map(docView1 => { diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index 2f4a25bfe..76af70cd1 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -2,7 +2,7 @@ import React = require("react"); import { library } from '@fortawesome/fontawesome-svg-core'; import { faPalette } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { action, observable, runInAction } from "mobx"; +import { action, observable, runInAction, computed } from "mobx"; import { observer } from "mobx-react"; import { Doc, DocListCast } from "../../../fields/Doc"; import { RichTextField } from "../../../fields/RichTextField"; @@ -279,8 +279,7 @@ export class CollectionStackingViewFieldColumn extends React.Component : (null); for (let i = 0; i < cols; i++) templatecols += `${style.columnWidth / style.numGroupColumns}px `; const chromeStatus = this.props.parent.props.Document._chromeStatus; + + return <> + {this.props.parent.Document._columnsHideIfEmpty ? (null) : headingView} + { + this.collapsed ? (null) : +
+
+ {this.props.parent.children(this.props.docList, uniqueHeadings.length)} + {singleColumn ? (null) : this.props.parent.columnDragger} +
+ {(chromeStatus !== 'view-mode' && chromeStatus !== 'disabled') ? +
+ +
: null} +
+ } + ; + } + + + render() { + TraceMobx(); + const headings = this.props.headings(); + const heading = this._heading; + const uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx); + const chromeStatus = this.props.parent.props.Document._chromeStatus; return (
- {this.props.parent.Document._columnsHideIfEmpty ? (null) : headingView} - { - this.collapsed ? (null) : -
-
- {this.props.parent.children(this.props.docList, uniqueHeadings.length)} - {singleColumn ? (null) : this.props.parent.columnDragger} -
- {(chromeStatus !== 'view-mode' && chromeStatus !== 'disabled') ? -
- -
: null} -
- } + {this.innards}
); } -- cgit v1.2.3-70-g09d2 From e613f4ebc268bb9d8a0bd1ea2f07fef73a870199 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 20 Jul 2020 17:01:39 -0400 Subject: fixed noAutoscroll functionality for creator icons --- src/client/documents/Documents.ts | 1 + src/client/util/CurrentUserUtils.ts | 7 +++---- src/client/util/DragManager.ts | 2 +- src/client/views/nodes/FontIconBox.scss | 3 ++- src/fields/ScriptField.ts | 2 +- 5 files changed, 8 insertions(+), 7 deletions(-) (limited to 'src/client/util') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 8e7d125b0..2d74c462d 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -69,6 +69,7 @@ export interface DocumentOptions { _showTitle?: string; // which field to display in the title area. leave empty to have no title _showCaption?: string; // which field to display in the caption area. leave empty to have no caption _scrollTop?: number; // scroll location for pdfs + _noAutoscroll?: boolean;// whether collectoins autoscroll when this item is dragged _chromeStatus?: string; _viewType?: string; // sub type of a collection _gridGap?: number; // gap between items in masonry view diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 4b8c342f1..d53a6fcdb 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -466,6 +466,7 @@ export class CurrentUserUtils { onClick: click ? ScriptField.MakeScript(click) : undefined, ischecked: ischecked ? ComputedField.MakeFunction(ischecked) : undefined, activeInkPen, + _noAutoscroll: true, backgroundColor, removeDropProperties: new List(["dropAction"]), dragFactory, @@ -735,15 +736,13 @@ 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, _noAutoscroll: true, _gridGap: 5, _xMargin: 5, _yMargin: 5, _height: 42, _width: 100, boxShadow: "0 0", forceActive: true, dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), backgroundColor: "black", treeViewPreventOpen: true, lockedPosition: true, _chromeStatus: "disabled", linearViewIsExpanded: true })) as any as Doc static ficon = (opts: DocumentOptions) => new PrefetchProxy(Docs.Create.FontIconDocument({ - ...opts, - dropAction: "alias", removeDropProperties: new List(["dropAction"]), _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100 + ...opts, _noAutoscroll: true, dropAction: "alias", removeDropProperties: new List(["dropAction"]), _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100 })) as any as Doc /// sets up the default list of buttons to be shown in the expanding button menu at the bottom of the Dash window diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 6a3108157..007336190 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -435,7 +435,7 @@ export namespace DragManager { const complete = new DragCompleteEvent(false, dragData); - if (target && !options?.noAutoscroll) { + if (target && !options?.noAutoscroll && !dragData.draggedDocuments?.some((d: any) => d._noAutoscroll)) { target.dispatchEvent( new CustomEvent("dashDragging", { bubbles: true, diff --git a/src/client/views/nodes/FontIconBox.scss b/src/client/views/nodes/FontIconBox.scss index fe0f067ad..5b85d8b0b 100644 --- a/src/client/views/nodes/FontIconBox.scss +++ b/src/client/views/nodes/FontIconBox.scss @@ -11,7 +11,6 @@ .fontIconBox-label { background: gray; color:white; - margin-left: -10px; border-radius: 8px; width:100%; position: absolute; @@ -19,6 +18,8 @@ font-size: 8px; margin-top:4px; letter-spacing: normal; + left: 0; + overflow: hidden; } svg { diff --git a/src/fields/ScriptField.ts b/src/fields/ScriptField.ts index ebca19430..4604a2132 100644 --- a/src/fields/ScriptField.ts +++ b/src/fields/ScriptField.ts @@ -51,7 +51,7 @@ async function deserializeScript(script: ScriptField) { return (script as any).script = (ScriptField.DeiconifyView ?? (ScriptField.DeiconifyView = ComputedField.MakeFunction('deiconifyView(self)')))?.script; } if (script.script.originalScript === 'convertToButtons(dragData)') { - return (script as any).script = (ScriptField.ConvertToButtons ?? (ScriptField.ConvertToButtons = ComputedField.MakeFunction('convertToButtons(dragData)')))?.script; + return (script as any).script = (ScriptField.ConvertToButtons ?? (ScriptField.ConvertToButtons = ComputedField.MakeFunction('convertToButtons(dragData)', { dragData: "DocumentDragData" })))?.script; } console.log(script.script.originalScript); const captures: ProxyField = (script as any).captures; -- cgit v1.2.3-70-g09d2 From c4499c610f377be4b80cf2999d25f97b619d4727 Mon Sep 17 00:00:00 2001 From: usodhi <61431818+usodhi@users.noreply.github.com> Date: Tue, 21 Jul 2020 17:17:47 +0530 Subject: distributing acls shifted to util.ts --- src/client/util/SharingManager.tsx | 47 +++------------ src/client/views/DocComponent.tsx | 34 ++++++----- src/client/views/collections/CollectionView.tsx | 76 +++++++++++++------------ src/fields/util.ts | 46 ++++++++++++++- 4 files changed, 109 insertions(+), 94 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx index 8b3ac2613..d3bc84770 100644 --- a/src/client/util/SharingManager.tsx +++ b/src/client/util/SharingManager.tsx @@ -1,4 +1,4 @@ -import { observable, runInAction, action } from "mobx"; +import { observable, runInAction, action, computed } from "mobx"; import * as React from "react"; import MainViewModal from "../views/MainViewModal"; import { Doc, Opt, DocListCastAsync, DataSym, DocListCast } from "../../fields/Doc"; @@ -20,6 +20,7 @@ import GroupMemberView from "./GroupMemberView"; import Select from "react-select"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { List } from "../../fields/List"; +import { distributeAcls } from "../../fields/util"; library.add(fa.faCopy, fa.faTimes); @@ -131,7 +132,7 @@ export default class SharingManager extends React.Component<{}> { // target[ACL] = permission; // Doc.GetProto(target)[ACL] = permission; - this.distributeAcls(ACL, permission as SharingPermissions); + distributeAcls(ACL, permission as SharingPermissions, this.targetDoc!); group.docsShared ? DocListCastAsync(group.docsShared).then(resolved => Doc.IndexOf(target, resolved!) === -1 && (group.docsShared as List).push(target)) : group.docsShared = new List([target]); @@ -174,7 +175,7 @@ export default class SharingManager extends React.Component<{}> { const ACL = `ACL-${StrCast(group.groupName)}`; // doc[ACL] = doc[DataSym][ACL] = "Not Shared"; - this.distributeAcls(ACL, SharingPermissions.None, doc); + distributeAcls(ACL, SharingPermissions.None, doc); const members: string[] = JSON.parse(StrCast(group.members)); const users: ValidatedUser[] = this.users.filter(({ user: { email } }) => members.includes(email)); @@ -186,6 +187,7 @@ export default class SharingManager extends React.Component<{}> { } } + // @action setInternalSharing = (recipient: ValidatedUser, permission: string) => { const { user, notificationDoc } = recipient; const target = this.targetDoc!; @@ -196,7 +198,7 @@ export default class SharingManager extends React.Component<{}> { // target[ACL] = permission; // Doc.GetProto(target)[ACL] = permission; - this.distributeAcls(ACL, permission as SharingPermissions); + distributeAcls(ACL, permission as SharingPermissions, this.targetDoc!); if (permission !== SharingPermissions.None) { DocListCastAsync(notificationDoc[storage]).then(resolved => { @@ -210,40 +212,6 @@ export default class SharingManager extends React.Component<{}> { } } - @action - distributeAcls = (key: string, acl: SharingPermissions, doc?: Doc) => { - const target = doc ? doc : this.targetDoc!; - const dataDoc = target[DataSym]; - target[key] = acl; - if (dataDoc) dataDoc[key] = acl; - // dataDoc[key] = target[key] = acl; - // next line distributes the acl to all children of the target - DocListCast(dataDoc[Doc.LayoutFieldKey(dataDoc)]).map(d => { - if (d.author === Doc.CurrentUserEmail) { - this.distributeAcls(key, acl, d); - d[key] = acl; - } - const data = d[DataSym]; - if (data && data.author === Doc.CurrentUserEmail) { - this.distributeAcls(key, acl, data); - data[key] = acl; - } - }); - - DocListCast(dataDoc[Doc.LayoutFieldKey(dataDoc) + "-annotations"]).map(d => { - if (d.author === Doc.CurrentUserEmail) { - this.distributeAcls(key, acl, d); - d[key] = acl; - } - const data = d[DataSym]; - if (data && data.author === Doc.CurrentUserEmail) { - this.distributeAcls(key, acl, data); - data[key] = acl; - } - console.log(d, d[DataSym]); - }); - - } // private setExternalSharing = (permission: string) => { // const sharingDoc = this.sharingDoc; @@ -344,7 +312,6 @@ export default class SharingManager extends React.Component<{}> { } private get sharingInterface() { - const groupList = GroupManager.Instance?.getAllGroups() || []; const sortedUsers = this.users.sort(this.sortUsers) @@ -368,7 +335,7 @@ export default class SharingManager extends React.Component<{}> { const users = this.individualSort === "ascending" ? this.users.sort(this.sortUsers) : this.individualSort === "descending" ? this.users.sort(this.sortUsers).reverse() : this.users; const groups = this.groupSort === "ascending" ? groupList.sort(this.sortGroups) : this.groupSort === "descending" ? groupList.sort(this.sortGroups).reverse() : groupList; - const userListContents: (JSX.Element | null)[] = users.map(({ user, notificationDoc }) => { // can't use async here + const userListContents: (JSX.Element | null)[] = users.map(({ user, notificationDoc }) => { const userKey = user.email.replace('.', '_'); const permissions = StrCast(this.targetDoc?.[`ACL-${userKey}`], SharingPermissions.None); diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index 2519360da..655be80ef 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -150,24 +150,28 @@ export function ViewBoxAnnotatableComponent

!docList.includes(d)); const effectiveAcl = GetEffectiveAcl(this.dataDoc); - if (this.props.Document[AclSym]) { - added.forEach(d => { - const dataDoc = d[DataSym]; - dataDoc[AclSym] = d[AclSym] = this.props.Document[AclSym]; - for (const [key, value] of Object.entries(this.props.Document[AclSym])) { - dataDoc[key] = d[key] = this.AclMap.get(value); - } - }); - } if (added.length) { if (effectiveAcl === AclReadonly && !getPlaygroundMode()) { return false; - } else if (effectiveAcl === AclAddonly) { - added.map(doc => console.log(Doc.AddDocToList(targetDataDoc, this.annotationKey, doc))); - } else { - added.map(doc => doc.context = this.props.Document); - targetDataDoc[this.annotationKey] = new List([...docList, ...added]); - targetDataDoc[this.annotationKey + "-lastModified"] = new DateField(new Date(Date.now())); + } + else { + if (this.props.Document[AclSym]) { + added.forEach(d => { + const dataDoc = d[DataSym]; + dataDoc[AclSym] = d[AclSym] = this.props.Document[AclSym]; + for (const [key, value] of Object.entries(this.props.Document[AclSym])) { + dataDoc[key] = d[key] = this.AclMap.get(value); + } + }); + } + if (effectiveAcl === AclAddonly) { + added.map(doc => console.log(Doc.AddDocToList(targetDataDoc, this.annotationKey, doc))); + } + else { + added.map(doc => doc.context = this.props.Document); + targetDataDoc[this.annotationKey] = new List([...docList, ...added]); + targetDataDoc[this.annotationKey + "-lastModified"] = new DateField(new Date(Date.now())); + } } } return true; diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 17567ea73..5cef6c44e 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -17,7 +17,7 @@ import { listSpec } from '../../../fields/Schema'; import { ComputedField, ScriptField } from '../../../fields/ScriptField'; import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { ImageField } from '../../../fields/URLField'; -import { TraceMobx, GetEffectiveAcl, getPlaygroundMode } from '../../../fields/util'; +import { TraceMobx, GetEffectiveAcl, getPlaygroundMode, distributeAcls } from '../../../fields/util'; import { emptyFunction, emptyPath, returnEmptyFilter, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; @@ -142,46 +142,48 @@ export class CollectionView extends Touchable !docList.includes(d)); const effectiveAcl = GetEffectiveAcl(this.props.Document); - if (this.props.Document[AclSym]) { - // change so it only adds if more restrictive - added.forEach(d => { - console.log(d[Id]); - const dataDoc = d[DataSym]; - console.log(dataDoc[Id]); - for (const [key, value] of Object.entries(this.props.Document[AclSym])) { - dataDoc[key] = d[key] = this.AclMap.get(value); - } - dataDoc[AclSym] = d[AclSym] = this.props.Document[AclSym]; - - }); - } if (added.length) { if (effectiveAcl === AclReadonly && !getPlaygroundMode()) { return false; - } else if (effectiveAcl === AclAddonly) { - added.map(doc => Doc.AddDocToList(targetDataDoc, this.props.fieldKey, doc)); - } else { - added.map(doc => { - const context = Cast(doc.context, Doc, null); - if (context && (context.type === DocumentType.VID || context.type === DocumentType.WEB || context.type === DocumentType.PDF || context.type === DocumentType.IMG)) { - const pushpin = Docs.Create.FontIconDocument({ - title: "pushpin", - icon: "map-pin", x: Cast(doc.x, "number", null), y: Cast(doc.y, "number", null), _backgroundColor: "#0000003d", color: "#ACCEF7", - _width: 15, _height: 15, _xPadding: 0, isLinkButton: true, displayTimecode: Cast(doc.displayTimecode, "number", null) - }); - pushpin.isPushpin = true; - Doc.GetProto(pushpin).annotationOn = doc.annotationOn; - Doc.SetInPlace(doc, "annotationOn", undefined, true); - Doc.AddDocToList(context, Doc.LayoutFieldKey(context) + "-annotations", pushpin); - const pushpinLink = DocUtils.MakeLink({ doc: pushpin }, { doc: doc }, "pushpin", ""); - doc.displayTimecode = undefined; - } - doc.context = this.props.Document; - }); - added.map(add => Doc.AddDocToList(Cast(Doc.UserDoc().myCatalog, Doc, null), "data", add)); - targetDataDoc[this.props.fieldKey] = new List([...docList, ...added]); - targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now())); + } + else { + if (this.props.Document[AclSym]) { + // change so it only adds if more restrictive + added.forEach(d => { + const dataDoc = d[DataSym]; + for (const [key, value] of Object.entries(this.props.Document[AclSym])) { + distributeAcls(key, this.AclMap.get(value) as SharingPermissions, d); + } + dataDoc[AclSym] = d[AclSym] = this.props.Document[AclSym]; + }); + } + + if (effectiveAcl === AclAddonly) { + added.map(doc => Doc.AddDocToList(targetDataDoc, this.props.fieldKey, doc)); + } + else { + added.map(doc => { + const context = Cast(doc.context, Doc, null); + if (context && (context.type === DocumentType.VID || context.type === DocumentType.WEB || context.type === DocumentType.PDF || context.type === DocumentType.IMG)) { + const pushpin = Docs.Create.FontIconDocument({ + title: "pushpin", + icon: "map-pin", x: Cast(doc.x, "number", null), y: Cast(doc.y, "number", null), _backgroundColor: "#0000003d", color: "#ACCEF7", + _width: 15, _height: 15, _xPadding: 0, isLinkButton: true, displayTimecode: Cast(doc.displayTimecode, "number", null) + }); + pushpin.isPushpin = true; + Doc.GetProto(pushpin).annotationOn = doc.annotationOn; + Doc.SetInPlace(doc, "annotationOn", undefined, true); + Doc.AddDocToList(context, Doc.LayoutFieldKey(context) + "-annotations", pushpin); + const pushpinLink = DocUtils.MakeLink({ doc: pushpin }, { doc: doc }, "pushpin", ""); + doc.displayTimecode = undefined; + } + doc.context = this.props.Document; + }); + added.map(add => Doc.AddDocToList(Cast(Doc.UserDoc().myCatalog, Doc, null), "data", add)); + targetDataDoc[this.props.fieldKey] = new List([...docList, ...added]); + targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now())); + } } } return true; diff --git a/src/fields/util.ts b/src/fields/util.ts index ee01f6213..a714b01e3 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, fetchProto } from "./Doc"; +import { Doc, FieldResult, UpdatingFromServer, LayoutSym, AclPrivate, AclEdit, AclReadonly, AclAddonly, AclSym, fetchProto, DataSym, DocListCast } from "./Doc"; import { SerializationHelper } from "../client/util/SerializationHelper"; import { ProxyField, PrefetchProxy } from "./Proxy"; import { RefField } from "./RefField"; @@ -8,7 +8,8 @@ import { action, trace } from "mobx"; import { Parent, OnUpdate, Update, Id, SelfProxy, Self } from "./FieldSymbols"; import { DocServer } from "../client/DocServer"; import { ComputedField } from "./ScriptField"; -import { ScriptCast } from "./Types"; +import { ScriptCast, StrCast } from "./Types"; +import { SharingPermissions } from "../client/util/SharingManager"; function _readOnlySetter(): never { @@ -168,6 +169,47 @@ export function GetEffectiveAcl(target: any, in_prop?: string | symbol | number) return AclEdit; } +export function distributeAcls(key: string, acl: SharingPermissions, target: Doc) { + + const HierarchyMapping = new Map([ + ["Not Shared", 0], + ["Can View", 1], + ["Can Add", 2], + ["Can Edit", 3] + ]); + + const dataDoc = target[DataSym]; + + if (!target[key] || HierarchyMapping.get(StrCast(target[key]))! < HierarchyMapping.get(acl)!) target[key] = acl; + + if (dataDoc && (!dataDoc[key] || HierarchyMapping.get(StrCast(dataDoc[key]))! < HierarchyMapping.get(acl)!)) { + dataDoc[key] = acl; + + DocListCast(dataDoc[Doc.LayoutFieldKey(dataDoc)]).map(d => { + if (d.author === Doc.CurrentUserEmail && d[key] && HierarchyMapping.get(StrCast(d[key]))! < HierarchyMapping.get(acl)!) { + distributeAcls(key, acl, d); + d[key] = acl; + } + const data = d[DataSym]; + if (data && data.author === Doc.CurrentUserEmail && data[key] && HierarchyMapping.get(StrCast(data[key]))! < HierarchyMapping.get(acl)!) { + distributeAcls(key, acl, data); + data[key] = acl; + } + }); + + DocListCast(dataDoc[Doc.LayoutFieldKey(dataDoc) + "-annotations"]).map(d => { + if (d.author === Doc.CurrentUserEmail && d[key] && HierarchyMapping.get(StrCast(d[key]))! < HierarchyMapping.get(acl)!) { + distributeAcls(key, acl, d); + d[key] = acl; + } + const data = d[DataSym]; + if (data && data.author === Doc.CurrentUserEmail && data[key] && HierarchyMapping.get(StrCast(data[key]))! < HierarchyMapping.get(acl)!) { + distributeAcls(key, acl, data); + data[key] = acl; + } + }); + } +} const layoutProps = ["panX", "panY", "width", "height", "nativeWidth", "nativeHeight", "fitWidth", "fitToBox", "chromeStatus", "viewType", "gridGap", "xMargin", "yMargin", "autoHeight"]; -- cgit v1.2.3-70-g09d2 From 2d0741800ed626ac3db2a8ac551904cbc0f7848e Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 21 Jul 2020 09:38:29 -0400 Subject: fixed up autoscrollin a bit. scrolls the correct collection and waits 250ms to start scrolling. --- src/client/documents/Documents.ts | 2 +- src/client/util/CurrentUserUtils.ts | 5 +- src/client/util/DragManager.ts | 96 ++++++++++++---------- .../collectionFreeForm/CollectionFreeFormView.tsx | 41 +++------ 4 files changed, 65 insertions(+), 79 deletions(-) (limited to 'src/client/util') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 2d74c462d..36c8a0d3b 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -69,7 +69,7 @@ export interface DocumentOptions { _showTitle?: string; // which field to display in the title area. leave empty to have no title _showCaption?: string; // which field to display in the caption area. leave empty to have no caption _scrollTop?: number; // scroll location for pdfs - _noAutoscroll?: boolean;// whether collectoins autoscroll when this item is dragged + _noAutoscroll?: boolean;// whether collections autoscroll when this item is dragged _chromeStatus?: string; _viewType?: string; // sub type of a collection _gridGap?: number; // gap between items in masonry view diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index d53a6fcdb..03a75381a 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -466,7 +466,6 @@ export class CurrentUserUtils { onClick: click ? ScriptField.MakeScript(click) : undefined, ischecked: ischecked ? ComputedField.MakeFunction(ischecked) : undefined, activeInkPen, - _noAutoscroll: true, backgroundColor, removeDropProperties: new List(["dropAction"]), dragFactory, @@ -736,13 +735,13 @@ export class CurrentUserUtils { } static blist = (opts: DocumentOptions, docs: Doc[]) => new PrefetchProxy(Docs.Create.LinearDocument(docs, { - ...opts, _noAutoscroll: true, _gridGap: 5, _xMargin: 5, _yMargin: 5, _height: 42, _width: 100, boxShadow: "0 0", forceActive: true, + ...opts, _gridGap: 5, _xMargin: 5, _yMargin: 5, _height: 42, _width: 100, boxShadow: "0 0", forceActive: true, dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), backgroundColor: "black", treeViewPreventOpen: true, lockedPosition: true, _chromeStatus: "disabled", linearViewIsExpanded: true })) as any as Doc static ficon = (opts: DocumentOptions) => new PrefetchProxy(Docs.Create.FontIconDocument({ - ...opts, _noAutoscroll: true, dropAction: "alias", removeDropProperties: new List(["dropAction"]), _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100 + ...opts, dropAction: "alias", removeDropProperties: new List(["dropAction"]), _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100 })) as any as Doc /// sets up the default list of buttons to be shown in the expanding button menu at the bottom of the Dash window diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 007336190..4291eee9c 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -7,7 +7,7 @@ import { listSpec } from "../../fields/Schema"; import { SchemaHeaderField } from "../../fields/SchemaHeaderField"; import { ScriptField } from "../../fields/ScriptField"; import { Cast, NumCast, ScriptCast, StrCast } from "../../fields/Types"; -import { emptyFunction } from "../../Utils"; +import { emptyFunction, returnTrue } from "../../Utils"; import { Docs, DocUtils } from "../documents/Documents"; import * as globalCssVariables from "../views/globalCssVariables.scss"; import { UndoManager } from "./UndoManager"; @@ -235,7 +235,8 @@ export namespace DragManager { e.docDragData && (e.docDragData.droppedDocuments = [bd]); return e; }; - options && (options.noAutoscroll = true); + options = options ?? {}; + options.noAutoscroll = true; // these buttons are being dragged on the overlay layer, so scrollin the underlay is not appropriate StartDrag(eles, new DragManager.DocumentDragData([]), downX, downY, options, finishDrag); } @@ -411,6 +412,8 @@ export namespace DragManager { const yFromTop = downY - elesCont.top; const xFromRight = elesCont.right - downX; const yFromBottom = elesCont.bottom - downY; + let paused = false; + let scrollAwaiter: Opt; const moveHandler = (e: PointerEvent) => { e.preventDefault(); // required or dragging text menu link item ends up dragging the link button as native drag/drop if (dragData instanceof DocumentDragData) { @@ -433,50 +436,55 @@ export namespace DragManager { const target = document.elementFromPoint(e.x, e.y); - const complete = new DragCompleteEvent(false, dragData); - if (target && !options?.noAutoscroll && !dragData.draggedDocuments?.some((d: any) => d._noAutoscroll)) { - target.dispatchEvent( - new CustomEvent("dashDragging", { - bubbles: true, - detail: { - shiftKey: e.shiftKey, - altKey: e.altKey, - metaKey: e.metaKey, - ctrlKey: e.ctrlKey, - clientX: e.clientX, - clientY: e.clientY, - dataTransfer: new DataTransfer, - button: e.button, - buttons: e.buttons, - getModifierState: e.getModifierState, - movementX: e.movementX, - movementY: e.movementY, - pageX: e.pageX, - pageY: e.pageY, - relatedTarget: e.relatedTarget, - screenX: e.screenX, - screenY: e.screenY, - detail: e.detail, - view: e.view ? e.view : new Window, - nativeEvent: new DragEvent("dashDragging"), - currentTarget: target, - target: target, + scrollAwaiter && clearTimeout(scrollAwaiter); + scrollAwaiter = setTimeout(() => autoScrollHandler(), 250); + const autoScrollHandler = () => { + target.dispatchEvent( + new CustomEvent("dashDragAutoScroll", { bubbles: true, - cancelable: true, - defaultPrevented: true, - eventPhase: e.eventPhase, - isTrusted: true, - preventDefault: e.preventDefault, - isDefaultPrevented: () => true, - stopPropagation: e.stopPropagation, - isPropagationStopped: () => true, - persist: emptyFunction, - timeStamp: e.timeStamp, - type: "dashDragging" - } - }) - ); + detail: { + shiftKey: e.shiftKey, + altKey: e.altKey, + metaKey: e.metaKey, + ctrlKey: e.ctrlKey, + clientX: e.clientX, + clientY: e.clientY, + dataTransfer: new DataTransfer, + button: e.button, + buttons: e.buttons, + getModifierState: e.getModifierState, + movementX: e.movementX, + movementY: e.movementY, + pageX: e.pageX, + pageY: e.pageY, + relatedTarget: e.relatedTarget, + screenX: e.screenX, + screenY: e.screenY, + detail: e.detail, + view: e.view ? e.view : new Window, + nativeEvent: new DragEvent("dashDragAutoScroll"), + currentTarget: target, + target: target, + bubbles: true, + cancelable: true, + defaultPrevented: true, + eventPhase: e.eventPhase, + isTrusted: true, + preventDefault: () => "not implemented for this event" ? false : false, + isDefaultPrevented: () => "not implemented for this event" ? false : false, + stopPropagation: () => "not implemented for this event" ? false : false, + isPropagationStopped: () => "not implemented for this event" ? false : false, + persist: emptyFunction, + timeStamp: e.timeStamp, + type: "dashDragAutoScroll" + } + }) + ); + + scrollAwaiter && clearTimeout(scrollAwaiter); + SnappingManager.GetIsDragging() && (scrollAwaiter = setTimeout(() => autoScrollHandler(), 25)); + } } const { thisX, thisY } = snapDrag(e, xFromLeft, yFromTop, xFromRight, yFromBottom); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 01b0c81d8..412f91417 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -85,8 +85,6 @@ export class CollectionFreeFormView extends CollectionSubView = new Map(); @@ -582,7 +580,6 @@ export class CollectionFreeFormView extends CollectionSubView { - this._lastClientY = this._lastClientX = undefined; if (InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) return; document.removeEventListener("pointermove", this.onPointerMove); @@ -1152,16 +1149,12 @@ export class CollectionFreeFormView extends CollectionSubView this._layoutElements = elements || [], { fireImmediately: true, name: "doLayout" }); - const handler = (e: any) => this.handleDragging(e, (e as CustomEvent).detail); - - document.addEventListener("dashDragging", handler); + this._marqueeRef.current?.addEventListener("dashDragAutoScroll", this.onDragAutoScroll as any); } componentWillUnmount() { this._layoutComputeReaction?.(); - - const handler = (e: any) => this.handleDragging(e, (e as CustomEvent).detail); - document.removeEventListener("dashDragging", handler); + this._marqueeRef.current?.removeEventListener("dashDragAutoScroll", this.onDragAutoScroll as any); } @computed get views() { return this._layoutElements.filter(ele => ele.bounds && !ele.bounds.z).map(ele => ele.ele); } @@ -1176,39 +1169,25 @@ export class CollectionFreeFormView extends CollectionSubView @action - handleDragging = (e: CustomEvent, de: DragEvent) => { - if ((e as any).handlePan) return; + onDragAutoScroll = (e: CustomEvent) => { + if ((e as any).handlePan || this.props.isAnnotationOverlay) return; (e as any).handlePan = true; - this._lastClientY = e.detail.clientY; - this._lastClientX = e.detail.clientX; if (this._marqueeRef?.current) { const dragX = e.detail.clientX; const dragY = e.detail.clientY; const bounds = this._marqueeRef.current?.getBoundingClientRect(); - const deltaX = dragX - bounds.left < 25 ? -2 : bounds.right - dragX < 25 ? 2 : 0; - const deltaY = dragY - bounds.top < 25 ? -2 : bounds.bottom - dragY < 25 ? 2 : 0; - (deltaX !== 0 || deltaY !== 0) && this.continuePan(deltaX, deltaY); + const deltaX = dragX - bounds.left < 25 ? -(25 + (bounds.left - dragX)) : bounds.right - dragX < 25 ? 25 - (bounds.right - dragX) : 0; + const deltaY = dragY - bounds.top < 25 ? -(25 + (bounds.top - dragY)) : bounds.bottom - dragY < 25 ? 25 - (bounds.bottom - dragY) : 0; + if (deltaX !== 0 || deltaY !== 0) { + this.Document._panY = NumCast(this.Document._panY) + deltaY / 2; + this.Document._panX = NumCast(this.Document._panX) + deltaX / 2; + } } e.stopPropagation(); } - continuePan = (deltaX: number, deltaY: number) => { - setTimeout(action(() => { - const dragY = this._lastClientY; - const dragX = this._lastClientX; - if (dragY !== undefined && dragX !== undefined && this._marqueeRef.current) { - const bounds = this._marqueeRef.current.getBoundingClientRect(); - this.Document._panY = NumCast(this.Document._panY) + deltaY; - this.Document._panX = NumCast(this.Document._panX) + deltaX; - if (dragY - bounds.top < 25 || bounds.bottom - dragY < 25 || dragX - bounds.left < 25 || bounds.right - dragX < 25) { - this.continuePan(deltaX, deltaY); - } - } else this._lastClientY !== undefined && this._lastClientX !== undefined && this.continuePan(deltaX, deltaY); - }), 50); - } - promoteCollection = undoBatch(action(() => { const childDocs = this.childDocs.slice(); childDocs.forEach(doc => { -- cgit v1.2.3-70-g09d2 From 3d06cdd362d58dfbc8d6efdcd9dc59250ab003a4 Mon Sep 17 00:00:00 2001 From: usodhi <61431818+usodhi@users.noreply.github.com> Date: Tue, 21 Jul 2020 23:16:49 +0530 Subject: distributeAcls only changes if container is more restrictive --- src/client/util/SharingManager.tsx | 14 +++++--------- src/client/views/DocComponent.tsx | 2 +- src/client/views/collections/CollectionView.tsx | 6 +++--- src/client/views/nodes/DocumentView.tsx | 5 +++-- src/fields/util.ts | 18 +++++++----------- 5 files changed, 19 insertions(+), 26 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx index d3bc84770..9c857a7c0 100644 --- a/src/client/util/SharingManager.tsx +++ b/src/client/util/SharingManager.tsx @@ -1,7 +1,7 @@ -import { observable, runInAction, action, computed } from "mobx"; +import { observable, runInAction, action } from "mobx"; import * as React from "react"; import MainViewModal from "../views/MainViewModal"; -import { Doc, Opt, DocListCastAsync, DataSym, DocListCast } from "../../fields/Doc"; +import { Doc, Opt, DocListCastAsync } from "../../fields/Doc"; import { DocServer } from "../DocServer"; import { Cast, StrCast } from "../../fields/Types"; import * as RequestPromise from "request-promise"; @@ -41,9 +41,9 @@ interface GroupOptions { options: UserOptions[]; } -const SharingKey = "sharingPermissions"; -const PublicKey = "publicLinkPermissions"; -const DefaultColor = "black"; +// const SharingKey = "sharingPermissions"; +// const PublicKey = "publicLinkPermissions"; +// const DefaultColor = "black"; const groupType = "!groupType/"; const indType = "!indType/"; @@ -192,12 +192,8 @@ export default class SharingManager extends React.Component<{}> { const { user, notificationDoc } = recipient; const target = this.targetDoc!; const key = user.email.replace('.', '_'); - const ACL = `ACL-${key}`; - // target[ACL] = permission; - // Doc.GetProto(target)[ACL] = permission; - distributeAcls(ACL, permission as SharingPermissions, this.targetDoc!); if (permission !== SharingPermissions.None) { diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index 655be80ef..95c1bcda8 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -165,7 +165,7 @@ export function ViewBoxAnnotatableComponent

console.log(Doc.AddDocToList(targetDataDoc, this.annotationKey, doc))); + added.map(doc => Doc.AddDocToList(targetDataDoc, this.annotationKey, doc)); } else { added.map(doc => doc.context = this.props.Document); diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 5cef6c44e..9b04deff5 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -151,11 +151,11 @@ export class CollectionView extends Touchable { - const dataDoc = d[DataSym]; + // const dataDoc = d[DataSym]; for (const [key, value] of Object.entries(this.props.Document[AclSym])) { - distributeAcls(key, this.AclMap.get(value) as SharingPermissions, d); + distributeAcls(key, this.AclMap.get(value) as SharingPermissions, d, true); } - dataDoc[AclSym] = d[AclSym] = this.props.Document[AclSym]; + // dataDoc[AclSym] = d[AclSym] = this.props.Document[AclSym]; }); } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 803720417..0b5bd707b 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -4,7 +4,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; import * as rp from "request-promise"; -import { Doc, DocListCast, HeightSym, Opt, WidthSym, DataSym, AclPrivate, AclReadonly } from "../../../fields/Doc"; +import { Doc, DocListCast, HeightSym, Opt, WidthSym, DataSym, AclPrivate, AclEdit } from "../../../fields/Doc"; import { Document } from '../../../fields/documentSchemas'; import { Id } from '../../../fields/FieldSymbols'; import { InkTool } from '../../../fields/InkField'; @@ -707,6 +707,7 @@ export class DocumentView extends DocComponent(Docu if (data && data.author === Doc.CurrentUserEmail) data.ACL = acl; }); } + @undoBatch @action testAcl = (acl: SharingPermissions) => { @@ -806,7 +807,7 @@ export class DocumentView extends DocComponent(Docu }); moreItems.push({ description: "Copy ID", event: () => Utils.CopyText(Utils.prepend("/doc/" + this.props.Document[Id])), icon: "fingerprint" }); } - moreItems.push({ description: "Delete", event: this.deleteClicked, icon: "trash" }); + GetEffectiveAcl(this.props.Document) === AclEdit && moreItems.push({ description: "Delete", event: this.deleteClicked, icon: "trash" }); moreItems.push({ description: "Share", event: () => SharingManager.Instance.open(this), icon: "external-link-alt" }); !more && cm.addItem({ description: "More...", subitems: moreItems, icon: "hand-point-right" }); cm.moveAfter(cm.findByDescription("More...")!, cm.findByDescription("OnClick...")!); diff --git a/src/fields/util.ts b/src/fields/util.ts index a714b01e3..81ccbf6d9 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -137,14 +137,10 @@ export function GetEffectiveAcl(target: any, in_prop?: string | symbol | number) if (target[AclSym] && Object.keys(target[AclSym]).length) { - // console.log(target[AclSym]); - if (target.__fields?.author === Doc.CurrentUserEmail || target.author === Doc.CurrentUserEmail || currentUserGroups.includes("admin")) return AclEdit; if (_overrideAcl || (in_prop && DocServer.PlaygroundFields?.includes(in_prop.toString()))) return AclEdit; - // if (target[AclSym].ACL) return target[AclSym].ACL; - let effectiveAcl = AclPrivate; let aclPresent = false; @@ -169,7 +165,7 @@ export function GetEffectiveAcl(target: any, in_prop?: string | symbol | number) return AclEdit; } -export function distributeAcls(key: string, acl: SharingPermissions, target: Doc) { +export function distributeAcls(key: string, acl: SharingPermissions, target: Doc, inheritingFromCollection?: boolean) { const HierarchyMapping = new Map([ ["Not Shared", 0], @@ -180,30 +176,30 @@ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc const dataDoc = target[DataSym]; - if (!target[key] || HierarchyMapping.get(StrCast(target[key]))! < HierarchyMapping.get(acl)!) target[key] = acl; + if (!inheritingFromCollection || !target[key] || HierarchyMapping.get(StrCast(target[key]))! > HierarchyMapping.get(acl)!) target[key] = acl; - if (dataDoc && (!dataDoc[key] || HierarchyMapping.get(StrCast(dataDoc[key]))! < HierarchyMapping.get(acl)!)) { + if (dataDoc && (!inheritingFromCollection || !dataDoc[key] || HierarchyMapping.get(StrCast(dataDoc[key]))! > HierarchyMapping.get(acl)!)) { dataDoc[key] = acl; DocListCast(dataDoc[Doc.LayoutFieldKey(dataDoc)]).map(d => { - if (d.author === Doc.CurrentUserEmail && d[key] && HierarchyMapping.get(StrCast(d[key]))! < HierarchyMapping.get(acl)!) { + if (d.author === Doc.CurrentUserEmail && (!inheritingFromCollection || !d[key] || HierarchyMapping.get(StrCast(d[key]))! > HierarchyMapping.get(acl)!)) { distributeAcls(key, acl, d); d[key] = acl; } const data = d[DataSym]; - if (data && data.author === Doc.CurrentUserEmail && data[key] && HierarchyMapping.get(StrCast(data[key]))! < HierarchyMapping.get(acl)!) { + if (data && data.author === Doc.CurrentUserEmail && (!inheritingFromCollection || !data[key] || HierarchyMapping.get(StrCast(data[key]))! > HierarchyMapping.get(acl)!)) { distributeAcls(key, acl, data); data[key] = acl; } }); DocListCast(dataDoc[Doc.LayoutFieldKey(dataDoc) + "-annotations"]).map(d => { - if (d.author === Doc.CurrentUserEmail && d[key] && HierarchyMapping.get(StrCast(d[key]))! < HierarchyMapping.get(acl)!) { + if (d.author === Doc.CurrentUserEmail && (!inheritingFromCollection || !d[key] || HierarchyMapping.get(StrCast(d[key]))! > HierarchyMapping.get(acl)!)) { distributeAcls(key, acl, d); d[key] = acl; } const data = d[DataSym]; - if (data && data.author === Doc.CurrentUserEmail && data[key] && HierarchyMapping.get(StrCast(data[key]))! < HierarchyMapping.get(acl)!) { + if (data && data.author === Doc.CurrentUserEmail && (!inheritingFromCollection || !data[key] || HierarchyMapping.get(StrCast(data[key]))! > HierarchyMapping.get(acl)!)) { distributeAcls(key, acl, data); data[key] = acl; } -- cgit v1.2.3-70-g09d2 From 12dd45618c0dc595b8e6663bf8d3635dd7161306 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 21 Jul 2020 16:02:53 -0400 Subject: fixed compile warnings --- src/client/documents/Documents.ts | 4 +++- src/client/util/DragManager.ts | 9 ++++----- src/client/views/DocumentDecorations.tsx | 11 +++++------ src/client/views/MetadataEntryMenu.tsx | 4 ++-- src/client/views/collections/CollectionMenu.tsx | 6 +++--- .../collectionFreeForm/CollectionFreeFormLinkView.tsx | 10 +++++----- 6 files changed, 22 insertions(+), 22 deletions(-) (limited to 'src/client/util') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 657ba521b..e2569ec70 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -550,7 +550,9 @@ export namespace Docs { const dataDoc = MakeDataDelegate(proto, protoProps, data, fieldKey); const viewDoc = Doc.MakeDelegate(dataDoc, delegId); - // so that the list of annotations is already initialised, prevents issues in addonly + // 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. + dataDoc[fieldKey + "-annotations"] = new List(); proto.links = ComputedField.MakeFunction("links(self)"); diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 4291eee9c..837f0b1db 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -412,7 +412,6 @@ export namespace DragManager { const yFromTop = downY - elesCont.top; const xFromRight = elesCont.right - downX; const yFromBottom = elesCont.bottom - downY; - let paused = false; let scrollAwaiter: Opt; const moveHandler = (e: PointerEvent) => { e.preventDefault(); // required or dragging text menu link item ends up dragging the link button as native drag/drop @@ -437,8 +436,6 @@ export namespace DragManager { const target = document.elementFromPoint(e.x, e.y); if (target && !options?.noAutoscroll && !dragData.draggedDocuments?.some((d: any) => d._noAutoscroll)) { - scrollAwaiter && clearTimeout(scrollAwaiter); - scrollAwaiter = setTimeout(() => autoScrollHandler(), 250); const autoScrollHandler = () => { target.dispatchEvent( new CustomEvent("dashDragAutoScroll", { @@ -483,8 +480,10 @@ export namespace DragManager { ); scrollAwaiter && clearTimeout(scrollAwaiter); - SnappingManager.GetIsDragging() && (scrollAwaiter = setTimeout(() => autoScrollHandler(), 25)); - } + SnappingManager.GetIsDragging() && (scrollAwaiter = setTimeout(autoScrollHandler, 25)); + }; + scrollAwaiter && clearTimeout(scrollAwaiter); + scrollAwaiter = setTimeout(autoScrollHandler, 250); } const { thisX, thisY } = snapDrag(e, xFromLeft, yFromTop, xFromRight, yFromBottom); diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 35c040f86..fec4ad9e0 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -293,13 +293,12 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> const doc = Document(element.rootDoc); if (doc.type === DocumentType.INK && doc.x && doc.y && doc._width && doc._height && doc.data) { doc.rotation = Number(doc.rotation) + Number(angle); - const ink = Cast(doc.data, InkField)?.inkData; - if (ink) { - + const inks = Cast(doc.data, InkField)?.inkData; + if (inks) { const newPoints: { X: number, Y: number }[] = []; - for (var i = 0; i < ink.length; i++) { - const newX = Math.cos(angle) * (ink[i].X - this._centerPoints[index].X) - Math.sin(angle) * (ink[i].Y - this._centerPoints[index].Y) + this._centerPoints[index].X; - const newY = Math.sin(angle) * (ink[i].X - this._centerPoints[index].X) + Math.cos(angle) * (ink[i].Y - this._centerPoints[index].Y) + this._centerPoints[index].Y; + for (const ink of inks) { + const newX = Math.cos(angle) * (ink.X - this._centerPoints[index].X) - Math.sin(angle) * (ink.Y - this._centerPoints[index].Y) + this._centerPoints[index].X; + const newY = Math.sin(angle) * (ink.X - this._centerPoints[index].X) + Math.cos(angle) * (ink.Y - this._centerPoints[index].Y) + this._centerPoints[index].Y; newPoints.push({ X: newX, Y: newY }); } doc.data = new InkField(newPoints); diff --git a/src/client/views/MetadataEntryMenu.tsx b/src/client/views/MetadataEntryMenu.tsx index ca8a6e1d7..82ec5a5b3 100644 --- a/src/client/views/MetadataEntryMenu.tsx +++ b/src/client/views/MetadataEntryMenu.tsx @@ -38,7 +38,7 @@ export class MetadataEntryMenu extends React.Component{ let field: Field | undefined | null = null; let onProto: boolean = false; let value: string | undefined = undefined; - let docs = this.props.docs; + const docs = this.props.docs; for (const doc of docs) { const v = await doc[this._currentKey]; onProto = onProto || !Object.keys(doc).includes(this._currentKey); @@ -110,7 +110,7 @@ export class MetadataEntryMenu extends React.Component{ getKeySuggestions = (value: string) => { value = value.toLowerCase(); - let docs = this.props.docs; + const docs = this.props.docs; const keys = new Set(); docs.forEach(doc => Doc.allKeys(doc).forEach(key => keys.add(key))); return Array.from(keys).filter(key => key.toLowerCase().startsWith(value)); diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index 2be57b6d2..e7c5ca86b 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -402,7 +402,7 @@ export class CollectionFreeFormViewChrome extends React.Component this._widthBtn = !this._widthBtn, "bars", null); + const widthPicker = this.toggleButton("stroke width", this._widthBtn, () => this._widthBtn = !this._widthBtn, "bars", null); return !this._widthBtn ? widthPicker :

{widthPicker} @@ -416,7 +416,7 @@ export class CollectionFreeFormViewChrome extends React.Component this._colorBtn = !this._colorBtn, "pen-nib", + const colorPicker = this.toggleButton("stroke color", this._colorBtn, () => this._colorBtn = !this._colorBtn, "pen-nib",
); return !this._colorBtn ? colorPicker :
@@ -431,7 +431,7 @@ export class CollectionFreeFormViewChrome extends React.Component; } @computed get fillPicker() { - var fillPicker = this.toggleButton("shape fill color", this._fillBtn, () => this._fillBtn = !this._fillBtn, "fill-drip", + const fillPicker = this.toggleButton("shape fill color", this._fillBtn, () => this._fillBtn = !this._fillBtn, "fill-drip",
); return !this._fillBtn ? fillPicker :
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index 6d44ac967..bfe569853 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -26,7 +26,7 @@ export class CollectionFreeFormLinkView extends React.Component (Date.now() < this._start++ + 1000) && setTimeout(this.timeout, 25); + timeout = () => (Date.now() < this._start++ + 1000) && setTimeout(this.timeout, 25) componentDidMount() { this._anchorDisposer = reaction(() => [this.props.A.props.ScreenToLocalTransform(), this.props.B.props.ScreenToLocalTransform(), this.props.A.isSelected() || Doc.IsBrushed(this.props.A.props.Document), this.props.A.isSelected() || Doc.IsBrushed(this.props.A.props.Document)], action(() => { @@ -111,10 +111,10 @@ export class CollectionFreeFormLinkView extends React.Component Date: Wed, 22 Jul 2020 11:33:28 -0400 Subject: restored download document. fixed clone() to clone to be async and handles lists properly. --- src/client/util/CurrentUserUtils.ts | 6 +++++ src/client/util/LinkManager.ts | 12 ++------- src/client/util/Scripting.ts | 10 +++----- src/client/views/GlobalKeyHandler.ts | 4 +-- src/client/views/PreviewCursor.tsx | 4 +-- .../collections/collectionFreeForm/MarqueeView.tsx | 8 +++--- src/client/views/linking/LinkEditor.tsx | 4 +-- src/client/views/linking/LinkMenuItem.tsx | 3 ++- src/client/views/nodes/DocumentView.tsx | 14 ++++------ src/client/views/nodes/LinkDocPreview.tsx | 9 +------ .../formattedText/FormattedTextBoxComment.tsx | 2 ++ .../views/nodes/formattedText/RichTextMenu.tsx | 4 ++- src/fields/Doc.ts | 30 +++++++++++----------- src/server/ApiManagers/DownloadManager.ts | 12 +++------ src/server/ApiManagers/UploadManager.ts | 14 +++------- 15 files changed, 56 insertions(+), 80 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 03a75381a..23b8f09de 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -22,6 +22,7 @@ import { DocumentType } from "../documents/DocumentTypes"; import { SchemaHeaderField } from "../../fields/SchemaHeaderField"; import { DimUnit } from "../views/collections/collectionMulticolumn/CollectionMulticolumnView"; import { LabelBox } from "../views/nodes/LabelBox"; +import { LinkManager } from "./LinkManager"; export class CurrentUserUtils { private static curr_id: string; @@ -888,3 +889,8 @@ export class CurrentUserUtils { Scripting.addGlobal(function createNewWorkspace() { return MainView.Instance.createNewWorkspace(); }, "creates a new workspace when called"); + +Scripting.addGlobal(function links(doc: any) { return new List(LinkManager.Instance.getAllRelatedLinks(doc)); }, + "returns all the links to the document or its annotations", "(doc: any)"); +Scripting.addGlobal(function directLinks(doc: any) { return new List(LinkManager.Instance.getAllDirectLinks(doc)); }, + "returns all the links directly to the document", "(doc: any)"); diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts index 974744344..223f0e7ef 100644 --- a/src/client/util/LinkManager.ts +++ b/src/client/util/LinkManager.ts @@ -2,8 +2,6 @@ import { Doc, DocListCast, Opt } from "../../fields/Doc"; import { List } from "../../fields/List"; import { listSpec } from "../../fields/Schema"; import { Cast, StrCast } from "../../fields/Types"; -import { Scripting } from "./Scripting"; -import { undoBatch } from "./UndoManager"; /* * link doc: @@ -25,12 +23,12 @@ export class LinkManager { private static _instance: LinkManager; - public static currentLink: Opt; public static get Instance(): LinkManager { return this._instance || (this._instance = new this()); } + private constructor() { } @@ -53,7 +51,6 @@ export class LinkManager { return false; } - @undoBatch public deleteLink(linkDoc: Doc): boolean { if (LinkManager.Instance.LinkManagerDoc && linkDoc instanceof Doc) { Doc.RemoveDocFromList(LinkManager.Instance.LinkManagerDoc, "data", linkDoc); @@ -210,9 +207,4 @@ export class LinkManager { if (Doc.AreProtosEqual(anchor, a2)) return a1; if (Doc.AreProtosEqual(anchor, linkDoc)) return linkDoc; } -} - -Scripting.addGlobal(function links(doc: any) { return new List(LinkManager.Instance.getAllRelatedLinks(doc)); }, - "returns all the links to the document or its annotations", "(doc: any)"); -Scripting.addGlobal(function directLinks(doc: any) { return new List(LinkManager.Instance.getAllDirectLinks(doc)); }, - "returns all the links directly to the document", "(doc: any)"); \ No newline at end of file +} \ No newline at end of file diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts index e6cf50de3..f1e6155d2 100644 --- a/src/client/util/Scripting.ts +++ b/src/client/util/Scripting.ts @@ -10,8 +10,6 @@ export { ts }; // @ts-ignore import * as typescriptlib from '!!raw-loader!./type_decls.d'; import { Doc, Field } from '../../fields/Doc'; -import { Cast } from "../../fields/Types"; -import { listSpec } from "../../fields/Schema"; export interface ScriptSucccess { success: true; @@ -95,10 +93,10 @@ export namespace Scripting { export function removeGlobal(name: string) { if (getGlobals().includes(name)) { delete _scriptingGlobals[name]; - if (_scriptingDescriptions[name]){ + if (_scriptingDescriptions[name]) { delete _scriptingDescriptions[name]; } - if (_scriptingParams[name]){ + if (_scriptingParams[name]) { delete _scriptingParams[name]; } return true; @@ -123,11 +121,11 @@ export namespace Scripting { return _scriptingGlobals; } - export function getDescriptions(){ + export function getDescriptions() { return _scriptingDescriptions; } - export function getParameters(){ + export function getParameters() { return _scriptingParams; } } diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index 4dfa7aec8..b63537b5f 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -309,13 +309,13 @@ export default class KeyManager { const targetDataDoc = Doc.GetProto(first.props.Document); const fieldKey = Doc.LayoutFieldKey(first.props.Document); const docList = DocListCast(targetDataDoc[fieldKey]); - docids.map((did, i) => i && DocServer.GetRefField(did).then(doc => { + docids.map((did, i) => i && DocServer.GetRefField(did).then(async doc => { count++; if (doc instanceof Doc) { list.push(doc); } if (count === docids.length) { - const added = list.filter(d => !docList.includes(d)).map(d => clone ? Doc.MakeClone(d) : d); + const added = await Promise.all(list.filter(d => !docList.includes(d)).map(async d => clone ? await Doc.MakeClone(d) : d)); if (added.length) { added.map(doc => doc.context = targetDataDoc); undoBatch(() => { diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx index 6583589f3..2d51403d7 100644 --- a/src/client/views/PreviewCursor.tsx +++ b/src/client/views/PreviewCursor.tsx @@ -69,11 +69,11 @@ export class PreviewCursor extends React.Component<{}> { const list: Doc[] = []; let first: Doc | undefined; - docids.map((did, i) => i && DocServer.GetRefField(did).then(doc => { + docids.map((did, i) => i && DocServer.GetRefField(did).then(async doc => { count++; if (doc instanceof Doc) { i === 1 && (first = doc); - const alias = clone ? Doc.MakeClone(doc) : doc; + const alias = clone ? await Doc.MakeClone(doc) : doc; const deltaX = NumCast(doc.x) - NumCast(first!.x) - ptx; const deltaY = NumCast(doc.y) - NumCast(first!.y) - pty; alias.x = newPoint[0] + deltaX; diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 6db8c8992..84719b2c9 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -189,8 +189,8 @@ export class MarqueeView extends React.Component { this._downX = this._lastX = e.clientX; this._downY = this._lastY = e.clientY; - if (!(e as any).marqueeHit) { - (e as any).marqueeHit = true; + if (!(e.nativeEvent as any).marqueeHit) { + (e.nativeEvent as any).marqueeHit = true; // allow marquee if right click OR alt+left click OR space bar + left click if (e.button === 2 || (e.button === 0 && (e.altKey || (MarqueeView.DragMarquee && this.props.active(true))))) { // if (e.altKey || (MarqueeView.DragMarquee && this.props.active(true))) { @@ -291,8 +291,8 @@ export class MarqueeView extends React.Component { //@observable description = this.props.linkDoc.description ? StrCast(this.props.linkDoc.description) : "DESCRIPTION"; + @undoBatch @action deleteLink = (): void => { LinkManager.Instance.deleteLink(this.props.linkDoc); @@ -422,8 +424,6 @@ export class LinkEditor extends React.Component {

Editing Link to: { destination.proto?.title ?? destination.title ?? "untitled"}

- {/* */}
Show more link information
} placement="top">
diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx index 0e847632b..d8ba39f09 100644 --- a/src/client/views/linking/LinkMenuItem.tsx +++ b/src/client/views/linking/LinkMenuItem.tsx @@ -17,6 +17,7 @@ import { DocumentLinksButton } from '../nodes/DocumentLinksButton'; import { LinkDocPreview } from '../nodes/LinkDocPreview'; import { Tooltip } from '@material-ui/core'; import { DocumentType } from '../../documents/DocumentTypes'; +import { undoBatch } from '../../util/UndoManager'; library.add(faEye, faEdit, faTimes, faArrowRight, faChevronDown, faChevronUp, faPencilAlt, faEyeSlash); @@ -163,10 +164,10 @@ export class LinkMenuItem extends React.Component { } } + @undoBatch @action deleteLink = (): void => { LinkManager.Instance.deleteLink(this.props.linkDoc); - //this.props.showLinks(); LinkDocPreview.LinkInfo = undefined; DocumentLinksButton.EditLink = undefined; } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 0b5bd707b..12d9890c9 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -794,16 +794,12 @@ export class DocumentView extends DocComponent(Docu } moreItems.push({ description: "Download document", icon: "download", event: async () => { - const response = await rp.get(Utils.CorsProxy("http://localhost:8983/solr/dash/select"), { - qs: { q: 'world', fq: 'NOT baseProto_b:true AND NOT deleted:true', start: '0', rows: '100', hl: true, 'hl.fl': '*' } - }); - console.log(response ? JSON.parse(response) : undefined); + const a = document.createElement("a"); + const url = Utils.prepend(`/downloadId/${this.props.Document[Id]}`); + a.href = url; + a.download = `DocExport-${this.props.Document[Id]}.zip`; + a.click(); } - // const a = document.createElement("a"); - // const url = Utils.prepend(`/downloadId/${this.props.Document[Id]}`); - // a.href = url; - // a.download = `DocExport-${this.props.Document[Id]}.zip`; - // a.click(); }); moreItems.push({ description: "Copy ID", event: () => Utils.CopyText(Utils.prepend("/doc/" + this.props.Document[Id])), icon: "fingerprint" }); } diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx index 1caa82380..ebb916307 100644 --- a/src/client/views/nodes/LinkDocPreview.tsx +++ b/src/client/views/nodes/LinkDocPreview.tsx @@ -15,6 +15,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { LinkManager } from '../../util/LinkManager'; import { DocumentLinksButton } from './DocumentLinksButton'; import { ContextMenu } from '../ContextMenu'; +import { undoBatch } from '../../util/UndoManager'; interface Props { linkDoc?: Doc; @@ -31,14 +32,6 @@ export class LinkDocPreview extends React.Component { @observable _toolTipText = ""; _editRef = React.createRef(); - @action - deleteLink = (): void => { - this.props.linkDoc ? LinkManager.Instance.deleteLink(this.props.linkDoc) : null; - //this.props.showLinks(); - LinkDocPreview.LinkInfo = undefined; - DocumentLinksButton.EditLink = undefined; - } - @action onContextMenu = (e: React.MouseEvent) => { DocumentLinksButton.EditLink = undefined; diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx index 3687d5513..6f3984f39 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx @@ -22,6 +22,7 @@ import { LinkManager } from "../../../util/LinkManager"; import { LinkDocPreview } from "../LinkDocPreview"; import { DocumentLinksButton } from "../DocumentLinksButton"; import { Tooltip } from "@material-ui/core"; +import { undoBatch } from "../../../util/UndoManager"; export let formattedTextBoxCommentPlugin = new Plugin({ view(editorView) { return new FormattedTextBoxComment(editorView); } @@ -143,6 +144,7 @@ export class FormattedTextBoxComment { } } + @undoBatch @action deleteLink = () => { FormattedTextBoxComment.linkDoc ? LinkManager.Instance.deleteLink(FormattedTextBoxComment.linkDoc) : null; diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index 2e0b0e659..47a4911b8 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -23,7 +23,7 @@ import { updateBullets } from "./ProsemirrorExampleTransfer"; import "./RichTextMenu.scss"; import { schema } from "./schema_rts"; import { TraceMobx } from "../../../../fields/util"; -import { UndoManager } from "../../../util/UndoManager"; +import { UndoManager, undoBatch } from "../../../util/UndoManager"; import { Tooltip } from "@material-ui/core"; const { toggleMark } = require("prosemirror-commands"); @@ -831,6 +831,8 @@ export default class RichTextMenu extends AntimodeMenu { ((this.view as any)?.TextView as FormattedTextBox).makeLinkToSelection("", target, "onRight", "", target); } + @undoBatch + @action deleteLink = () => { if (this.view) { const link = this.view.state.selection.$from.nodeAfter?.marks.find(m => m.type === this.view!.state.schema.marks.linkAnchor); diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 2f3b7025e..16ade5912 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -483,25 +483,25 @@ export namespace Doc { return alias; } - - - export function makeClone(doc: Doc, cloneMap: Map, rtfs: { copy: Doc, key: string, field: RichTextField }[]): Doc { + export async function makeClone(doc: Doc, cloneMap: Map, rtfs: { copy: Doc, key: string, field: RichTextField }[], exclusions: string[]): Promise { if (Doc.IsBaseProto(doc)) return doc; if (cloneMap.get(doc[Id])) return cloneMap.get(doc[Id])!; const copy = new Doc(undefined, true); cloneMap.set(doc[Id], copy); if (LinkManager.Instance.getAllLinks().includes(doc) && LinkManager.Instance.getAllLinks().indexOf(copy) === -1) LinkManager.Instance.addLink(copy); - const exclude = Cast(doc.excludeFields, listSpec("string"), []); - Object.keys(doc).forEach(key => { - if (exclude.includes(key)) return; + const filter = Cast(doc.cloneFieldFilter, listSpec("string"), exclusions); + Object.keys(doc).forEach(async key => { + if (filter.includes(key)) return; const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key])); const field = ProxyField.WithoutProxy(() => doc[key]); - const copyObjectField = (field: ObjectField) => { - const list = Cast(doc[key], listSpec(Doc)); - if (list !== undefined && !(list instanceof Promise)) { - copy[key] = new List(list.filter(d => d instanceof Doc).map(d => Doc.makeClone(d as Doc, cloneMap, rtfs))); + const copyObjectField = async (field: ObjectField) => { + 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 = docs.map(async d => await Doc.makeClone(d as Doc, cloneMap, rtfs, exclusions)); + copy[key] = new List(await Promise.all(clones)); } else if (doc[key] instanceof Doc) { - copy[key] = key.includes("layout[") ? undefined : Doc.makeClone(doc[key] as Doc, cloneMap, rtfs); // reference documents except copy documents that are expanded teplate fields + copy[key] = key.includes("layout[") ? undefined : key.startsWith("layout") ? doc[key] as Doc : await Doc.makeClone(doc[key] as Doc, cloneMap, rtfs, exclusions); // reference documents except copy documents that are expanded teplate fields } else { copy[key] = ObjectField.MakeCopy(field); if (field instanceof RichTextField) { @@ -513,7 +513,7 @@ export namespace Doc { }; if (key === "proto") { if (doc[key] instanceof Doc) { - copy[key] = Doc.makeClone(doc[key]!, cloneMap, rtfs); + copy[key] = await Doc.makeClone(doc[key]!, cloneMap, rtfs, exclusions); } } else { if (field instanceof RefField) { @@ -535,10 +535,10 @@ export namespace Doc { cloneMap.set(doc[Id], copy); return copy; } - export function MakeClone(doc: Doc): Doc { + export async function MakeClone(doc: Doc): Promise { const cloneMap = new Map(); const rtfMap: { copy: Doc, key: string, field: RichTextField }[] = []; - const copy = Doc.makeClone(doc, cloneMap, rtfMap); + const copy = await Doc.makeClone(doc, cloneMap, rtfMap, ["context", "annotationOn", "cloneOf"]); rtfMap.map(({ copy, key, field }) => { const replacer = (match: any, attr: string, id: string, offset: any, string: any) => { const mapped = cloneMap.get(id); @@ -657,7 +657,7 @@ export namespace Doc { export function MakeCopy(doc: Doc, copyProto: boolean = false, copyProtoId?: string): Doc { const copy = new Doc(copyProtoId, true); - const exclude = Cast(doc.excludeFields, listSpec("string"), []); + const exclude = Cast(doc.cloneFieldFilter, listSpec("string"), []); Object.keys(doc).forEach(key => { if (exclude.includes(key)) return; const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key])); diff --git a/src/server/ApiManagers/DownloadManager.ts b/src/server/ApiManagers/DownloadManager.ts index c5f3ca717..0d4472fdc 100644 --- a/src/server/ApiManagers/DownloadManager.ts +++ b/src/server/ApiManagers/DownloadManager.ts @@ -80,20 +80,14 @@ async function getDocs(id: string) { } const ids: string[] = []; for (const key in doc.fields) { - if (!doc.fields.hasOwnProperty(key)) { - continue; - } + if (!doc.fields.hasOwnProperty(key)) { continue; } const field = doc.fields[key]; - if (field === undefined || field === null) { - continue; - } + if (field === undefined || field === null) { continue; } if (field.__type === "proxy" || field.__type === "prefetch_proxy") { ids.push(field.fieldId); } else if (field.__type === "script" || field.__type === "computed") { - if (field.captures) { - ids.push(field.captures.fieldId); - } + field.captures && ids.push(field.captures.fieldId); } else if (field.__type === "list") { ids.push(...fn(field)); } else if (typeof field === "string") { diff --git a/src/server/ApiManagers/UploadManager.ts b/src/server/ApiManagers/UploadManager.ts index 55ceab9fb..0b9e999ac 100644 --- a/src/server/ApiManagers/UploadManager.ts +++ b/src/server/ApiManagers/UploadManager.ts @@ -139,13 +139,9 @@ export default class UploadManager extends ApiManager { doc.id = getId(doc.id); } for (const key in doc.fields) { - if (!doc.fields.hasOwnProperty(key)) { - continue; - } + if (!doc.fields.hasOwnProperty(key)) { continue; } const field = doc.fields[key]; - if (field === undefined || field === null) { - continue; - } + if (field === undefined || field === null) { continue; } if (field.__type === "proxy" || field.__type === "prefetch_proxy") { field.fieldId = getId(field.fieldId); @@ -208,11 +204,7 @@ export default class UploadManager extends ApiManager { } catch (e) { console.log(e); } unlink(path_2, () => { }); } - if (id) { - res.send(JSON.stringify(getId(id))); - } else { - res.send(JSON.stringify("error")); - } + res.send(JSON.stringify(id ? getId(id) : "error")); } catch (e) { console.log(e); } resolve(); }); -- cgit v1.2.3-70-g09d2 From 3bcc0e3a8ce4ab67dff4b3d62191c346764aa351 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 23 Jul 2020 11:56:05 -0400 Subject: got rid of lots of console.logs(). fixed fonticon box to show a 'label' if defined otherwise 'title'. if neither, then it shows no tooltip. --- src/client/ClientRecommender.tsx | 2 -- src/client/apis/IBM_Recommender.ts | 2 -- .../apis/google_docs/GooglePhotosClientUtils.ts | 2 -- src/client/cognitive_services/CognitiveServices.ts | 2 -- src/client/documents/Documents.ts | 3 ++- src/client/util/CurrentUserUtils.ts | 1 - src/client/util/DictationManager.ts | 2 +- src/client/util/InteractionUtils.tsx | 2 -- src/client/util/ScriptManager.ts | 10 --------- src/client/util/SearchUtil.ts | 1 - src/client/util/SelectionManager.ts | 1 - src/client/views/EditableView.tsx | 1 - src/client/views/GestureOverlay.tsx | 1 - src/client/views/KeyphraseQueryView.tsx | 1 - src/client/views/ScriptBox.tsx | 2 +- src/client/views/SearchDocBox.tsx | 9 -------- src/client/views/Touchable.tsx | 3 --- src/client/views/animationtimeline/Keyframe.tsx | 4 ---- src/client/views/animationtimeline/Timeline.tsx | 1 - src/client/views/animationtimeline/Track.tsx | 4 ---- .../views/collections/CollectionCarousel3DView.tsx | 3 --- .../views/collections/CollectionCarouselView.tsx | 2 -- .../collections/CollectionMasonryViewFieldRow.tsx | 1 - src/client/views/collections/CollectionMenu.tsx | 2 +- .../views/collections/CollectionSchemaCells.tsx | 12 ----------- .../views/collections/CollectionSchemaView.tsx | 1 - src/client/views/collections/CollectionSubView.tsx | 2 -- .../views/collections/CollectionTreeView.tsx | 4 ---- src/client/views/collections/CollectionView.tsx | 2 +- src/client/views/collections/SchemaTable.tsx | 3 +-- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 -- .../collections/collectionFreeForm/MarqueeView.tsx | 3 --- src/client/views/linking/LinkMenu.tsx | 1 - src/client/views/linking/LinkMenuItem.tsx | 5 ----- src/client/views/nodes/DocumentContentsView.tsx | 2 +- src/client/views/nodes/DocumentLinksButton.tsx | 2 -- src/client/views/nodes/DocumentView.tsx | 1 - src/client/views/nodes/FontIconBox.tsx | 24 ++++++++++++---------- src/client/views/nodes/PresBox.tsx | 1 - src/client/views/nodes/RadialMenu.tsx | 1 - src/client/views/nodes/ScreenshotBox.tsx | 2 +- src/client/views/nodes/ScriptingBox.tsx | 1 - src/client/views/nodes/VideoBox.tsx | 2 +- src/client/views/nodes/WebBox.tsx | 2 +- .../views/nodes/formattedText/DashDocView.tsx | 2 +- .../views/nodes/formattedText/RichTextSchema.tsx | 2 +- src/client/views/search/FilterBox.tsx | 1 - src/client/views/search/SearchBox.tsx | 5 +---- src/client/views/search/ToggleBar.tsx | 1 - src/fields/Doc.ts | 1 - src/fields/ScriptField.ts | 1 - src/fields/util.ts | 1 - src/server/Recommender.ts | 4 ---- src/server/downsize.ts | 2 +- 54 files changed, 28 insertions(+), 127 deletions(-) (limited to 'src/client/util') diff --git a/src/client/ClientRecommender.tsx b/src/client/ClientRecommender.tsx index d18669b02..3f875057e 100644 --- a/src/client/ClientRecommender.tsx +++ b/src/client/ClientRecommender.tsx @@ -50,7 +50,6 @@ export class ClientRecommender extends React.Component { @observable private corr_matrix = [[0, 0], [0, 0]]; // for testing constructor(props: RecommenderProps) { - //console.log("creating client recommender..."); super(props); if (!ClientRecommender.Instance) ClientRecommender.Instance = this; ClientRecommender.Instance.docVectors = new Set(); @@ -383,7 +382,6 @@ export class ClientRecommender extends React.Component { case 200: const title_vals: string[] = []; const url_vals: string[] = []; - //console.log(result); if (xml) { const titles = xml.getElementsByTagName("title"); let counter = 1; diff --git a/src/client/apis/IBM_Recommender.ts b/src/client/apis/IBM_Recommender.ts index 480b9cb1c..e6265fcb5 100644 --- a/src/client/apis/IBM_Recommender.ts +++ b/src/client/apis/IBM_Recommender.ts @@ -29,10 +29,8 @@ // export const analyze = async (_parameters: any): Promise> => { // try { // const response = await naturalLanguageUnderstanding.analyze(_parameters); -// console.log(response); // return (JSON.stringify(response, null, 2)); // } catch (err) { -// console.log('error: ', err); // return undefined; // } // }; diff --git a/src/client/apis/google_docs/GooglePhotosClientUtils.ts b/src/client/apis/google_docs/GooglePhotosClientUtils.ts index 13bfb3a91..92eaf2e73 100644 --- a/src/client/apis/google_docs/GooglePhotosClientUtils.ts +++ b/src/client/apis/google_docs/GooglePhotosClientUtils.ts @@ -156,8 +156,6 @@ export namespace GooglePhotos { const values = Object.values(ContentCategories).filter(value => value !== ContentCategories.NONE); for (const value of values) { const searched = (await ContentSearch({ included: [value] }))?.mediaItems?.map(({ id }) => id); - console.log("Searching " + value); - console.log(searched); searched?.forEach(async id => { const image = await Cast(idMapping[id], Doc); if (image) { diff --git a/src/client/cognitive_services/CognitiveServices.ts b/src/client/cognitive_services/CognitiveServices.ts index 6b0b3e029..80961af14 100644 --- a/src/client/cognitive_services/CognitiveServices.ts +++ b/src/client/cognitive_services/CognitiveServices.ts @@ -377,7 +377,6 @@ export namespace CognitiveServices { console.log("successful vectorization!"); const vectorValues = new List(); indices.forEach((ind: any) => { - //console.log(wordvec.word); vectorValues.push(wordvecs[ind]); }); ClientRecommender.Instance.processVector(vectorValues, dataDoc, mainDoc); @@ -385,7 +384,6 @@ export namespace CognitiveServices { else { console.log("unsuccessful :( word(s) not in vocabulary"); } - //console.log(vectorValues.size); } ); } diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index e2569ec70..cd2792226 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -92,6 +92,7 @@ export interface DocumentOptions { layoutKey?: string; type?: string; title?: string; + label?: string; toolTip?: string; // tooltip to display on hover style?: string; page?: number; @@ -494,7 +495,7 @@ export namespace Docs { Doc.Get.FromJson({ data: device, appendToExisting: { targetDoc: Doc.GetProto(doc) } }); Doc.AddDocToList(parentProto, "data", doc); } else if (errors) { - console.log(errors); + console.log("Documents:" + errors); } else { alert("A Buxton document import was completely empty (??)"); } diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 23b8f09de..b47cfb33a 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -487,7 +487,6 @@ export class CurrentUserUtils { // Sets up mobile menu if it is undefined creates a new one, otherwise returns existing menu static setupActiveMobileMenu(doc: Doc) { if (doc.activeMobileMenu === undefined) { - console.log("undefined"); doc.activeMobileMenu = this.setupMobileMenu(); } return doc.activeMobileMenu as Doc; diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts index 28b1ca6cf..540540642 100644 --- a/src/client/util/DictationManager.ts +++ b/src/client/util/DictationManager.ts @@ -121,7 +121,7 @@ export namespace DictationManager { const listenImpl = (options?: Partial) => { if (!recognizer) { - console.log(unsupported); + console.log("DictationManager:" + unsupported); return unsupported; } if (isListening) { diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx index 473d4a263..8b3614ea7 100644 --- a/src/client/util/InteractionUtils.tsx +++ b/src/client/util/InteractionUtils.tsx @@ -161,7 +161,6 @@ export namespace InteractionUtils { // return ( // InkOptionsMenu.Instance.getColors().map(color => { // const id1 = "arrowStartTest" + color; - // console.log(color); // // // ; @@ -383,7 +382,6 @@ export namespace InteractionUtils { // let dist12 = TwoPointEuclidist(pt1, pt2); // let dist23 = TwoPointEuclidist(pt2, pt3); // let dist13 = TwoPointEuclidist(pt1, pt3); - // console.log(`distances: ${dist12}, ${dist23}, ${dist13}`); // let dist12close = dist12 < leniency; // let dist23close = dist23 < leniency; // let dist13close = dist13 < leniency; diff --git a/src/client/util/ScriptManager.ts b/src/client/util/ScriptManager.ts index 785e63d9a..94806a7ba 100644 --- a/src/client/util/ScriptManager.ts +++ b/src/client/util/ScriptManager.ts @@ -32,24 +32,17 @@ export class ScriptManager { } public addScript(scriptDoc: Doc): boolean { - - console.log("in add script method"); - const scriptList = this.getAllScripts(); scriptList.push(scriptDoc); if (ScriptManager.Instance.ScriptManagerDoc) { ScriptManager.Instance.ScriptManagerDoc.data = new List(scriptList); ScriptManager.addScriptToGlobals(scriptDoc); - console.log("script added"); return true; } return false; } public deleteScript(scriptDoc: Doc): boolean { - - console.log("in delete script method"); - if (scriptDoc.name) { Scripting.removeGlobal(StrCast(scriptDoc.name)); } @@ -70,7 +63,6 @@ export class ScriptManager { Scripting.removeGlobal(StrCast(scriptDoc.name)); const params = Cast(scriptDoc["data-params"], listSpec("string"), []); - console.log(params); const paramNames = params.reduce((o: string, p: string) => { if (params.indexOf(p) === params.length - 1) { o = o + p.split(":")[0].trim(); @@ -82,8 +74,6 @@ export class ScriptManager { const f = new Function(paramNames, StrCast(scriptDoc.script)); - console.log(scriptDoc.script); - Object.defineProperty(f, 'name', { value: StrCast(scriptDoc.name), writable: false }); let parameters = "("; diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts index 1ac68480e..0a01d8ac7 100644 --- a/src/client/util/SearchUtil.ts +++ b/src/client/util/SearchUtil.ts @@ -128,7 +128,6 @@ export namespace SearchUtil { }); const result: IdSearchResult = JSON.parse(response); const { ids, numFound, highlighting } = result; - //console.log(ids.length); const docMap = await DocServer.GetRefFields(ids); const docs: Doc[] = []; for (const id of ids) { diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index 9a968aeda..20d881961 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -22,7 +22,6 @@ export namespace SelectionManager { } manager.SelectedDocuments.set(docView, true); - // console.log(manager.SelectedDocuments); docView.props.whenActiveChanged(true); } else if (!ctrlPressed && Array.from(manager.SelectedDocuments.entries()).length > 1) { Array.from(manager.SelectedDocuments.keys()).map(dv => dv !== docView && dv.props.whenActiveChanged(false)); diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx index 25a87ab56..ad61d3f91 100644 --- a/src/client/views/EditableView.tsx +++ b/src/client/views/EditableView.tsx @@ -73,7 +73,6 @@ export class EditableView extends React.Component { // // this is done because when autosuggest is turned on, the suggestions are passed in as a prop, // // so when the suggestions are passed in, and no editing prop is passed in, it used to set it // // to false. this will no longer do so -syip - // console.log("props editing = " + nextProps.editing); // if (nextProps.editing && nextProps.editing !== this._editing) { // this._editing = nextProps.editing; // EditableView.loadId = ""; diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index b0b0d72b1..2e588ceb5 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -160,7 +160,6 @@ export default class GestureOverlay extends Touchable { if (nts.nt.length === 1) { // -- radial menu code -- this._holdTimer = setTimeout(() => { - console.log("hold"); const target = document.elementFromPoint(te.changedTouches?.item(0).clientX, te.changedTouches?.item(0).clientY); const pt: any = te.touches[te.touches?.length - 1]; if (nts.nt.length === 1 && pt.radiusX > 1 && pt.radiusY > 1) { diff --git a/src/client/views/KeyphraseQueryView.tsx b/src/client/views/KeyphraseQueryView.tsx index 1dc156968..13d52db88 100644 --- a/src/client/views/KeyphraseQueryView.tsx +++ b/src/client/views/KeyphraseQueryView.tsx @@ -11,7 +11,6 @@ export interface KP_Props { export class KeyphraseQueryView extends React.Component{ constructor(props: KP_Props) { super(props); - console.log("FIRST KEY PHRASE: ", props.keyphrases[0]); } render() { diff --git a/src/client/views/ScriptBox.tsx b/src/client/views/ScriptBox.tsx index 888f84dfa..2c185be86 100644 --- a/src/client/views/ScriptBox.tsx +++ b/src/client/views/ScriptBox.tsx @@ -39,7 +39,7 @@ export class ScriptBox extends React.Component { @action onError = (error: string) => { - console.log(error); + console.log("ScriptBox: " + error); } overlayDisposer?: () => void; diff --git a/src/client/views/SearchDocBox.tsx b/src/client/views/SearchDocBox.tsx index e038d8213..084f952a3 100644 --- a/src/client/views/SearchDocBox.tsx +++ b/src/client/views/SearchDocBox.tsx @@ -60,8 +60,6 @@ export class SearchDocBox extends React.Component { componentDidMount() { runInAction(() => { - console.log("didit" - ); this.query = StrCast(this.props.Document.searchText); this.content = (Docs.Create.TreeDocument(DocListCast(Doc.GetProto(this.props.Document).data), { _width: 200, _height: 400, _chromeStatus: "disabled", title: `Search Docs:` + this.query })); @@ -83,12 +81,9 @@ export class SearchDocBox extends React.Component { if (newKey.length > 1) { const newdocs = await this.getAllResults(this.query); const things = newdocs.docs; - console.log(things); - console.log(this.content); runInAction(() => { this.content = Docs.Create.TreeDocument(things, { _width: 200, _height: 400, _chromeStatus: "disabled", title: `Search Docs:` + this.query }); }); - console.log(this.content); } @@ -150,12 +145,9 @@ export class SearchDocBox extends React.Component { } enter = async (e: React.KeyboardEvent) => { - console.log(e.key); if (e.key === "Enter") { const newdocs = await this.getAllResults(this.query); - console.log(newdocs.docs); this.content = Docs.Create.TreeDocument(newdocs.docs, { _width: 200, _height: 400, _chromeStatus: "disabled", title: `Search Docs: "Results"` }); - } } @@ -256,7 +248,6 @@ export class SearchDocBox extends React.Component { startDragCollection = async () => { const res = await this.getAllResults(FilterBox.Instance.getFinalQuery(this._searchString)); const filtered = FilterBox.Instance.filterDocsByType(res.docs); - // console.log(this._results) const docs = filtered.map(doc => { const isProto = Doc.GetT(doc, "isPrototype", "boolean", true); if (isProto) { diff --git a/src/client/views/Touchable.tsx b/src/client/views/Touchable.tsx index 5e48d5ffb..c4cae7e8d 100644 --- a/src/client/views/Touchable.tsx +++ b/src/client/views/Touchable.tsx @@ -54,7 +54,6 @@ export abstract class Touchable extends React.Component { } }); - // console.log(ptsToDelete.length); ptsToDelete.forEach(pt => this.prevPoints.delete(pt)); if (this.prevPoints.size) { @@ -86,7 +85,6 @@ export abstract class Touchable extends React.Component { // if we're not actually moving a lot, don't consider it as dragging yet if (!InteractionUtils.IsDragging(this.prevPoints, myTouches, 5) && !this._touchDrag) return; this._touchDrag = true; - // console.log(myTouches.length); switch (myTouches.length) { case 1: this.handle1PointerMove(te, me); @@ -107,7 +105,6 @@ export abstract class Touchable extends React.Component { @action protected onTouchEnd = (e: Event, me: InteractionUtils.MultiTouchEvent): void => { - // console.log(InteractionUtils.GetMyTargetTouches(e, this.prevPoints).length + " up"); // remove all the touches associated with the event const te = me.touchEvent; for (const pt of me.changedTouches) { diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index 3a7182a94..1b81c544a 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -527,10 +527,6 @@ export class Keyframe extends React.Component { */ //154, 206, 223 render() { - trace(); - console.log(this.props.RegionData.position); - console.log(this.regiondata.position); - console.log(this.pixelPosition); return (
{ //TODO: remove undefineds and duplicates } }); - // console.log(longestTime); return longestTime; } diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index 4987006e7..25c2e68e7 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -134,7 +134,6 @@ export class Track extends React.Component { autoCreateKeyframe = () => { const objects = this.objectWhitelist.map(key => this.props.node[key]); intercept(this.props.node, change => { - console.log(change); return change; }); return reaction(() => { @@ -174,7 +173,6 @@ export class Track extends React.Component { if (regiondata) { this.props.node.hidden = false; // if (!this._autoKfReaction) { - // // console.log("creating another reaction"); // // this._autoKfReaction = this.autoCreateKeyframe(); // } this.timeChange(); @@ -204,7 +202,6 @@ export class Track extends React.Component { } }); } else { - console.log("reverting state"); //this.revertState(); } }); @@ -229,7 +226,6 @@ export class Track extends React.Component { const rightkf: (Doc | undefined) = await KeyframeFunc.calcMinRight(regiondata, this.time); //right keyframe, if it exists const currentkf: (Doc | undefined) = await this.calcCurrent(regiondata); //if the scrubber is on top of the keyframe if (currentkf) { - console.log("is current"); await this.applyKeys(currentkf); this.saveStateKf = currentkf; this.saveStateRegion = regiondata; diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx index 8e9970ada..0f3b6f212 100644 --- a/src/client/views/collections/CollectionCarousel3DView.tsx +++ b/src/client/views/collections/CollectionCarousel3DView.tsx @@ -86,7 +86,6 @@ export class CollectionCarousel3DView extends CollectionSubView(Carousel3DDocume interval?: number; startAutoScroll = (direction: number) => { this.interval = window.setInterval(() => { - console.log(this.interval, this.scrollSpeed); this.changeSlide(direction); }, this.scrollSpeed); } @@ -113,13 +112,11 @@ export class CollectionCarousel3DView extends CollectionSubView(Carousel3DDocume onPointerDown = (e: React.PointerEvent) => { this._downX = e.clientX; this._downY = e.clientY; - console.log("CAROUSEL down"); document.addEventListener("pointerup", this.onpointerup); } private _lastTap: number = 0; private _doubleTap = false; onpointerup = (e: PointerEvent) => { - console.log("CAROUSEL up"); this._doubleTap = (Date.now() - this._lastTap < 300 && e.button === 0 && Math.abs(e.clientX - this._downX) < 2 && Math.abs(e.clientY - this._downY) < 2); this._lastTap = Date.now(); } diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx index 404dc0daa..27aea4b99 100644 --- a/src/client/views/collections/CollectionCarouselView.tsx +++ b/src/client/views/collections/CollectionCarouselView.tsx @@ -91,13 +91,11 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument) onPointerDown = (e: React.PointerEvent) => { this._downX = e.clientX; this._downY = e.clientY; - console.log("CAROUSEL down"); document.addEventListener("pointerup", this.onpointerup); } private _lastTap: number = 0; private _doubleTap = false; onpointerup = (e: PointerEvent) => { - console.log("CAROUSEL up"); this._doubleTap = (Date.now() - this._lastTap < 300 && e.button === 0 && Math.abs(e.clientX - this._downX) < 2 && Math.abs(e.clientY - this._downY) < 2); this._lastTap = Date.now(); } diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx index 627b22417..9a7ea2c93 100644 --- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx +++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx @@ -84,7 +84,6 @@ export class CollectionMasonryViewFieldRow extends React.Component { - console.log("masronry row drop"); this._createAliasSelected = false; if (de.complete.docDragData) { (this.props.parent.Document.dropConverter instanceof ScriptField) && diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index 5d95b214a..992c1f600 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -462,7 +462,7 @@ export class CollectionFreeFormViewChrome extends React.Component -
+
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx index d76b6d204..eecaf7672 100644 --- a/src/client/views/collections/CollectionSchemaCells.tsx +++ b/src/client/views/collections/CollectionSchemaCells.tsx @@ -151,7 +151,6 @@ export class CollectionSchemaCell extends React.Component { // let field = this.props.rowProps.original[this.props.rowProps.column.id as string]; // let doc = FieldValue(Cast(field, Doc)); - // console.log("Expanding doc", StrCast(doc!.title)); // this.props.setPreviewDoc(doc!); // // this.props.changeFocusedCellByIndex(this.props.row, this.props.col); @@ -265,7 +264,6 @@ export class CollectionSchemaCell extends React.Component { return "0"; } else { const cfield = ComputedField.WithoutComputed(() => FieldValue(props.Document[props.fieldKey])); - console.log(cfield); if (type === "number") { return StrCast(cfield); } @@ -286,7 +284,6 @@ export class CollectionSchemaCell extends React.Component { const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); if (script.compiled) { retVal = this.applyToDoc(props.Document, this.props.row, this.props.col, script.run); - console.log("compiled"); } } @@ -350,17 +347,13 @@ export class CollectionSchemaDateCell extends CollectionSchemaCell { @action handleChange = (date: any) => { - console.log(date); this._date = date; // const script = CompileScript(date.toString(), { requiredType: "Date", addReturn: true, params: { this: Doc.name } }); // if (script.compiled) { - // console.log("scripting"); // this.applyToDoc(this._document, this.props.row, this.props.col, script.run); // } else { - console.log(DateCast(date)); // ^ DateCast is always undefined for some reason, but that is what the field should be set to this._document[this.props.rowProps.column.id as string] = date as Date; - console.log(this._document[this.props.rowProps.column.id as string]); //} } @@ -425,8 +418,6 @@ export class CollectionSchemaDocCell extends CollectionSchemaCell { const results = script.compiled && script.run(); if (results && results.success) { - - console.log(results.result); this._doc = results.result; this._document[this.prop.fieldKey] = results.result; this._docTitle = this._doc?.title; @@ -457,10 +448,8 @@ export class CollectionSchemaDocCell extends CollectionSchemaCell { this._preview = false; } else { if (bool) { - console.log("show doc"); this.props.showDoc(this._doc, this.prop.DataDoc, e.clientX, e.clientY); } else { - console.log("no doc"); this.props.showDoc(undefined); } } @@ -675,7 +664,6 @@ export class CollectionSchemaListCell extends CollectionSchemaCell { @action toggleOpened(open: boolean) { - console.log("open: " + open); this._opened = open; } diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 3c42a2f1c..5553bbbb7 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -332,7 +332,6 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { @action openHeader = (col: any, screenx: number, screeny: number) => { - console.log("header opening"); this._col = col; this._headerOpen = !this._headerOpen; this._pointerX = screenx; diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index a147b06a3..8480a56cc 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -340,7 +340,6 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: // if ((matches = /(https:\/\/)?photos\.google\.com\/(u\/3\/)?album\/([^\\]+)/g.exec(text)) !== null) { // const albumId = matches[3]; // const mediaItems = await GooglePhotos.Query.AlbumSearch(albumId); - // console.log(mediaItems); // return; // } } @@ -381,7 +380,6 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: file?.type && files.push(file); file?.type === "application/json" && Utils.readUploadedFileAsText(file).then(result => { - console.log(result); const json = JSON.parse(result as string); this.addDocument(Docs.Create.TreeDocument( json["rectangular-puzzle"].crossword.clues[0].clue.map((c: any) => { diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 96a2e23c9..651357e5d 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -796,9 +796,6 @@ export class CollectionTreeView extends CollectionSubView; } - onKeyPress = (e: React.KeyboardEvent) => { - console.log(e); - } onChildClick = () => { return this.props.onChildClick?.() || ScriptCast(this.doc.onChildClick); } @@ -819,7 +816,6 @@ export class CollectionTreeView extends CollectionSubView this._mainEle && this._mainEle.scrollHeight > this._mainEle.clientHeight && e.stopPropagation()} onDrop={this.onTreeDrop} ref={this.createTreeDropTarget}> diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 53fd83f26..e2f78d6f9 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -167,7 +167,7 @@ export class CollectionView extends Touchable { @action changeSorting = (col: any) => { - console.log(col.heading); if (col.desc === undefined) { // no sorting this.props.changeColumnSort(col, true); @@ -149,7 +148,7 @@ export class SchemaTable extends React.Component { } @action - changeTitleMode = () => { console.log("header clicked"); this._showTitleDropdown = !this._showTitleDropdown; } + changeTitleMode = () => this._showTitleDropdown = !this._showTitleDropdown; @computed get borderWidth() { return Number(COLLECTION_BORDER_WIDTH); } @computed get tableColumns(): Column[] { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 3b19a2ab8..979b21321 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -497,10 +497,8 @@ export class CollectionFreeFormView extends CollectionSubView p.X)), Math.min(...ge.points.map(p => p.Y))); this._inkToTextStartX = start[0]; this._inkToTextStartY = start[1]; - console.log("start"); break; case GestureUtils.Gestures.EndBracket: - console.log("end"); if (this._inkToTextStartX && this._inkToTextStartY) { const end = this.getTransform().transformPoint(Math.max(...ge.points.map(p => p.X)), Math.max(...ge.points.map(p => p.Y))); const setDocs = this.getActiveDocuments().filter(s => s.proto?.type === "rtf" && s.color); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 84719b2c9..aa9a3b4ae 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -434,8 +434,6 @@ export class MarqueeView extends React.Component { // const wordResults = results.filter((r: any) => r.category === "inkWord"); - // console.log(wordResults); - // console.log(results); // for (const word of wordResults) { // const indices: number[] = word.strokeIds; // indices.forEach(i => { @@ -476,7 +474,6 @@ export class MarqueeView extends React.Component r.category === "line"); - console.log(lines); const text = lines.map((l: any) => l.recognizedText).join("\r\n"); this.props.addDocument(Docs.Create.TextDocument(text, { _width: this.Bounds.width, _height: this.Bounds.height, x: this.Bounds.left + this.Bounds.width, y: this.Bounds.top, title: text })); }); diff --git a/src/client/views/linking/LinkMenu.tsx b/src/client/views/linking/LinkMenu.tsx index 2d151e9bc..7b5fb0127 100644 --- a/src/client/views/linking/LinkMenu.tsx +++ b/src/client/views/linking/LinkMenu.tsx @@ -46,7 +46,6 @@ export class LinkMenu extends React.Component { if (this._linkMenuRef && !this._linkMenuRef.current?.contains(e.target as any)) { if (this._editorRef && !this._editorRef.current?.contains(e.target as any)) { - console.log("outside click"); DocumentLinksButton.EditLink = undefined; } } diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx index d8ba39f09..d1c839c3b 100644 --- a/src/client/views/linking/LinkMenuItem.tsx +++ b/src/client/views/linking/LinkMenuItem.tsx @@ -81,10 +81,7 @@ export class LinkMenuItem extends React.Component { @action toggleShowMore(e: React.PointerEvent) { e.stopPropagation(); this._showMore = !this._showMore; } onEdit = (e: React.PointerEvent): void => { - - console.log("Edit"); LinkManager.currentLink = this.props.linkDoc; - console.log(this.props.linkDoc); setupMoveUpEvents(this, e, this.editMoved, emptyFunction, () => this.props.showEditor(this.props.linkDoc)); } @@ -119,7 +116,6 @@ export class LinkMenuItem extends React.Component { document.addEventListener("pointerup", this.onLinkButtonUp); if (this._buttonRef && !!!this._buttonRef.current?.contains(e.target as any)) { - console.log("outside click"); LinkDocPreview.LinkInfo = undefined; } } @@ -153,7 +149,6 @@ export class LinkMenuItem extends React.Component { @action.bound async followDefault() { - console.log("FOLLOWWW"); DocumentLinksButton.EditLink = undefined; LinkDocPreview.LinkInfo = undefined; diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index f2f8ada68..47dc0a773 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -200,7 +200,7 @@ export class DocumentContentsView extends React.Component { console.log(test); }} + onError={(test: any) => { console.log("DocumentContentsView:" + test); }} />; } } \ No newline at end of file diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx index 13bec5d7f..b17accfd6 100644 --- a/src/client/views/nodes/DocumentLinksButton.tsx +++ b/src/client/views/nodes/DocumentLinksButton.tsx @@ -68,8 +68,6 @@ export class DocumentLinksButton extends React.Component Doc.BrushDoc(this.props.View.Document)); DocumentLinksButton.StartLink = this.props.View; } else if (!this.props.InMenu) { - console.log("editing"); - this.props.View ? console.log("view") : null; DocumentLinksButton.EditLink = this.props.View; DocumentLinksButton.EditLinkLoc = [e.clientX + 10, e.clientY]; } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 9e492650b..998c6798e 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -910,7 +910,6 @@ export class DocumentView extends DocComponent(Docu if (!ClientRecommender.Instance) new ClientRecommender({ title: "Client Recommender" }); const documents: Doc[] = []; const allDocs = await SearchUtil.GetAllDocs(); - // allDocs.forEach(doc => console.log(doc.title)); // clears internal representation of documents as vectors ClientRecommender.Instance.reset_docs(); //ClientRecommender.Instance.arxivrequest("electrons"); diff --git a/src/client/views/nodes/FontIconBox.tsx b/src/client/views/nodes/FontIconBox.tsx index a4d16fe0e..ab34e13b0 100644 --- a/src/client/views/nodes/FontIconBox.tsx +++ b/src/client/views/nodes/FontIconBox.tsx @@ -61,16 +61,18 @@ export class FontIconBox extends DocComponent( render() { const referenceDoc = (this.layoutDoc.dragFactory instanceof Doc ? this.layoutDoc.dragFactory : this.layoutDoc); const refLayout = Doc.Layout(referenceDoc); - return {StrCast(this.layoutDoc.toolTip)}
}> - - ; + const button = ; + return !this.layoutDoc.toolTip ? button : + {StrCast(this.layoutDoc.toolTip)}
}> + {button} + ; } } \ No newline at end of file diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index 8818d375e..a304ced18 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -297,7 +297,6 @@ export class PresBox extends ViewBoxBaseComponent (this.layoutDoc.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false) render() { - // console.log("render = " + this.layoutDoc.title + " " + this.layoutDoc.presStatus); // const presOrderedDocs = DocListCast(this.rootDoc.presOrderedDocs); // if (presOrderedDocs.length != this.childDocs.length || presOrderedDocs.some((pd, i) => pd !== this.childDocs[i])) { // this.rootDoc.presOrderedDocs = new List(this.childDocs.slice()); diff --git a/src/client/views/nodes/RadialMenu.tsx b/src/client/views/nodes/RadialMenu.tsx index a3ac09a11..7f0956e51 100644 --- a/src/client/views/nodes/RadialMenu.tsx +++ b/src/client/views/nodes/RadialMenu.tsx @@ -89,7 +89,6 @@ export class RadialMenu extends React.Component { @action componentDidMount = () => { - console.log(this._pageX); document.addEventListener("pointerdown", this.onPointerDown); document.addEventListener("pointerup", this.onPointerUp); this.previewcircle(); diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx index f7dee0896..1cd29d795 100644 --- a/src/client/views/nodes/ScreenshotBox.tsx +++ b/src/client/views/nodes/ScreenshotBox.tsx @@ -112,7 +112,7 @@ export class ScreenshotBox extends ViewBoxBaseComponent([]); } catch (e) { - console.log("Error in URL :" + this._url); + console.log("WebBox URL error:" + this._url); } } diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx index 5c3f3dcc9..212da3f3d 100644 --- a/src/client/views/nodes/formattedText/DashDocView.tsx +++ b/src/client/views/nodes/formattedText/DashDocView.tsx @@ -209,7 +209,7 @@ export class DashDocView extends React.Component { try { // bcz: an exception will be thrown if two aliases are open at the same time when a doc view comment is made view.dispatch(view.state.tr.setNodeMarkup(getPos(), null, { ...node.attrs, width: dashDoc._width + "px", height: dashDoc._height + "px" })); } catch (e) { - console.log(e); + console.log("DashDocView:" + e); } } diff --git a/src/client/views/nodes/formattedText/RichTextSchema.tsx b/src/client/views/nodes/formattedText/RichTextSchema.tsx index 7a50ec3af..33a080fe4 100644 --- a/src/client/views/nodes/formattedText/RichTextSchema.tsx +++ b/src/client/views/nodes/formattedText/RichTextSchema.tsx @@ -170,7 +170,7 @@ export class DashDocView { } } } catch (e) { - console.log(e); + console.log("RichTextSchema: " + e); } } }; diff --git a/src/client/views/search/FilterBox.tsx b/src/client/views/search/FilterBox.tsx index 4b53963a5..eb61f9a14 100644 --- a/src/client/views/search/FilterBox.tsx +++ b/src/client/views/search/FilterBox.tsx @@ -352,7 +352,6 @@ export class FilterBox extends React.Component { getDataStatus() { return this._deletedDocsStatus; } getActiveFilters() { - console.log(this._authorFieldStatus, this._titleFieldStatus, this._dataFieldStatus); return (
{!this._basicWordStatus ?
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index c9d29e485..99fa6da21 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -125,7 +125,7 @@ export class SearchBox extends React.Component { return returnedUri; } catch (e) { - console.log(e); + console.log("SearchBox:" + e); } } @@ -582,7 +582,6 @@ export class SearchBox extends React.Component { } expandSection(thing: string) { - console.log("expand"); const element = document.getElementById(thing)!; // get the height of the element's inner content, regardless of its actual size const sectionHeight = element.scrollHeight; @@ -593,7 +592,6 @@ export class SearchBox extends React.Component { // when the next css transition finishes (which should be the one we just triggered) element.addEventListener('transitionend', function handler(e) { // remove this event listener so it only gets triggered once - console.log("autoset"); element.removeEventListener('transitionend', handler); // remove "height" from the element's inline styles, so it can return to its initial value @@ -608,7 +606,6 @@ export class SearchBox extends React.Component { autoset(thing: string) { const element = document.getElementById(thing)!; - console.log("autoset"); element.removeEventListener('transitionend', function (e) { }); // remove "height" from the element's inline styles, so it can return to its initial value diff --git a/src/client/views/search/ToggleBar.tsx b/src/client/views/search/ToggleBar.tsx index e4d7f2fd5..466822eba 100644 --- a/src/client/views/search/ToggleBar.tsx +++ b/src/client/views/search/ToggleBar.tsx @@ -58,7 +58,6 @@ export class ToggleBar extends React.Component{ this._forwardTimeline.play(); this._forwardTimeline.reverse(); this.props.handleChange(); - console.log(this.props.getStatus()); } @action.bound diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 917a6853c..7e91a7761 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -566,7 +566,6 @@ export namespace Doc { export async function Zip(doc: Doc) { const { clone, map } = await Doc.MakeClone(doc, true); function replacer(key: any, value: any) { - console.log("Checkin: " + key); if (["cloneOf", "context", "cursors"].includes(key)) return undefined; else if (value instanceof Doc) { if (key !== "field" && Number.isNaN(Number(key))) { diff --git a/src/fields/ScriptField.ts b/src/fields/ScriptField.ts index 4604a2132..bd08b2f32 100644 --- a/src/fields/ScriptField.ts +++ b/src/fields/ScriptField.ts @@ -53,7 +53,6 @@ async function deserializeScript(script: ScriptField) { if (script.script.originalScript === 'convertToButtons(dragData)') { return (script as any).script = (ScriptField.ConvertToButtons ?? (ScriptField.ConvertToButtons = ComputedField.MakeFunction('convertToButtons(dragData)', { dragData: "DocumentDragData" })))?.script; } - console.log(script.script.originalScript); const captures: ProxyField = (script as any).captures; if (captures) { const doc = (await captures.value())!; diff --git a/src/fields/util.ts b/src/fields/util.ts index 20b072786..ef66d9633 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -35,7 +35,6 @@ export namespace Plugins { } const _setterImpl = action(function (target: any, prop: string | symbol | number, value: any, receiver: any): boolean { - //console.log("-set " + target[SelfProxy].title + "(" + target[SelfProxy][prop] + ")." + prop.toString() + " = " + value); if (SerializationHelper.IsSerializing()) { target[prop] = value; return true; diff --git a/src/server/Recommender.ts b/src/server/Recommender.ts index 423ce9b46..935ec3871 100644 --- a/src/server/Recommender.ts +++ b/src/server/Recommender.ts @@ -21,7 +21,6 @@ // private choice: string = ""; // Tensorflow or Word2Vec // constructor() { -// console.log("creating recommender..."); // Recommender.Instance = this; // } @@ -70,7 +69,6 @@ // if (this._model) { // if (this.choice === "WV") { // let similarity = this._model.similarity('father', 'mother'); -// console.log(similarity); // } // else if (this.choice === "TF") { // const model = this._model as use.UniversalSentenceEncoder; @@ -119,7 +117,6 @@ // } // // public async trainModel() { -// // console.log("phrasing..."); // // w2v.word2vec("./node_modules/word2vec/examples/eng_news-typical_2016_1M-sentences.txt", './node_modules/word2vec/examples/my_phrases.txt', { // // cbow: 1, // // size: 200, @@ -131,7 +128,6 @@ // // iter: 200, // // minCount: 2 // // }); -// // console.log("phrased!!!"); // // } // } diff --git a/src/server/downsize.ts b/src/server/downsize.ts index cd0d83812..5cd709fa3 100644 --- a/src/server/downsize.ts +++ b/src/server/downsize.ts @@ -7,7 +7,7 @@ const jpgTypes = ["jpg", "JPG", "jpeg", "JPEG"]; const smallResizer = sharp().resize(100); fs.readdir(folder, async (err, files) => { if (err) { - console.log(err); + console.log("readdir:" + err); return; } // files.forEach(file => { -- cgit v1.2.3-70-g09d2 From a22f9b3c98c11d1170d1b0548bab61fc73fbc44f Mon Sep 17 00:00:00 2001 From: usodhi <61431818+usodhi@users.noreply.github.com> Date: Thu, 23 Jul 2020 22:20:49 +0530 Subject: groups bugfix --- src/client/util/GroupManager.tsx | 8 ++++++++ src/client/views/DocumentDecorations.scss | 5 +++-- src/client/views/DocumentDecorations.tsx | 6 +++--- 3 files changed, 14 insertions(+), 5 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx index 2e5ecc543..a679c9087 100644 --- a/src/client/util/GroupManager.tsx +++ b/src/client/util/GroupManager.tsx @@ -48,6 +48,14 @@ export default class GroupManager extends React.Component<{}> { componentDidMount() { this.populateUsers(); + DocListCastAsync(this.GroupManagerDoc?.data).then(groups => { + groups?.forEach(group => { + const members: string[] = JSON.parse(StrCast(group.members)); + if (members.includes(Doc.CurrentUserEmail)) this.currentUserGroups.push(StrCast(group.groupName)); + }); + + setGroups(this.currentUserGroups); + }); } /** diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss index 5948ada88..424a06431 100644 --- a/src/client/views/DocumentDecorations.scss +++ b/src/client/views/DocumentDecorations.scss @@ -157,6 +157,7 @@ $linkGap : 3px; grid-column-end: 2; pointer-events: all; padding-left: 5px; + cursor: pointer; } .documentDecorations-title { @@ -204,7 +205,7 @@ $linkGap : 3px; width: 20px; } -.documentDecorations-closeButton { +.documentDecorations-openInTab { opacity: 1; grid-column-start: 4; grid-column-end: 5; @@ -216,7 +217,7 @@ $linkGap : 3px; margin-top: auto; } -.documentDecorations-minimizeButton { +.documentDecorations-closeButton { opacity: 1; grid-column-start: 1; grid-column-end: 3; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index fec4ad9e0..46411c05b 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -549,8 +549,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
) : ( -
Iconify
} placement="top"> -
+
Delete
} placement="top"> +
{/* Currently, this is set to be enabled if there is no ink selected. It might be interesting to think about minimizing ink if it's useful? -syip2*/}
); @@ -616,7 +616,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
{"_"}
} -
Open Document In Tab
} placement="top">
+
Open Document In Tab
} placement="top">
{SelectionManager.SelectedDocuments().length === 1 ? DocumentDecorations.DocumentIcon(StrCast(seldoc.props.Document.layout, "...")) : "..."}
Date: Thu, 23 Jul 2020 22:24:23 +0530 Subject: groups bugfix --- src/client/util/GroupManager.tsx | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx index a679c9087..7d02b1e66 100644 --- a/src/client/util/GroupManager.tsx +++ b/src/client/util/GroupManager.tsx @@ -48,14 +48,6 @@ export default class GroupManager extends React.Component<{}> { componentDidMount() { this.populateUsers(); - DocListCastAsync(this.GroupManagerDoc?.data).then(groups => { - groups?.forEach(group => { - const members: string[] = JSON.parse(StrCast(group.members)); - if (members.includes(Doc.CurrentUserEmail)) this.currentUserGroups.push(StrCast(group.groupName)); - }); - - setGroups(this.currentUserGroups); - }); } /** @@ -82,6 +74,17 @@ export default class GroupManager extends React.Component<{}> { return Promise.all(evaluating); } + populateGroups = () => { + DocListCastAsync(this.GroupManagerDoc?.data).then(groups => { + groups?.forEach(group => { + const members: string[] = JSON.parse(StrCast(group.members)); + if (members.includes(Doc.CurrentUserEmail)) this.currentUserGroups.push(StrCast(group.groupName)); + }); + + setGroups(this.currentUserGroups); + }); + } + /** * @returns the options to be rendered in the dropdown menu to add users and create a group. */ @@ -97,14 +100,7 @@ export default class GroupManager extends React.Component<{}> { SelectionManager.DeselectAll(); this.isOpen = true; this.populateUsers(); - DocListCastAsync(this.GroupManagerDoc?.data).then(groups => { - groups?.forEach(group => { - const members: string[] = JSON.parse(StrCast(group.members)); - if (members.includes(Doc.CurrentUserEmail)) this.currentUserGroups.push(StrCast(group.groupName)); - }); - - setGroups(this.currentUserGroups); - }); + this.populateGroups(); } /** -- cgit v1.2.3-70-g09d2 From 17ccb0a1a37c906c0151d3da5e92de3d94205924 Mon Sep 17 00:00:00 2001 From: usodhi <61431818+usodhi@users.noreply.github.com> Date: Fri, 24 Jul 2020 01:45:05 +0530 Subject: groups and acl bugfix --- src/client/util/GroupManager.tsx | 1 + src/fields/util.ts | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'src/client/util') diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx index 7d02b1e66..a727d21d0 100644 --- a/src/client/util/GroupManager.tsx +++ b/src/client/util/GroupManager.tsx @@ -48,6 +48,7 @@ export default class GroupManager extends React.Component<{}> { componentDidMount() { this.populateUsers(); + this.populateGroups(); } /** diff --git a/src/fields/util.ts b/src/fields/util.ts index 20b072786..cd1e24826 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -210,7 +210,8 @@ export function setter(target: any, in_prop: string | symbol | number, value: an return true; } - if (typeof prop === "string" && prop.startsWith("ACL") && !["Can Edit", "Can Add", "Can View", "Not Shared", undefined].includes(value)) return true; + if (typeof prop === "string" && prop.startsWith("ACL") && ((target.author && Doc.CurrentUserEmail !== target.author) || !["Can Edit", "Can Add", "Can View", "Not Shared", undefined].includes(value))) return true; + // if (typeof prop === "string" && prop.startsWith("ACL") && !["Can Edit", "Can Add", "Can View", "Not Shared", undefined].includes(value)) return true; if (typeof prop === "string" && prop !== "__id" && prop !== "__fields" && (prop.startsWith("_") || layoutProps.includes(prop))) { if (!prop.startsWith("_")) { -- cgit v1.2.3-70-g09d2 From 2f49497e9d74eda97b2327ca4dbcb0a11ac6c6c9 Mon Sep 17 00:00:00 2001 From: usodhi <61431818+usodhi@users.noreply.github.com> Date: Fri, 24 Jul 2020 17:11:09 +0530 Subject: added admin acl + renamed LinkCreatedBox to TaskCompletedBox and added custom text functionality + popups on sharing docs and creating groups + relocated SharingPermissions --- src/client/util/GroupManager.tsx | 15 +++++++- src/client/util/SharingManager.tsx | 46 +++++++++++++++---------- src/client/views/DocComponent.tsx | 3 +- src/client/views/MainView.tsx | 4 +-- src/client/views/collections/CollectionView.tsx | 8 ++--- src/client/views/nodes/DocumentLinksButton.tsx | 18 +++++----- src/client/views/nodes/DocumentView.tsx | 17 +++++---- src/client/views/nodes/LinkCreatedBox.scss | 21 ----------- src/client/views/nodes/LinkCreatedBox.tsx | 31 ----------------- src/client/views/nodes/LinkDescriptionPopup.tsx | 4 +-- src/client/views/nodes/TaskCompletedBox.scss | 20 +++++++++++ src/client/views/nodes/TaskCompletedBox.tsx | 32 +++++++++++++++++ src/fields/Doc.ts | 7 ++-- src/fields/util.ts | 28 +++++++++------ 14 files changed, 143 insertions(+), 111 deletions(-) delete mode 100644 src/client/views/nodes/LinkCreatedBox.scss delete mode 100644 src/client/views/nodes/LinkCreatedBox.tsx create mode 100644 src/client/views/nodes/TaskCompletedBox.scss create mode 100644 src/client/views/nodes/TaskCompletedBox.tsx (limited to 'src/client/util') diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx index a727d21d0..72fba5c1b 100644 --- a/src/client/util/GroupManager.tsx +++ b/src/client/util/GroupManager.tsx @@ -16,6 +16,7 @@ import { StrCast, Cast } from "../../fields/Types"; import GroupMemberView from "./GroupMemberView"; import { setGroups } from "../../fields/util"; import { DocServer } from "../DocServer"; +import { TaskCompletionBox } from "../views/nodes/TaskCompletedBox"; library.add(fa.faPlus, fa.faTimes, fa.faInfoCircle); @@ -36,11 +37,13 @@ export default class GroupManager extends React.Component<{}> { @observable currentGroup: Opt; // the currently selected group. @observable private createGroupModalOpen: boolean = false; private inputRef: React.RefObject = React.createRef(); // the ref for the input box. + private createGroupButtonRef: React.RefObject = React.createRef(); private currentUserGroups: string[] = []; @observable private buttonColour: "#979797" | "black" = "#979797"; @observable private groupSort: "ascending" | "descending" | "none" = "none"; + constructor(props: Readonly<{}>) { super(props); GroupManager.Instance = this; @@ -303,6 +306,14 @@ export default class GroupManager extends React.Component<{}> { this.selectedUsers = null; this.inputRef.current.value = ""; this.buttonColour = "#979797"; + + const { left, width, top } = this.createGroupButtonRef.current!.getBoundingClientRect(); + TaskCompletionBox.popupX = left - 2 * width; + TaskCompletionBox.popupY = top; + TaskCompletionBox.textDisplayed = "Group created!"; + TaskCompletionBox.taskCompleted = true; + setTimeout(action(() => TaskCompletionBox.taskCompleted = false), 2000); + } private get groupCreationModal() { @@ -345,7 +356,9 @@ export default class GroupManager extends React.Component<{}> { }) }} /> -
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index 95c1bcda8..00d570670 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -7,8 +7,7 @@ import { InteractionUtils } from '../util/InteractionUtils'; import { List } from '../../fields/List'; import { DateField } from '../../fields/DateField'; import { ScriptField } from '../../fields/ScriptField'; -import { GetEffectiveAcl, getPlaygroundMode } from '../../fields/util'; -import { SharingPermissions } from '../util/SharingManager'; +import { GetEffectiveAcl, getPlaygroundMode, SharingPermissions } from '../../fields/util'; /// DocComponent returns a generic React base class used by views that don't have 'fieldKey' props (e.g.,CollectionFreeFormDocumentView, DocumentView) diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 225fb2e8e..81f2feee0 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -61,7 +61,7 @@ import { DocumentManager } from '../util/DocumentManager'; import { DocumentLinksButton } from './nodes/DocumentLinksButton'; import { LinkMenu } from './linking/LinkMenu'; import { LinkDocPreview } from './nodes/LinkDocPreview'; -import { LinkCreatedBox } from './nodes/LinkCreatedBox'; +import { TaskCompletionBox } from './nodes/TaskCompletedBox'; import { LinkDescriptionPopup } from './nodes/LinkDescriptionPopup'; import FormatShapePane from "./collections/collectionFreeForm/FormatShapePane"; import HypothesisAuthenticationManager from '../apis/HypothesisAuthenticationManager'; @@ -623,7 +623,7 @@ export class MainView extends React.Component { {this.mainContent} - + diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 53fd83f26..4848508be 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -8,7 +8,7 @@ import * as React from 'react'; import Lightbox from 'react-image-lightbox-with-rotate'; import 'react-image-lightbox-with-rotate/style.css'; // This only needs to be imported once in your app import { DateField } from '../../../fields/DateField'; -import { AclAddonly, AclReadonly, DataSym, Doc, DocListCast, Field, Opt, AclEdit, AclSym, AclPrivate } from '../../../fields/Doc'; +import { AclAddonly, AclReadonly, DataSym, Doc, DocListCast, Field, Opt, AclEdit, AclSym, AclPrivate, AclAdmin } from '../../../fields/Doc'; import { Id } from '../../../fields/FieldSymbols'; import { List } from '../../../fields/List'; import { ObjectField } from '../../../fields/ObjectField'; @@ -17,7 +17,7 @@ import { listSpec } from '../../../fields/Schema'; import { ComputedField, ScriptField } from '../../../fields/ScriptField'; import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { ImageField } from '../../../fields/URLField'; -import { TraceMobx, GetEffectiveAcl, getPlaygroundMode, distributeAcls } from '../../../fields/util'; +import { TraceMobx, GetEffectiveAcl, getPlaygroundMode, distributeAcls, SharingPermissions } from '../../../fields/util'; import { emptyFunction, emptyPath, returnEmptyFilter, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; @@ -48,7 +48,6 @@ import { CollectionTimeView } from './CollectionTimeView'; import { CollectionTreeView } from "./CollectionTreeView"; import './CollectionView.scss'; import CollectionMenu from './CollectionMenu'; -import { SharingPermissions } from '../../util/SharingManager'; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -111,7 +110,8 @@ export class CollectionView extends Touchable { if (linkDoc) { - LinkCreatedBox.popupX = e.screenX; - LinkCreatedBox.popupY = e.screenY - 133; - LinkCreatedBox.linkCreated = true; + TaskCompletionBox.popupX = e.screenX; + TaskCompletionBox.popupY = e.screenY - 133; + TaskCompletionBox.taskCompleted = true; LinkDescriptionPopup.popupX = e.screenX; LinkDescriptionPopup.popupY = e.screenY - 100; LinkDescriptionPopup.descriptionPopup = true; - setTimeout(action(() => { LinkCreatedBox.linkCreated = false; }), 2500); + setTimeout(action(() => { TaskCompletionBox.taskCompleted = false; }), 2500); } }); @@ -134,9 +134,9 @@ export class DocumentLinksButton extends React.Component { if (linkDoc) { - LinkCreatedBox.popupX = e.screenX; - LinkCreatedBox.popupY = e.screenY - 133; - LinkCreatedBox.linkCreated = true; + TaskCompletionBox.popupX = e.screenX; + TaskCompletionBox.popupY = e.screenY - 133; + TaskCompletionBox.taskCompleted = true; if (LinkDescriptionPopup.showDescriptions === "ON" || !LinkDescriptionPopup.showDescriptions) { LinkDescriptionPopup.popupX = e.screenX; @@ -144,7 +144,7 @@ export class DocumentLinksButton extends React.Component { LinkCreatedBox.linkCreated = false; }), 2500); + setTimeout(action(() => { TaskCompletionBox.taskCompleted = false; }), 2500); } }); } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 9e492650b..1d4b61545 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -11,7 +11,7 @@ import { listSpec } from "../../../fields/Schema"; import { SchemaHeaderField } from '../../../fields/SchemaHeaderField'; import { ScriptField } from '../../../fields/ScriptField'; import { BoolCast, Cast, NumCast, StrCast, ScriptCast } from "../../../fields/Types"; -import { TraceMobx, GetEffectiveAcl } from '../../../fields/util'; +import { TraceMobx, GetEffectiveAcl, SharingPermissions } from '../../../fields/util'; import { GestureUtils } from '../../../pen-gestures/GestureUtils'; import { emptyFunction, OmitKeys, returnOne, returnTransparent, Utils, emptyPath } from "../../../Utils"; import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils'; @@ -25,7 +25,7 @@ import { InteractionUtils } from '../../util/InteractionUtils'; import { Scripting } from '../../util/Scripting'; import { SearchUtil } from '../../util/SearchUtil'; import { SelectionManager } from "../../util/SelectionManager"; -import SharingManager, { SharingPermissions } from '../../util/SharingManager'; +import SharingManager from '../../util/SharingManager'; import { Transform } from "../../util/Transform"; import { undoBatch, UndoManager } from "../../util/UndoManager"; import { CollectionView, CollectionViewType } from '../collections/CollectionView'; @@ -41,7 +41,7 @@ import { RadialMenu } from './RadialMenu'; import React = require("react"); import { DocumentLinksButton } from './DocumentLinksButton'; import { MobileInterface } from '../../../mobile/MobileInterface'; -import { LinkCreatedBox } from './LinkCreatedBox'; +import { TaskCompletionBox } from './TaskCompletedBox'; import { LinkDescriptionPopup } from './LinkDescriptionPopup'; import { LinkManager } from '../../util/LinkManager'; @@ -629,15 +629,15 @@ export class DocumentView extends DocComponent(Docu const makeLink = action((linkDoc: Doc) => { LinkManager.currentLink = linkDoc; - LinkCreatedBox.popupX = de.x; - LinkCreatedBox.popupY = de.y - 33; - LinkCreatedBox.linkCreated = true; + TaskCompletionBox.popupX = de.x; + TaskCompletionBox.popupY = de.y - 33; + TaskCompletionBox.taskCompleted = true; LinkDescriptionPopup.popupX = de.x; LinkDescriptionPopup.popupY = de.y; LinkDescriptionPopup.descriptionPopup = true; - setTimeout(action(() => LinkCreatedBox.linkCreated = false), 2500); + setTimeout(action(() => TaskCompletionBox.taskCompleted = false), 2500); }); if (de.complete.annoDragData) { /// this whole section for handling PDF annotations looks weird. Need to rethink this to make it cleaner @@ -818,6 +818,9 @@ export class DocumentView extends DocComponent(Docu !Doc.UserDoc().novice && helpItems.push({ description: "Show Fields ", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "onRight"), icon: "layer-group" }); cm.addItem({ description: "Help...", noexpand: true, subitems: helpItems, icon: "question" }); + // to be removed for baseline + cm.addItem({ description: "Print Document in Console", event: () => console.log(this.props.Document), icon: "hand-point-right" }); + // const existingAcls = cm.findByDescription("Privacy..."); // const aclItems: ContextMenuProps[] = existingAcls && "subitems" in existingAcls ? existingAcls.subitems : []; // aclItems.push({ description: "Make Add Only", event: () => this.setAcl(SharingPermissions.Add), icon: "concierge-bell" }); diff --git a/src/client/views/nodes/LinkCreatedBox.scss b/src/client/views/nodes/LinkCreatedBox.scss deleted file mode 100644 index 3cbd38b55..000000000 --- a/src/client/views/nodes/LinkCreatedBox.scss +++ /dev/null @@ -1,21 +0,0 @@ -.linkCreatedBox-fade { - border: 1px solid rgb(100, 100, 100); - - - width: auto; - position: absolute; - - height: auto; - z-index: 10000; - border-radius: 13px; - font-size: 13px; - white-space: nowrap; - - color: rgb(100, 100, 100); - background-color: rgba(250, 250, 250, 0.85); - padding-top: 6.5px; - padding-bottom: 6.5px; - font-weight: bold; - padding-left: 9px; - padding-right: 9px; -} \ No newline at end of file diff --git a/src/client/views/nodes/LinkCreatedBox.tsx b/src/client/views/nodes/LinkCreatedBox.tsx deleted file mode 100644 index 648ae23c8..000000000 --- a/src/client/views/nodes/LinkCreatedBox.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import React = require("react"); -import { observer } from "mobx-react"; -import { documentSchema } from "../../../fields/documentSchemas"; -import { makeInterface } from "../../../fields/Schema"; -import "./LinkCreatedBox.scss"; -import { observable, action } from "mobx"; -import { Fade } from "@material-ui/core"; - - -@observer -export class LinkCreatedBox extends React.Component<{}> { - - @observable public static linkCreated: boolean = false; - @observable public static popupX: number = 500; - @observable public static popupY: number = 150; - - @action - public static changeLinkCreated = () => { - LinkCreatedBox.linkCreated = !LinkCreatedBox.linkCreated; - } - - render() { - return -
Link Created
-
; - } -} \ No newline at end of file diff --git a/src/client/views/nodes/LinkDescriptionPopup.tsx b/src/client/views/nodes/LinkDescriptionPopup.tsx index 06e8d30d1..d8fe47f4e 100644 --- a/src/client/views/nodes/LinkDescriptionPopup.tsx +++ b/src/client/views/nodes/LinkDescriptionPopup.tsx @@ -4,7 +4,7 @@ import "./LinkDescriptionPopup.scss"; import { observable, action } from "mobx"; import { EditableView } from "../EditableView"; import { LinkManager } from "../../util/LinkManager"; -import { LinkCreatedBox } from "./LinkCreatedBox"; +import { TaskCompletionBox } from "./TaskCompletedBox"; @observer @@ -31,7 +31,7 @@ export class LinkDescriptionPopup extends React.Component<{}> { onClick = (e: PointerEvent) => { if (this.popupRef && !!!this.popupRef.current?.contains(e.target as any)) { LinkDescriptionPopup.descriptionPopup = false; - LinkCreatedBox.linkCreated = false; + TaskCompletionBox.taskCompleted = false; } } diff --git a/src/client/views/nodes/TaskCompletedBox.scss b/src/client/views/nodes/TaskCompletedBox.scss new file mode 100644 index 000000000..80b750b39 --- /dev/null +++ b/src/client/views/nodes/TaskCompletedBox.scss @@ -0,0 +1,20 @@ +.taskCompletedBox-fade { + border: 1px solid rgb(100, 100, 100); + + width: auto; + position: absolute; + + height: auto; + z-index: 10000; + border-radius: 13px; + font-size: 13px; + white-space: nowrap; + + color: rgb(100, 100, 100); + background-color: rgba(250, 250, 250, 0.85); + padding-top: 6.5px; + padding-bottom: 6.5px; + font-weight: bold; + padding-left: 9px; + padding-right: 9px; +} \ No newline at end of file diff --git a/src/client/views/nodes/TaskCompletedBox.tsx b/src/client/views/nodes/TaskCompletedBox.tsx new file mode 100644 index 000000000..1ba2d1713 --- /dev/null +++ b/src/client/views/nodes/TaskCompletedBox.tsx @@ -0,0 +1,32 @@ +import React = require("react"); +import { observer } from "mobx-react"; +import { documentSchema } from "../../../fields/documentSchemas"; +import { makeInterface } from "../../../fields/Schema"; +import "./TaskCompletedBox.scss"; +import { observable, action } from "mobx"; +import { Fade } from "@material-ui/core"; + + +@observer +export class TaskCompletionBox extends React.Component<{}> { + + @observable public static taskCompleted: boolean = false; + @observable public static popupX: number = 500; + @observable public static popupY: number = 150; + @observable public static textDisplayed: string = "Link Created"; + + @action + public static toggleTaskCompleted = () => { + TaskCompletionBox.taskCompleted = !TaskCompletionBox.taskCompleted; + } + + render() { + return +
{TaskCompletionBox.textDisplayed}
+
; + } +} \ No newline at end of file diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 917a6853c..0c816461c 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -19,9 +19,8 @@ import { DateField } from "./DateField"; import { listSpec } from "./Schema"; import { ComputedField } from "./ScriptField"; import { Cast, FieldValue, NumCast, StrCast, ToConstructor } from "./Types"; -import { deleteProperty, getField, getter, makeEditable, makeReadOnly, setter, updateFunction, GetEffectiveAcl } from "./util"; +import { deleteProperty, getField, getter, makeEditable, makeReadOnly, setter, updateFunction, GetEffectiveAcl, SharingPermissions } from "./util"; import { LinkManager } from "../client/util/LinkManager"; -import { SharingPermissions } from "../client/util/SharingManager"; import JSZip = require("jszip"); import { saveAs } from "file-saver"; @@ -103,6 +102,7 @@ export const AclPrivate = Symbol("AclOwnerOnly"); export const AclReadonly = Symbol("AclReadOnly"); export const AclAddonly = Symbol("AclAddonly"); export const AclEdit = Symbol("AclEdit"); +export const AclAdmin = Symbol("AclAdmin"); export const UpdatingFromServer = Symbol("UpdatingFromServer"); const CachedUpdates = Symbol("Cached updates"); @@ -110,7 +110,8 @@ const AclMap = new Map([ [SharingPermissions.None, AclPrivate], [SharingPermissions.View, AclReadonly], [SharingPermissions.Add, AclAddonly], - [SharingPermissions.Edit, AclEdit] + [SharingPermissions.Edit, AclEdit], + [SharingPermissions.Admin, AclAdmin] ]); export function fetchProto(doc: Doc) { diff --git a/src/fields/util.ts b/src/fields/util.ts index cd1e24826..eba398dfb 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, fetchProto, DataSym, DocListCast } from "./Doc"; +import { Doc, FieldResult, UpdatingFromServer, LayoutSym, AclPrivate, AclEdit, AclReadonly, AclAddonly, AclSym, fetchProto, DataSym, DocListCast, AclAdmin } from "./Doc"; import { SerializationHelper } from "../client/util/SerializationHelper"; import { ProxyField, PrefetchProxy } from "./Proxy"; import { RefField } from "./RefField"; @@ -9,7 +9,6 @@ import { Parent, OnUpdate, Update, Id, SelfProxy, Self } from "./FieldSymbols"; import { DocServer } from "../client/DocServer"; import { ComputedField } from "./ScriptField"; import { ScriptCast, StrCast } from "./Types"; -import { SharingPermissions } from "../client/util/SharingManager"; function _readOnlySetter(): never { @@ -127,12 +126,20 @@ export function setGroups(groups: string[]) { currentUserGroups = groups; } +export enum SharingPermissions { + Admin = "Admin", + Edit = "Can Edit", + Add = "Can Add", + View = "Can View", + None = "Not Shared" +} + export function GetEffectiveAcl(target: any, in_prop?: string | symbol | number): symbol { if (in_prop === UpdatingFromServer || target[UpdatingFromServer]) return AclEdit; if (target[AclSym] && Object.keys(target[AclSym]).length) { - if (target.__fields?.author === Doc.CurrentUserEmail || target.author === Doc.CurrentUserEmail || currentUserGroups.includes("admin")) return AclEdit; + if (target.__fields?.author === Doc.CurrentUserEmail || target.author === Doc.CurrentUserEmail || currentUserGroups.includes("admin")) return AclAdmin; if (_overrideAcl || (in_prop && DocServer.PlaygroundFields?.includes(in_prop.toString()))) return AclEdit; @@ -143,7 +150,8 @@ export function GetEffectiveAcl(target: any, in_prop?: string | symbol | number) [AclPrivate, 0], [AclReadonly, 1], [AclAddonly, 2], - [AclEdit, 3] + [AclEdit, 3], + [AclAdmin, 4] ]); for (const [key, value] of Object.entries(target[AclSym])) { @@ -157,7 +165,7 @@ export function GetEffectiveAcl(target: any, in_prop?: string | symbol | number) } return aclPresent ? effectiveAcl : AclEdit; } - return AclEdit; + return AclAdmin; } export function distributeAcls(key: string, acl: SharingPermissions, target: Doc, inheritingFromCollection?: boolean) { @@ -166,7 +174,8 @@ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc ["Not Shared", 0], ["Can View", 1], ["Can Add", 2], - ["Can Edit", 3] + ["Can Edit", 3], + ["Admin", 4] ]); const dataDoc = target[DataSym]; @@ -206,11 +215,10 @@ const layoutProps = ["panX", "panY", "width", "height", "nativeWidth", "nativeHe "chromeStatus", "viewType", "gridGap", "xMargin", "yMargin", "autoHeight"]; export function setter(target: any, in_prop: string | symbol | number, value: any, receiver: any): boolean { let prop = in_prop; - if (GetEffectiveAcl(target, in_prop) !== AclEdit) { - return true; - } + const effectiveAcl = GetEffectiveAcl(target, in_prop); + if (effectiveAcl !== AclEdit && effectiveAcl !== AclAdmin) return true; - if (typeof prop === "string" && prop.startsWith("ACL") && ((target.author && Doc.CurrentUserEmail !== target.author) || !["Can Edit", "Can Add", "Can View", "Not Shared", undefined].includes(value))) return true; + if (typeof prop === "string" && prop.startsWith("ACL") && (effectiveAcl !== AclAdmin || ![...Object.values(SharingPermissions), undefined].includes(value))) return true; // if (typeof prop === "string" && prop.startsWith("ACL") && !["Can Edit", "Can Add", "Can View", "Not Shared", undefined].includes(value)) return true; if (typeof prop === "string" && prop !== "__id" && prop !== "__fields" && (prop.startsWith("_") || layoutProps.includes(prop))) { -- cgit v1.2.3-70-g09d2 From 99e0b01dbe41e56cfdb748b53f03fe71d73a80b7 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 25 Jul 2020 10:54:12 -0400 Subject: pushpin annotations can follow links to multple targets at once. chaned text boxes so that they can be made isBackround .fixed addin/remoin documents from freeform collections. --- src/client/util/DocumentManager.ts | 44 +++++++++++----------- .../collectionFreeForm/CollectionFreeFormView.tsx | 3 ++ .../views/nodes/formattedText/FormattedTextBox.tsx | 2 +- src/fields/Doc.ts | 1 - 4 files changed, 27 insertions(+), 23 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 51b50878d..523dbfca0 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -152,18 +152,18 @@ export class DocumentManager { const first = getFirstDocView(annotatedDoc); if (first) { annotatedDoc = first.props.Document; - if (docView) { - docView.props.focus(annotatedDoc, false); - } + docView?.props.focus(annotatedDoc, false); } } if (docView) { // we have a docView already and aren't forced to create a new one ... just focus on the document. TODO move into view if necessary otherwise just highlight? - if (originatingDoc?.isPushpin) docView.props.Document.hidden = !docView.props.Document.hidden; + if (originatingDoc?.isPushpin) { + docView.props.Document.hidden = !docView.props.Document.hidden; + } else { docView.props.Document.hidden && (docView.props.Document.hidden = undefined); docView.props.focus(docView.props.Document, willZoom, undefined, focusAndFinish); + highlight(); } - highlight(); } else { const contextDocs = docContext ? await DocListCastAsync(docContext.data) : undefined; const contextDoc = contextDocs?.find(doc => Doc.AreProtosEqual(doc, targetDoc)) ? docContext : undefined; @@ -218,25 +218,27 @@ export class DocumentManager { const backLinkWithoutTargetView = secondDocs.find(d => DocumentManager.Instance.getDocumentViews(d.anchor1 as Doc).length === 0); const linkWithoutTargetDoc = traverseBacklink === undefined ? fwdLinkWithoutTargetView || backLinkWithoutTargetView : traverseBacklink ? backLinkWithoutTargetView : fwdLinkWithoutTargetView; const linkDocList = linkWithoutTargetDoc ? [linkWithoutTargetDoc] : (traverseBacklink === undefined ? firstDocs.concat(secondDocs) : traverseBacklink ? secondDocs : firstDocs); - const linkDoc = linkDocList.length && linkDocList[0]; - if (linkDoc) { - const target = (doc === linkDoc.anchor1 ? linkDoc.anchor2 : doc === linkDoc.anchor2 ? linkDoc.anchor1 : - (Doc.AreProtosEqual(doc, linkDoc.anchor1 as Doc) ? linkDoc.anchor2 : linkDoc.anchor1)) as Doc; - const targetTimecode = (doc === linkDoc.anchor1 ? Cast(linkDoc.anchor2_timecode, "number") : - doc === linkDoc.anchor2 ? Cast(linkDoc.anchor1_timecode, "number") : - (Doc.AreProtosEqual(doc, linkDoc.anchor1 as Doc) ? Cast(linkDoc.anchor2_timecode, "number") : Cast(linkDoc.anchor1_timecode, "number"))); - if (target) { - const containerDoc = (await Cast(target.annotationOn, Doc)) || target; - containerDoc.currentTimecode = targetTimecode; - const targetContext = await target?.context as Doc; - const targetNavContext = !Doc.AreProtosEqual(targetContext, currentContext) ? targetContext : undefined; - DocumentManager.Instance.jumpToDocument(target, zoom, (doc, finished) => createViewFunc(doc, StrCast(linkDoc.followLinkLocation, "onRight"), finished), targetNavContext, linkDoc, undefined, doc, finished); + const followLinks = linkDocList.length ? (doc.isPushpin ? linkDocList : [linkDocList[0]]) : []; + followLinks.forEach(async linkDoc => { + if (linkDoc) { + const target = (doc === linkDoc.anchor1 ? linkDoc.anchor2 : doc === linkDoc.anchor2 ? linkDoc.anchor1 : + (Doc.AreProtosEqual(doc, linkDoc.anchor1 as Doc) ? linkDoc.anchor2 : linkDoc.anchor1)) as Doc; + const targetTimecode = (doc === linkDoc.anchor1 ? Cast(linkDoc.anchor2_timecode, "number") : + doc === linkDoc.anchor2 ? Cast(linkDoc.anchor1_timecode, "number") : + (Doc.AreProtosEqual(doc, linkDoc.anchor1 as Doc) ? Cast(linkDoc.anchor2_timecode, "number") : Cast(linkDoc.anchor1_timecode, "number"))); + if (target) { + const containerDoc = (await Cast(target.annotationOn, Doc)) || target; + containerDoc.currentTimecode = targetTimecode; + const targetContext = await target?.context as Doc; + const targetNavContext = !Doc.AreProtosEqual(targetContext, currentContext) ? targetContext : undefined; + DocumentManager.Instance.jumpToDocument(target, zoom, (doc, finished) => createViewFunc(doc, StrCast(linkDoc.followLinkLocation, "onRight"), finished), targetNavContext, linkDoc, undefined, doc, finished); + } else { + finished?.(); + } } else { finished?.(); } - } else { - finished?.(); - } + }); } } Scripting.addGlobal(function DocFocus(doc: any) { DocumentManager.Instance.getDocumentViews(Doc.GetProto(doc)).map(view => view.props.focus(doc, true)); }); \ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 38c1edde2..079add4b0 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -944,6 +944,9 @@ export class CollectionFreeFormView extends CollectionSubView this.props.active(outsideReaction) || this.backgroundActive ? true : false; getChildDocumentViewProps(childLayout: Doc, childData?: Doc): DocumentViewProps { return { + addDocument: this.props.addDocument, + removeDocument: this.props.removeDocument, + moveDocument: this.props.moveDocument, pinToPres: this.props.pinToPres, whenActiveChanged: this.props.whenActiveChanged, NativeHeight: returnZero, diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 53234d819..966aaa895 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1406,7 +1406,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 9020dcc84..3ea53a9e0 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -916,7 +916,6 @@ export namespace Doc { return doc; } export function UnBrushDoc(doc: Doc) { - if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(Doc.GetProto(doc)) === AclPrivate) return doc; brushManager.BrushedDoc.delete(doc); brushManager.BrushedDoc.delete(Doc.GetProto(doc)); -- cgit v1.2.3-70-g09d2 From 5454385b6fabbcafee4d797829fb9ceaa8a71ed1 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 25 Jul 2020 20:14:16 -0400 Subject: made buttons turn into fonticons on iconify. droppin fonticons onto linear views keeps them as buttons. droppin buttons on linear view makes them fonticons. fixed ColletionMenu scripts to work with templates by usin self instead of this. fixed pointer events with text boxes for filterview & normal. fixed fieldKey deletin and addin --- src/client/util/CurrentUserUtils.ts | 12 +++++++++-- src/client/util/DragManager.ts | 7 +++---- src/client/util/DropConverter.ts | 2 +- src/client/views/MainView.tsx | 4 ++-- src/client/views/collections/CollectionMenu.tsx | 23 ++++++++++++++-------- src/client/views/nodes/DocumentView.tsx | 2 +- src/client/views/nodes/FontIconBox.tsx | 2 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 4 ++-- src/fields/util.ts | 4 ++-- 9 files changed, 37 insertions(+), 23 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index b47cfb33a..6d752832a 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -346,6 +346,14 @@ export class CurrentUserUtils { 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)") + }); + 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)") @@ -359,11 +367,11 @@ export class CurrentUserUtils { 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-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 })); } else { const templateIconsDoc = Cast(doc["template-icons"], Doc, null); - const requiredTypes = [doc["template-icon-view"] as Doc, doc["template-icon-view-img"] as Doc, + 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 => { await Promise.all(curIcons!); diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 837f0b1db..4b1860b5c 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -224,11 +224,10 @@ export namespace DragManager { } // drag a button template and drop a new button - export function StartButtonDrag(eles: HTMLElement[], script: string, title: string, vars: { [name: string]: Field }, params: string[], initialize: (button: Doc) => void, downX: number, downY: number, options?: DragOptions) { + export function + StartButtonDrag(eles: HTMLElement[], script: string, title: string, vars: { [name: string]: Field }, params: string[], initialize: (button: Doc) => void, downX: number, downY: number, options?: DragOptions) { const finishDrag = (e: DragCompleteEvent) => { - const bd = params.length > Object.keys(vars).length ? - Docs.Create.ButtonDocument({ toolTip: title, z: 1, _width: 150, _height: 50, title, onClick: ScriptField.MakeScript(script) }) : - Docs.Create.FontIconDocument({ toolTip: title, z: 1, _nativeWidth: 30, _nativeHeight: 30, _width: 30, _height: 30, title, onClick: ScriptField.MakeScript(script) }); + const bd = Docs.Create.ButtonDocument({ toolTip: title, z: 1, _width: 150, _height: 50, title, onClick: ScriptField.MakeScript(script) }); params.map(p => Object.keys(vars).indexOf(p) !== -1 && (Doc.GetProto(bd)[p] = new PrefetchProxy(vars[p] as Doc))); // copy all "captured" arguments into document parameterfields initialize?.(bd); Doc.GetProto(bd)["onClick-paramFieldKeys"] = new List(params); diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts index f9837298d..d0acf14c3 100644 --- a/src/client/util/DropConverter.ts +++ b/src/client/util/DropConverter.ts @@ -57,7 +57,7 @@ export function convertDropDataToButtons(data: DragManager.DocumentDragData) { data?.draggedDocuments.map((doc, i) => { let dbox = doc; // bcz: isButtonBar is intended to allow a collection of linear buttons to be dropped and nested into another collection of buttons... it's not being used yet, and isn't very elegant - if (doc.type === DocumentType.FONTICON) { + if (doc.type === DocumentType.FONTICON || StrCast(Doc.Layout(doc).layout).includes("FontIconBox")) { dbox = Doc.MakeAlias(doc); } else if (!doc.onDragStart && !doc.isButtonBar) { const layoutDoc = doc.layout instanceof Doc && doc.layout.isTemplateForField ? doc.layout : doc; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 81f2feee0..ae3f05fb7 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -8,7 +8,7 @@ import { faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote, faTimesCircle, faThumbtack, faTree, faTv, faUndoAlt, faVideo, faAsterisk, faBrain, faImage, faPaintBrush, faTimes, faEye, faArrowsAlt, faQuoteLeft, faSortAmountDown, faAlignLeft, faAlignCenter, faAlignRight, faHeading, faRulerCombined, faFillDrip, faLink, faUnlink, faBold, faItalic, faChevronLeft, faUnderline, faStrikethrough, faSuperscript, faSubscript, faIndent, faEyeDropper, - faPaintRoller, faBars, faBrush, faShapes, faEllipsisH, faHandPaper, faMap + faPaintRoller, faBars, faBrush, faShapes, faEllipsisH, faHandPaper, faMap, faUser } from '@fortawesome/free-solid-svg-icons'; import { ANTIMODEMENU_HEIGHT } from './globalCssVariables.scss'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; @@ -150,7 +150,7 @@ export class MainView extends React.Component { faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote, faTrashAlt, faAngleRight, faBell, faThumbtack, faTree, faTv, faUndoAlt, faVideo, faAsterisk, faBrain, faImage, faPaintBrush, faTimes, faEye, faArrowsAlt, faQuoteLeft, faSortAmountDown, faAlignLeft, faAlignCenter, faAlignRight, faHeading, faRulerCombined, faFillDrip, faLink, faUnlink, faBold, faItalic, faChevronLeft, faUnderline, faStrikethrough, faSuperscript, faSubscript, faIndent, faEyeDropper, - faPaintRoller, faBars, faBrush, faShapes, faEllipsisH, faHandPaper, faMap); + faPaintRoller, faBars, faBrush, faShapes, faEllipsisH, faHandPaper, faMap, faUser); this.initEventListeners(); this.initAuthenticationRouters(); } diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index 992c1f600..81c349b26 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -2,7 +2,7 @@ import React = require("react"); import { FontAwesomeIcon, FontAwesomeIconProps } from "@fortawesome/react-fontawesome"; import { action, computed, observable, reaction, runInAction, Lambda } from "mobx"; import { observer } from "mobx-react"; -import { Doc, DocListCast, Opt } from "../../../fields/Doc"; +import { Doc, DocListCast, Opt, Field } from "../../../fields/Doc"; import { BoolCast, Cast, StrCast, NumCast } from "../../../fields/Types"; import AntimodeMenu from "../AntimodeMenu"; import "./CollectionMenu.scss"; @@ -24,6 +24,7 @@ import { Document } from "../../../fields/documentSchemas"; import { SelectionManager } from "../../util/SelectionManager"; import { DocumentView } from "../nodes/DocumentView"; import { ColorState } from "react-color"; +import { ObjectField } from "../../../fields/ObjectField"; @observer export default class CollectionMenu extends AntimodeMenu { @@ -72,42 +73,48 @@ export class CollectionViewBaseChrome extends React.Component source.length && (this.target.childLayoutTemplate = Doc.getDocTemplate(source?.[0]))), initialize: emptyFunction, }; _narrativeCommand = { params: ["target", "source"], title: "child click view", - script: "this.target.childClickedOpenTemplateView = getDocTemplate(this.source?.[0])", + script: "self.target.childClickedOpenTemplateView = getDocTemplate(self.source?.[0])", immediate: undoBatch((source: Doc[]) => source.length && (this.target.childClickedOpenTemplateView = Doc.getDocTemplate(source?.[0]))), initialize: emptyFunction, }; _contentCommand = { params: ["target", "source"], title: "clear content", - script: "getProto(this.target).data = copyField(this.source);", + script: "getProto(self.target).data = copyField(self.source);", immediate: undoBatch((source: Doc[]) => Doc.GetProto(this.target).data = new List(source)), // Doc.aliasDocs(source), initialize: emptyFunction, }; _viewCommand = { params: ["target"], title: "bookmark view", - script: "this.target._panX = this['target-panX']; this.target._panY = this['target-panY']; this.target._viewScale = this['target-viewScale'];", + script: "self.target._panX = self['target-panX']; self.target._panY = self['target-panY']; self.target._viewScale = self['target-viewScale'];", immediate: undoBatch((source: Doc[]) => { this.target._panX = 0; this.target._panY = 0; this.target._viewScale = 1; }), initialize: (button: Doc) => { button['target-panX'] = this.target._panX; button['target-panY'] = this.target._panY; button['target-viewScale'] = this.target._viewScale; }, }; _clusterCommand = { params: ["target"], title: "fit content", - script: "this.target._fitToBox = !this.target._fitToBox;", + script: "self.target._fitToBox = !self.target._fitToBox;", immediate: undoBatch((source: Doc[]) => this.target._fitToBox = !this.target._fitToBox), initialize: emptyFunction }; _fitContentCommand = { params: ["target"], title: "toggle clusters", - script: "this.target.useClusters = !this.target.useClusters;", + script: "self.target.useClusters = !self.target.useClusters;", immediate: undoBatch((source: Doc[]) => this.target.useClusters = !this.target.useClusters), initialize: emptyFunction }; + _saveFilterCommand = { + params: ["target"], title: "save filter", + script: "self.target._docFilters = copyField(self['target-docFilters']);", + immediate: undoBatch((source: Doc[]) => this.target._docFilters = undefined), + initialize: (button: Doc) => { button['target-docFilters'] = this.target._docFilters instanceof ObjectField && ObjectField.MakeCopy(this.target._docFilters as any as ObjectField); }, + }; - _freeform_commands = [this._viewCommand, this._fitContentCommand, this._clusterCommand, this._contentCommand, this._templateCommand, this._narrativeCommand]; + _freeform_commands = [this._viewCommand, this._saveFilterCommand, this._fitContentCommand, this._clusterCommand, this._contentCommand, this._templateCommand, this._narrativeCommand]; _stacking_commands = [this._contentCommand, this._templateCommand]; _masonry_commands = [this._contentCommand, this._templateCommand]; _schema_commands = [this._templateCommand, this._narrativeCommand]; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 8cadafccd..df4576243 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -294,7 +294,7 @@ export class DocumentView extends DocComponent(Docu let stopPropagate = true; let preventDefault = true; !this.props.Document.isBackground && this.props.bringToFront(this.props.Document); - if (this._doubleTap && this.props.renderDepth && !this.onClickHandler?.script) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click + if (this._doubleTap && this.props.renderDepth) {// && !this.onClickHandler?.script) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click if (!(e.nativeEvent as any).formattedHandled) { if (this.onDoubleClickHandler?.script && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes("ScriptingBox")) { // bcz: hack? don't execute script if you're clicking on a scripting box itself const func = () => this.onDoubleClickHandler.script.run({ diff --git a/src/client/views/nodes/FontIconBox.tsx b/src/client/views/nodes/FontIconBox.tsx index ab34e13b0..2611d2ca7 100644 --- a/src/client/views/nodes/FontIconBox.tsx +++ b/src/client/views/nodes/FontIconBox.tsx @@ -67,7 +67,7 @@ export class FontIconBox extends DocComponent( background: StrCast(refLayout._backgroundColor, StrCast(refLayout.backgroundColor)), boxShadow: this.layoutDoc.ischecked ? `4px 4px 12px black` : undefined }}> - + {!this.rootDoc.title ? (null) :
{StrCast(this.rootDoc.label, StrCast(this.rootDoc.title).substring(0, 6))}
} ; return !this.layoutDoc.toolTip ? button : diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 966aaa895..6b6fc5da2 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1401,12 +1401,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp onDoubleClick={this.onDoubleClick} >
diff --git a/src/fields/util.ts b/src/fields/util.ts index e0b1843a1..47da7d7bf 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -77,10 +77,10 @@ const _setterImpl = action(function (target: any, prop: string | symbol | number if (writeToDoc) { if (value === undefined) { - delete target.__fieldKeys[prop]; + target.__fieldKeys && (delete target.__fieldKeys[prop]); delete target.__fields[prop]; } else { - target.__fieldKeys[prop] = true; + target.__fieldKeys && (target.__fieldKeys[prop] = true); target.__fields[prop] = value; } //if (typeof value === "object" && !(value instanceof ObjectField)) debugger; -- cgit v1.2.3-70-g09d2