aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/documents/Documents.ts10
-rw-r--r--src/client/util/CurrentUserUtils.ts1
-rw-r--r--src/client/util/InteractionUtils.tsx4
-rw-r--r--src/client/util/SelectionManager.ts26
-rw-r--r--src/client/util/SharingManager.tsx6
-rw-r--r--src/client/views/DocumentButtonBar.tsx2
-rw-r--r--src/client/views/DocumentDecorations.tsx32
-rw-r--r--src/client/views/GestureOverlay.tsx4
-rw-r--r--src/client/views/InkingStroke.tsx18
-rw-r--r--src/client/views/MainView.tsx11
-rw-r--r--src/client/views/PropertiesButtons.tsx49
-rw-r--r--src/client/views/collections/CollectionMenu.scss12
-rw-r--r--src/client/views/collections/CollectionMenu.tsx25
-rw-r--r--src/client/views/collections/CollectionSchemaCells.tsx14
-rw-r--r--src/client/views/collections/CollectionSchemaHeaders.tsx226
-rw-r--r--src/client/views/collections/CollectionSchemaView.tsx31
-rw-r--r--src/client/views/collections/CollectionView.tsx1
-rw-r--r--src/client/views/collections/SchemaTable.tsx23
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx8
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx3
-rw-r--r--src/client/views/collections/collectionFreeForm/PropertiesView.tsx6
-rw-r--r--src/client/views/collections/collectionGrid/CollectionGridView.tsx4
-rw-r--r--src/client/views/nodes/DocumentView.tsx8
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx6
-rw-r--r--src/client/views/search/SearchBox.tsx47
-rw-r--r--src/fields/RichTextField.ts2
26 files changed, 320 insertions, 259 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 3316e6b48..f07b718ba 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -20,7 +20,7 @@ import { dropActionType } from "../util/DragManager";
import { DirectoryImportBox } from "../util/Import & Export/DirectoryImportBox";
import { LinkManager } from "../util/LinkManager";
import { Scripting } from "../util/Scripting";
-import { UndoManager } from "../util/UndoManager";
+import { UndoManager, undoBatch } from "../util/UndoManager";
import { DocumentType } from "./DocumentTypes";
import { SearchBox } from "../views/search/SearchBox";
import { CollectionDockingView } from "../views/collections/CollectionDockingView";
@@ -1042,7 +1042,7 @@ export namespace DocUtils {
description: "Add Note ...",
subitems: DocListCast((Doc.UserDoc()["template-notes"] as Doc).data).map((note, i) => ({
description: ":" + StrCast(note.title),
- event: (args: { x: number, y: number }) => {
+ event: undoBatch((args: { x: number, y: number }) => {
const textDoc = Docs.Create.TextDocument("", {
_width: 200, x, y, _autoHeight: note._autoHeight !== false,
title: StrCast(note.title) + "#" + (note.aliasCount = NumCast(note.aliasCount) + 1)
@@ -1050,7 +1050,7 @@ export namespace DocUtils {
textDoc.layoutKey = "layout_" + note.title;
textDoc[textDoc.layoutKey] = note;
docTextAdder(textDoc);
- },
+ }),
icon: "eye"
})) as ContextMenuProps[],
icon: "eye"
@@ -1059,7 +1059,7 @@ export namespace DocUtils {
description: "Add Template Doc ...",
subitems: DocListCast(Cast(Doc.UserDoc().myItemCreators, Doc, null)?.data).map(btnDoc => Cast(btnDoc?.dragFactory, Doc, null)).filter(doc => doc).map((dragDoc, i) => ({
description: ":" + StrCast(dragDoc.title),
- event: (args: { x: number, y: number }) => {
+ event: undoBatch((args: { x: number, y: number }) => {
const newDoc = Doc.ApplyTemplate(dragDoc);
if (newDoc) {
newDoc.author = Doc.CurrentUserEmail;
@@ -1067,7 +1067,7 @@ export namespace DocUtils {
newDoc.y = y;
docAdder(newDoc);
}
- },
+ }),
icon: "eye"
})) as ContextMenuProps[],
icon: "eye"
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 5d747584a..4385b164b 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -810,7 +810,6 @@ export class CurrentUserUtils {
if (doc.sidebar === undefined) {
const sidebarContainer = new Doc();
sidebarContainer._chromeStatus = "disabled";
- sidebarContainer.onClick = ScriptField.MakeScript("freezeSidebar()");
sidebarContainer.system = true;
doc.sidebar = new PrefetchProxy(sidebarContainer);
}
diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx
index ae3b3e064..13c4fac25 100644
--- a/src/client/util/InteractionUtils.tsx
+++ b/src/client/util/InteractionUtils.tsx
@@ -140,7 +140,7 @@ export namespace InteractionUtils {
export function CreatePolyline(points: { X: number, Y: number }[], left: number, top: number,
color: string, width: number, strokeWidth: number, bezier: string, fill: string, arrowStart: string, arrowEnd: string,
- dash: string, scalex: number, scaley: number, shape: string, pevents: string, drawHalo: boolean, nodefs: boolean) {
+ dash: string | undefined, scalex: number, scaley: number, shape: string, pevents: string, drawHalo: boolean, nodefs: boolean) {
let pts: { X: number; Y: number; }[] = [];
if (shape) { //if any of the shape are true
pts = makePolygon(shape, points);
@@ -182,7 +182,7 @@ export namespace InteractionUtils {
const strpts = pts.reduce((acc: string, pt: { X: number, Y: number }) => acc +
`${(pt.X - left - width / 2) * scalex + width / 2},
${(pt.Y - top - width / 2) * scaley + width / 2} `, "");
- const dashArray = String(Number(width) * Number(dash));
+ const dashArray = dash && Number(dash) ? String(Number(width) * Number(dash)) : undefined;
const defGuid = Utils.GenerateGuid();
const arrowDim = Math.max(0.5, 8 / Math.log(Math.max(2, strokeWidth)));
diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index 113278593..35b82cc30 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -1,10 +1,9 @@
import { observable, action, runInAction, ObservableMap } from "mobx";
-import { Doc } from "../../fields/Doc";
+import { Doc, Opt } from "../../fields/Doc";
import { DocumentView } from "../views/nodes/DocumentView";
import { computedFn } from "mobx-utils";
import { List } from "../../fields/List";
-import { Scripting } from "./Scripting";
-import { DocumentManager } from "./DocumentManager";
+import { CollectionSchemaView } from "../views/collections/CollectionSchemaView";
export namespace SelectionManager {
@@ -12,8 +11,15 @@ export namespace SelectionManager {
@observable IsDragging: boolean = false;
SelectedDocuments: ObservableMap<DocumentView, boolean> = new ObservableMap();
+ @observable SelectedSchemaDocument: Doc | undefined;
+ @observable SelectedSchemaCollection: CollectionSchemaView | undefined;
@action
+ SelectSchemaDoc(collectionView: Opt<CollectionSchemaView>, doc: Opt<Doc>) {
+ manager.SelectedSchemaDocument = doc;
+ manager.SelectedSchemaCollection = collectionView;
+ }
+ @action
SelectDoc(docView: DocumentView, ctrlPressed: boolean): void {
// if doc is not in SelectedDocuments, add it
@@ -26,6 +32,8 @@ export namespace SelectionManager {
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));
+ manager.SelectedSchemaDocument = undefined;
+ manager.SelectedSchemaCollection = undefined;
manager.SelectedDocuments.clear();
manager.SelectedDocuments.set(docView, true);
}
@@ -42,7 +50,8 @@ export namespace SelectionManager {
}
@action
DeselectAll(): void {
-
+ manager.SelectedSchemaCollection = undefined;
+ manager.SelectedSchemaDocument = undefined;
Array.from(manager.SelectedDocuments.keys()).map(dv => dv.props.whenActiveChanged(false));
manager.SelectedDocuments.clear();
Doc.UserDoc().activeSelection = new List<Doc>([]);
@@ -57,6 +66,9 @@ export namespace SelectionManager {
export function SelectDoc(docView: DocumentView, ctrlPressed: boolean): void {
manager.SelectDoc(docView, ctrlPressed);
}
+ export function SelectSchemaDoc(colSchema: Opt<CollectionSchemaView>, document: Opt<Doc>): void {
+ manager.SelectSchemaDoc(colSchema, document);
+ }
// computed functions, such as used in IsSelected generate errors if they're called outside of a
// reaction context. Specifying the context with 'outsideReaction' allows an efficiency feature
@@ -84,4 +96,10 @@ export namespace SelectionManager {
export function SelectedDocuments(): Array<DocumentView> {
return Array.from(manager.SelectedDocuments.keys());
}
+ export function SelectedSchemaDoc(): Doc | undefined {
+ return manager.SelectedSchemaDocument;
+ }
+ export function SelectedSchemaCollection(): CollectionSchemaView | undefined {
+ return manager.SelectedSchemaCollection;
+ }
} \ No newline at end of file
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index 5a863c813..b9918e900 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -82,15 +82,15 @@ export default class SharingManager extends React.Component<{}> {
// return this.sharingDoc ? this.sharingDoc[PublicKey] !== SharingPermissions.None : false;
// }
- public open = (target: DocumentView) => {
+ public open = (target?: DocumentView, target_doc?: Doc) => {
runInAction(() => this.users = []);
// SelectionManager.DeselectAll();
this.populateUsers();
runInAction(() => {
this.targetDocView = target;
- this.targetDoc = target.props.Document;
+ this.targetDoc = target_doc || target?.props.Document;
DictationOverlay.Instance.hasActiveModal = true;
- this.isOpen = true;
+ this.isOpen = this.targetDoc !== undefined;
this.permissions = SharingPermissions.Edit;
});
this.targetDoc!.author === Doc.CurrentUserEmail && !this.targetDoc![`ACL-${Doc.CurrentUserEmail.replace(".", "_")}`] && distributeAcls(`ACL-${Doc.CurrentUserEmail.replace(".", "_")}`, SharingPermissions.Admin, this.targetDoc!);
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index 8748b1880..7effc4aa0 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -199,7 +199,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
return !targetDoc ? (null) : <Tooltip title={<><div className="dash-tooltip">{Doc.isDocPinned(targetDoc) ? "Unpin from presentation" : "Pin to presentation"}</div></>}>
<div className="documentButtonBar-linker"
style={{ backgroundColor: isPinned ? "white" : "", color: isPinned ? "black" : "white", border: isPinned ? "black 1px solid " : "" }}
- onClick={e => DockedFrameRenderer.PinDoc(targetDoc, isPinned)}>
+ onClick={e => this.props.views().map(view => view && DockedFrameRenderer.PinDoc(view.props.Document, isPinned))}>
<FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="map-pin"
/>
</div></Tooltip>;
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index e546ca858..0cc492ee9 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -1,34 +1,30 @@
import { IconProp, library } from '@fortawesome/fontawesome-svg-core';
-import { faCaretUp, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote, faTextHeight, faArrowAltCircleDown, faArrowAltCircleUp, faCheckCircle, faCloudUploadAlt, faLink, faShare, faStopCircle, faSyncAlt, faTag, faTimes, faAngleLeft, faAngleRight, faAngleDoubleLeft, faAngleDoubleRight, faPause, faExternalLinkAlt } from '@fortawesome/free-solid-svg-icons';
+import { faAngleDoubleLeft, faAngleDoubleRight, faAngleLeft, faAngleRight, faArrowAltCircleDown, faArrowAltCircleUp, faCaretUp, faCheckCircle, faCloudUploadAlt, faExternalLinkAlt, faFilePdf, faFilm, faImage, faLink, faObjectGroup, faPause, faShare, faStickyNote, faStopCircle, faSyncAlt, faTag, faTextHeight, faTimes } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { action, computed, observable, reaction, runInAction, get } from "mobx";
+import { Tooltip } from '@material-ui/core';
+import { action, computed, observable, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
-import { Doc, DataSym, Field, WidthSym, HeightSym, AclEdit, AclAdmin } from "../../fields/Doc";
+import { AclAdmin, AclEdit, DataSym, Doc, Field } from "../../fields/Doc";
import { Document } from '../../fields/documentSchemas';
+import { HtmlField } from '../../fields/HtmlField';
+import { InkField } from "../../fields/InkField";
import { ScriptField } from '../../fields/ScriptField';
-import { Cast, StrCast, NumCast } from "../../fields/Types";
-import { Utils, setupMoveUpEvents, emptyFunction, returnFalse, simulateMouseClick } from "../../Utils";
+import { Cast, NumCast } from "../../fields/Types";
+import { GetEffectiveAcl } from '../../fields/util';
+import { emptyFunction, returnFalse, setupMoveUpEvents, simulateMouseClick } from "../../Utils";
import { DocUtils } from "../documents/Documents";
import { DocumentType } from '../documents/DocumentTypes';
import { DragManager } from "../util/DragManager";
import { SelectionManager } from "../util/SelectionManager";
+import { SnappingManager } from '../util/SnappingManager';
import { undoBatch, UndoManager } from "../util/UndoManager";
+import { CollectionDockingView } from './collections/CollectionDockingView';
+import FormatShapePane from './collections/collectionFreeForm/FormatShapePane';
import { DocumentButtonBar } from './DocumentButtonBar';
import './DocumentDecorations.scss';
import { DocumentView } from "./nodes/DocumentView";
import React = require("react");
import e = require('express');
-import { CollectionDockingView } from './collections/CollectionDockingView';
-import { SnappingManager } from '../util/SnappingManager';
-import { HtmlField } from '../../fields/HtmlField';
-import { InkField } from "../../fields/InkField";
-import { Tooltip } from '@material-ui/core';
-import { GetEffectiveAcl } from '../../fields/util';
-import { DocumentIcon } from './nodes/DocumentIcon';
-import { render } from 'react-dom';
-import { createLessThan } from 'typescript';
-import FormatShapePane from './collections/collectionFreeForm/FormatShapePane';
-import { PropertiesView } from './collections/collectionFreeForm/PropertiesView';
library.add(faCaretUp);
library.add(faObjectGroup);
@@ -364,7 +360,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
this._offY = this._resizeHdlId.toLowerCase().includes("top") ? bounds.bottom - e.clientY : bounds.top - e.clientY;
this.Interacting = true;
this._resizeUndo = UndoManager.StartBatch("DocDecs resize");
- SelectionManager.SelectedDocuments()[0].props.setupDragLines?.();
+ SelectionManager.SelectedDocuments()[0].props.setupDragLines?.(e.ctrlKey || e.shiftKey);
}
this._snapX = e.pageX;
this._snapY = e.pageY;
@@ -603,7 +599,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
const darkScheme = Cast(Doc.UserDoc().activeWorkspace, Doc, null)?.darkScheme ? "dimgray" : undefined;
const bounds = this.Bounds;
const seldoc = SelectionManager.SelectedDocuments().length ? SelectionManager.SelectedDocuments()[0] : undefined;
- if (SnappingManager.GetIsDragging() || bounds.r - bounds.x < 2 || bounds.x === Number.MAX_VALUE || !seldoc || this._hidden || isNaN(bounds.r) || isNaN(bounds.b) || isNaN(bounds.x) || isNaN(bounds.y)) {
+ if (SnappingManager.GetIsDragging() || bounds.r - bounds.x < 1 || bounds.x === Number.MAX_VALUE || !seldoc || this._hidden || isNaN(bounds.r) || isNaN(bounds.b) || isNaN(bounds.x) || isNaN(bounds.y)) {
return (null);
}
const canDelete = SelectionManager.SelectedDocuments().some(docView => {
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 76e786257..c25ebbf11 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -613,10 +613,10 @@ export default class GestureOverlay extends Touchable {
}
}
// if we're not drawing in a toolglass try to recognize as gesture
- else {
+ else { // need to decide when to turn gestures back on
const result = points.length > 2 && GestureUtils.GestureRecognizer.Recognize(new Array(points));
let actionPerformed = false;
- if (result && result.Score > 0.7) {
+ if (Doc.UserDoc().recognizeGestures && result && result.Score > 0.7) {
switch (result.Name) {
case GestureUtils.Gestures.Box: actionPerformed = this.dispatchGesture(GestureUtils.Gestures.Box); break;
case GestureUtils.Gestures.StartBracket: actionPerformed = this.dispatchGesture(GestureUtils.Gestures.StartBracket); break;
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index 41311ed86..3376fcd97 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -103,11 +103,15 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
const strokeWidth = Number(this.layoutDoc.strokeWidth);
const xs = data.map(p => p.X);
const ys = data.map(p => p.Y);
- const left = Math.min(...xs) - strokeWidth / 2;
- const top = Math.min(...ys) - strokeWidth / 2;
- const right = Math.max(...xs) + strokeWidth / 2;
- const bottom = Math.max(...ys) + strokeWidth / 2;
- const width = Math.max(right - left);
+ const lineTop = Math.min(...ys);
+ const lineBot = Math.max(...ys);
+ const lineLft = Math.min(...xs);
+ const lineRgt = Math.max(...xs);
+ const left = lineLft - strokeWidth / 2;
+ const top = lineTop - strokeWidth / 2;
+ const right = lineRgt + strokeWidth / 2;
+ const bottom = lineBot + strokeWidth / 2;
+ const width = Math.max(1, right - left);
const height = Math.max(1, bottom - top);
const scaleX = width === strokeWidth ? 1 : (this.props.PanelWidth() - strokeWidth) / (width - strokeWidth);
const scaleY = height === strokeWidth ? 1 : (this.props.PanelHeight() - strokeWidth) / (height - strokeWidth);
@@ -116,12 +120,12 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
const points = InteractionUtils.CreatePolyline(data, left, top, strokeColor, strokeWidth, strokeWidth,
StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "transparent"),
StrCast(this.layoutDoc.strokeStartMarker), StrCast(this.layoutDoc.strokeEndMarker),
- StrCast(this.layoutDoc.strokeDash), scaleX, scaleY, "", "none", this.props.isSelected() && strokeWidth <= 5, false);
+ StrCast(this.layoutDoc.strokeDash), scaleX, scaleY, "", "none", this.props.isSelected() && strokeWidth <= 5 && lineBot - lineTop > 1 && lineRgt - lineLft > 1, false);
const hpoints = InteractionUtils.CreatePolyline(data, left, top,
this.props.isSelected() && strokeWidth > 5 ? strokeColor : "transparent", strokeWidth, (strokeWidth + 15),
StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "transparent"),
- "none", "none", "0", scaleX, scaleY, "", this.props.active() ? "visiblepainted" : "none", false, true);
+ "none", "none", undefined, scaleX, scaleY, "", this.props.active() ? "visiblepainted" : "none", false, true);
//points for adding
const apoints = InteractionUtils.CreatePoints(data, left, top, strokeColor, strokeWidth, strokeWidth,
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index ec43e6e1d..f3d8fc181 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -70,7 +70,6 @@ import RichTextMenu from './nodes/formattedText/RichTextMenu';
export class MainView extends React.Component {
public static Instance: MainView;
private _buttonBarHeight = 36;
- private _flyoutSizeOnDown = 0;
private _urlState: HistoryUtil.DocUrl;
private _docBtnRef = React.createRef<HTMLDivElement>();
private _mainViewRef = React.createRef<HTMLDivElement>();
@@ -423,7 +422,7 @@ export class MainView extends React.Component {
onFlyoutPointerDown = (e: React.PointerEvent) => {
if (this._flyoutTranslate) {
setupMoveUpEvents(this, e, action((e: PointerEvent) => {
- this.flyoutWidth = Math.max(e.clientX, 0);
+ this.flyoutWidth = Math.max(e.clientX - 58, 0);
if (this.flyoutWidth < 5) {
this.panelContent = "none";
this._lastButton && (this._lastButton.color = "white");
@@ -545,7 +544,12 @@ export class MainView extends React.Component {
switch (this.panelContent = title) {
case "Tools": panelDoc = Doc.UserDoc()["sidebar-tools"] as Doc ?? undefined; break;
case "Workspace": panelDoc = Doc.UserDoc()["sidebar-workspaces"] as Doc ?? undefined; break;
- case "Catalog": panelDoc = Doc.UserDoc()["sidebar-catalog"] as Doc ?? undefined; break;
+ case "Catalog": SearchBox.Instance.searchFullDB = "My Stuff";
+ SearchBox.Instance.newsearchstring = "";
+ SearchBox.Instance.enter(undefined);
+ break;
+
+ // panelDoc = Doc.UserDoc()["sidebar-catalog"] as Doc ?? undefined; break;
case "Archive": panelDoc = Doc.UserDoc()["sidebar-recentlyClosed"] as Doc ?? undefined; break;
case "Settings": SettingsManager.Instance.open(); break;
case "Import": panelDoc = Doc.UserDoc()["sidebar-import"] as Doc ?? undefined; break;
@@ -978,7 +982,6 @@ export class MainView extends React.Component {
}
}
Scripting.addGlobal(function selectMainMenu(doc: Doc, title: string) { MainView.Instance.selectMenu(doc); });
-Scripting.addGlobal(function freezeSidebar() { MainView.expandFlyout(); });
Scripting.addGlobal(function toggleComicMode() { Doc.UserDoc().fontFamily = "Comic Sans MS"; Doc.UserDoc().renderStyle = Doc.UserDoc().renderStyle === "comic" ? undefined : "comic"; });
Scripting.addGlobal(function copyWorkspace() {
const copiedWorkspace = Doc.MakeCopy(Cast(Doc.UserDoc().activeWorkspace, Doc, null), true);
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index dfedc9ccc..e220bd7fc 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -77,12 +77,12 @@ export class PropertiesButtons extends React.Component<{}, {}> {
public static hasPulledHack = false;
+ @computed get selectedDoc() { return SelectionManager.SelectedSchemaDoc() || this.selectedDocumentView?.rootDoc; }
@computed get selectedDocumentView() {
if (SelectionManager.SelectedDocuments().length) {
return SelectionManager.SelectedDocuments()[0];
- } else { return undefined; }
+ } else return undefined;
}
- @computed get selectedDoc() { return this.selectedDocumentView?.rootDoc; }
@computed get dataDoc() { return this.selectedDocumentView?.dataDoc; }
@computed get onClick() { return this.selectedDoc?.onClickBehavior ? this.selectedDoc?.onClickBehavior : "nothing"; }
@@ -297,9 +297,9 @@ export class PropertiesButtons extends React.Component<{}, {}> {
}
@undoBatch
onAliasButtonMoved = () => {
- if (this._dragRef.current) {
+ if (this._dragRef.current && this.selectedDoc) {
const dragDocView = this.selectedDocumentView!;
- const dragData = new DragManager.DocumentDragData([dragDocView.props.Document]);
+ const dragData = new DragManager.DocumentDragData([this.selectedDoc]);
const [left, top] = dragDocView.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
dragData.dropAction = "alias";
DragManager.StartDocumentDrag([dragDocView.ContentDiv!], dragData, left, top, {
@@ -314,7 +314,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
@computed
get templateButton() {
- const docView = this.selectedDocumentView;
+ const docView = this.selectedDocumentView?.props.Document === this.selectedDoc ? this.selectedDocumentView : undefined;
const templates: Map<Template, boolean> = new Map();
const views = [this.selectedDocumentView];
Array.from(Object.values(Templates.TemplateList)).map(template =>
@@ -366,7 +366,8 @@ export class PropertiesButtons extends React.Component<{}, {}> {
@action @undoBatch
onLock = () => {
- this.selectedDocumentView?.toggleLockPosition();
+ const docView = this.selectedDocumentView?.props.Document === this.selectedDoc ? this.selectedDocumentView : undefined;
+ docView?.toggleLockPosition();
}
@computed
@@ -401,8 +402,8 @@ export class PropertiesButtons extends React.Component<{}, {}> {
<div>
<div className={"propertiesButtons-linkButton-empty"}
onPointerDown={async () => {
- if (this.selectedDocumentView?.props.Document) {
- Doc.Zip(this.selectedDocumentView?.props.Document);
+ if (this.selectedDoc) {
+ Doc.Zip(this.selectedDoc);
}
}}>
{<FontAwesomeIcon className="propertiesButtons-icon"
@@ -432,23 +433,22 @@ export class PropertiesButtons extends React.Component<{}, {}> {
@undoBatch
@action
deleteDocument = () => {
- const selected = SelectionManager.SelectedDocuments().slice();
- selected.map(dv => dv.props.removeDocument?.(dv.props.Document));
- this.selectedDoc && (this.selectedDoc.deleted = true);
- this.selectedDocumentView?.props.ContainingCollectionView?.removeDocument(this.selectedDocumentView?.props.Document);
+ const removeDoc = this.selectedDocumentView?.props.Document === this.selectedDoc ? this.selectedDocumentView?.props.removeDocument : SelectionManager.SelectedSchemaCollection()?.props.removeDocument;
+ this.selectedDoc && removeDoc?.(this.selectedDoc);
SelectionManager.DeselectAll();
}
@computed
get sharingButton() {
const targetDoc = this.selectedDoc;
+ const docView = this.selectedDocumentView?.props.Document === this.selectedDoc ? this.selectedDocumentView : undefined;
return !targetDoc ? (null) : <Tooltip
title={<><div className="dash-tooltip">{"Share Document"}</div></>} placement="top">
<div>
<div className={"propertiesButtons-linkButton-empty"}
onPointerDown={() => {
if (this.selectedDocumentView) {
- SharingManager.Instance.open(this.selectedDocumentView);
+ SharingManager.Instance.open(docView, this.selectedDoc);
}
}}>
{<FontAwesomeIcon className="propertiesButtons-icon"
@@ -485,20 +485,21 @@ export class PropertiesButtons extends React.Component<{}, {}> {
handleOptionChange = (e: any) => {
const value = e.target.value;
this.selectedDoc && (this.selectedDoc.onClickBehavior = e.target.value);
+ const docView = this.selectedDocumentView?.props.Document === this.selectedDoc ? this.selectedDocumentView : undefined;
if (value === "nothing") {
- this.selectedDocumentView?.noOnClick();
+ docView?.noOnClick();
} else if (value === "enterPortal") {
- this.selectedDocumentView?.noOnClick();
- this.selectedDocumentView?.makeIntoPortal();
+ docView?.noOnClick();
+ docView?.makeIntoPortal();
} else if (value === "toggleDetail") {
- this.selectedDocumentView?.noOnClick();
- this.selectedDocumentView?.toggleDetail();
+ docView?.noOnClick();
+ docView?.toggleDetail();
} else if (value === "linkInPlace") {
- this.selectedDocumentView?.noOnClick();
- this.selectedDocumentView?.toggleFollowLink("inPlace", true, false);
+ docView?.noOnClick();
+ docView?.toggleFollowLink("inPlace", true, false);
} else if (value === "linkOnRight") {
- this.selectedDocumentView?.noOnClick();
- this.selectedDocumentView?.toggleFollowLink("onRight", false, false);
+ docView?.noOnClick();
+ docView?.toggleFollowLink("onRight", false, false);
}
}
@@ -565,8 +566,8 @@ export class PropertiesButtons extends React.Component<{}, {}> {
<div>
<div className={"propertiesButtons-linkButton-empty"}
onPointerDown={() => {
- if (this.selectedDocumentView) {
- GooglePhotos.Export.CollectionToAlbum({ collection: this.selectedDocumentView.Document }).then(console.log);
+ if (this.selectedDoc) {
+ GooglePhotos.Export.CollectionToAlbum({ collection: this.selectedDoc }).then(console.log);
}
}}>
{<FontAwesomeIcon className="documentdecorations-icon"
diff --git a/src/client/views/collections/CollectionMenu.scss b/src/client/views/collections/CollectionMenu.scss
index 9d23c8647..d0bfd0a41 100644
--- a/src/client/views/collections/CollectionMenu.scss
+++ b/src/client/views/collections/CollectionMenu.scss
@@ -229,14 +229,18 @@
.flexLabel {
margin-bottom: 0;
}
- }
- .collectionGridViewChrome-entryBox {
- width: 50%;
+ .collectionGridViewChrome-entryBox {
+ width: 50%;
+ color: black;
+ }
+
+ .collectionGridViewChrome-columnButton {
+ color: black;
+ }
}
}
-
.collectionStackingViewChrome-sort,
.collectionTreeViewChrome-sort {
display: flex;
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 59debd35a..276ed0652 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -1091,16 +1091,10 @@ export class CollectionGridViewChrome extends React.Component<CollectionMenuProp
get numCols() { return NumCast(this.document.gridNumCols, 10); }
/**
- * Sets the value of `numCols` on the grid's Document to the value entered.
- */
- @undoBatch
- onNumColsEnter = (e: React.KeyboardEvent<HTMLInputElement>) => {
- if (e.key === "Enter" || e.key === "Tab") {
- if (e.currentTarget.valueAsNumber > 0) {
- this.document.gridNumCols = e.currentTarget.valueAsNumber;
- }
-
- }
+ * Sets the value of `numCols` on the grid's Document to the value entered.
+ */
+ onNumColsChange = (e: React.ChangeEvent<HTMLInputElement>) => {
+ if (e.currentTarget.valueAsNumber > 0) undoBatch(() => this.document.gridNumCols = e.currentTarget.valueAsNumber)();
}
/**
@@ -1138,9 +1132,10 @@ export class CollectionGridViewChrome extends React.Component<CollectionMenuProp
*/
onDecrementButtonClick = () => {
this.clicked = true;
- if (!this.decrementLimitReached) {
+ if (this.numCols > 1 && !this.decrementLimitReached) {
this.entered && (this.document.gridNumCols as number)++;
undoBatch(() => this.document.gridNumCols = this.numCols - 1)();
+ if (this.numCols === 1) this.decrementLimitReached = true;
}
this.entered = false;
}
@@ -1163,7 +1158,7 @@ export class CollectionGridViewChrome extends React.Component<CollectionMenuProp
decrementValue = () => {
this.entered = true;
if (!this.clicked) {
- if (this.numCols !== 1) {
+ if (this.numCols > 1) {
this.document.gridNumCols = this.numCols - 1;
}
else {
@@ -1196,9 +1191,9 @@ export class CollectionGridViewChrome extends React.Component<CollectionMenuProp
<span className="grid-icon">
<FontAwesomeIcon icon="columns" size="1x" />
</span>
- <input className="collectionGridViewChrome-entryBox" type="number" placeholder={this.numCols.toString()} onKeyDown={this.onNumColsEnter} onClick={(e: React.MouseEvent<HTMLInputElement, MouseEvent>) => { e.stopPropagation(); e.preventDefault(); e.currentTarget.focus(); }} />
- <input className="columnButton" onClick={this.onIncrementButtonClick} onMouseEnter={this.incrementValue} onMouseLeave={this.decrementValue} type="button" value="↑" />
- <input className="columnButton" style={{ marginRight: 5 }} onClick={this.onDecrementButtonClick} onMouseEnter={this.decrementValue} onMouseLeave={this.incrementValue} type="button" value="↓" />
+ <input className="collectionGridViewChrome-entryBox" type="number" value={this.numCols} onChange={this.onNumColsChange} onClick={(e: React.MouseEvent<HTMLInputElement, MouseEvent>) => { e.stopPropagation(); e.preventDefault(); e.currentTarget.focus(); }} />
+ <input className="collectionGridViewChrome-columnButton" onClick={this.onIncrementButtonClick} onMouseEnter={this.incrementValue} onMouseLeave={this.decrementValue} type="button" value="↑" />
+ <input className="collectionGridViewChrome-columnButton" style={{ marginRight: 5 }} onClick={this.onDecrementButtonClick} onMouseEnter={this.decrementValue} onMouseLeave={this.incrementValue} type="button" value="↓" />
</span>
{/* <span className="grid-control">
<span className="grid-icon">
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index fa4d8c51b..f95de5201 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -257,7 +257,7 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
};
let contents: any = "incorrect type";
- if (type === undefined) contents = StrCast(field) === "" ? "--" : <FieldView {...props} fieldKey={fieldKey} />;
+ if (type === undefined) contents = field === undefined ? undefined : Field.toString(field as Field);//StrCast(field) === "" ? "--" : <FieldView {...props} fieldKey={fieldKey} />;
if (type === "number") contents = typeof field === "number" ? NumCast(field) : "--" + typeof field + "--";
if (type === "string") {
fieldKey === "text" ?
@@ -320,6 +320,7 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
search = true;
}
+ const placeholder = type === "number" ? "0" : contents === "" ? "--" : "undefined";
return (
<div className="collectionSchemaView-cellContainer" style={{ cursor: fieldIsDoc ? "grab" : "auto" }}
ref={dragRef} onPointerDown={this.onPointerDown} onPointerEnter={onPointerEnter} onPointerLeave={onPointerLeave}>
@@ -329,16 +330,16 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
{!search ?
<EditableView
positions={positions.length > 0 ? positions : undefined}
- search={StrCast(this.props.Document._searchString) ? StrCast(this.props.Document._searchString) : undefined}
+ search={Cast(this.props.Document._searchString, "string", null)}
editing={this._isEditing}
isEditingCallback={this.isEditingCallback}
display={"inline"}
- contents={contents ? contents : type === "number" ? "0" : "undefined"}
+ contents={contents}
highlight={positions.length > 0 ? true : undefined}
//contents={StrCast(contents)}
height={"auto"}
maxHeight={Number(MAX_ROW_HEIGHT)}
- placeholder={"undefined"}
+ placeholder={placeholder}
bing={() => {
const cfield = ComputedField.WithoutComputed(() => FieldValue(props.Document[props.fieldKey]));
if (cfield !== undefined) {
@@ -380,8 +381,9 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
SetValue={action((value: string) => {
let retVal = false;
- if (value.startsWith(":=")) {
- retVal = this.props.setComputed(value.substring(2), props.Document, this.props.rowProps.column.id!, this.props.row, this.props.col);
+ if (value.startsWith(":=") || value.startsWith("=:=")) {
+ const script = value.substring(value.startsWith("=:=") ? 3 : 2);
+ retVal = this.props.setComputed(script, value.startsWith(":=") ? Doc.GetProto(props.Document) : props.Document, this.props.rowProps.column.id!, this.props.row, this.props.col);
} else {
const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } });
if (script.compiled) {
diff --git a/src/client/views/collections/CollectionSchemaHeaders.tsx b/src/client/views/collections/CollectionSchemaHeaders.tsx
index be25bf9de..73f319e9b 100644
--- a/src/client/views/collections/CollectionSchemaHeaders.tsx
+++ b/src/client/views/collections/CollectionSchemaHeaders.tsx
@@ -13,57 +13,11 @@ import { SearchBox } from "../search/SearchBox";
import { ColumnType } from "./CollectionSchemaView";
import "./CollectionSchemaView.scss";
import { CollectionView } from "./CollectionView";
-import * as fa from '@fortawesome/free-solid-svg-icons';
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
-export interface HeaderProps {
- keyValue: SchemaHeaderField;
- possibleKeys: string[];
- existingKeys: string[];
- keyType: ColumnType;
- typeConst: boolean;
- onSelect: (oldKey: string, newKey: string, addnew: boolean) => void;
- setIsEditing: (isEditing: boolean) => void;
- deleteColumn: (column: string) => void;
- setColumnType: (column: SchemaHeaderField, type: ColumnType) => void;
- setColumnSort: (column: SchemaHeaderField, desc: boolean | undefined) => void;
- setColumnColor: (column: SchemaHeaderField, color: string) => void;
-
-}
-
-export class CollectionSchemaHeader extends React.Component<HeaderProps> {
- render() {
- const icon: IconProp = this.props.keyType === ColumnType.Number ? "hashtag" : this.props.keyType === ColumnType.String ? "font" :
- this.props.keyType === ColumnType.Boolean ? "check-square" : this.props.keyType === ColumnType.Doc ? "sort-amount-down" :
- this.props.keyType === ColumnType.Image ? "image" : this.props.keyType === ColumnType.List ? "list-ul" : this.props.keyType === ColumnType.Date ? "calendar" :
- "align-justify";
- return (
- <div className="collectionSchemaView-header" style={{ background: this.props.keyValue.color }}>
- <CollectionSchemaColumnMenu
- columnField={this.props.keyValue}
- // keyValue={this.props.keyValue.heading}
- possibleKeys={this.props.possibleKeys}
- existingKeys={this.props.existingKeys}
- // keyType={this.props.keyType}
- typeConst={this.props.typeConst}
- menuButtonContent={<div><FontAwesomeIcon icon={icon} size="sm" />{this.props.keyValue.heading}</div>}
- addNew={false}
- onSelect={this.props.onSelect}
- setIsEditing={this.props.setIsEditing}
- deleteColumn={this.props.deleteColumn}
- onlyShowOptions={false}
- setColumnType={this.props.setColumnType}
- setColumnSort={this.props.setColumnSort}
- setColumnColor={this.props.setColumnColor}
- />
- </div>
- );
- }
-}
-
export interface AddColumnHeaderProps {
createColumn: () => void;
@@ -79,7 +33,6 @@ export class CollectionSchemaAddColumnHeader extends React.Component<AddColumnHe
}
-
export interface ColumnMenuProps {
columnField: SchemaHeaderField;
// keyValue: string;
@@ -103,37 +56,29 @@ export class CollectionSchemaColumnMenu extends React.Component<ColumnMenuProps>
@observable private _isOpen: boolean = false;
@observable private _node: HTMLDivElement | null = null;
- componentDidMount() {
- document.addEventListener("pointerdown", this.detectClick);
- }
+ componentDidMount() { document.addEventListener("pointerdown", this.detectClick); }
- componentWillUnmount() {
- document.removeEventListener("pointerdown", this.detectClick);
- }
+ componentWillUnmount() { document.removeEventListener("pointerdown", this.detectClick); }
- detectClick = (e: PointerEvent): void => {
- if (this._node && this._node.contains(e.target as Node)) {
- } else {
- this._isOpen = false;
- this.props.setIsEditing(false);
- }
+ @action
+ detectClick = (e: PointerEvent) => {
+ !this._node?.contains(e.target as Node) && this.props.setIsEditing(this._isOpen = false);
}
@action
toggleIsOpen = (): void => {
- this._isOpen = !this._isOpen;
- this.props.setIsEditing(this._isOpen);
+ this.props.setIsEditing(this._isOpen = !this._isOpen);
}
- changeColumnType = (type: ColumnType): void => {
+ changeColumnType = (type: ColumnType) => {
this.props.setColumnType(this.props.columnField, type);
}
- changeColumnSort = (desc: boolean | undefined): void => {
+ changeColumnSort = (desc: boolean | undefined) => {
this.props.setColumnSort(this.props.columnField, desc);
}
- changeColumnColor = (color: string): void => {
+ changeColumnColor = (color: string) => {
this.props.setColumnColor(this.props.columnField, color);
}
@@ -145,7 +90,7 @@ export class CollectionSchemaColumnMenu extends React.Component<ColumnMenuProps>
}
renderTypes = () => {
- if (this.props.typeConst) return <></>;
+ if (this.props.typeConst) return (null);
const type = this.props.columnField.type;
return (
@@ -291,7 +236,7 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> {
@observable private _key: string = this.props.keyValue;
@observable private _searchTerm: string = this.props.keyValue;
@observable private _isOpen: boolean = false;
- @observable private _canClose: boolean = true;
+ @observable private _node: HTMLDivElement | null = null;
@observable private _inputRef: React.RefObject<HTMLInputElement> = React.createRef();
@action setSearchTerm = (value: string): void => { this._searchTerm = value; };
@@ -306,6 +251,35 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> {
this.props.setIsEditing(false);
}
+ @action
+ setNode = (node: HTMLDivElement): void => {
+ if (node) {
+ this._node = node;
+ }
+ }
+
+ componentDidMount() {
+ document.addEventListener("pointerdown", this.detectClick);
+ }
+
+ @action
+ detectClick = (e: PointerEvent): void => {
+ if (this._node && this._node.contains(e.target as Node)) {
+ } else {
+ this._isOpen = false;
+ this.props.setIsEditing(false);
+ }
+ }
+
+ componentWillMount() {
+ document.removeEventListener("pointerdown", this.detectClick);
+ const filters = Cast(this.props.Document._docFilters, listSpec("string"));
+ if (filters?.includes(this._key)) {
+ runInAction(() => { this.closeResultsVisibility = "contents" });
+ }
+ }
+
+ private tempfilter: string = "";
@undoBatch
onKeyDown = (e: React.KeyboardEvent): void => {
if (e.key === "Enter") {
@@ -313,23 +287,29 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> {
const colpos = this._searchTerm.indexOf(":");
const temp = this._searchTerm.slice(colpos + 1, this._searchTerm.length);
if (temp === "") {
- Doc.setDocFilter(this.props.Document, this._key, temp, undefined);
+ console.log("here we are first");
+ Doc.setDocFilter(this.props.Document, this._key, this.tempfilter, undefined);
+ this.updateFilter();
}
else {
- Doc.setDocFilter(this.props.Document, this._key, temp, "match");
+ console.log("here we are first");
+ Doc.setDocFilter(this.props.Document, this._key, this.tempfilter, undefined);
+ this.tempfilter = temp;
+ Doc.setDocFilter(this.props.Document, this._key, temp, "check");
this.props.col.setColor("green");
+ this.closeResultsVisibility = "contents";
}
}
else {
+ Doc.setDocFilter(this.props.Document, this._key, this.tempfilter, undefined);
+ this.updateFilter();
let keyOptions = this._searchTerm === "" ? this.props.possibleKeys : this.props.possibleKeys.filter(key => key.toUpperCase().indexOf(this._searchTerm.toUpperCase()) > -1);
- const blockedkeys = ["_scrollTop", "customTitle", "limitHeight", "proto", "x", "y", "_width", "_height", "_autoHeight", "_fontSize", "_fontFamily", "context", "zIndex", "_timeStampOnEnter", "lines", "highlighting", "searchMatch", "creationDate", "isPrototype", "text-annotations", "aliases", "text-lastModified", "text-noTemplate", "layoutKey", "baseProto", "_xMargin", "_yMargin", "layout", "layout_keyValue", "links"];
+ const blockedkeys = ["system", "ACL-Public", "_scrollTop", "customTitle", "limitHeight", "proto", "x", "y", "_width", "_height", "_autoHeight", "_fontSize", "_fontFamily", "context", "zIndex", "_timeStampOnEnter", "lines", "highlighting", "searchMatch", "creationDate", "isPrototype", "text-annotations", "aliases", "text-lastModified", "text-noTemplate", "layoutKey", "baseProto", "_xMargin", "_yMargin", "layout", "layout_keyValue", "links"];
keyOptions = keyOptions.filter(n => !blockedkeys.includes(n));
if (keyOptions.length) {
this.onSelect(keyOptions[0]);
- console.log("case1");
} else if (this._searchTerm !== "" && this.props.canAddNew) {
this.setSearchTerm(this._searchTerm || this._key);
- console.log("case2");
this.onSelect(this._searchTerm);
}
}
@@ -347,23 +327,6 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> {
}
@action
- onBlur = (e: React.FocusEvent): void => {
- if (this._canClose) {
- this._isOpen = false;
- this.props.setIsEditing(false);
- }
- }
-
- @action
- onPointerEnter = (e: React.PointerEvent): void => {
- this._canClose = false;
- }
-
- @action
- onPointerOut = (e: React.PointerEvent): void => {
- this._canClose = true;
- }
- @action
renderOptions = (): JSX.Element[] | JSX.Element => {
if (!this._isOpen) {
this.defaultMenuHeight = 0;
@@ -383,7 +346,13 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> {
border: "1px solid lightgray",
width: this.props.width, maxWidth: this.props.width, overflowX: "hidden", background: "white",
}}
- onPointerDown={e => e.stopPropagation()} onClick={() => { this.onSelect(key); this.setSearchTerm(""); }}>{key}</div>;
+ onPointerDown={e => {
+ e.stopPropagation();
+ }}
+ onClick={() => {
+ this.onSelect(key);
+ this.setSearchTerm("");
+ }}>{key}</div>;
});
// if search term does not already exist as a group type, give option to create new group type
@@ -422,7 +391,6 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> {
this.defaultMenuHeight = 0;
return <></>;
}
-
const keyOptions: string[] = [];
const colpos = this._searchTerm.indexOf(":");
const temp = this._searchTerm.slice(colpos + 1, this._searchTerm.length);
@@ -432,22 +400,21 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> {
const docs = this.docSafe;
docs.forEach((doc) => {
const key = StrCast(doc[this._key]);
- if (keyOptions.includes(key) === false && key.includes(temp)) {
+ if (keyOptions.includes(key) === false && key.includes(temp) && key !== "") {
keyOptions.push(key);
}
});
const filters = Cast(this.props.Document._docFilters, listSpec("string"));
+ if (filters === undefined || filters.length === 0 || filters.includes(this._key) === false) {
+ this.props.col.setColor("rgb(241, 239, 235)");
+ this.closeResultsVisibility = "none";
+ }
for (let i = 0; i < (filters?.length ?? 0) - 1; i += 3) {
if (filters![i] === this.props.col.heading && keyOptions.includes(filters![i + 1]) === false) {
keyOptions.push(filters![i + 1]);
}
}
-
- if (filters === undefined || filters.length === 0 || filters.includes(this._key) === false) {
- this.props.col.setColor("rgb(241, 239, 235)");
- }
-
const options = keyOptions.map(key => {
//Doc.setDocFilter(this.props.Document!, this._key, key, undefined);
let bool = false;
@@ -461,12 +428,17 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> {
width: this.props.width, maxWidth: this.props.width, overflowX: "hidden", background: "white", backgroundColor: "white",
}}
>
- <input type="checkbox" onChange={(e) => {
- e.target.checked === true ? Doc.setDocFilter(this.props.Document, this._key, key, "check") : Doc.setDocFilter(this.props.Document, this._key, key, undefined);
- e.target.checked === true ? this.props.col.setColor("green") : "";
- e.target.checked === true && SearchBox.Instance.filter === true ? Doc.setDocFilter(docs[0], this._key, key, "check") : Doc.setDocFilter(docs[0], this._key, key, undefined);
- }}
- checked={bool} ></input>
+ <input type="checkbox"
+ onPointerDown={e => e.stopPropagation()}
+ onClick={e => e.stopPropagation()}
+ onChange={(e) => {
+ e.target.checked === true ? Doc.setDocFilter(this.props.Document, this._key, key, "check") : Doc.setDocFilter(this.props.Document, this._key, key, undefined);
+ e.target.checked === true ? this.closeResultsVisibility = "contents" : console.log("");
+ e.target.checked === true ? this.props.col.setColor("green") : this.updateFilter();
+ e.target.checked === true && SearchBox.Instance.filter === true ? Doc.setDocFilter(docs[0], this._key, key, "check") : Doc.setDocFilter(docs[0], this._key, key, undefined);
+ }}
+ checked={bool}
+ />
<span style={{ paddingLeft: 4 }}>
{key}
</span>
@@ -492,6 +464,15 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> {
@observable defaultMenuHeight = 0;
+ updateFilter() {
+ const filters = Cast(this.props.Document._docFilters, listSpec("string"));
+ if (filters === undefined || filters.length === 0 || filters.includes(this._key) === false) {
+ console.log("PLEASE");
+ this.props.col.setColor("rgb(241, 239, 235)");
+ this.closeResultsVisibility = "none";
+ }
+ }
+
get ignoreFields() { return ["_docFilters", "_docRangeFilters"]; }
@@ -501,29 +482,56 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> {
return script ? () => script : undefined;
}
filterBackground = () => "rgba(105, 105, 105, 0.432)";
-
@observable filterOpen: boolean | undefined = undefined;
+ closeResultsVisibility: string = "none";
+
+ removeFilters = (e: React.PointerEvent): void => {
+ const keyOptions: string[] = [];
+ if (this.docSafe.length === 0) {
+ this.docSafe = DocListCast(this.props.dataDoc![this.props.fieldKey]);
+ }
+ const docs = this.docSafe;
+ docs.forEach((doc) => {
+ const key = StrCast(doc[this._key]);
+ if (keyOptions.includes(key) === false) {
+ keyOptions.push(key);
+ }
+ });
+
+ keyOptions.forEach(key => {
+ Doc.setDocFilter(this.props.Document, this._key, key, undefined);
+ }
+ );
+ Doc.setDocFilter(this.props.Document, this._key, this.tempfilter, undefined);
+ this.props.col.setColor("rgb(241, 239, 235)");
+ this.closeResultsVisibility = "none";
+ }
render() {
return (
- <div style={{ display: "flex" }}>
+ <div style={{ display: "flex" }} ref={this.setNode}>
<FontAwesomeIcon onClick={e => { this.props.openHeader(this.props.col, e.clientX, e.clientY); e.stopPropagation(); }} icon={this.props.icon} size="lg" style={{ display: "inline", paddingBottom: "1px", paddingTop: "4px", cursor: "hand" }} />
{/* <FontAwesomeIcon icon={fa.faSearchMinus} size="lg" style={{ display: "inline", paddingBottom: "1px", paddingTop: "4px", cursor: "hand" }} onClick={e => {
runInAction(() => { this._isOpen === undefined ? this._isOpen = true : this._isOpen = !this._isOpen })
}} /> */}
- <div className="keys-dropdown" style={{ zIndex: 10, width: this.props.width, maxWidth: this.props.width }}>
+ <div className="keys-dropdown" style={{ zIndex: 1, width: this.props.width, maxWidth: this.props.width }}>
<input className="keys-search" style={{ width: "100%" }}
ref={this._inputRef} type="text" value={this._searchTerm} placeholder="Column key" onKeyDown={this.onKeyDown}
- onChange={e => this.onChange(e.target.value)}
+ onChange={e => {
+ this.onChange(e.target.value);
+ }}
onClick={(e) => {
//this._inputRef.current!.select();
e.stopPropagation();
- }} onFocus={this.onFocus} onBlur={this.onBlur}></input>
+ }} onFocus={this.onFocus} ></input>
+ <div style={{ display: this.closeResultsVisibility }}>
+ <FontAwesomeIcon onPointerDown={this.removeFilters} icon={"times-circle"} size="lg"
+ style={{ cursor: "hand", color: "grey", padding: 2, left: -20, top: -1, height: 15, position: "relative" }} />
+ </div>
{!this._isOpen ? (null) : <div className="keys-options-wrapper" style={{
width: this.props.width, maxWidth: this.props.width, height: "auto",
- }}
- onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerOut}>
+ }}>
{this._searchTerm.includes(":") ? this.renderFilterOptions() : this.renderOptions()}
</div>}
</div >
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index a72b349ec..ed8496544 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -7,7 +7,7 @@ import { observer } from "mobx-react";
import Measure from "react-measure";
import { Resize } from "react-table";
import "react-table/react-table.css";
-import { Doc } from "../../../fields/Doc";
+import { Doc, Opt } from "../../../fields/Doc";
import { List } from "../../../fields/List";
import { listSpec } from "../../../fields/Schema";
import { PastelSchemaPalette, SchemaHeaderField } from "../../../fields/SchemaHeaderField";
@@ -20,10 +20,12 @@ import { undoBatch } from "../../util/UndoManager";
import { COLLECTION_BORDER_WIDTH } from '../../views/globalCssVariables.scss';
import '../DocumentDecorations.scss';
import { ContentFittingDocumentView } from "../nodes/ContentFittingDocumentView";
-import { KeysDropdown } from "./CollectionSchemaHeaders";
import "./CollectionSchemaView.scss";
import { CollectionSubView } from "./CollectionSubView";
import { SchemaTable } from "./SchemaTable";
+import { SelectionManager } from "../../util/SelectionManager";
+import { ContextMenu } from "../ContextMenu";
+import { ContextMenuProps } from "../ContextMenuItem";
library.add(faCog, faPlus, faSortUp, faSortDown);
library.add(faTable);
@@ -388,7 +390,10 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
@action setFocused = (doc: Doc) => this._focusedTable = doc;
- @action setPreviewDoc = (doc: Doc) => this.previewDoc = doc;
+ @action setPreviewDoc = (doc: Opt<Doc>) => {
+ SelectionManager.SelectSchemaDoc(this, doc);
+ this.previewDoc = doc;
+ }
//toggles preview side-panel of schema
@action
@@ -515,9 +520,24 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
</div>
</div>;
}
+ onSpecificMenu = (e: React.MouseEvent) => {
+ if ((e.target as any)?.className?.includes?.("collectionSchemaView-cell") || (e.target instanceof HTMLSpanElement)) {
+ const cm = ContextMenu.Instance;
+ const options = cm.findByDescription("Options...");
+ const optionItems: ContextMenuProps[] = options && "subitems" in options ? options.subitems : [];
+ optionItems.push({ description: "remove", event: () => this.previewDoc && this.props.removeDocument(this.previewDoc), icon: "trash" });
+ !options && cm.addItem({ description: "Options...", subitems: optionItems, icon: "compass" });
+ cm.displayMenu(e.clientX, e.clientY);
+ (e.nativeEvent as any).SchemaHandled = true; // not sure why this is needed, but if you right-click quickly on a cell, the Document/Collection contextMenu handlers still fire without this.
+ e.stopPropagation();
+ }
+ }
@action
onTablePointerDown = (e: React.PointerEvent): void => {
+ if (!(e.target as any)?.className?.includes?.("collectionSchemaView-cell") && !(e.target instanceof HTMLSpanElement)) {
+ this.setPreviewDoc(undefined);
+ }
this.setFocused(this.props.Document);
if (e.button === 0 && !e.altKey && !e.ctrlKey && !e.metaKey && this.props.isSelected(true)) {
e.stopPropagation();
@@ -594,13 +614,14 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
</div>;
return <div className={name}
style={{
- overflow: this.props.overflow === true ? "scroll" : undefined,
+ overflow: this.props.overflow === true ? "scroll" : undefined, backgroundColor: "white",
pointerEvents: !this.props.active() && !SnappingManager.GetIsDragging() ? "none" : undefined,
width: name === "collectionSchemaView-searchContainer" ? "auto" : this.props.PanelWidth() || "100%", height: this.props.PanelHeight() || "100%", position: "relative",
}} >
<div className="collectionSchemaView-tableContainer"
- style={{ backgroundColor: "white", width: `calc(100% - ${this.previewWidth()}px)` }}
+ style={{ width: `calc(100% - ${this.previewWidth()}px)` }}
onKeyPress={this.onKeyPress}
+ onContextMenu={this.onSpecificMenu}
onPointerDown={this.onPointerDown}
onWheel={e => this.props.active(true) && e.stopPropagation()}
onDrop={e => this.onExternalDrop(e, {})}
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 2064b0be4..0aaceb7f4 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -289,7 +289,6 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
subItems.push({ description: "Tree", event: () => func(CollectionViewType.Tree), icon: "tree" });
subItems.push({ description: "Stacking", event: () => func(CollectionViewType.Stacking), icon: "ellipsis-v" });
subItems.push({ description: "Stacking (AutoHeight)", event: () => func(CollectionViewType.Stacking)._autoHeight = true, icon: "ellipsis-v" });
- subItems.push({ description: "Staff", event: () => func(CollectionViewType.Staff), icon: "music" });
subItems.push({ description: "Multicolumn", event: () => func(CollectionViewType.Multicolumn), icon: "columns" });
subItems.push({ description: "Multirow", event: () => func(CollectionViewType.Multirow), icon: "columns" });
subItems.push({ description: "Masonry", event: () => func(CollectionViewType.Masonry), icon: "columns" });
diff --git a/src/client/views/collections/SchemaTable.tsx b/src/client/views/collections/SchemaTable.tsx
index 763e5a410..904eaf99f 100644
--- a/src/client/views/collections/SchemaTable.tsx
+++ b/src/client/views/collections/SchemaTable.tsx
@@ -42,7 +42,7 @@ enum ColumnType {
// this map should be used for keys that should have a const type of value
const columnTypes: Map<string, ColumnType> = new Map([
- ["title", ColumnType.String], ["text", ColumnType.String],
+ ["title", ColumnType.String],
["x", ColumnType.Number], ["y", ColumnType.Number], ["_width", ColumnType.Number], ["_height", ColumnType.Number],
["_nativeWidth", ColumnType.Number], ["_nativeHeight", ColumnType.Number], ["isPrototype", ColumnType.Boolean],
["page", ColumnType.Number], ["curPage", ColumnType.Number], ["currentTimecode", ColumnType.Number], ["zIndex", ColumnType.Number]
@@ -70,7 +70,7 @@ export interface SchemaTableProps {
isSelected: (outsideReaction?: boolean) => boolean;
isFocused: (document: Doc, outsideReaction: boolean) => boolean;
setFocused: (document: Doc) => void;
- setPreviewDoc: (document: Doc) => void;
+ setPreviewDoc: (document: Opt<Doc>) => void;
columns: SchemaHeaderField[];
documentKeys: any[];
headerIsEditing: boolean;
@@ -322,8 +322,8 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
const newSchemaHeaders = oldSchemaHeaders.map(i => typeof i === "string" ? new SchemaHeaderField(i, "#f1efeb") : i);
this.props.Document._schemaHeaders = new List<SchemaHeaderField>(newSchemaHeaders);
} else if (this.props.Document._schemaHeaders === undefined) {
- this.props.Document._schemaHeaders = new List<SchemaHeaderField>([new SchemaHeaderField("title", "#f1efeb"), new SchemaHeaderField("author", "#f1efeb"), new SchemaHeaderField("*lastModified", "#f1efeb"),
- new SchemaHeaderField("text", "#f1efeb"), new SchemaHeaderField("type", "#f1efeb"), new SchemaHeaderField("context", "#f1efeb", ColumnType.Doc)]);
+ this.props.Document._schemaHeaders = new List<SchemaHeaderField>([new SchemaHeaderField("title", "#f1efeb"), new SchemaHeaderField("author", "#f1efeb"), new SchemaHeaderField("*lastModified", "#f1efeb", ColumnType.Date),
+ new SchemaHeaderField("text", "#f1efeb", ColumnType.String), new SchemaHeaderField("type", "#f1efeb"), new SchemaHeaderField("context", "#f1efeb", ColumnType.Doc)]);
}
}
@@ -385,7 +385,9 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
const pdoc = FieldValue(this.childDocs[this._focusedCell.row]);
pdoc && this.props.setPreviewDoc(pdoc);
- } else if ((this._cellIsEditing || this.props.headerIsEditing) && (e.keyCode === 37 || e.keyCode === 39)) {
+ e.stopPropagation();
+ } else if (e.keyCode === 27) {
+ this.props.setPreviewDoc(undefined);
e.stopPropagation(); // stopPropagation for left/right arrows
}
}
@@ -410,9 +412,10 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
}
@undoBatch
- createRow = () => {
+ createRow = action(() => {
this.props.addDocument(Docs.Create.TextDocument("", { title: "", _width: 100, _height: 30 }));
- }
+ this._focusedCell = { row: this.childDocs.length, col: this._focusedCell.col };
+ })
@undoBatch
@action
@@ -564,10 +567,8 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
setComputed = (script: string, doc: Doc, field: string, row: number, col: number): boolean => {
script =
`const $ = (row:number, col?:number) => {
- if(col === undefined) {
- return (doc as any)[key][row + ${row}];
- }
- return (doc as any)[key][row + ${row}][(doc as any)._schemaHeaders[col + ${col}].heading];
+ const rval = (doc as any)[key][row + ${row}];
+ return col === undefined ? rval : rval[(doc as any)._schemaHeaders[col + ${col}].heading];
}
return ${script}`;
const compiled = CompileScript(script, { params: { this: Doc.name }, capturedVariables: { doc: this.props.Document, key: this.props.fieldKey }, typecheck: false, transformer: this.createTransformer(row, col) });
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 46e30f616..5d6d7924e 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -850,7 +850,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
} else {
const docs = this.childLayoutPairs.map(pair => pair.layout);
docs.slice().sort((doc1, doc2) => NumCast(doc1.zIndex) - NumCast(doc2.zIndex));
- let zlast = docs.length ? NumCast(docs[docs.length - 1].zIndex) : 1;
+ let zlast = docs.length ? Math.max(docs.length, NumCast(docs[docs.length - 1].zIndex)) : 1;
if (zlast - docs.length > 100) {
for (let i = 0; i < docs.length; i++) doc.zIndex = i + 1;
zlast = docs.length + 1;
@@ -1315,7 +1315,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
}
@action
- setupDragLines = () => {
+ setupDragLines = (snapToDraggedDoc: boolean = false) => {
const activeDocs = this.getActiveDocuments();
if (activeDocs.length > 50) {
DragManager.SetSnapLines([], []);
@@ -1337,7 +1337,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
const horizLines: number[] = [];
const vertLines: number[] = [];
- snappableDocs.filter(doc => !DragManager.docsBeingDragged.includes(Cast(doc.rootDocument, Doc, null) || doc)).forEach(doc => {
+ snappableDocs.filter(doc => snapToDraggedDoc || !DragManager.docsBeingDragged.includes(Cast(doc.rootDocument, Doc, null) || doc)).forEach(doc => {
const { left, top, width, height } = docDims(doc);
const topLeftInScreen = this.getTransform().inverse().transformPoint(left, top);
const docSize = this.getTransform().inverse().transformDirection(width, height);
@@ -1349,7 +1349,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
}
onPointerOver = (e: React.PointerEvent) => {
if (SnappingManager.GetIsDragging()) {
- this.setupDragLines();
+ this.setupDragLines(e.ctrlKey || e.shiftKey);
}
e.stopPropagation();
}
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 4e8c26e5d..e5af1b0cc 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -12,7 +12,7 @@ import { CognitiveServices } from "../../../cognitive_services/CognitiveServices
import { Docs, DocumentOptions, DocUtils } from "../../../documents/Documents";
import { SelectionManager } from "../../../util/SelectionManager";
import { Transform } from "../../../util/Transform";
-import { undoBatch } from "../../../util/UndoManager";
+import { undoBatch, UndoManager } from "../../../util/UndoManager";
import { ContextMenu } from "../../ContextMenu";
import { FormattedTextBox } from "../../nodes/formattedText/FormattedTextBox";
import { PreviewCursor } from "../../PreviewCursor";
@@ -138,6 +138,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
tbox.layoutKey = "layout_" + StrCast(template.title);
Doc.GetProto(tbox)[StrCast(tbox.layoutKey)] = template;
}
+ FormattedTextBox.LiveTextUndo = UndoManager.StartBatch("live text batch");
this.props.addLiveTextDocument(tbox);
e.stopPropagation();
}
diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
index ed451beab..fb138ecc0 100644
--- a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
+++ b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
@@ -49,6 +49,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
@computed get MAX_EMBED_HEIGHT() { return 200; }
+ @computed get selectedDoc() { return SelectionManager.SelectedSchemaDoc() || this.selectedDocumentView?.rootDoc; }
@computed get selectedDocumentView() {
if (SelectionManager.SelectedDocuments().length) {
return SelectionManager.SelectedDocuments()[0];
@@ -60,7 +61,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
if (this.selectedDoc?.type === DocumentType.PRES) return true;
return false;
}
- @computed get selectedDoc() { return this.selectedDocumentView?.rootDoc; }
@computed get dataDoc() { return this.selectedDocumentView?.dataDoc; }
@observable layoutFields: boolean = false;
@@ -345,8 +345,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
@computed get expansionIcon() {
return <Tooltip title={<div className="dash-tooltip">{"Show more permissions"}</div>}>
<div className="expansion-button" onPointerDown={() => {
- if (this.selectedDocumentView) {
- SharingManager.Instance.open(this.selectedDocumentView);
+ if (this.selectedDocumentView || this.selectedDoc) {
+ SharingManager.Instance.open(this.selectedDocumentView?.props.Document === this.selectedDocumentView ? this.selectedDocumentView : undefined, this.selectedDoc);
}
}}>
<FontAwesomeIcon className="expansion-button-icon" icon="ellipsis-h" color="black" size="sm" />
diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
index e6ac7021a..70ebca5e7 100644
--- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx
+++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
@@ -94,8 +94,8 @@ export class CollectionGridView extends CollectionSubView(GridSchema) {
*/
unflexedPosition(index: number): Omit<Layout, "i"> {
return {
- x: (index % Math.floor(this.numCols / this.defaultW)) * this.defaultW,
- y: Math.floor(index / Math.floor(this.numCols / this.defaultH)) * this.defaultH,
+ x: (index % (Math.floor(this.numCols / this.defaultW) || 1)) * this.defaultW,
+ y: Math.floor(index / (Math.floor(this.numCols / this.defaultH) || 1)) * this.defaultH,
w: this.defaultW,
h: this.defaultH,
static: true
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index f0b6e0ccb..7cf6b0f39 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -69,7 +69,7 @@ export interface DocumentViewProps {
removeDocument?: (doc: Doc | Doc[]) => boolean;
moveDocument?: (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean;
ScreenToLocalTransform: () => Transform;
- setupDragLines?: () => void;
+ setupDragLines?: (snapToDraggedDoc: boolean) => void;
renderDepth: number;
ContentScaling: () => number;
PanelWidth: () => number;
@@ -291,7 +291,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(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.props.Document.type !== DocumentType.FONTICON || !this.onDoubleClickHandler)) {// && !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({
@@ -694,7 +694,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
}
@action
- onContextMenu = async (e: React.MouseEvent | Touch): Promise<void> => {
+ onContextMenu = (e: React.MouseEvent | Touch) => {
// the touch onContextMenu is button 0, the pointer onContextMenu is button 2
if (!(e instanceof Touch)) {
if (e.button === 0 && !e.ctrlKey) {
@@ -713,7 +713,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
}
const cm = ContextMenu.Instance;
- if (!cm) return;
+ if (!cm || ((e as any)?.nativeEvent as any)?.SchemaHandled) return;
const customScripts = Cast(this.props.Document.contextMenuScripts, listSpec(ScriptField), []);
Cast(this.props.Document.contextMenuLabels, listSpec("string"), []).forEach((label, i) =>
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index d4c9f74d5..0f2f90c1d 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -509,7 +509,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
if (node.isTextblock) {
let index = 0, foundAt;
const ep = this.getNodeEndpoints(pm.state.doc, node);
- while (ep && (foundAt = node.textContent.slice(index).search(RegExp(find, "i"))) > -1) {
+ const regexp = find.replace("*", "");
+ if (regexp) while (ep && (foundAt = node.textContent.slice(index).search(regexp, "i")) > -1) {
const sel = new TextSelection(pm.state.doc.resolve(ep.from + index + foundAt + 1), pm.state.doc.resolve(ep.from + index + foundAt + find.length + 1));
ret.push(sel);
index = index + foundAt + find.length;
@@ -1433,6 +1434,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
return wasUndoing;
}
+ public static LiveTextUndo: UndoManager.Batch | undefined;
public static HadSelection: boolean = false;
onBlur = (e: any) => {
FormattedTextBox.HadSelection = window.getSelection()?.toString() !== "";
@@ -1440,6 +1442,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
this.endUndoTypingBatch();
this.doLinkOnDeselect();
+ FormattedTextBox.LiveTextUndo?.end();
+ FormattedTextBox.LiveTextUndo = undefined;
// move the richtextmenu offscreen
//if (!RichTextMenu.Instance.Pinned) RichTextMenu.Instance.delayHide();
}
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 847bda137..10a45b34a 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -189,21 +189,14 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
}
}
- enter = (e: React.KeyboardEvent) => {
- if (e.key === "Enter") {
+ enter = action((e: React.KeyboardEvent | undefined) => {
+ if (!e || e.key === "Enter") {
this.layoutDoc._searchString = this.newsearchstring;
- runInAction(() => this._pageStart = 0);
-
- if (StrCast(this.layoutDoc._searchString) !== "" || !this.searchFullDB) {
- runInAction(() => this.open = true);
- }
- else {
- runInAction(() => this.open = false);
-
- }
+ this._pageStart = 0;
+ this.open = StrCast(this.layoutDoc._searchString) !== "" || this.searchFullDB !== "DB";
this.submitSearch();
}
- }
+ });
@observable open: boolean = false;
@@ -468,6 +461,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
}
}
this._numTotalResults = found.length;
+ this.realTotalResults = found.length;
}
else {
this.noresults = "No collection selected :(";
@@ -576,7 +570,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
}, 60000);
}
- if (query !== "") {
+ if (query !== "" || this.searchFullDB === "My Stuff") {
this._endIndex = 12;
this._maxSearchIndex = 0;
this._numTotalResults = -1;
@@ -591,7 +585,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
}
}
- @observable searchFullDB = true;
+ @observable searchFullDB = "DB";
@observable _timeout: any = undefined;
@@ -608,10 +602,11 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
private get filterQuery() {
const types = ["preselement", "docholder", "search", "searchitem", "fonticonbox"]; // this.filterTypes;
const baseExpr = "NOT system_b:true";
+ const authorExpr = this.searchFullDB === "My Stuff" ? ` author_t:${Doc.CurrentUserEmail}` : undefined;
const includeDeleted = this.getDataStatus() ? "" : " NOT deleted_b:true";
const typeExpr = this._onlyAliases ? "NOT {!join from=id to=proto_i}type_t:*" : `(type_t:* OR {!join from=id to=proto_i}type_t:*) ${types.map(type => `NOT ({!join from=id to=proto_i}type_t:${type}) AND NOT type_t:${type}`).join(" AND ")}`;
// fq: type_t:collection OR {!join from=id to=proto_i}type_t:collection q:text_t:hello
- const query = [baseExpr, includeDeleted, typeExpr].join(" AND ").replace(/AND $/, "");
+ const query = [baseExpr, authorExpr, includeDeleted, typeExpr].filter(q => q).join(" AND ").replace(/AND $/, "");
return query;
}
@@ -625,7 +620,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
case ColumnType.Boolean: return "_b";
case ColumnType.Number: return "_n";
}
- }
+ };
const headers = Cast(this.props.Document._schemaHeaders, listSpec(SchemaHeaderField), []);
return headers.reduce((p: Opt<string>, header: SchemaHeaderField) => p || (header.desc !== undefined && suffixMap(header.type) ? (header.heading + suffixMap(header.type) + (header.desc ? " desc" : " asc")) : undefined), undefined);
}
@@ -724,6 +719,9 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
@action.bound
openSearch(e: React.SyntheticEvent) {
+ this._results.forEach(result => {
+ Doc.BrushDoc(result[0]);
+ });
e.stopPropagation();
this._openNoResults = false;
this._resultsOpen = true;
@@ -734,6 +732,10 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
@action.bound
closeSearch = () => {
+ this._results.forEach(result => {
+ Doc.UnBrushDoc(result[0]);
+ result[0].searchMatch = undefined;
+ });
//this.closeResults();
this._searchbarOpen = false;
}
@@ -888,7 +890,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
<div style={{ pointerEvents: "all" }} className="searchBox-container">
<div style={{ position: "absolute", left: 15, height: 32, alignItems: "center", display: "flex" }}>{Doc.CurrentUserEmail}</div>
<div className="searchBox-bar">
- <div style={{ position: "relative", display: "flex", width: 400 }}>
+ <div style={{ position: "relative", display: "flex", width: 450 }}>
<input value={this.newsearchstring} autoComplete="off" onChange={this.onChange} type="text" placeholder="Search..." id="search-input" ref={this.inputRef}
className="searchBox-barChild searchBox-input" onPointerDown={this.openSearch} onKeyPress={this.enter} onFocus={this.openSearch}
style={{ padding: 1, paddingLeft: 20, paddingRight: 60, color: "black", height: 20, width: 250 }} />
@@ -973,7 +975,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
<label style={{ fontSize: 12, marginTop: 6 }} >
<input type="radio" style={{ marginLeft: -16, marginTop: -1 }} checked={!this.searchFullDB} onChange={() => {
runInAction(() => {
- this.searchFullDB = !this.searchFullDB;
+ this.searchFullDB = "";
this.dataDoc[this.fieldKey] = new List<Doc>([]);
if (this.currentSelectedCollection !== undefined) {
let newarray: Doc[] = [];
@@ -1005,9 +1007,9 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
</div>
<div className="radio" style={{ margin: 0 }}>
<label style={{ fontSize: 12, marginTop: 6 }} >
- <input style={{ marginLeft: -16, marginTop: -1 }} type="radio" checked={this.searchFullDB} onChange={() => {
+ <input style={{ marginLeft: -16, marginTop: -1 }} type="radio" checked={this.searchFullDB?.length ? true : false} onChange={() => {
runInAction(() => {
- this.searchFullDB = !this.searchFullDB;
+ this.searchFullDB = "DB";
this.dataDoc[this.fieldKey] = new List<Doc>([]);
this.filter = false;
if (this.currentSelectedCollection !== undefined) {
@@ -1036,7 +1038,10 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
});
}} />
DB
- </label>
+ <span onClick={action(() => this.searchFullDB = this.searchFullDB === "My Stuff" ? "DB" : "My Stuff")}>
+ {this.searchFullDB === "My Stuff" ? "(me)" : "(full)"}
+ </span>
+ </label>
</div>
</div>
</form>
diff --git a/src/fields/RichTextField.ts b/src/fields/RichTextField.ts
index 2ca5ac082..ae5f301d0 100644
--- a/src/fields/RichTextField.ts
+++ b/src/fields/RichTextField.ts
@@ -28,7 +28,7 @@ export class RichTextField extends ObjectField {
}
[ToScriptString]() {
- return `new RichTextField("${this.Data}", "${this.Text}")`;
+ return `new RichTextField("${this.Data.replace(/"/g, "\\\"")}", "${this.Text}")`;
}
[ToString]() {
return this.Text;