aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2020-09-20 23:53:04 -0400
committerbobzel <zzzman@gmail.com>2020-09-20 23:53:04 -0400
commite4ae6fa6df6bb0118f113bbdf3a40f768405f7b3 (patch)
treed6b59231fc2ad1e729abfb472d0fa5bf407e122c
parentf87037b13e0c97d1c9383ac023c8358963a58cff (diff)
fixed undo for bullet points to not take multiple steps and to work properly. no longer adds cursorfiels to the undo stack. fixed sharing manager to no create unnecesary documents..
-rw-r--r--src/client/util/SelectionManager.ts3
-rw-r--r--src/client/util/SharingManager.tsx102
-rw-r--r--src/client/views/GlobalKeyHandler.ts2
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx15
-rw-r--r--src/client/views/collections/TreeView.tsx10
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx8
-rw-r--r--src/fields/Doc.ts7
-rw-r--r--src/fields/util.ts12
8 files changed, 62 insertions, 97 deletions
diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index 7795a4a59..008ce281c 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -37,7 +37,6 @@ export namespace SelectionManager {
manager.SelectedDocuments.clear();
manager.SelectedDocuments.set(docView, true);
}
- Doc.UserDoc().activeSelection = new List(SelectionManager.SelectedDocuments().map(dv => dv.props.Document));
}
@action
DeselectDoc(docView: DocumentView): void {
@@ -45,7 +44,6 @@ export namespace SelectionManager {
if (manager.SelectedDocuments.get(docView)) {
manager.SelectedDocuments.delete(docView);
docView.props.whenActiveChanged(false);
- Doc.UserDoc().activeSelection = new List(SelectionManager.SelectedDocuments().map(dv => dv.props.Document));
}
}
@action
@@ -54,7 +52,6 @@ export namespace SelectionManager {
manager.SelectedSchemaDocument = undefined;
Array.from(manager.SelectedDocuments.keys()).map(dv => dv.props.whenActiveChanged(false));
manager.SelectedDocuments.clear();
- Doc.UserDoc().activeSelection = new List<Doc>([]);
}
}
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index 7991022d2..d3500970d 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -1,5 +1,5 @@
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 * as React from "react";
import Select from "react-select";
@@ -7,7 +7,7 @@ import * as RequestPromise from "request-promise";
import { AclAdmin, AclPrivate, DataSym, Doc, DocListCast, Opt, AclSym } from "../../fields/Doc";
import { List } from "../../fields/List";
import { Cast, StrCast } from "../../fields/Types";
-import { distributeAcls, GetEffectiveAcl, SharingPermissions } from "../../fields/util";
+import { distributeAcls, GetEffectiveAcl, SharingPermissions, TraceMobx } from "../../fields/util";
import { Utils } from "../../Utils";
import { DocServer } from "../DocServer";
import { CollectionView } from "../views/collections/CollectionView";
@@ -148,7 +148,7 @@ export class SharingManager extends React.Component<{}> {
* @param group
* @param permission
*/
- setInternalGroupSharing = (group: Doc, permission: string, targetDoc?: Doc) => {
+ setInternalGroupSharing = (group: Doc | { groupName: string }, permission: string, targetDoc?: Doc) => {
const target = targetDoc || this.targetDoc!;
const key = StrCast(group.groupName).replace(".", "_");
@@ -160,7 +160,7 @@ export class SharingManager extends React.Component<{}> {
doc.author === Doc.CurrentUserEmail && !doc[`acl-${Doc.CurrentUserEmail.replace(".", "_")}`] && distributeAcls(`acl-${Doc.CurrentUserEmail.replace(".", "_")}`, SharingPermissions.Admin, doc);
GetEffectiveAcl(doc) === AclAdmin && distributeAcls(acl, permission as SharingPermissions, doc);
- if (key !== "Public") {
+ if (group instanceof Doc) {
const members: string[] = JSON.parse(StrCast(group.members));
const users: ValidatedUser[] = this.users.filter(({ user: { email } }) => members.includes(email));
@@ -393,39 +393,22 @@ export class SharingManager extends React.Component<{}> {
/**
* @returns the main interface of the SharingManager.
*/
- private get sharingInterface() {
-
+ @computed get sharingInterface() {
+ TraceMobx();
const groupList = GroupManager.Instance?.getAllGroups() || [];
- const sortedUsers = this.users.slice().sort(this.sortUsers)
- .map(({ user: { email } }) => ({ label: email, value: indType + email }));
- const sortedGroups = groupList.slice().sort(this.sortGroups)
- .map(({ groupName }) => ({ label: StrCast(groupName), value: groupType + StrCast(groupName) }));
+ const sortedUsers = this.users.slice().sort(this.sortUsers).map(({ user: { email } }) => ({ label: email, value: indType + email }));
+ const sortedGroups = groupList.slice().sort(this.sortGroups).map(({ groupName }) => ({ label: StrCast(groupName), value: groupType + StrCast(groupName) }));
// the next block handles the users shown (individuals/groups/both)
const options: GroupedOptions[] = [];
if (GroupManager.Instance) {
if ((this.showUserOptions && this.showGroupOptions) || (!this.showUserOptions && !this.showGroupOptions)) {
- options.push({
- label: 'Individuals',
- options: sortedUsers
- },
- {
- label: 'Groups',
- options: sortedGroups
- });
- }
- else if (this.showUserOptions) {
- options.push({
- label: 'Individuals',
- options: sortedUsers
- });
- }
- else {
- options.push({
- label: 'Groups',
- options: sortedGroups
- });
+ options.push(
+ { label: 'Individuals', options: sortedUsers },
+ { label: 'Groups', options: sortedGroups });
}
+ else if (this.showUserOptions) options.push({ label: 'Individuals', options: sortedUsers });
+ else options.push({ label: 'Groups', options: sortedGroups });
}
const users = this.individualSort === "ascending" ? this.users.slice().sort(this.sortUsers) : this.individualSort === "descending" ? this.users.slice().sort(this.sortUsers).reverse() : this.users;
@@ -510,12 +493,10 @@ export class SharingManager extends React.Component<{}> {
) : null
);
- // dummy doc for public acl
- const publicDoc = new Doc;
- publicDoc.groupName = "Public";
+
// the list of groups shared with
- const groupListMap = groups.filter(({ groupName }) => docs.length > 1 ? commonKeys.includes(`acl-${StrCast(groupName).replace('.', '_')}`) : true);
- groupListMap.unshift(publicDoc);
+ const groupListMap: (Doc | { groupName: string })[] = groups.filter(({ groupName }) => docs.length > 1 ? commonKeys.includes(`acl-${StrCast(groupName).replace('.', '_')}`) : true);
+ groupListMap.unshift({ groupName: "Public" });
const groupListContents = groupListMap.map(group => {
const groupKey = `acl-${StrCast(group.groupName)}`;
const uniform = docs.every(doc => this.layoutDocAcls ? doc?.[AclSym]?.[groupKey] === docs[0]?.[AclSym]?.[groupKey] : doc?.[DataSym]?.[AclSym]?.[groupKey] === docs[0]?.[DataSym]?.[AclSym]?.[groupKey]);
@@ -527,7 +508,7 @@ export class SharingManager extends React.Component<{}> {
className={"container"}
>
<div className={"padding"}>{group.groupName}</div>
- {group.groupName !== "Public" ?
+ {group instanceof Doc ?
(<div className="group-info" onClick={action(() => GroupManager.Instance.currentGroup = group)}>
<FontAwesomeIcon icon={"info-circle"} color={"#e8e8e8"} size={"sm"} style={{ backgroundColor: "#1e89d7", borderRadius: "100%", border: "1px solid #1e89d7" }} />
</div>)
@@ -559,36 +540,6 @@ export class SharingManager extends React.Component<{}> {
onCloseButtonClick={action(() => GroupManager.Instance.currentGroup = undefined)}
/> :
null}
- {/* <p className={"share-link"}>Manage the public link to {this.focusOn("this document...")}</p>
- {!this.linkVisible ? (null) :
- <div className={"link-container"}>
- <div className={"link-box"} onClick={this.copy}>{this.sharingUrl}</div>
- <div
- title={"Copy link to clipboard"}
- className={"copy"}
- style={{ backgroundColor: this.copied ? "lawngreen" : "gainsboro" }}
- onClick={this.copy}
- >
- <FontAwesomeIcon icon={"copy"} />
- </div>
- </div>
- }
- <div className={"people-with-container"}>
- {!this.linkVisible ? (null) : <p className={"people-with"}>People with this link</p>}
- <select
- className={"people-with-select"}
- value={this.sharingDoc ? StrCast(this.sharingDoc[PublicKey], SharingPermissions.None) : SharingPermissions.None}
- style={{
- marginLeft: this.linkVisible ? 10 : 0,
- color: this.sharingDoc ? ColorMapping.get(StrCast(this.sharingDoc[PublicKey], SharingPermissions.None)) : DefaultColor,
- borderColor: this.sharingDoc ? ColorMapping.get(StrCast(this.sharingDoc[PublicKey], SharingPermissions.None)) : DefaultColor
- }}
- onChange={e => this.setExternalSharing(e.currentTarget.value)}
- >
- {this.sharingOptions}
- </select>
- </div>
- <div className={"hr-substitute"} /> */}
<div className="sharing-contents">
<p className={"share-title"}><b>Share </b>{this.focusOn(docs.length < 2 ? StrCast(targetDoc?.title, "this document") : "-multiple-")}</p>
<div className={"close-button"} onClick={this.close}>
@@ -660,16 +611,13 @@ export class SharingManager extends React.Component<{}> {
}
render() {
- return (
- <MainViewModal
- contents={this.sharingInterface}
- isDisplayed={this.isOpen}
- interactive={true}
- dialogueBoxDisplayedOpacity={this.dialogueBoxOpacity}
- overlayDisplayedOpacity={this.overlayOpacity}
- closeOnExternalClick={this.close}
- />
- );
+ return <MainViewModal
+ contents={this.sharingInterface}
+ isDisplayed={this.isOpen}
+ interactive={true}
+ dialogueBoxDisplayedOpacity={this.dialogueBoxOpacity}
+ overlayDisplayedOpacity={this.overlayOpacity}
+ closeOnExternalClick={this.close}
+ />;
}
-
} \ No newline at end of file
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index ba9334c40..0c05a1b69 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -206,10 +206,12 @@ export class KeyManager {
preventDefault = false;
break;
case "y":
+ SelectionManager.DeselectAll();
UndoManager.Redo();
stopPropagation = false;
break;
case "z":
+ SelectionManager.DeselectAll();
UndoManager.Undo();
stopPropagation = false;
break;
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index e61b9624a..efbe5581b 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -24,6 +24,8 @@ import { CollectionSubView } from "./CollectionSubView";
import "./CollectionTreeView.scss";
import { TreeView } from "./TreeView";
import React = require("react");
+import { DocumentManager } from '../../util/DocumentManager';
+import { FormattedTextBoxComment } from '../nodes/formattedText/FormattedTextBoxComment';
export type collectionTreeViewProps = {
treeViewHideTitle?: boolean;
@@ -61,19 +63,26 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
this.treedropDisposer?.();
}
- @action
- remove = (doc: Doc | Doc[]): boolean => {
+ @undoBatch
+ remove = action((doc: Doc | Doc[]): boolean => {
const docs = doc instanceof Doc ? [doc] : doc;
const targetDataDoc = this.doc[DataSym];
const value = DocListCast(targetDataDoc[this.props.fieldKey]);
const result = value.filter(v => !docs.includes(v));
SelectionManager.DeselectAll();
if (result.length !== value.length) {
+ const ind = targetDataDoc[this.props.fieldKey].indexOf(doc);
targetDataDoc[this.props.fieldKey] = new List<Doc>(result);
+ if (ind > 0) {
+ const prev = targetDataDoc[this.props.fieldKey][ind - 1];
+ FormattedTextBox.SelectOnLoad = prev[Id];
+ const prevView = DocumentManager.Instance.getDocumentView(prev, this.props.CollectionView);
+ prevView?.select(false);
+ }
return true;
}
return false;
- }
+ })
@action
addDoc = (doc: Doc | Doc[], relativeTo: Opt<Doc>, before?: boolean): boolean => {
const doAddDoc = (doc: Doc | Doc[]) =>
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index e509eb78d..edb703135 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -121,12 +121,16 @@ export class TreeView extends React.Component<TreeViewProps> {
}
@undoBatch @action remove = (doc: Doc | Doc[], key: string) => {
this.props.treeView.props.select(false);
- return (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && Doc.RemoveDocFromList(this.dataDoc, key, doc), true);
+ const ind = this.dataDoc[key].indexOf(doc);
+ const res = (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && Doc.RemoveDocFromList(this.dataDoc, key, doc), true);
+ res && ind > 0 && DocumentManager.Instance.getDocumentView(this.dataDoc[key][ind - 1], this.props.treeView.props.CollectionView)?.select(false);
+ return res;
}
@undoBatch @action removeDoc = (doc: Doc | Doc[]) => this.remove(doc, Doc.LayoutFieldKey(this.doc));
constructor(props: any) {
super(props);
+ console.log("Ttile = " + this.props.document.title);
const titleScript = ScriptField.MakeScript(`{setInPlace(self, 'editTitle', '${this._uniqueId}'); documentView.select();} `, { documentView: "any" });
const openScript = ScriptField.MakeScript(`openOnRight(self)`);
const treeOpenScript = ScriptField.MakeScript(`self.treeViewOpen = !self.treeViewOpen`);
@@ -218,7 +222,6 @@ export class TreeView extends React.Component<TreeViewProps> {
})}
onClick={() => {
SelectionManager.DeselectAll();
- Doc.UserDoc().activeSelection = new List([this.doc]);
return false;
}}
OnEmpty={undoBatch(() => this.props.treeView.doc.treeViewOutlineMode && this.props.removeDoc?.(this.doc))}
@@ -552,8 +555,9 @@ export class TreeView extends React.Component<TreeViewProps> {
: <div className={`treeView-container${selected ? "-active" : ""}`} ref={this.createTreeDropTarget} onPointerDown={e => this.props.active(true) && SelectionManager.DeselectAll()}
onKeyDown={e => {
e.stopPropagation();
+ e.preventDefault();
switch (e.key) {
- case "Backspace": return this.doc.text && !(this.doc.text as RichTextField)?.Text && UndoManager.RunInBatch(() => this.props.removeDoc?.(this.doc), "delete");
+ case "Backspace": return !(this.doc.text as RichTextField)?.Text && this.props.removeDoc?.(this.doc);
case "Enter": return UndoManager.RunInBatch(() => this.makeTextCollection(), "bullet");
case "Tab": setTimeout(() => RichTextMenu.Instance.TextView?.EditorView?.focus(), 150);
return UndoManager.RunInBatch(() => e.shiftKey ? this.props.outdentDocument?.() : this.props.indentDocument?.(), "tab");
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 771b6bbbe..41969fd3e 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1162,6 +1162,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
FormattedTextBox.SelectOnLoadChar = "";
} else if (curText?.Text) {
selectAll(this._editorView!.state, this._editorView?.dispatch);
+ this.startUndoTypingBatch();
}
}
@@ -1411,7 +1412,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
public startUndoTypingBatch() {
- this._undoTyping = UndoManager.StartBatch("undoTyping");
+ !this._undoTyping && (this._undoTyping = UndoManager.StartBatch("undoTyping"));
}
public endUndoTypingBatch() {
@@ -1425,6 +1426,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
public static LiveTextUndo: UndoManager.Batch | undefined;
public static HadSelection: boolean = false;
onBlur = (e: any) => {
+ console.log("blur ", document.activeElement?.textContent);
FormattedTextBox.HadSelection = window.getSelection()?.toString() !== "";
this.endUndoTypingBatch();
this.doLinkOnDeselect();
@@ -1473,9 +1475,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
this._editorView!.dispatch(this._editorView!.state.tr.removeStoredMark(schema.marks.user_mark.create({})).addStoredMark(mark));
}
- if (!this._undoTyping) {
- this.startUndoTypingBatch();
- }
+ this.startUndoTypingBatch();
}
ondrop = (eve: React.DragEvent) => {
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index ba7c9c7da..470f9d4be 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -24,6 +24,7 @@ import { LinkManager } from "../client/util/LinkManager";
import JSZip = require("jszip");
import { saveAs } from "file-saver";
import { CollectionDockingView } from "../client/views/collections/CollectionDockingView";
+import { SelectionManager } from "../client/util/SelectionManager";
export namespace Field {
export function toKeyValueString(doc: Doc, key: string): string {
@@ -1295,8 +1296,8 @@ Scripting.addGlobal(function docList(field: any) { return DocListCast(field); })
Scripting.addGlobal(function setInPlace(doc: any, field: any, value: any) { return Doc.SetInPlace(doc, field, value, false); });
Scripting.addGlobal(function sameDocs(doc1: any, doc2: any) { return Doc.AreProtosEqual(doc1, doc2); });
Scripting.addGlobal(function deiconifyView(doc: any) { Doc.deiconifyView(doc); });
-Scripting.addGlobal(function undo() { return UndoManager.Undo(); });
-Scripting.addGlobal(function redo() { return UndoManager.Redo(); });
+Scripting.addGlobal(function undo() { SelectionManager.DeselectAll(); return UndoManager.Undo(); });
+Scripting.addGlobal(function redo() { SelectionManager.DeselectAll(); return UndoManager.Redo(); });
Scripting.addGlobal(function DOC(id: string) { console.log("Can't parse a document id in a script"); return "invalid"; });
Scripting.addGlobal(function assignDoc(doc: Doc, field: string, id: string) { return Doc.assignDocToField(doc, field, id); });
Scripting.addGlobal(function docCast(doc: FieldResult): any { return DocCastAsync(doc); });
@@ -1305,7 +1306,7 @@ Scripting.addGlobal(function activePresentationItem() {
return curPres && DocListCast(curPres[Doc.LayoutFieldKey(curPres)])[NumCast(curPres._itemIndex)];
});
Scripting.addGlobal(function selectedDocs(container: Doc, excludeCollections: boolean, prevValue: any) {
- const docs = DocListCast(Doc.UserDoc().activeSelection).
+ const docs = SelectionManager.SelectedDocuments().map(dv => dv.props.Document).
filter(d => !Doc.AreProtosEqual(d, container) && !d.annotationOn && d.type !== DocumentType.DOCHOLDER && d.type !== DocumentType.KVP &&
(!excludeCollections || d.type !== DocumentType.COL || !Cast(d.data, listSpec(Doc), null)));
return docs.length ? new List(docs) : prevValue;
diff --git a/src/fields/util.ts b/src/fields/util.ts
index 9db79ced1..9e5890aa8 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -10,6 +10,8 @@ import { DocServer } from "../client/DocServer";
import { ComputedField } from "./ScriptField";
import { ScriptCast, StrCast } from "./Types";
import { returnZero } from "../Utils";
+import CursorField from "./CursorField";
+import { List } from "@material-ui/core";
function _readOnlySetter(): never {
@@ -360,10 +362,12 @@ export function updateFunction(target: any, prop: any, value: any, receiver: any
const oldValue = current;
const newValue = ObjectField.MakeCopy(value);
current = newValue;
- UndoManager.AddEvent({
- redo() { receiver[prop] = newValue; },
- undo() { receiver[prop] = oldValue; }
- });
+ if (!(value instanceof CursorField) && !(value?.some((v: any) => v instanceof CursorField))) {
+ UndoManager.AddEvent({
+ redo() { receiver[prop] = newValue; },
+ undo() { receiver[prop] = oldValue; }
+ });
+ }
}
target[Update](diff);
};