aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Utils.ts2
-rw-r--r--src/client/documents/Documents.ts4
-rw-r--r--src/client/util/CurrentUserUtils.ts46
-rw-r--r--src/client/util/DictationManager.ts4
-rw-r--r--src/client/util/DragManager.ts2
-rw-r--r--src/client/util/DropConverter.ts6
-rw-r--r--src/client/util/InteractionUtils.tsx4
-rw-r--r--src/client/util/SelectionManager.ts6
-rw-r--r--src/client/util/UndoManager.ts22
-rw-r--r--src/client/views/ContextMenu.tsx2
-rw-r--r--src/client/views/DocumentDecorations.scss18
-rw-r--r--src/client/views/DocumentDecorations.tsx29
-rw-r--r--src/client/views/GestureOverlay.tsx3
-rw-r--r--src/client/views/GlobalKeyHandler.ts8
-rw-r--r--src/client/views/MainView.scss1
-rw-r--r--src/client/views/MainView.tsx18
-rw-r--r--src/client/views/OverlayView.tsx3
-rw-r--r--src/client/views/Palette.tsx3
-rw-r--r--src/client/views/RecommendationsBox.tsx5
-rw-r--r--src/client/views/TemplateMenu.tsx3
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx4
-rw-r--r--src/client/views/collections/CollectionLinearView.tsx1
-rw-r--r--src/client/views/collections/CollectionMasonryViewFieldRow.tsx12
-rw-r--r--src/client/views/collections/CollectionSchemaCells.tsx3
-rw-r--r--src/client/views/collections/CollectionSchemaView.tsx1
-rw-r--r--src/client/views/collections/CollectionStackingView.scss8
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx1
-rw-r--r--src/client/views/collections/CollectionStackingViewFieldColumn.tsx10
-rw-r--r--src/client/views/collections/CollectionSubView.tsx9
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx10
-rw-r--r--src/client/views/collections/CollectionView.tsx30
-rw-r--r--src/client/views/collections/CollectionViewChromes.scss2
-rw-r--r--src/client/views/collections/CollectionViewChromes.tsx10
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx20
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx14
-rw-r--r--src/client/views/collections/collectionGrid/CollectionGridView.tsx2
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx1
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx1
-rw-r--r--src/client/views/nodes/ComparisonBox.tsx10
-rw-r--r--src/client/views/nodes/DocHolderBox.tsx2
-rw-r--r--src/client/views/nodes/DocumentContentsView.tsx2
-rw-r--r--src/client/views/nodes/DocumentView.tsx19
-rw-r--r--src/client/views/nodes/FieldView.tsx1
-rw-r--r--src/client/views/nodes/ImageBox.tsx18
-rw-r--r--src/client/views/nodes/KeyValueBox.tsx51
-rw-r--r--src/client/views/nodes/KeyValuePair.tsx3
-rw-r--r--src/client/views/nodes/LabelBox.tsx2
-rw-r--r--src/client/views/nodes/LinkAnchorBox.tsx12
-rw-r--r--src/client/views/nodes/PDFBox.tsx14
-rw-r--r--src/client/views/nodes/VideoBox.tsx1
-rw-r--r--src/client/views/nodes/WebBox.tsx1
-rw-r--r--src/client/views/nodes/formattedText/DashDocView.tsx3
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.scss108
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx113
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx5
-rw-r--r--src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts10
-rw-r--r--src/client/views/nodes/formattedText/RichTextMenu.tsx36
-rw-r--r--src/client/views/nodes/formattedText/RichTextRules.ts2
-rw-r--r--src/client/views/nodes/formattedText/RichTextSchema.tsx1
-rw-r--r--src/client/views/nodes/formattedText/SummaryView.tsx2
-rw-r--r--src/client/views/nodes/formattedText/marks_rts.ts70
-rw-r--r--src/client/views/nodes/formattedText/nodes_rts.ts85
-rw-r--r--src/client/views/pdf/PDFViewer.tsx1
-rw-r--r--src/client/views/presentationview/PresElementBox.tsx1
-rw-r--r--src/client/views/search/SearchItem.tsx3
-rw-r--r--src/fields/Doc.ts2
-rw-r--r--src/fields/RichTextUtils.ts2
-rw-r--r--src/fields/util.ts10
-rw-r--r--src/mobile/MobileInterface.tsx23
69 files changed, 565 insertions, 376 deletions
diff --git a/src/Utils.ts b/src/Utils.ts
index e527634fd..dba802f98 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -395,6 +395,8 @@ export function returnZero() { return 0; }
export function returnEmptyString() { return ""; }
+export function returnEmptyFilter() { return [] as string[]; }
+
export let emptyPath = [];
export function emptyFunction() { }
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 56ed6febb..dac3a1aaa 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -161,6 +161,7 @@ export interface DocumentOptions {
targetContainer?: Doc; // document whose proto will be set to 'panel' as the result of a onClick click script
searchFileTypes?: List<string>; // file types allowed in a search query
strokeWidth?: number;
+ stayInCollection?: boolean;// whether the document should remain in its collection when someone tries to drag and drop it elsewhere
treeViewPreventOpen?: boolean; // ignores the treeViewOpen Doc flag which allows a treeViewItem's expand/collapse state to be independent of other views of the same document in the tree view
treeViewHideTitle?: boolean; // whether to hide the title of a tree view
treeViewHideHeaderFields?: boolean; // whether to hide the drop down options for tree view items.
@@ -489,7 +490,7 @@ export namespace Docs {
Scripting.addGlobal(Buxton);
- const delegateKeys = ["x", "y", "layoutKey", "dropAction", "childDropAction", "isLinkButton", "isBackground", "removeDropProperties", "treeViewOpen"];
+ const delegateKeys = ["x", "y", "layoutKey", "dropAction", "lockedPosiiton", "childDropAction", "isLinkButton", "isBackground", "removeDropProperties", "treeViewOpen"];
/**
* This function receives the relevant document prototype and uses
@@ -658,6 +659,7 @@ export namespace Docs {
I._backgroundColor = "transparent";
I._width = options._width;
I._height = options._height;
+ I.author = Doc.CurrentUserEmail;
I.data = new InkField(points);
return I;
// return I;
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 5edb2225f..69f8404bb 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -21,6 +21,7 @@ import { MainView } from "../views/MainView";
import { DocumentType } from "../documents/DocumentTypes";
import { SchemaHeaderField } from "../../fields/SchemaHeaderField";
import { DimUnit } from "../views/collections/collectionMulticolumn/CollectionMulticolumnView";
+import { LabelBox } from "../views/nodes/LabelBox";
export class CurrentUserUtils {
private static curr_id: string;
@@ -323,9 +324,17 @@ export class CurrentUserUtils {
iconView.isTemplateDoc = makeTemplate(iconView);
doc["template-icon-view"] = new PrefetchProxy(iconView);
}
+ if (doc["template-icon-view-pdf"] === undefined) {
+ const iconPdfView = Docs.Create.LabelDocument({
+ title: "icon_" + DocumentType.PDF, textTransform: "unset", letterSpacing: "unset", layout: LabelBox.LayoutString("title"), _backgroundColor: "dimGray",
+ _width: 150, _height: 70, _xPadding: 10, _yPadding: 10, isTemplateDoc: true, onDoubleClick: ScriptField.MakeScript("deiconifyView(self)")
+ });
+ iconPdfView.isTemplateDoc = makeTemplate(iconPdfView, true, "icon_" + DocumentType.PDF);
+ doc["template-icon-view-pdf"] = new PrefetchProxy(iconPdfView);
+ }
if (doc["template-icon-view-rtf"] === undefined) {
const iconRtfView = Docs.Create.LabelDocument({
- title: "icon_" + DocumentType.RTF, textTransform: "unset", letterSpacing: "unset",
+ title: "icon_" + DocumentType.RTF, textTransform: "unset", letterSpacing: "unset", layout: LabelBox.LayoutString("text"),
_width: 150, _height: 70, _xPadding: 10, _yPadding: 10, isTemplateDoc: true, onDoubleClick: ScriptField.MakeScript("deiconifyView(self)")
});
iconRtfView.isTemplateDoc = makeTemplate(iconRtfView, true, "icon_" + DocumentType.RTF);
@@ -345,11 +354,11 @@ export class CurrentUserUtils {
}
if (doc["template-icons"] === undefined) {
doc["template-icons"] = new PrefetchProxy(Docs.Create.TreeDocument([doc["template-icon-view"] as Doc, doc["template-icon-view-img"] as Doc,
- doc["template-icon-view-col"] as Doc, doc["template-icon-view-rtf"] as Doc], { title: "icon templates", _height: 75 }));
+ doc["template-icon-view-col"] as Doc, doc["template-icon-view-rtf"] as Doc, doc["template-icon-view-pdf"] as Doc], { title: "icon templates", _height: 75 }));
} else {
const templateIconsDoc = Cast(doc["template-icons"], Doc, null);
const requiredTypes = [doc["template-icon-view"] as Doc, doc["template-icon-view-img"] as Doc,
- doc["template-icon-view-col"] as Doc, doc["template-icon-view-rtf"] as Doc];
+ doc["template-icon-view-col"] as Doc, doc["template-icon-view-rtf"] as Doc, doc["template-icon-view-pdf"] as Doc];
DocListCastAsync(templateIconsDoc.data).then(async curIcons => {
await Promise.all(curIcons!);
requiredTypes.map(ntype => Doc.AddDocToList(templateIconsDoc, "data", ntype));
@@ -583,12 +592,17 @@ export class CurrentUserUtils {
}
if (doc["tabs-button-tools"] === undefined) {
+ const toolsStack = new PrefetchProxy(Docs.Create.StackingDocument([doc.myCreators as Doc, doc.myColorPicker as Doc], {
+ _width: 500, lockedPosition: true, _chromeStatus: "disabled", title: "tools stack", forceActive: true
+ })) as any as Doc;
doc["tabs-button-tools"] = new PrefetchProxy(Docs.Create.ButtonDocument({
_width: 35, _height: 25, title: "Tools", _fontSize: 10,
letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)",
- sourcePanel: new PrefetchProxy(Docs.Create.StackingDocument([doc.myCreators as Doc, doc.myColorPicker as Doc], {
- _width: 500, lockedPosition: true, _chromeStatus: "disabled", title: "tools stack", forceActive: true
- })) as any as Doc,
+ sourcePanel: toolsStack,
+ onDragStart: ScriptField.MakeFunction('getAlias(this.dragFactory, true)'),
+ dragFactory: toolsStack,
+ removeDropProperties: new List<string>(["lockedPosition"]),
+ stayInCollection: true,
targetContainer: new PrefetchProxy(sidebarContainer) as any as Doc,
onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel"),
}));
@@ -613,8 +627,8 @@ export class CurrentUserUtils {
static setupCatalog(doc: Doc) {
if (doc.myCatalog === undefined) {
doc.myCatalog = new PrefetchProxy(Docs.Create.SchemaDocument([], [], {
- title: "CATALOG", _height: 1000, _fitWidth: true, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: false, lockedPosition: true,
- childDropAction: "alias", targetDropAction: "same", treeViewExpandedView: "layout"
+ title: "CATALOG", _height: 1000, _fitWidth: true, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: false,
+ childDropAction: "alias", targetDropAction: "same", treeViewExpandedView: "layout", stayInCollection: true,
}));
}
return doc.myCatalog as Doc;
@@ -623,7 +637,7 @@ export class CurrentUserUtils {
// setup Recently Closed library item
if (doc.myRecentlyClosed === undefined) {
doc.myRecentlyClosed = new PrefetchProxy(Docs.Create.TreeDocument([], {
- title: "RECENTLY CLOSED", _height: 75, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: true, lockedPosition: true,
+ title: "RECENTLY CLOSED", _height: 75, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: true, stayInCollection: true,
}));
}
// this is equivalent to using PrefetchProxies to make sure the recentlyClosed doc is ready
@@ -641,13 +655,18 @@ export class CurrentUserUtils {
const recentlyClosed = CurrentUserUtils.setupRecentlyClosed(doc);
if (doc["tabs-button-library"] === undefined) {
+ const libraryStack = new PrefetchProxy(Docs.Create.TreeDocument([workspaces, documents, recentlyClosed, doc], {
+ title: "Library", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias",
+ lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same"
+ })) as any as Doc;
doc["tabs-button-library"] = new PrefetchProxy(Docs.Create.ButtonDocument({
_width: 50, _height: 25, title: "Library", _fontSize: 10, targetDropAction: "same",
letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)",
- sourcePanel: new PrefetchProxy(Docs.Create.TreeDocument([workspaces, documents, recentlyClosed, doc], {
- title: "Library", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias",
- lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same"
- })) as any as Doc,
+ sourcePanel: libraryStack,
+ onDragStart: ScriptField.MakeFunction('getAlias(this.dragFactory, true)'),
+ dragFactory: libraryStack,
+ removeDropProperties: new List<string>(["lockedPosition"]),
+ stayInCollection: true,
targetContainer: new PrefetchProxy(sidebarContainer) as any as Doc,
onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel;")
}));
@@ -791,6 +810,7 @@ export class CurrentUserUtils {
}
static async updateUserDocument(doc: Doc) {
+ doc.noviceMode = doc.noviceMode === undefined ? "true" : doc.noviceMode;
doc.title = Doc.CurrentUserEmail;
doc.activeInkPen = doc;
doc.activeInkColor = StrCast(doc.activeInkColor, "rgb(0, 0, 0)");
diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts
index e46225b4a..28b1ca6cf 100644
--- a/src/client/util/DictationManager.ts
+++ b/src/client/util/DictationManager.ts
@@ -144,7 +144,7 @@ export namespace DictationManager {
recognizer.start();
return new Promise<string>((resolve, reject) => {
- recognizer.onerror = (e: SpeechRecognitionError) => {
+ recognizer.onerror = (e: any) => { // e is SpeechRecognitionError but where is that defined?
if (!(indefinite && e.error === "no-speech")) {
recognizer.stop();
reject(e);
@@ -335,7 +335,7 @@ export namespace DictationManager {
const prompt = "Press alt + r to start dictating here...";
const head = 3;
const anchor = head + prompt.length;
- const proseMirrorState = `{"doc":{"type":"doc","content":[{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"type":"text","text":"${prompt}"}]}]}]}]},"selection":{"type":"text","anchor":${anchor},"head":${head}}}`;
+ const proseMirrorState = `{"doc":{"type":"doc","content":[{"type":"ordered_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"type":"text","text":"${prompt}"}]}]}]}]},"selection":{"type":"text","anchor":${anchor},"head":${head}}}`;
proto.data = new RichTextField(proseMirrorState);
proto.backgroundColor = "#eeffff";
target.props.addDocTab(newBox, "onRight");
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 21564c92e..26e7250f4 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -328,7 +328,7 @@ export namespace DragManager {
dragLabel.style.zIndex = "100001";
dragLabel.style.fontSize = "10";
dragLabel.style.position = "absolute";
- dragLabel.innerText = "press 'a' to embed on drop";
+ // dragLabel.innerText = "press 'a' to embed on drop"; // bcz: need to move this to a status bar
dragDiv.appendChild(dragLabel);
DragManager.Root().appendChild(dragDiv);
}
diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts
index ea1769d85..f9837298d 100644
--- a/src/client/util/DropConverter.ts
+++ b/src/client/util/DropConverter.ts
@@ -54,10 +54,12 @@ export function makeTemplate(doc: Doc, first: boolean = true, rename: Opt<string
return any;
}
export function convertDropDataToButtons(data: DragManager.DocumentDragData) {
- data && data.draggedDocuments.map((doc, i) => {
+ data?.draggedDocuments.map((doc, i) => {
let dbox = doc;
// bcz: isButtonBar is intended to allow a collection of linear buttons to be dropped and nested into another collection of buttons... it's not being used yet, and isn't very elegant
- if (!doc.onDragStart && !doc.isButtonBar) {
+ if (doc.type === DocumentType.FONTICON) {
+ dbox = Doc.MakeAlias(doc);
+ } else if (!doc.onDragStart && !doc.isButtonBar) {
const layoutDoc = doc.layout instanceof Doc && doc.layout.isTemplateForField ? doc.layout : doc;
if (layoutDoc.type !== DocumentType.FONTICON) {
!layoutDoc.isTemplateDoc && makeTemplate(layoutDoc);
diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx
index 3b42fcaee..7bdf631fc 100644
--- a/src/client/util/InteractionUtils.tsx
+++ b/src/client/util/InteractionUtils.tsx
@@ -100,9 +100,9 @@ export namespace InteractionUtils {
const newPoints = points.reduce((p, pts) => { p.push([pts.X, pts.Y]); return p; }, [] as number[][]);
newPoints.pop();
const bezierCurves = fitCurve(newPoints, parseInt(bezier));
- for (var i = 0; i < bezierCurves.length; i++) {
+ for (const curve of bezierCurves) {
for (var t = 0; t < 1; t += 0.01) {
- const point = beziercurve(t, bezierCurves[i]);
+ const point = beziercurve(t, curve);
pts.push({ X: point[0], Y: point[1] });
}
}
diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index 05515e502..eb905d237 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -10,13 +10,17 @@ export namespace SelectionManager {
@observable IsDragging: boolean = false;
SelectedDocuments: ObservableMap<DocumentView, boolean> = new ObservableMap();
-
+ clearSelection() {
+ if (window.getSelection) { window.getSelection()?.removeAllRanges(); }
+ else if (document.getSelection()) { document.getSelection()?.empty(); }
+ }
@action
SelectDoc(docView: DocumentView, ctrlPressed: boolean): void {
// if doc is not in SelectedDocuments, add it
if (!manager.SelectedDocuments.get(docView)) {
if (!ctrlPressed) {
this.DeselectAll();
+ this.clearSelection();
}
manager.SelectedDocuments.set(docView, true);
diff --git a/src/client/util/UndoManager.ts b/src/client/util/UndoManager.ts
index 314b52bf3..c7b7bb215 100644
--- a/src/client/util/UndoManager.ts
+++ b/src/client/util/UndoManager.ts
@@ -78,10 +78,12 @@ export namespace UndoManager {
let currentBatch: UndoBatch | undefined;
let batchCounter = 0;
let undoing = false;
+ let tempEvents: UndoEvent[] | undefined = undefined;
export function AddEvent(event: UndoEvent): void {
if (currentBatch && batchCounter && !undoing) {
currentBatch.push(event);
+ tempEvents?.push(event);
}
}
@@ -135,7 +137,7 @@ export namespace UndoManager {
const EndBatch = action((cancel: boolean = false) => {
batchCounter--;
- if (batchCounter === 0 && currentBatch && currentBatch.length) {
+ if (batchCounter === 0 && currentBatch?.length) {
if (!cancel) {
undoStack.push(currentBatch);
}
@@ -144,6 +146,13 @@ export namespace UndoManager {
}
});
+ export function ClearTempBatch() {
+ tempEvents = undefined;
+ }
+ export function RunInTempBatch<T>(fn: () => T) {
+ tempEvents = [];
+ return runInAction(fn);
+ }
//TODO Make this return the return value
export function RunInBatch<T>(fn: () => T, batchName: string) {
const batch = StartBatch(batchName);
@@ -153,7 +162,16 @@ export namespace UndoManager {
batch.end();
}
}
-
+ export const UndoTempBatch = action(() => {
+ if (tempEvents) {
+ undoing = true;
+ for (let i = tempEvents.length - 1; i >= 0; i--) {
+ tempEvents[i].undo();
+ }
+ undoing = false;
+ }
+ tempEvents = undefined;
+ });
export const Undo = action(() => {
if (undoStack.length === 0) {
return;
diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx
index 5b66b63ed..941d7b44a 100644
--- a/src/client/views/ContextMenu.tsx
+++ b/src/client/views/ContextMenu.tsx
@@ -236,7 +236,7 @@ export class ContextMenu extends React.Component {
<span className="icon-background">
<FontAwesomeIcon icon="search" size="lg" />
</span>
- <input className="contextMenu-item contextMenu-description search" type="text" placeholder="Search . . ." value={this._searchString} onKeyDown={this.onKeyDown} onChange={this.onChange} autoFocus />
+ <input className="contextMenu-item contextMenu-description search" type="text" placeholder="Search Menu..." value={this._searchString} onKeyDown={this.onKeyDown} onChange={this.onChange} autoFocus />
</span>
{this.menuItems}
</>
diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss
index 0a96b058b..11aaaaf8c 100644
--- a/src/client/views/DocumentDecorations.scss
+++ b/src/client/views/DocumentDecorations.scss
@@ -172,6 +172,20 @@ $linkGap : 3px;
}
+.documentDecorations-iconifyButton {
+ opacity: 1;
+ grid-column-start: 4;
+ grid-column-end: 6;
+ pointer-events: all;
+ text-align: center;
+ left: -20px;
+ top: -2px;
+ cursor: pointer;
+ position: absolute;
+ background: transparent;
+ width: 20px;
+}
+
.documentDecorations-closeButton {
opacity: 1;
grid-column-start: 4;
@@ -222,13 +236,15 @@ $linkGap : 3px;
}
.link-button-container {
- margin-top: $linkGap;
+ padding: $linkGap;
+ border-radius: 10px;
width: max-content;
height: auto;
display: flex;
flex-direction: row;
z-index: 998;
position: absolute;
+ background: $alt-accent;
}
.linkButtonWrapper {
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 6ca7331d6..d92fe5203 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -70,6 +70,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
get Bounds(): { x: number, y: number, b: number, r: number } {
return SelectionManager.SelectedDocuments().reduce((bounds, documentView) => {
if (documentView.props.renderDepth === 0 ||
+ documentView.props.treeViewId ||
Doc.AreProtosEqual(documentView.props.Document, Doc.UserDoc())) {
return bounds;
}
@@ -174,7 +175,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
}
@undoBatch
@action
- onCloseClick = async (e: PointerEvent | undefined) => {
+ onCloseClick = async (e: React.MouseEvent) => {
if (!e?.button) {
const recent = Cast(Doc.UserDoc().myRecentlyClosed, Doc) as Doc;
const selected = SelectionManager.SelectedDocuments().slice();
@@ -459,7 +460,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
<div className="documentDecorations-contextMenu" title="Show context menu" onPointerDown={this.onSettingsDown}>
<FontAwesomeIcon size="lg" icon="cog" />
</div>) : (
- <div className="documentDecorations-minimizeButton" title="Iconify" onPointerDown={this.onIconifyDown}>
+ <div className="documentDecorations-minimizeButton" title="Iconify" onClick={this.onCloseClick}>
{/* Currently, this is set to be enabled if there is no ink selected. It might be interesting to think about minimizing ink if it's useful? -syip2*/}
<FontAwesomeIcon className="documentdecorations-times" icon={faTimes} size="lg" />
</div>);
@@ -468,16 +469,17 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
<>
<input ref={this._keyinput} className="documentDecorations-title" type="text" name="dynbox" autoComplete="on" value={this._accumulatedTitle}
onBlur={e => this.titleBlur(true)} onChange={action(e => this._accumulatedTitle = e.target.value)} onKeyPress={this.titleEntered} />
- {minimal ? (null) : <div className="publishBox" title="make document referenceable by its title"
- onPointerDown={action(e => {
- if (!seldoc.props.Document.customTitle) {
- seldoc.props.Document.customTitle = true;
- StrCast(Doc.GetProto(seldoc.props.Document).title).startsWith("-") && (Doc.GetProto(seldoc.props.Document).title = StrCast(seldoc.props.Document.title).substring(1));
- this._accumulatedTitle = StrCast(seldoc.props.Document.title);
- }
- DocUtils.Publish(seldoc.props.Document, this._accumulatedTitle, seldoc.props.addDocument, seldoc.props.removeDocument);
- })}>
- <FontAwesomeIcon size="lg" color={SelectionManager.SelectedDocuments()[0].props.Document.title === SelectionManager.SelectedDocuments()[0].props.Document[Id] ? "green" : undefined} icon="sticky-note"></FontAwesomeIcon>
+ {minimal ? (null) : <div className="publishBox" // title="make document referenceable by its title"
+ // onPointerDown={action(e => {
+ // if (!seldoc.props.Document.customTitle) {
+ // seldoc.props.Document.customTitle = true;
+ // StrCast(Doc.GetProto(seldoc.props.Document).title).startsWith("-") && (Doc.GetProto(seldoc.props.Document).title = StrCast(seldoc.props.Document.title).substring(1));
+ // this._accumulatedTitle = StrCast(seldoc.props.Document.title);
+ // }
+ // DocUtils.Publish(seldoc.props.Document, this._accumulatedTitle, seldoc.props.addDocument, seldoc.props.removeDocument);
+ // })}
+ >
+ {/* <FontAwesomeIcon size="lg" color={SelectionManager.SelectedDocuments()[0].props.Document.title === SelectionManager.SelectedDocuments()[0].props.Document[Id] ? "green" : undefined} icon="sticky-note"></FontAwesomeIcon> */}
</div>}
</> :
<>
@@ -518,6 +520,9 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
}}>
{maximizeIcon}
{titleArea}
+ <div className="documentDecorations-iconifyButton" title={`${seldoc.finalLayoutKey.includes("icon") ? "De" : ""}Iconify Document`} onPointerDown={this.onIconifyDown}>
+ {"_"}
+ </div>
<div className="documentDecorations-closeButton" title="Open Document in Tab" onPointerDown={this.onMaximizeDown}>
{SelectionManager.SelectedDocuments().length === 1 ? DocumentDecorations.DocumentIcon(StrCast(seldoc.props.Document.layout, "...")) : "..."}
</div>
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 1c305ebeb..53e81dbd2 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -7,7 +7,7 @@ import { Cast, FieldValue, NumCast } from "../../fields/Types";
import MobileInkOverlay from "../../mobile/MobileInkOverlay";
import { GestureUtils } from "../../pen-gestures/GestureUtils";
import { MobileInkOverlayContent } from "../../server/Message";
-import { emptyFunction, emptyPath, returnEmptyString, returnFalse, returnOne, returnTrue, returnZero } from "../../Utils";
+import { emptyFunction, emptyPath, returnEmptyString, returnFalse, returnOne, returnTrue, returnZero, returnEmptyFilter } from "../../Utils";
import { CognitiveServices } from "../cognitive_services/CognitiveServices";
import { DocServer } from "../DocServer";
import { DocUtils } from "../documents/Documents";
@@ -837,6 +837,7 @@ export default class GestureOverlay extends Touchable {
parentActive={returnTrue}
whenActiveChanged={emptyFunction}
bringToFront={emptyFunction}
+ docFilters={returnEmptyFilter}
ContainingCollectionView={undefined}
ContainingCollectionDoc={undefined}
/>;
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index a3b144055..c696625db 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -17,7 +17,6 @@ import { undoBatch, UndoManager } from "../util/UndoManager";
import { CollectionDockingView } from "./collections/CollectionDockingView";
import { MarqueeView } from "./collections/collectionFreeForm/MarqueeView";
import { DocumentDecorations } from "./DocumentDecorations";
-import { InkingStroke } from "./InkingStroke";
import { MainView } from "./MainView";
import { DocumentView } from "./nodes/DocumentView";
@@ -75,7 +74,7 @@ export default class KeyManager {
case "a": DragManager.CanEmbed = true;
break;
case " ":
- MarqueeView.DragMarquee = !MarqueeView.DragMarquee;
+ // MarqueeView.DragMarquee = !MarqueeView.DragMarquee; // bcz: this needs a better disclosure UI
break;
case "escape":
const main = MainView.Instance;
@@ -104,6 +103,7 @@ export default class KeyManager {
}
UndoManager.RunInBatch(() =>
SelectionManager.SelectedDocuments().map(dv => dv.props.removeDocument?.(dv.props.Document)), "delete");
+ SelectionManager.DeselectAll();
break;
case "arrowleft":
UndoManager.RunInBatch(() => SelectionManager.SelectedDocuments().map(dv => dv.props.nudge?.(-1, 0)), "nudge left");
@@ -262,14 +262,14 @@ export default class KeyManager {
}
break;
case "c":
- if (SelectionManager.SelectedDocuments().length) {
+ if (DocumentDecorations.Instance.Bounds.r - DocumentDecorations.Instance.Bounds.x > 2) {
const bds = DocumentDecorations.Instance.Bounds;
const pt = SelectionManager.SelectedDocuments()[0].props.ScreenToLocalTransform().transformPoint(bds.x + (bds.r - bds.x) / 2, bds.y + (bds.b - bds.y) / 2);
const text = `__DashDocId(${pt?.[0] || 0},${pt?.[1] || 0}):` + SelectionManager.SelectedDocuments().map(dv => dv.Document[Id]).join(":");
SelectionManager.SelectedDocuments().length && navigator.clipboard.writeText(text);
stopPropagation = false;
- preventDefault = false;
}
+ preventDefault = false;
break;
}
diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss
index a7048eb23..e84969565 100644
--- a/src/client/views/MainView.scss
+++ b/src/client/views/MainView.scss
@@ -84,6 +84,7 @@
height: 100%;
position: absolute;
display: flex;
+ user-select: none;
}
.mainView-flyoutContainer {
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 3677746cd..fcaa349cd 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -20,7 +20,7 @@ import { listSpec } from '../../fields/Schema';
import { BoolCast, Cast, FieldValue, StrCast } from '../../fields/Types';
import { TraceMobx } from '../../fields/util';
import { CurrentUserUtils } from '../util/CurrentUserUtils';
-import { emptyFunction, emptyPath, returnFalse, returnOne, returnZero, returnTrue, Utils } from '../../Utils';
+import { emptyFunction, emptyPath, returnFalse, returnOne, returnZero, returnTrue, Utils, returnEmptyFilter } from '../../Utils';
import GoogleAuthenticationManager from '../apis/GoogleAuthenticationManager';
import { DocServer } from '../DocServer';
import { Docs, DocumentOptions } from '../documents/Documents';
@@ -58,7 +58,7 @@ import { DocumentManager } from '../util/DocumentManager';
@observer
export class MainView extends React.Component {
public static Instance: MainView;
- private _buttonBarHeight = 26;
+ private _buttonBarHeight = 36;
private _flyoutSizeOnDown = 0;
private _urlState: HistoryUtil.DocUrl;
private _docBtnRef = React.createRef<HTMLDivElement>();
@@ -201,9 +201,9 @@ export class MainView extends React.Component {
const toggleTheme = ScriptField.MakeScript(`self.darkScheme = !self.darkScheme`);
const toggleComic = ScriptField.MakeScript(`toggleComicMode()`);
- const cloneWorkspace = ScriptField.MakeScript(`cloneWorkspace()`);
- workspaceDoc.contextMenuScripts = new List<ScriptField>([toggleTheme!, toggleComic!, cloneWorkspace!]);
- workspaceDoc.contextMenuLabels = new List<string>(["Toggle Theme Colors", "Toggle Comic Mode", "New Workspace Layout"]);
+ const copyWorkspace = ScriptField.MakeScript(`copyWorkspace()`);
+ workspaceDoc.contextMenuScripts = new List<ScriptField>([toggleTheme!, toggleComic!, copyWorkspace!]);
+ workspaceDoc.contextMenuLabels = new List<string>(["Toggle Theme Colors", "Toggle Comic Mode", "Snapshot Workspace"]);
Doc.AddDocToList(workspaces, "data", workspaceDoc);
// bcz: strangely, we need a timeout to prevent exceptions/issues initializing GoldenLayout (the rendering engine for Main Container)
@@ -310,6 +310,7 @@ export class MainView extends React.Component {
parentActive={returnTrue}
whenActiveChanged={emptyFunction}
bringToFront={emptyFunction}
+ docFilters={returnEmptyFilter}
ContainingCollectionView={undefined}
ContainingCollectionDoc={undefined}
/>;
@@ -389,7 +390,7 @@ export class MainView extends React.Component {
return (null);
}
return <div className="mainView-flyoutContainer" >
- <div className="mainView-tabButtons" style={{ height: `${this._buttonBarHeight}px`, backgroundColor: StrCast(this.sidebarButtonsDoc.backgroundColor) }}>
+ <div className="mainView-tabButtons" style={{ height: `${this._buttonBarHeight - 10/*margin-top*/}px`, backgroundColor: StrCast(this.sidebarButtonsDoc.backgroundColor) }}>
<DocumentView
Document={this.sidebarButtonsDoc}
DataDoc={undefined}
@@ -412,6 +413,7 @@ export class MainView extends React.Component {
parentActive={returnTrue}
whenActiveChanged={emptyFunction}
bringToFront={emptyFunction}
+ docFilters={returnEmptyFilter}
ContainingCollectionView={undefined}
ContainingCollectionDoc={undefined} />
</div>
@@ -438,6 +440,7 @@ export class MainView extends React.Component {
parentActive={returnTrue}
whenActiveChanged={emptyFunction}
bringToFront={emptyFunction}
+ docFilters={returnEmptyFilter}
ContainingCollectionView={undefined}
ContainingCollectionDoc={undefined} />
<button className="mainView-settings" key="settings" onClick={() => SettingsManager.Instance.open()}>
@@ -529,6 +532,7 @@ export class MainView extends React.Component {
renderDepth={0}
focus={emptyFunction}
whenActiveChanged={emptyFunction}
+ docFilters={returnEmptyFilter}
ContainingCollectionView={undefined}
ContainingCollectionDoc={undefined} />
</div>;
@@ -578,7 +582,7 @@ export class MainView extends React.Component {
}
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 cloneWorkspace() {
+Scripting.addGlobal(function copyWorkspace() {
const copiedWorkspace = Doc.MakeCopy(Cast(Doc.UserDoc().activeWorkspace, Doc, null), true);
const workspaces = Cast(Doc.UserDoc().myWorkspaces, Doc, null);
Doc.AddDocToList(workspaces, "data", copiedWorkspace);
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index f6e5e1705..37d8dd23b 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -4,7 +4,7 @@ import * as React from "react";
import { Doc, DocListCast, Opt } from "../../fields/Doc";
import { Id } from "../../fields/FieldSymbols";
import { NumCast, Cast } from "../../fields/Types";
-import { emptyFunction, emptyPath, returnEmptyString, returnFalse, returnOne, returnTrue, returnZero, Utils, setupMoveUpEvents } from "../../Utils";
+import { emptyFunction, emptyPath, returnEmptyString, returnFalse, returnOne, returnTrue, returnZero, Utils, setupMoveUpEvents, returnEmptyFilter } from "../../Utils";
import { Transform } from "../util/Transform";
import { CollectionFreeFormLinksView } from "./collections/collectionFreeForm/CollectionFreeFormLinksView";
import { DocumentView } from "./nodes/DocumentView";
@@ -202,6 +202,7 @@ export class OverlayView extends React.Component {
backgroundColor={returnEmptyString}
addDocTab={returnFalse}
pinToPres={emptyFunction}
+ docFilters={returnEmptyFilter}
ContainingCollectionView={undefined}
ContainingCollectionDoc={undefined} />
</div>;
diff --git a/src/client/views/Palette.tsx b/src/client/views/Palette.tsx
index 108eb83d6..0a4334302 100644
--- a/src/client/views/Palette.tsx
+++ b/src/client/views/Palette.tsx
@@ -3,7 +3,7 @@ import { observer } from "mobx-react";
import * as React from "react";
import { Doc } from "../../fields/Doc";
import { NumCast } from "../../fields/Types";
-import { emptyFunction, emptyPath, returnEmptyString, returnZero, returnFalse, returnOne, returnTrue } from "../../Utils";
+import { emptyFunction, emptyPath, returnEmptyString, returnZero, returnFalse, returnOne, returnTrue, returnEmptyFilter } from "../../Utils";
import { Transform } from "../util/Transform";
import { DocumentView } from "./nodes/DocumentView";
import "./Palette.scss";
@@ -59,6 +59,7 @@ export default class Palette extends React.Component<PaletteProps> {
parentActive={returnTrue}
whenActiveChanged={emptyFunction}
bringToFront={emptyFunction}
+ docFilters={returnEmptyFilter}
ContainingCollectionView={undefined}
ContainingCollectionDoc={undefined} />
<div className="palette-cover" style={{ transform: `translate(${Math.max(0, this._selectedIndex) * 50.75 + 23}px, 0px)` }}></div>
diff --git a/src/client/views/RecommendationsBox.tsx b/src/client/views/RecommendationsBox.tsx
index 8ca81c070..cdde32c21 100644
--- a/src/client/views/RecommendationsBox.tsx
+++ b/src/client/views/RecommendationsBox.tsx
@@ -6,7 +6,7 @@ import "./RecommendationsBox.scss";
import { Doc, DocListCast, WidthSym, HeightSym } from "../../fields/Doc";
import { DocumentIcon } from "./nodes/DocumentIcon";
import { StrCast, NumCast } from "../../fields/Types";
-import { returnFalse, emptyFunction, returnEmptyString, returnOne, emptyPath, returnZero } from "../../Utils";
+import { returnFalse, emptyFunction, returnEmptyString, returnOne, emptyPath, returnZero, returnEmptyFilter } from "../../Utils";
import { Transform } from "../util/Transform";
import { ObjectField } from "../../fields/ObjectField";
import { DocumentView } from "./nodes/DocumentView";
@@ -56,7 +56,7 @@ export class RecommendationsBox extends React.Component<FieldViewProps> {
}
const returnXDimension = () => 150;
const returnYDimension = () => 150;
- const scale = () => returnXDimension() / NumCast(renderDoc.nativeWidth, returnXDimension());
+ const scale = () => returnXDimension() / NumCast(renderDoc._nativeWidth, returnXDimension());
//let scale = () => 1;
const newRenderDoc = Doc.MakeAlias(renderDoc); /// newRenderDoc -> renderDoc -> render"data"Doc -> TextProt
newRenderDoc.height = NumCast(this.props.Document.documentIconHeight);
@@ -82,6 +82,7 @@ export class RecommendationsBox extends React.Component<FieldViewProps> {
parentActive={returnFalse}
whenActiveChanged={returnFalse}
bringToFront={emptyFunction}
+ docFilters={returnEmptyFilter}
ContainingCollectionView={undefined}
ContainingCollectionDoc={undefined}
ContentScaling={scale}
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index f135823a8..916e631d0 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -10,7 +10,7 @@ import { Doc, DocListCast } from "../../fields/Doc";
import { Docs, DocUtils, } from "../documents/Documents";
import { StrCast, Cast } from "../../fields/Types";
import { CollectionTreeView } from "./collections/CollectionTreeView";
-import { returnTrue, emptyFunction, returnFalse, returnOne, emptyPath, returnZero } from "../../Utils";
+import { returnTrue, emptyFunction, returnFalse, returnOne, emptyPath, returnZero, returnEmptyFilter } from "../../Utils";
import { Transform } from "../util/Transform";
import { ScriptField, ComputedField } from "../../fields/ScriptField";
import { Scripting } from "../util/Scripting";
@@ -140,6 +140,7 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
CollectionView={undefined}
ContainingCollectionDoc={undefined}
ContainingCollectionView={undefined}
+ docFilters={returnEmptyFilter}
rootSelected={returnFalse}
onCheckedClick={this.scriptField!}
onChildClick={this.scriptField!}
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 657e2a08b..4e5491df5 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -8,11 +8,10 @@ import * as GoldenLayout from "../../../client/goldenLayout";
import { DateField } from '../../../fields/DateField';
import { Doc, DocListCast, Field, Opt, DataSym } from "../../../fields/Doc";
import { Id } from '../../../fields/FieldSymbols';
-import { List } from '../../../fields/List';
import { FieldId } from "../../../fields/RefField";
import { Cast, NumCast, StrCast } from "../../../fields/Types";
import { TraceMobx } from '../../../fields/util';
-import { emptyFunction, returnOne, returnTrue, Utils, returnZero } from "../../../Utils";
+import { emptyFunction, returnOne, returnTrue, Utils, returnZero, returnEmptyFilter } from "../../../Utils";
import { DocServer } from "../../DocServer";
import { Docs } from '../../documents/Documents';
import { DocumentManager } from '../../util/DocumentManager';
@@ -843,6 +842,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
backgroundColor={CollectionDockingView.Instance?.props.backgroundColor}
addDocTab={this.addDocTab}
pinToPres={DockedFrameRenderer.PinDoc}
+ docFilters={returnEmptyFilter}
ContainingCollectionView={undefined}
ContainingCollectionDoc={undefined} />;
}
diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx
index f1002044a..f38eeaf41 100644
--- a/src/client/views/collections/CollectionLinearView.tsx
+++ b/src/client/views/collections/CollectionLinearView.tsx
@@ -124,6 +124,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
parentActive={returnTrue}
whenActiveChanged={emptyFunction}
bringToFront={emptyFunction}
+ docFilters={this.props.docFilters}
ContainingCollectionView={undefined}
ContainingCollectionDoc={undefined} />
</div>;
diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
index cc7a9f5ac..e0b53e762 100644
--- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
+++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
@@ -43,6 +43,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
@observable private heading: string = "";
@observable private color: string = "#f1efeb";
@observable private collapsed: boolean = false;
+ @observable private _paletteOn = false;
private set _heading(value: string) { runInAction(() => this.props.headingObject && (this.props.headingObject.heading = this.heading = value)); }
private set _color(value: string) { runInAction(() => this.props.headingObject && (this.props.headingObject.color = this.color = value)); }
private set _collapsed(value: boolean) { runInAction(() => this.props.headingObject && (this.props.headingObject.collapsed = this.collapsed = value)); }
@@ -293,11 +294,10 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
{noChrome ? evContents : <EditableView {...headerEditableViewProps} />}
{noChrome || evContents === `NO ${key.toUpperCase()} VALUE` ? (null) :
<div className="collectionStackingView-sectionColor">
- <Flyout anchorPoint={anchorPoints.CENTER_RIGHT} content={this.renderColorPicker()}>
- <button className="collectionStackingView-sectionColorButton">
- <FontAwesomeIcon icon="palette" size="lg" />
- </button>
- </ Flyout >
+ <button className="collectionStackingView-sectionColorButton" onClick={action(e => this._paletteOn = !this._paletteOn)}>
+ <FontAwesomeIcon icon="palette" size="lg" />
+ </button>
+ {this._paletteOn ? this.renderColorPicker() : (null)}
</div>
}
{noChrome ? (null) : <button className="collectionStackingView-sectionDelete" onClick={noChrome ? undefined : this.collapseSection}>
@@ -305,7 +305,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
</button>}
{noChrome || evContents === `NO ${key.toUpperCase()} VALUE` ? (null) :
<div className="collectionStackingView-sectionOptions">
- <Flyout anchorPoint={anchorPoints.TOP_RIGHT} content={this.renderMenu()}>
+ <Flyout anchorPoint={anchorPoints.TOP_CENTER} content={this.renderMenu()}>
<button className="collectionStackingView-sectionOptionButton">
<FontAwesomeIcon icon="ellipsis-v" size="lg" />
</button>
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index baf9d4156..2b8110e27 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -3,7 +3,7 @@ import { action, observable, trace } from "mobx";
import { observer } from "mobx-react";
import { CellInfo } from "react-table";
import "react-table/react-table.css";
-import { emptyFunction, returnFalse, returnZero, returnOne } from "../../../Utils";
+import { emptyFunction, returnFalse, returnZero, returnOne, returnEmptyFilter } from "../../../Utils";
import { Doc, DocListCast, Field, Opt } from "../../../fields/Doc";
import { Id } from "../../../fields/FieldSymbols";
import { KeyCodes } from "../../util/KeyCodes";
@@ -159,6 +159,7 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
bringToFront: emptyFunction,
rootSelected: returnFalse,
fieldKey: this.props.rowProps.column.id as string,
+ docFilters: returnEmptyFilter,
ContainingCollectionView: this.props.CollectionView,
ContainingCollectionDoc: this.props.CollectionView && this.props.CollectionView.props.Document,
isSelected: returnFalse,
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 6dbee217a..56a2a517c 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -133,6 +133,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
PanelWidth={this.previewWidth}
PanelHeight={this.previewHeight}
ScreenToLocalTransform={this.getPreviewTransform}
+ docFilters={this.docFilters}
ContainingCollectionDoc={this.props.CollectionView?.props.Document}
ContainingCollectionView={this.props.CollectionView}
moveDocument={this.props.moveDocument}
diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss
index 342773db8..8fc74a9c6 100644
--- a/src/client/views/collections/CollectionStackingView.scss
+++ b/src/client/views/collections/CollectionStackingView.scss
@@ -241,11 +241,15 @@
}
.collectionStackingView-sectionColorButton {
- height: 35px;
+ height: 30px;
+ display: inherit;
}
.collectionStackingView-colorPicker {
width: 78px;
+ z-index: 10;
+ position: relative;
+ background: white;
.colorOptions {
display: flex;
@@ -279,7 +283,7 @@
}
.collectionStackingView-sectionOptionButton {
- height: 35px;
+ height: 30px;
}
.collectionStackingView-optionPicker {
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 9f1b5d63c..1c58b4bcc 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -217,6 +217,7 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument)
ScreenToLocalTransform={dxf}
opacity={opacity}
focus={this.focusDocument}
+ docFilters={this.docFilters}
ContainingCollectionDoc={this.props.CollectionView?.props.Document}
ContainingCollectionView={this.props.CollectionView}
addDocument={this.props.addDocument}
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index bcd55f0fe..b60ed853b 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -50,6 +50,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
private dropDisposer?: DragManager.DragDropDisposer;
private _headerRef: React.RefObject<HTMLDivElement> = React.createRef();
+ @observable _paletteOn = false;
@observable _heading = this.props.headingObject ? this.props.headingObject.heading : this.props.heading;
@observable _color = this.props.headingObject ? this.props.headingObject.color : "#f1efeb";
_ele: HTMLElement | null = null;
@@ -326,11 +327,10 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
<EditableView {...headerEditableViewProps} />
{evContents === `NO ${key.toUpperCase()} VALUE` ? (null) :
<div className="collectionStackingView-sectionColor">
- <Flyout anchorPoint={anchorPoints.CENTER_RIGHT} content={this.renderColorPicker()}>
- <button className="collectionStackingView-sectionColorButton">
- <FontAwesomeIcon icon="palette" size="lg" />
- </button>
- </ Flyout >
+ <button className="collectionStackingView-sectionColorButton" onClick={action(e => this._paletteOn = !this._paletteOn)}>
+ <FontAwesomeIcon icon="palette" size="lg" />
+ </button>
+ {this._paletteOn ? this.renderColorPicker() : (null)}
</div>
}
{evContents === `NO ${key.toUpperCase()} VALUE` ?
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 93d20c475..00d6d59c8 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -10,7 +10,7 @@ import { WebField } from "../../../fields/URLField";
import { Cast, ScriptCast, NumCast } from "../../../fields/Types";
import { GestureUtils } from "../../../pen-gestures/GestureUtils";
import { Upload } from "../../../server/SharedMediaTypes";
-import { Utils, returnFalse } from "../../../Utils";
+import { Utils, returnFalse, returnEmptyFilter } from "../../../Utils";
import { DocServer } from "../../DocServer";
import { Networking } from "../../Network";
import { ImageUtils } from "../../util/Import & Export/ImageUtils";
@@ -101,8 +101,13 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
get childDocList() {
return Cast(this.dataField, listSpec(Doc));
}
+ docFilters = () => {
+ return this.props.ignoreFields?.includes("_docFilters") ? [] :
+ this.props.docFilters !== returnEmptyFilter ? this.props.docFilters() :
+ Cast(this.props.Document._docFilters, listSpec("string"), []);
+ }
@computed get childDocs() {
- const docFilters = this.props.ignoreFields?.includes("_docFilters") ? [] : Cast(this.props.Document._docFilters, listSpec("string"), []);
+ const docFilters = this.docFilters();
const docRangeFilters = this.props.ignoreFields?.includes("_docRangeFilters") ? [] : Cast(this.props.Document._docRangeFilters, listSpec("string"), []);
const filterFacets: { [key: string]: { [value: string]: string } } = {}; // maps each filter key to an object with value=>modifier fields
for (let i = 0; i < docFilters.length; i += 3) {
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index d631a492e..747eb36a1 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -8,7 +8,7 @@ import { PrefetchProxy } from '../../../fields/Proxy';
import { Document, listSpec } from '../../../fields/Schema';
import { ComputedField, ScriptField } from '../../../fields/ScriptField';
import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
-import { emptyFunction, emptyPath, returnFalse, returnOne, returnTrue, returnZero, simulateMouseClick, Utils } from '../../../Utils';
+import { emptyFunction, emptyPath, returnFalse, returnOne, returnTrue, returnZero, simulateMouseClick, Utils, returnEmptyFilter } from '../../../Utils';
import { Docs, DocUtils } from '../../documents/Documents';
import { DocumentType } from "../../documents/DocumentTypes";
import { DocumentManager } from '../../util/DocumentManager';
@@ -250,7 +250,7 @@ class TreeView extends React.Component<TreeViewProps> {
const aspect = NumCast(layoutDoc._nativeHeight, layoutDoc._fitWidth ? 0 : layoutDoc[HeightSym]()) / NumCast(layoutDoc._nativeWidth, layoutDoc._fitWidth ? 1 : layoutDoc[WidthSym]());
if (aspect) return this.docWidth() * aspect;
if (bounds) return this.docWidth() * (bounds.b - bounds.y) / (bounds.r - bounds.x);
- return layoutDoc._fitWidth ? (!this.props.document.nativeHeight ? NumCast(this.props.containingCollection._height) :
+ return layoutDoc._fitWidth ? (!this.props.document._nativeHeight ? NumCast(this.props.containingCollection._height) :
Math.min(this.docWidth() * NumCast(layoutDoc.scrollHeight, NumCast(layoutDoc._nativeHeight)) / NumCast(layoutDoc._nativeWidth,
NumCast(this.props.containingCollection._height)))) :
NumCast(layoutDoc._height) ? NumCast(layoutDoc._height) : 50;
@@ -345,6 +345,7 @@ class TreeView extends React.Component<TreeViewProps> {
LibraryPath={emptyPath}
renderDepth={this.props.renderDepth + 1}
rootSelected={returnTrue}
+ treeViewId={this.props.treeViewId[Id]}
backgroundColor={this.props.backgroundColor}
fitToBox={this.boundsOfCollectionDocument !== undefined}
FreezeDimensions={true}
@@ -354,6 +355,7 @@ class TreeView extends React.Component<TreeViewProps> {
PanelHeight={panelHeight}
focus={returnFalse}
ScreenToLocalTransform={this.docTransform}
+ docFilters={returnEmptyFilter}
ContainingCollectionDoc={this.props.containingCollection}
ContainingCollectionView={undefined}
addDocument={returnFalse}
@@ -471,6 +473,7 @@ class TreeView extends React.Component<TreeViewProps> {
whenActiveChanged={emptyFunction}
bringToFront={emptyFunction}
dontRegisterView={BoolCast(this.props.treeViewId.dontRegisterChildViews)}
+ docFilters={returnEmptyFilter}
ContainingCollectionView={undefined}
ContainingCollectionDoc={this.props.containingCollection}
/>}
@@ -484,12 +487,13 @@ class TreeView extends React.Component<TreeViewProps> {
TraceMobx();
const sorting = this.props.document[`${this.fieldKey}-sortAscending`];
//setTimeout(() => runInAction(() => untracked(() => this._overrideTreeViewOpen = this.treeViewOpen)), 0);
- return <div className="treeViewItem-container" ref={this.createTreeDropTarget}>
+ return <div className="treeViewItem-container" ref={this.createTreeDropTarget} onPointerDown={e => this.props.active() && SelectionManager.DeselectAll()}>
<li className="collection-child">
<div className="treeViewItem-header" ref={this._header} onClick={e => {
if (this.props.active(true)) {
e.stopPropagation();
e.preventDefault();
+ SelectionManager.DeselectAll();
}
}}
onPointerDown={e => {
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 0a84e6f72..29e5c78a9 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -17,7 +17,7 @@ import { ComputedField, ScriptField } from '../../../fields/ScriptField';
import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
import { ImageField } from '../../../fields/URLField';
import { TraceMobx } from '../../../fields/util';
-import { emptyFunction, emptyPath, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils } from '../../../Utils';
+import { emptyFunction, emptyPath, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils, returnEmptyFilter } from '../../../Utils';
import { Docs } from '../../documents/Documents';
import { DocumentType } from '../../documents/DocumentTypes';
import { CurrentUserUtils } from '../../util/CurrentUserUtils';
@@ -45,6 +45,7 @@ import { CollectionTreeView } from "./CollectionTreeView";
import { CollectionGridView } from './collectionGrid/CollectionGridView';
import './CollectionView.scss';
import { CollectionViewBaseChrome } from './CollectionViewChromes';
+import { UndoManager } from '../../util/UndoManager';
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
@@ -166,7 +167,17 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
return true;
}
const first = doc instanceof Doc ? doc : doc[0];
- return !first?.stayInCollection && addDocument !== returnFalse && this.removeDocument(doc) ? addDocument(doc) : false;
+ if (!first?.stayInCollection && addDocument !== returnFalse) {
+ if (UndoManager.RunInTempBatch(() => this.removeDocument(doc))) {
+ const added = addDocument(doc);
+ if (!added) UndoManager.UndoTempBatch();
+ else UndoManager.ClearTempBatch();
+
+ return added;
+ }
+ UndoManager.ClearTempBatch();
+ }
+ return false;
}
showIsTagged = () => {
@@ -180,8 +191,9 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
// return !allTagged ? (null) : <img id={"google-tags"} src={"/assets/google_tags.png"} />;
}
+ screenToLocalTransform = () => this.props.ScreenToLocalTransform().scale(this.props.PanelWidth() / this.bodyPanelWidth());
private SubViewHelper = (type: CollectionViewType, renderProps: CollectionRenderProps) => {
- const props: SubCollectionViewProps = { ...this.props, ...renderProps, CollectionView: this, annotationsKey: "" };
+ const props: SubCollectionViewProps = { ...this.props, ...renderProps, ScreenToLocalTransform: this.screenToLocalTransform, CollectionView: this, annotationsKey: "" };
switch (type) {
case CollectionViewType.Schema: return (<CollectionSchemaView key="collview" {...props} />);
case CollectionViewType.Docking: return (<CollectionDockingView key="collview" {...props} />);
@@ -455,6 +467,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
DataDoc={facetCollection}
fieldKey={`${this.props.fieldKey}-filter`}
CollectionView={this}
+ docFilters={returnEmptyFilter}
ContainingCollectionDoc={this.props.ContainingCollectionDoc}
ContainingCollectionView={this.props.ContainingCollectionView}
PanelWidth={this.facetWidth}
@@ -503,13 +516,10 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
ChildLayoutTemplate: this.childLayoutTemplate,
ChildLayoutString: this.childLayoutString,
};
- return (<div className={"collectionView"}
- style={{
- pointerEvents: this.props.Document.isBackground ? "none" : undefined,
- boxShadow: Doc.UserDoc().renderStyle === "comic" || this.props.Document.isBackground || this.collectionViewType === CollectionViewType.Linear ? undefined :
- `${Cast(Doc.UserDoc().activeWorkspace, Doc, null)?.darkScheme ? "rgb(30, 32, 31)" : "#9c9396"} ${StrCast(this.props.Document.boxShadow, "0.2vw 0.2vw 0.8vw")}`
- }}
- onContextMenu={this.onContextMenu}>
+ const boxShadow = Doc.UserDoc().renderStyle === "comic" || this.props.Document.isBackground || this.collectionViewType === CollectionViewType.Linear ? undefined :
+ `${Cast(Doc.UserDoc().activeWorkspace, Doc, null)?.darkScheme ? "rgb(30, 32, 31) " : "#9c9396 "} ${StrCast(this.props.Document.boxShadow, "0.2vw 0.2vw 0.8vw")}`;
+ return (<div className={"collectionView"} onContextMenu={this.onContextMenu}
+ style={{ pointerEvents: this.props.Document.isBackground ? "none" : undefined, boxShadow }}>
{this.showIsTagged()}
<div className="collectionView-facetCont" style={{ width: `calc(100% - ${this.facetWidth()}px)` }}>
{this.collectionViewType !== undefined ? this.SubView(this.collectionViewType, props) : (null)}
diff --git a/src/client/views/collections/CollectionViewChromes.scss b/src/client/views/collections/CollectionViewChromes.scss
index ec2d78735..086a56f9d 100644
--- a/src/client/views/collections/CollectionViewChromes.scss
+++ b/src/client/views/collections/CollectionViewChromes.scss
@@ -15,7 +15,7 @@
padding-bottom: 1px;
height: 32px;
border-bottom: .5px solid rgb(180, 180, 180);
- overflow: hidden;
+ overflow: visible;
.collectionViewBaseChrome {
display: flex;
diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx
index ec908f034..5920a432a 100644
--- a/src/client/views/collections/CollectionViewChromes.tsx
+++ b/src/client/views/collections/CollectionViewChromes.tsx
@@ -259,10 +259,8 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
<FontAwesomeIcon icon="bullseye" size="2x" />
</div>
<select
- className="collectionViewBaseChrome-cmdPicker"
- onPointerDown={stopPropagation}
- onChange={this.commandChanged}
- value={this._currentKey}>
+ className="collectionViewBaseChrome-cmdPicker" onPointerDown={stopPropagation} onChange={this.commandChanged} value={this._currentKey}
+ style={{ width: this.props.PanelWidth() < 300 ? 15 : undefined }}>
<option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} key={"empty"} value={""} />
{this._buttonizableCommands.map(cmd =>
<option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} key={cmd.title} value={cmd.title}>{cmd.title}</option>
@@ -280,7 +278,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
<FontAwesomeIcon icon="bullseye" size="2x" />
</div>
<select
- className="collectionViewBaseChrome-viewPicker"
+ className="collectionViewBaseChrome-viewPicker" style={{ width: this.props.PanelWidth() < 300 ? 15 : undefined }}
onPointerDown={stopPropagation}
onChange={this.viewChanged}
value={StrCast(this.props.CollectionView.props.Document._viewType)}>
@@ -713,7 +711,7 @@ export class CollectionGridViewChrome extends React.Component<CollectionViewChro
</span>
<select className="collectionGridViewChrome-viewPicker"
- style={{ marginRight: 5 }}
+ style={{ marginRight: 5, width: this.props.PanelWidth() < 300 ? 25 : undefined }}
onPointerDown={stopPropagation}
onChange={this.changeCompactType}
value={StrCast(this.props.CollectionView.props.Document.gridStartCompaction, StrCast(this.props.CollectionView.props.Document.gridCompaction))}>
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index 6cac39f77..859bbc8f8 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -56,27 +56,27 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
const targetAhyperlink = linkEles.find((ele: any) => ele.getAttribute("targetids")?.includes(AanchorId));
const targetBhyperlink = linkEles.find((ele: any) => ele.getAttribute("targetids")?.includes(BanchorId));
if (!targetBhyperlink) {
- this.props.A.props.Document[afield + "_x"] = (apt.point.x - abounds.left) / abounds.width * 100;
- this.props.A.props.Document[afield + "_y"] = (apt.point.y - abounds.top) / abounds.height * 100;
+ this.props.A.rootDoc[afield + "_x"] = (apt.point.x - abounds.left) / abounds.width * 100;
+ this.props.A.rootDoc[afield + "_y"] = (apt.point.y - abounds.top) / abounds.height * 100;
} else {
setTimeout(() => {
- (this.props.A.props.Document[(this.props.A.props as any).fieldKey] as Doc);
+ (this.props.A.rootDoc[(this.props.A.props as any).fieldKey] as Doc);
const m = targetBhyperlink.getBoundingClientRect();
const mp = this.props.A.props.ScreenToLocalTransform().transformPoint(m.right, m.top + 5);
- this.props.A.props.Document[afield + "_x"] = mp[0] / this.props.A.props.PanelWidth() * 100;
- this.props.A.props.Document[afield + "_y"] = mp[1] / this.props.A.props.PanelHeight() * 100;
+ this.props.A.rootDoc[afield + "_x"] = Math.min(1, mp![0] / this.props.A.props.PanelWidth()) * 100;
+ this.props.A.rootDoc[afield + "_y"] = Math.min(1, mp![1] / this.props.A.props.PanelHeight()) * 100;
}, 0);
}
if (!targetAhyperlink) {
- this.props.A.props.Document[bfield + "_x"] = (bpt.point.x - bbounds.left) / bbounds.width * 100;
- this.props.A.props.Document[bfield + "_y"] = (bpt.point.y - bbounds.top) / bbounds.height * 100;
+ this.props.A.rootDoc[bfield + "_x"] = (bpt.point.x - bbounds.left) / bbounds.width * 100;
+ this.props.A.rootDoc[bfield + "_y"] = (bpt.point.y - bbounds.top) / bbounds.height * 100;
} else {
setTimeout(() => {
- (this.props.B.props.Document[(this.props.B.props as any).fieldKey] as Doc);
+ (this.props.B.rootDoc[(this.props.B.props as any).fieldKey] as Doc);
const m = targetAhyperlink.getBoundingClientRect();
const mp = this.props.B.props.ScreenToLocalTransform().transformPoint(m.right, m.top + 5);
- this.props.B.props.Document[bfield + "_x"] = mp[0] / this.props.B.props.PanelWidth() * 100;
- this.props.B.props.Document[bfield + "_y"] = mp[1] / this.props.B.props.PanelHeight() * 100;
+ this.props.B.rootDoc[bfield + "_x"] = Math.min(1, mp![0] / this.props.B.props.PanelWidth()) * 100;
+ this.props.B.rootDoc[bfield + "_y"] = Math.min(1, mp![1] / this.props.B.props.PanelHeight()) * 100;
}, 0);
}
})
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index bed871f8d..f85f15d87 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -158,8 +158,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
}
if (retVal) {
const newBoxes = (newBox instanceof Doc) ? [newBox] : newBox;
- for (let i = 0; i < newBoxes.length; i++) {
- const newBox = newBoxes[i];
+ for (const newBox of newBoxes) {
if (newBox.activeFrame !== undefined) {
const x = newBox.x;
const y = newBox.y;
@@ -240,7 +239,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
@undoBatch
@action
internalLinkDrop(e: Event, de: DragManager.DropEvent, linkDragData: DragManager.LinkDragData, xp: number, yp: number) {
- if (linkDragData.linkSourceDocument === this.props.Document) return false;
+ if (linkDragData.linkSourceDocument === this.props.Document || this.props.Document.annotationOn) return false;
const source = Docs.Create.TextDocument("", { _width: 200, _height: 75, x: xp, y: yp, title: "dropped annotation" });
this.props.addDocument(source);
linkDragData.linkDocument = DocUtils.MakeLink({ doc: source }, { doc: linkDragData.linkSourceDocument }, "doc annotation"); // TODODO this is where in text links get passed
@@ -258,8 +257,6 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
return this.internalPdfAnnoDrop(e, de.complete.annoDragData, xp, yp);
} else if (de.complete.docDragData?.droppedDocuments.length && this.internalDocDrop(e, de, de.complete.docDragData, xp, yp)) {
return true;
- } else {
- UndoManager.Undo();
}
return false;
}
@@ -865,7 +862,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
focusDocument = (doc: Doc, willZoom: boolean, scale?: number, afterFocus?: () => boolean) => {
const state = HistoryUtil.getState();
- // TODO This technically isn't correct if type !== "doc", as
+ // TODO This technically isn't correct if type !== "doc", as
// currently nothing is done, but we should probably push a new state
if (state.type === "doc" && this.Document._panX !== undefined && this.Document._panY !== undefined) {
const init = state.initializers![this.Document[Id]];
@@ -961,6 +958,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
ContentScaling: returnOne,
ContainingCollectionView: this.props.CollectionView,
ContainingCollectionDoc: this.props.Document,
+ docFilters: this.docFilters,
focus: this.focusDocument,
backgroundColor: this.getClusterColor,
backgroundHalo: this.backgroundHalo,
@@ -1199,7 +1197,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
onContextMenu = (e: React.MouseEvent) => {
if (this.props.annotationsKey) return;
- ContextMenu.Instance?.addItem({
+ !this.props.isAnnotationOverlay && ContextMenu.Instance?.addItem({
description: (this._timelineVisible ? "Close" : "Open") + " Animation Timeline", event: action(() => {
this._timelineVisible = !this._timelineVisible;
}), icon: this._timelineVisible ? faEyeSlash : faEye
@@ -1449,4 +1447,4 @@ class CollectionFreeFormViewPannableContents extends React.Component<CollectionF
{this.props.children()}
</div>;
}
-} \ No newline at end of file
+}
diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
index a5d355abc..2015ca930 100644
--- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx
+++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
@@ -163,7 +163,7 @@ export class CollectionGridView extends CollectionSubView(GridSchema) {
const savedLayouts = this.savedLayoutList;
this.childLayoutPairs.forEach(({ layout: doc }) => {
const gridLayout = savedLayouts.find(gridLayout => gridLayout.i === doc[Id]);
- gridLayout && Object.assign(gridLayout, layoutArray.find(layout => layout.i === doc[Id]) || gridLayout);
+ if (gridLayout) Object.assign(gridLayout, layoutArray.find(layout => layout.i === doc[Id]) || gridLayout);
});
if (this.props.Document.gridStartCompaction) {
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index c0e1a0232..776266ce6 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -234,6 +234,7 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
onDoubleClick={this.onChildDoubleClickHandler}
ScreenToLocalTransform={dxf}
focus={this.props.focus}
+ docFilters={this.docFilters}
ContainingCollectionDoc={this.props.CollectionView?.props.Document}
ContainingCollectionView={this.props.CollectionView}
addDocument={this.props.addDocument}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index 602246d07..1703ff4dc 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -233,6 +233,7 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
onDoubleClick={this.onChildDoubleClickHandler}
ScreenToLocalTransform={dxf}
focus={this.props.focus}
+ docFilters={this.docFilters}
ContainingCollectionDoc={this.props.CollectionView?.props.Document}
ContainingCollectionView={this.props.CollectionView}
addDocument={this.props.addDocument}
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index 14a2c25bf..f140cc6e5 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -39,10 +39,12 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps, C
@undoBatch
private dropHandler = (event: Event, dropEvent: DragManager.DropEvent, fieldKey: string) => {
- event.stopPropagation(); // prevent parent Doc from registering new position so that it snaps back into place
- const droppedDocs = dropEvent.complete.docDragData?.droppedDocuments;
- if (droppedDocs?.length) {
- this.dataDoc[fieldKey] = droppedDocs[0];
+ if (dropEvent.complete.docDragData) {
+ event.stopPropagation(); // prevent parent Doc from registering new position so that it snaps back into place
+ const droppedDocs = dropEvent.complete.docDragData?.droppedDocuments;
+ if (droppedDocs?.length) {
+ this.dataDoc[fieldKey] = droppedDocs[0];
+ }
}
}
diff --git a/src/client/views/nodes/DocHolderBox.tsx b/src/client/views/nodes/DocHolderBox.tsx
index a4c4663dd..0cf5505cc 100644
--- a/src/client/views/nodes/DocHolderBox.tsx
+++ b/src/client/views/nodes/DocHolderBox.tsx
@@ -119,6 +119,7 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent<FieldViewProps, Do
Document={containedDoc}
DataDoc={undefined}
LibraryPath={emptyPath}
+ docFilters={this.props.docFilters}
ContainingCollectionView={this as any} // bcz: hack! need to pass a prop that can be used to select the container (ie, 'this') when the up selector in document decorations is clicked. currently, the up selector allows only a containing collection to be selected
ContainingCollectionDoc={undefined}
fitToBox={true}
@@ -147,6 +148,7 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent<FieldViewProps, Do
Document={containedDoc}
DataDoc={undefined}
LibraryPath={emptyPath}
+ docFilters={this.props.docFilters}
ContainingCollectionView={this as any} // bcz: hack! need to pass a prop that can be used to select the container (ie, 'this') when the up selector in document decorations is clicked. currently, the up selector allows only a containing collection to be selected
ContainingCollectionDoc={undefined}
fitToBox={true}
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 126e9ac14..f1438fd54 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -3,7 +3,7 @@ import { observer } from "mobx-react";
import { Doc, Opt, Field, AclSym, AclPrivate } from "../../../fields/Doc";
import { Cast, StrCast, NumCast } from "../../../fields/Types";
import { OmitKeys, Without, emptyPath } from "../../../Utils";
-import DirectoryImportBox from "../../util/Import & Export/DirectoryImportBox";
+import { DirectoryImportBox } from "../../util/Import & Export/DirectoryImportBox";
import { CollectionDockingView } from "../collections/CollectionDockingView";
import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView";
import { CollectionSchemaView } from "../collections/CollectionSchemaView";
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 2f868d558..3179409a8 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -17,10 +17,8 @@ import { GestureUtils } from '../../../pen-gestures/GestureUtils';
import { emptyFunction, OmitKeys, returnOne, returnTransparent, Utils, emptyPath } from "../../../Utils";
import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils';
import { ClientRecommender } from '../../ClientRecommender';
-import { DocServer } from "../../DocServer";
import { Docs, DocUtils } from "../../documents/Documents";
import { DocumentType } from '../../documents/DocumentTypes';
-import { ClientUtils } from '../../util/ClientUtils';
import { DocumentManager } from "../../util/DocumentManager";
import { SnappingManager } from '../../util/SnappingManager';
import { DragManager, dropActionType } from "../../util/DragManager";
@@ -54,6 +52,7 @@ export type DocFocusFunc = () => boolean;
export interface DocumentViewProps {
ContainingCollectionView: Opt<CollectionView>;
ContainingCollectionDoc: Opt<Doc>;
+ docFilters: () => string[];
FreezeDimensions?: boolean;
NativeWidth: () => number;
NativeHeight: () => number;
@@ -138,7 +137,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
this.removeEndListeners();
document.removeEventListener("pointermove", this.onPointerMove);
document.removeEventListener("pointerup", this.onPointerUp);
- console.log(SelectionManager.SelectedDocuments());
if (RadialMenu.Instance._display === false) {
this.addHoldMoveListeners();
this.addHoldEndListeners();
@@ -734,7 +732,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
let options = cm?.findByDescription("Options...");
const optionItems: ContextMenuProps[] = options && "subitems" in options ? options.subitems : [];
const templateDoc = Cast(this.props.Document[StrCast(this.props.Document.layoutKey)], Doc, null);
- optionItems.push({ description: "Open Fields ", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "onRight"), icon: "layer-group" });
templateDoc && optionItems.push({ description: "Open Template ", event: () => this.props.addDocTab(templateDoc, "onRight"), icon: "eye" });
if (!options) {
options = { description: "Options...", subitems: optionItems, icon: "compass" };
@@ -794,12 +791,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
const help = cm?.findByDescription("Help...");
const helpItems: ContextMenuProps[] = help && "subitems" in help ? help.subitems : [];
- helpItems.push({
- description: "Keyboard Shortcuts Ctrl+/",
- event: () => this.props.addDocTab(Docs.Create.PdfDocument("http://localhost:1050/assets/cheat-sheet.pdf", { _width: 300, _height: 300 }), "onRight"),
- icon: "keyboard"
- });
- cm?.addItem({ description: "Help...", subitems: helpItems, icon: "question" });
+ helpItems.push({ description: "Text Shortcuts Ctrl+/", event: () => this.props.addDocTab(Docs.Create.PdfDocument("http://localhost:1050/assets/cheat-sheet.pdf", { _width: 300, _height: 300 }), "onRight"), icon: "keyboard" });
+ helpItems.push({ description: "Show Fields ", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "onRight"), icon: "layer-group" });
+ cm.addItem({ description: "Help...", subitems: helpItems, icon: "question" });
const existingAcls = cm?.findByDescription("Privacy...");
const aclItems: ContextMenuProps[] = existingAcls && "subitems" in existingAcls ? existingAcls.subitems : [];
@@ -1003,8 +997,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
childScaling = () => (this.layoutDoc._fitWidth ? this.props.PanelWidth() / this.nativeWidth : this.props.ContentScaling());
@computed get contents() {
TraceMobx();
- return (<>
+ return (<div style={{ position: "absolute", width: "100%", height: "100%" }}>
<DocumentContentsView key={1}
+ docFilters={this.props.docFilters}
ContainingCollectionView={this.props.ContainingCollectionView}
ContainingCollectionDoc={this.props.ContainingCollectionDoc}
NativeWidth={this.NativeWidth}
@@ -1040,7 +1035,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
onClick={this.onClickHandler}
layoutKey={this.finalLayoutKey} />
{this.anchors}
- </>
+ </div>
);
}
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index e9dc43bd8..305c04a90 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -27,6 +27,7 @@ export interface FieldViewProps {
LibraryPath: Doc[];
onClick?: ScriptField;
dropAction: dropActionType;
+ docFilters: () => string[];
isSelected: (outsideReaction?: boolean) => boolean;
select: (isCtrlPressed: boolean) => void;
rootSelected: (outsideReaction?: boolean) => boolean;
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index f5e996ca4..27b20db14 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -396,12 +396,23 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD
const aspect = (rotation % 180) ? nativeHeight / nativeWidth : 1;
const shift = (rotation % 180) ? (nativeHeight - nativeWidth) * (1 - 1 / aspect) : 0;
this.resize(srcpath);
+ let transformOrigin = "center center";
+ let transform = `translate(0%, 0%) rotate(${rotation}deg) scale(${aspect})`
+ if (rotation === 90 || rotation === -270) {
+ transformOrigin = "top left";
+ transform = `translate(100%, 0%) rotate(${rotation}deg) scale(${aspect})`
+ } else if (rotation === 180) {
+ transform = `rotate(${rotation}deg) scale(${aspect})`
+ } else if (rotation === 270 || rotation === -90) {
+ transformOrigin = "right top";
+ transform = `translate(-100%, 0%) rotate(${rotation}deg) scale(${aspect})`
+ }
return <div className="imageBox-cont" key={this.layoutDoc[Id]} ref={this.createDropTarget}>
<div className="imageBox-fader" >
<img key={this._smallRetryCount + (this._mediumRetryCount << 4) + (this._largeRetryCount << 8)} // force cache to update on retrys
src={srcpath}
- style={{ transform: `scale(${aspect}) translate(0px, ${shift}px) rotate(${rotation}deg)` }}
+ style={{ transform, transformOrigin }}
width={nativeWidth}
ref={this._imgRef}
onError={this.onError} />
@@ -409,7 +420,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD
<img className="imageBox-fadeaway"
key={"fadeaway" + this._smallRetryCount + (this._mediumRetryCount << 4) + (this._largeRetryCount << 8)} // force cache to update on retrys
src={fadepath}
- style={{ transform: `translate(0px, ${shift}px) rotate(${rotation}deg) scale(${aspect})`, }}
+ style={{ transform, transformOrigin }}
width={nativeWidth}
ref={this._imgRef}
onError={this.onError} /></div>}
@@ -447,7 +458,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD
TraceMobx();
return (<div className={`imageBox`} onContextMenu={this.specificContextMenu}
style={{
- transform: this.props.PanelWidth() ? `translate(0px, ${this.ycenter}px)` : `scale(${this.props.ContentScaling()})`,
+ transform: this.props.PanelWidth() ? undefined : `scale(${this.props.ContentScaling()})`,
width: this.props.PanelWidth() ? undefined : `${100 / this.props.ContentScaling()}%`,
height: this.props.PanelWidth() ? undefined : `${100 / this.props.ContentScaling()}%`,
pointerEvents: this.layoutDoc.isBackground ? "none" : undefined,
@@ -473,6 +484,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD
CollectionView={undefined}
ScreenToLocalTransform={this.screenToLocalTransform}
renderDepth={this.props.renderDepth + 1}
+ docFilters={this.props.docFilters}
ContainingCollectionDoc={this.props.ContainingCollectionDoc}>
{this.contentFunc}
</CollectionFreeFormView>
diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index e983852ea..4442ee2eb 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -18,6 +18,7 @@ import { KeyValuePair } from "./KeyValuePair";
import React = require("react");
import { ContextMenu } from "../ContextMenu";
import { ContextMenuProps } from "../ContextMenuItem";
+import e = require("express");
export type KVPScript = {
script: CompiledScript;
@@ -31,10 +32,11 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
private _mainCont = React.createRef<HTMLDivElement>();
private _keyHeader = React.createRef<HTMLTableHeaderCellElement>();
+ private _keyInput = React.createRef<HTMLInputElement>();
+ private _valInput = React.createRef<HTMLInputElement>();
@observable private rows: KeyValuePair[] = [];
- @observable private _keyInput: string = "";
- @observable private _valueInput: string = "";
+
@computed get splitPercentage() { return NumCast(this.props.Document.schemaSplitPercentage, 50); }
get fieldDocToLayout() { return this.props.fieldKey ? Cast(this.props.Document[this.props.fieldKey], Doc, null) : this.props.Document; }
@@ -42,10 +44,11 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
onEnterKey = (e: React.KeyboardEvent): void => {
if (e.key === 'Enter') {
e.stopPropagation();
- if (this._keyInput && this._valueInput && this.fieldDocToLayout) {
- if (KeyValueBox.SetField(this.fieldDocToLayout, this._keyInput, this._valueInput)) {
- this._keyInput = "";
- this._valueInput = "";
+ if (this._keyInput.current?.value && this._valInput.current?.value && this.fieldDocToLayout) {
+ if (KeyValueBox.SetField(this.fieldDocToLayout, this._keyInput.current.value, this._valInput.current.value)) {
+ this._keyInput.current.value = "";
+ this._valInput.current.value = "";
+ document.body.focus();
}
}
}
@@ -103,7 +106,7 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
rowHeight = () => 30;
- createTable = () => {
+ @computed get createTable() {
const doc = this.fieldDocToLayout;
if (!doc) {
return <tr><td>Loading...</td></tr>;
@@ -136,30 +139,18 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
}
return rows;
}
-
- @action
- keyChanged = (e: React.ChangeEvent<HTMLInputElement>) => {
- this._keyInput = e.currentTarget.value;
+ @computed get newKeyValue() {
+ return <tr className="keyValueBox-valueRow">
+ <td className="keyValueBox-td-key" onClick={(e) => { this._keyInput.current!.select(); e.stopPropagation(); }} style={{ width: `${100 - this.splitPercentage}%` }}>
+ <input style={{ width: "100%" }} ref={this._keyInput} type="text" placeholder="Key" />
+ </td>
+ <td className="keyValueBox-td-value" onClick={(e) => { this._valInput.current!.select(); e.stopPropagation(); }} style={{ width: `${this.splitPercentage}%` }}>
+ <input style={{ width: "100%" }} ref={this._valInput} type="text" placeholder="Value" onKeyDown={this.onEnterKey} />
+ </td>
+ </tr>
}
@action
- valueChanged = (e: React.ChangeEvent<HTMLInputElement>) => {
- this._valueInput = e.currentTarget.value;
- }
-
- newKeyValue = () =>
- (
- <tr className="keyValueBox-valueRow">
- <td className="keyValueBox-td-key" style={{ width: `${100 - this.splitPercentage}%` }}>
- <input style={{ width: "100%" }} type="text" value={this._keyInput} placeholder="Key" onChange={this.keyChanged} />
- </td>
- <td className="keyValueBox-td-value" style={{ width: `${this.splitPercentage}%` }}>
- <input style={{ width: "100%" }} type="text" value={this._valueInput} placeholder="Value" onChange={this.valueChanged} onKeyDown={this.onEnterKey} />
- </td>
- </tr>
- )
-
- @action
onDividerMove = (e: PointerEvent): void => {
const nativeWidth = this._mainCont.current!.getBoundingClientRect();
this.props.Document.schemaSplitPercentage = Math.max(0, 100 - Math.round((e.clientX - nativeWidth.left) / nativeWidth.width * 100));
@@ -260,8 +251,8 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
>Key</th>
<th className="keyValueBox-fields" style={{ width: `${this.splitPercentage}%` }}>Fields</th>
</tr>
- {this.createTable()}
- {this.newKeyValue()}
+ {this.createTable}
+ {this.newKeyValue}
</tbody>
</table>
{dividerDragger}
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index 3cbe3e494..4568a6b16 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -1,7 +1,7 @@
import { action, observable } from 'mobx';
import { observer } from "mobx-react";
import { Doc, Field, Opt } from '../../../fields/Doc';
-import { emptyFunction, returnFalse, returnOne, returnZero } from '../../../Utils';
+import { emptyFunction, returnFalse, returnOne, returnZero, returnEmptyFilter } from '../../../Utils';
import { Docs } from '../../documents/Documents';
import { Transform } from '../../util/Transform';
import { undoBatch } from '../../util/UndoManager';
@@ -56,6 +56,7 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
Document: this.props.doc,
DataDoc: this.props.doc,
LibraryPath: [],
+ docFilters:returnEmptyFilter,
ContainingCollectionView: undefined,
ContainingCollectionDoc: undefined,
fieldKey: this.props.keyName,
diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
index ad9e49369..360ead18e 100644
--- a/src/client/views/nodes/LabelBox.tsx
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -77,7 +77,7 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps, LabelDocument
paddingBottom: NumCast(this.layoutDoc._yPadding),
whiteSpace: this.layoutDoc._singleLine ? "pre" : "pre-wrap"
}} >
- {StrCast(this.rootDoc.text, StrCast(this.rootDoc.title))}
+ {StrCast(this.rootDoc[this.fieldKey], StrCast(this.rootDoc.title))}
</div>
<div className="labelBox-fieldKeyParams" >
{!missingParams?.length ? (null) : missingParams.map(m => <div key={m} className="labelBox-missingParam">{m}</div>)}
diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx
index 3c232eff8..233acc481 100644
--- a/src/client/views/nodes/LinkAnchorBox.tsx
+++ b/src/client/views/nodes/LinkAnchorBox.tsx
@@ -17,6 +17,7 @@ import { LinkEditor } from "../linking/LinkEditor";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { SelectionManager } from "../../util/SelectionManager";
import { TraceMobx } from "../../../fields/util";
+import { Id } from "../../../fields/FieldSymbols";
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
@@ -55,8 +56,8 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps, LinkAnch
DragManager.StartDocumentDrag([this._ref.current!], dragData, down[0], down[1]);
return true;
} else if (dragdist > separation) {
- this.layoutDoc[this.fieldKey + "_x"] = (pt[0] - bounds.left) / bounds.width * 100;
- this.layoutDoc[this.fieldKey + "_y"] = (pt[1] - bounds.top) / bounds.height * 100;
+ this.rootDoc[this.fieldKey + "_x"] = (pt[0] - bounds.left) / bounds.width * 100;
+ this.rootDoc[this.fieldKey + "_y"] = (pt[1] - bounds.top) / bounds.height * 100;
}
}
return false;
@@ -113,8 +114,8 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps, LinkAnch
render() {
TraceMobx();
- const x = this.props.PanelWidth() > 1 ? NumCast(this.layoutDoc[this.fieldKey + "_x"], 100) : 0;
- const y = this.props.PanelWidth() > 1 ? NumCast(this.layoutDoc[this.fieldKey + "_y"], 100) : 0;
+ const x = this.props.PanelWidth() > 1 ? NumCast(this.rootDoc[this.fieldKey + "_x"], 100) : 0;
+ const y = this.props.PanelWidth() > 1 ? NumCast(this.rootDoc[this.fieldKey + "_y"], 100) : 0;
const c = StrCast(this.layoutDoc.backgroundColor, "lightblue");
const anchor = this.fieldKey === "anchor1" ? "anchor2" : "anchor1";
const anchorScale = (x === 0 || x === 100 || y === 0 || y === 100) ? 1 : .25;
@@ -130,7 +131,8 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps, LinkAnch
</div>
);
const small = this.props.PanelWidth() <= 1;
- return <div className={`linkAnchorBox-cont${small ? "-small" : ""}`} onPointerDown={this.onPointerDown} onClick={this.onClick} title={targetTitle} onContextMenu={this.specificContextMenu}
+ return <div className={`linkAnchorBox-cont${small ? "-small" : ""} ${this.rootDoc[Id]}`}
+ onPointerDown={this.onPointerDown} onClick={this.onClick} title={targetTitle} onContextMenu={this.specificContextMenu}
ref={this._ref} style={{
background: c,
left: !small ? `calc(${x}% - 7.5px)` : undefined,
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 4b4348d3c..afd70bace 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -146,11 +146,12 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps, PdfDocum
<FontAwesomeIcon style={{ color: "white" }} icon={"arrow-right"} size="sm" />
</button>
</>;
+ const searchTitle = `${!this._searching ? "Open" : "Close"} Search Bar`;
return !this.active() ? (null) :
(<div className="pdfBox-ui" onKeyDown={e => e.keyCode === KeyCodes.BACKSPACE || e.keyCode === KeyCodes.DELETE ? e.stopPropagation() : true}
onPointerDown={e => e.stopPropagation()} style={{ display: this.active() ? "flex" : "none" }}>
<div className="pdfBox-overlayCont" key="cont" onPointerDown={(e) => e.stopPropagation()} style={{ left: `${this._searching ? 0 : 100}%` }}>
- <button className="pdfBox-overlayButton" title="Open Search Bar" />
+ <button className="pdfBox-overlayButton" title={searchTitle} />
<input className="pdfBox-searchBar" placeholder="Search" ref={this._searchRef} onChange={this.searchStringChanged} onKeyDown={e => e.keyCode === KeyCodes.ENTER && this.search(this._searchString, !e.shiftKey)} />
<button className="pdfBox-search" title="Search" onClick={e => this.search(this._searchString, !e.shiftKey)}>
<FontAwesomeIcon icon="search" size="sm" color="white" /></button>
@@ -161,14 +162,17 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps, PdfDocum
<FontAwesomeIcon style={{ color: "white" }} icon={"arrow-down"} size="lg" />
</button>
</div>
- <button className="pdfBox-overlayButton" key="search" onClick={action(() => this._searching = !this._searching)} title="Open Search Bar" style={{ bottom: 0, right: 0 }}>
+ <button className="pdfBox-overlayButton" key="search" onClick={action(() => {
+ this._searching = !this._searching;
+ this.search("mxytzlaf", true);
+ })} title={searchTitle} style={{ bottom: 0, right: 0 }}>
<div className="pdfBox-overlayButton-arrow" onPointerDown={(e) => e.stopPropagation()}></div>
<div className="pdfBox-overlayButton-iconCont" onPointerDown={(e) => e.stopPropagation()}>
<FontAwesomeIcon style={{ color: "white" }} icon={this._searching ? "times" : "search"} size="lg" /></div>
</button>
<input value={`${(this.Document.curPage || 1)}`}
onChange={e => this.gotoPage(Number(e.currentTarget.value))}
- style={{ left: 5, top: 5, height: "20px", width: "20px", position: "absolute", pointerEvents: "all" }}
+ style={{ left: 5, top: 5, height: "20px", width: "3ch", position: "absolute", pointerEvents: "all" }}
onClick={action(() => this._pageControls = !this._pageControls)} />
{this._pageControls ? pageBtns : (null)}
<div className="pdfBox-settingsCont" key="settings" onPointerDown={(e) => e.stopPropagation()}>
@@ -238,7 +242,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps, PdfDocum
<PDFViewer {...this.props} pdf={this._pdf!} url={pdfUrl!.url.pathname} active={this.props.active} loaded={this.loaded}
setPdfViewer={this.setPdfViewer} ContainingCollectionView={this.props.ContainingCollectionView}
renderDepth={this.props.renderDepth} PanelHeight={this.props.PanelHeight} PanelWidth={this.props.PanelWidth}
- addDocTab={this.props.addDocTab} focus={this.props.focus}
+ addDocTab={this.props.addDocTab} focus={this.props.focus} docFilters={this.props.docFilters}
pinToPres={this.props.pinToPres} addDocument={this.addDocument}
Document={this.props.Document} DataDoc={this.dataDoc} ContentScaling={this.props.ContentScaling}
ScreenToLocalTransform={this.props.ScreenToLocalTransform} select={this.props.select}
@@ -252,7 +256,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps, PdfDocum
_pdfjsRequested = false;
render() {
const pdfUrl = Cast(this.dataDoc[this.props.fieldKey], PdfField, null);
- if (this.props.isSelected() || this.props.renderDepth <= 1 || this.props.Document._scrollY !== undefined) this._everActive = true;
+ if (this.props.isSelected() || this.props.renderDepth === 0 || this.props.Document._scrollY !== undefined) this._everActive = true;
if (pdfUrl && (this._everActive || this.props.Document._scrollTop || (this.dataDoc[this.props.fieldKey + "-nativeWidth"] && this.props.ScreenToLocalTransform().Scale < 2.5))) {
if (pdfUrl instanceof PdfField && this._pdf) {
return this.renderPdfView;
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index e4dbceca6..71556bfd3 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -383,6 +383,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
CollectionView={undefined}
ScreenToLocalTransform={this.props.ScreenToLocalTransform}
renderDepth={this.props.renderDepth + 1}
+ docFilters={this.props.docFilters}
ContainingCollectionDoc={this.props.ContainingCollectionDoc}>
{this.contentFunc}
</CollectionFreeFormView>
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index fb9e57b51..b726a6df9 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -488,6 +488,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
CollectionView={undefined}
ScreenToLocalTransform={this.scrollXf}
renderDepth={this.props.renderDepth + 1}
+ docFilters={this.props.docFilters}
ContainingCollectionDoc={this.props.ContainingCollectionDoc}>
</CollectionFreeFormView>
</div>
diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx
index 55b3f6f1e..5c3f3dcc9 100644
--- a/src/client/views/nodes/formattedText/DashDocView.tsx
+++ b/src/client/views/nodes/formattedText/DashDocView.tsx
@@ -5,7 +5,7 @@ import { Id } from "../../../../fields/FieldSymbols";
import { ObjectField } from "../../../../fields/ObjectField";
import { ComputedField } from "../../../../fields/ScriptField";
import { BoolCast, Cast, NumCast, StrCast } from "../../../../fields/Types";
-import { emptyFunction, returnEmptyString, returnFalse, Utils, returnZero } from "../../../../Utils";
+import { emptyFunction, returnEmptyString, returnFalse, Utils, returnZero, returnEmptyFilter } from "../../../../Utils";
import { DocServer } from "../../../DocServer";
import { Docs, DocUtils } from "../../../documents/Documents";
import { DocumentView } from "../DocumentView";
@@ -254,6 +254,7 @@ export class DashDocView extends React.Component<IDashDocView> {
whenActiveChanged={returnFalse}
bringToFront={emptyFunction}
dontRegisterView={false}
+ docFilters={this.props.tbox?.props.docFilters||returnEmptyFilter}
ContainingCollectionView={this._textBox.props.ContainingCollectionView}
ContainingCollectionDoc={this._textBox.props.ContainingCollectionDoc}
ContentScaling={this.contentScaling}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.scss b/src/client/views/nodes/formattedText/FormattedTextBox.scss
index 7b0ceb6cf..17a1e83c1 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.scss
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.scss
@@ -73,7 +73,7 @@
.collectionfreeformview-container {
position: relative;
}
-
+
>.formattedTextBox-sidebar-handle {
right: unset;
left: -5;
@@ -93,10 +93,13 @@
left: 10%;
}
-.formattedTextBox-inner-rounded,
-.formattedTextBox-inner {
+.formattedTextBox-inner-rounded, .formattedTextBox-inner-rounded-selected,
+.formattedTextBox-inner, .formattedTextBox-inner-selected {
height: 100%;
- white-space: pre-wrap;
+ white-space: pre-wrap;
+ .ProseMirror:hover {
+ background: rgba(200,200,200,0.8);
+ }
hr {
display: block;
unicode-bidi: isolate;
@@ -260,23 +263,25 @@ footnote::after {
padding:0px;
}
-
+
.prosemirror-links a {
float: left;
color: white;
text-decoration: none;
}
-
+
.prosemirror-links a:hover {
background-color: #eee;
color: black;
}
-
+
.prosemirror-anchor:hover .prosemirror-links {
display: grid;
}
.ProseMirror {
+ padding: 0px;
+ height: max-content;
touch-action: none;
span {
font-family: inherit;
@@ -291,6 +296,9 @@ footnote::after {
margin-left: 1em;
font-family: inherit;
}
+ .bullet { p {display: inline; font-family: inherit} margin-left: 0; }
+ .bullet1 { p {display: inline; font-family: inherit} }
+ .bullet2,.bullet3,.bullet4,.bullet5,.bullet6 { p {display: inline; font-family: inherit} font-size: smaller; }
.decimal1-ol { counter-reset: deci1; p {display: inline; font-family: inherit} margin-left: 0; }
.decimal2-ol { counter-reset: deci2; p {display: inline; font-family: inherit} font-size: smaller; padding-left: 1em;}
@@ -305,6 +313,8 @@ footnote::after {
.multi3-ol { counter-reset: multi3; p {display: inline; font-family: inherit} font-size: smaller; padding-left: 2em;}
.multi4-ol { counter-reset: multi4; p {display: inline; font-family: inherit} font-size: smaller; padding-left: 3.4em;}
+ .bullet:before, .bullet1:before, .bullet2:before, .bullet3:before, .bullet4:before, .bullet5:before { transition: 0.5s; display: inline-block; margin-left: -1em; width: 1em; content:" " }
+
.decimal1:before { transition: 0.5s;counter-increment: deci1; display: inline-block; margin-left: -1em; width: 1em; content: counter(deci1) ". "; }
.decimal2:before { transition: 0.5s;counter-increment: deci2; display: inline-block; margin-left: -2.1em; width: 2.1em; content: counter(deci1) "."counter(deci2) ". "; }
.decimal3:before { transition: 0.5s;counter-increment: deci3; display: inline-block; margin-left: -2.85em;width: 2.85em; content: counter(deci1) "."counter(deci2) "."counter(deci3) ". "; }
@@ -312,11 +322,21 @@ footnote::after {
.decimal5:before { transition: 0.5s;counter-increment: deci5; display: inline-block; margin-left: -2em; width: 5em; content: counter(deci1) "."counter(deci2) "."counter(deci3) "."counter(deci4) "."counter(deci5) ". "; }
.decimal6:before { transition: 0.5s;counter-increment: deci6; display: inline-block; margin-left: -2em; width: 6em; content: counter(deci1) "."counter(deci2) "."counter(deci3) "."counter(deci4) "."counter(deci5) "."counter(deci6) ". "; }
.decimal7:before { transition: 0.5s;counter-increment: deci7; display: inline-block; margin-left: -2em; width: 7em; content: counter(deci1) "."counter(deci2) "."counter(deci3) "."counter(deci4) "."counter(deci5) "."counter(deci6) "."counter(deci7) ". "; }
-
+
.multi1:before { transition: 0.5s;counter-increment: multi1; display: inline-block; margin-left: -1em; width: 1.2em; content: counter(multi1, upper-alpha) ". "; }
.multi2:before { transition: 0.5s;counter-increment: multi2; display: inline-block; margin-left: -2em; width: 2em; content: counter(multi1, upper-alpha) "."counter(multi2, decimal) ". "; }
.multi3:before { transition: 0.5s;counter-increment: multi3; display: inline-block; margin-left: -2.85em; width:2.85em; content: counter(multi1, upper-alpha) "."counter(multi2, decimal) "."counter(multi3, lower-alpha) ". "; }
- .multi4:before { transition: 0.5s;counter-increment: multi4; display: inline-block; margin-left: -4.2em; width: 4.2em; content: counter(multi1, upper-alpha) "."counter(multi2, decimal) "."counter(multi3, lower-alpha) "."counter(multi4, lower-roman) ". "; }
+ .multi4:before { transition: 0.5s;counter-increment: multi4; display: inline-block; margin-left: -4.2em; width: 4.2em; content: counter(multi1, upper-alpha) "."counter(multi2, decimal) "."counter(multi3, lower-alpha) "."counter(multi4, lower-roman) ". "; }
+}
+
+.formattedTextBox-inner-rounded-selected,
+.formattedTextBox-inner-selected {
+ .ProseMirror {
+ padding:10px;
+ }
+ .ProseMirror:hover {
+ background: unset;
+ }
}
@media only screen and (max-width: 1000px) {
@@ -327,11 +347,11 @@ footnote::after {
height: 100%;
min-height: 100%;
}
-
+
.ProseMirror:focus {
outline: none !important;
}
-
+
.formattedTextBox-cont {
touch-action: none;
cursor: text;
@@ -350,7 +370,7 @@ footnote::after {
display: flex;
flex-direction: row;
transition: opacity 1s;
-
+
.formattedTextBox-dictation {
height: 12px;
width: 10px;
@@ -359,7 +379,7 @@ footnote::after {
position: absolute;
}
}
-
+
.formattedTextBox-outer {
position: relative;
overflow: auto;
@@ -367,7 +387,7 @@ footnote::after {
width: 100%;
height: 100%;
}
-
+
.formattedTextBox-sidebar-handle {
position: absolute;
top: calc(50% - 17.5px);
@@ -377,12 +397,12 @@ footnote::after {
border-radius: 20px;
cursor:grabbing;
}
-
+
.formattedTextBox-cont>.formattedTextBox-sidebar-handle {
right: 0;
left: unset;
}
-
+
.formattedTextBox-sidebar,
.formattedTextBox-sidebar-inking {
border-left: dashed 1px black;
@@ -390,21 +410,21 @@ footnote::after {
display: inline-block;
position: absolute;
right: 0;
-
+
.collectionfreeformview-container {
position: relative;
}
-
+
>.formattedTextBox-sidebar-handle {
right: unset;
left: -5;
}
}
-
+
.formattedTextBox-sidebar-inking {
pointer-events: all;
}
-
+
.formattedTextBox-inner-rounded {
height: 70%;
width: 85%;
@@ -413,11 +433,11 @@ footnote::after {
top: 15%;
left: 10%;
}
-
+
.formattedTextBox-inner-rounded,
.formattedTextBox-inner {
height: 100%;
- white-space: pre-wrap;
+ white-space: pre-wrap;
hr {
display: block;
unicode-bidi: isolate;
@@ -430,7 +450,7 @@ footnote::after {
border-width: 1px;
}
}
-
+
// .menuicon {
// display: inline-block;
// border-right: 1px solid rgba(0, 0, 0, 0.2);
@@ -442,21 +462,21 @@ footnote::after {
// text-align: center;
// min-width: 1.4em;
// }
-
+
.strong,
.heading {
font-weight: bold;
}
-
+
.em {
font-style: italic;
}
-
+
.userMarkOpen {
background: rgba(255, 255, 0, 0.267);
display: inline;
}
-
+
.userMark {
background: rgba(255, 255, 0, 0.267);
font-size: 2px;
@@ -469,28 +489,28 @@ footnote::after {
text-align: center;
align-content: center;
}
-
+
footnote {
display: inline-block;
position: relative;
cursor: pointer;
-
+
div {
padding: 0 !important;
}
}
-
+
footnote::after {
content: counter(prosemirror-footnote);
vertical-align: super;
font-size: 75%;
counter-increment: prosemirror-footnote;
}
-
+
.ProseMirror {
counter-reset: prosemirror-footnote;
}
-
+
.footnote-tooltip {
cursor: auto;
font-size: 75%;
@@ -504,11 +524,11 @@ footnote::after {
min-width: 50px;
width: max-content;
}
-
+
.prosemirror-attribution {
font-size: 8px;
}
-
+
.footnote-tooltip::before {
border: 5px solid silver;
border-top-width: 0px;
@@ -521,8 +541,8 @@ footnote::after {
height: 0;
width: 0;
}
-
-
+
+
.formattedTextBox-inlineComment {
position: relative;
width: 40px;
@@ -534,7 +554,7 @@ footnote::after {
background: orange;
}
}
-
+
.formattedTextBox-summarizer {
opacity: 0.5;
position: relative;
@@ -544,7 +564,7 @@ footnote::after {
content: "←";
}
}
-
+
.formattedTextBox-summarizer-collapsed {
opacity: 0.5;
position: relative;
@@ -554,13 +574,13 @@ footnote::after {
content: "...";
}
}
-
+
.ProseMirror {
touch-action: none;
span {
font-family: inherit;
}
-
+
ol, ul {
counter-reset: deci1 0 multi1 0;
padding-left: 1em;
@@ -570,7 +590,7 @@ footnote::after {
margin-left: 1em;
font-family: inherit;
}
-
+
.decimal1-ol { counter-reset: deci1; p {display: inline; font-family: inherit} margin-left: 0; }
.decimal2-ol { counter-reset: deci2; p {display: inline; font-family: inherit} font-size: smaller; padding-left: 1em;}
.decimal3-ol { counter-reset: deci3; p {display: inline; font-family: inherit} font-size: smaller; padding-left: 2em;}
@@ -578,12 +598,12 @@ footnote::after {
.decimal5-ol { counter-reset: deci5; p {display: inline; font-family: inherit} font-size: smaller; }
.decimal6-ol { counter-reset: deci6; p {display: inline; font-family: inherit} font-size: smaller; }
.decimal7-ol { counter-reset: deci7; p {display: inline; font-family: inherit} font-size: smaller; }
-
+
.multi1-ol { counter-reset: multi1; p {display: inline; font-family: inherit} margin-left: 0; padding-left: 1.2em }
.multi2-ol { counter-reset: multi2; p {display: inline; font-family: inherit} font-size: smaller; padding-left: 1.4em;}
.multi3-ol { counter-reset: multi3; p {display: inline; font-family: inherit} font-size: smaller; padding-left: 2em;}
.multi4-ol { counter-reset: multi4; p {display: inline; font-family: inherit} font-size: smaller; padding-left: 3.4em;}
-
+
.decimal1:before { transition: 0.5s;counter-increment: deci1; display: inline-block; margin-left: -1em; width: 1em; content: counter(deci1) ". "; }
.decimal2:before { transition: 0.5s;counter-increment: deci2; display: inline-block; margin-left: -2.1em; width: 2.1em; content: counter(deci1) "."counter(deci2) ". "; }
.decimal3:before { transition: 0.5s;counter-increment: deci3; display: inline-block; margin-left: -2.85em;width: 2.85em; content: counter(deci1) "."counter(deci2) "."counter(deci3) ". "; }
@@ -591,7 +611,7 @@ footnote::after {
.decimal5:before { transition: 0.5s;counter-increment: deci5; display: inline-block; margin-left: -2em; width: 5em; content: counter(deci1) "."counter(deci2) "."counter(deci3) "."counter(deci4) "."counter(deci5) ". "; }
.decimal6:before { transition: 0.5s;counter-increment: deci6; display: inline-block; margin-left: -2em; width: 6em; content: counter(deci1) "."counter(deci2) "."counter(deci3) "."counter(deci4) "."counter(deci5) "."counter(deci6) ". "; }
.decimal7:before { transition: 0.5s;counter-increment: deci7; display: inline-block; margin-left: -2em; width: 7em; content: counter(deci1) "."counter(deci2) "."counter(deci3) "."counter(deci4) "."counter(deci5) "."counter(deci6) "."counter(deci7) ". "; }
-
+
.multi1:before { transition: 0.5s;counter-increment: multi1; display: inline-block; margin-left: -1em; width: 1.2em; content: counter(multi1, upper-alpha) ". "; }
.multi2:before { transition: 0.5s;counter-increment: multi2; display: inline-block; margin-left: -2em; width: 2em; content: counter(multi1, upper-alpha) "."counter(multi2, decimal) ". "; }
.multi3:before { transition: 0.5s;counter-increment: multi3; display: inline-block; margin-left: -2.85em; width:2.85em; content: counter(multi1, upper-alpha) "."counter(multi2, decimal) "."counter(multi3, lower-alpha) ". "; }
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index ae508cd67..e6cf2da07 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -13,8 +13,9 @@ import { EditorState, NodeSelection, Plugin, TextSelection, Transaction } from "
import { ReplaceStep } from 'prosemirror-transform';
import { EditorView } from "prosemirror-view";
import { DateField } from '../../../../fields/DateField';
-import { DataSym, Doc, DocListCast, DocListCastAsync, Field, HeightSym, Opt, WidthSym } from "../../../../fields/Doc";
+import { DataSym, Doc, DocListCast, DocListCastAsync, Field, HeightSym, Opt, WidthSym, AclSym } from "../../../../fields/Doc";
import { documentSchema } from '../../../../fields/documentSchemas';
+import applyDevTools = require("prosemirror-dev-tools");
import { Id } from '../../../../fields/FieldSymbols';
import { InkTool } from '../../../../fields/InkField';
import { PrefetchProxy } from '../../../../fields/Proxy';
@@ -22,7 +23,7 @@ import { RichTextField } from "../../../../fields/RichTextField";
import { RichTextUtils } from '../../../../fields/RichTextUtils';
import { createSchema, makeInterface } from "../../../../fields/Schema";
import { Cast, DateCast, NumCast, StrCast } from "../../../../fields/Types";
-import { TraceMobx } from '../../../../fields/util';
+import { TraceMobx, OVERRIDE_ACL } from '../../../../fields/util';
import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, returnOne, returnZero, Utils, setupMoveUpEvents } from '../../../../Utils';
import { GoogleApiClientUtils, Pulls, Pushes } from '../../../apis/google_docs/GoogleApiClientUtils';
import { DocServer } from "../../../DocServer";
@@ -57,7 +58,7 @@ import { FieldView, FieldViewProps } from "../FieldView";
import "./FormattedTextBox.scss";
import { FormattedTextBoxComment, formattedTextBoxCommentPlugin } from './FormattedTextBoxComment';
import React = require("react");
-import { InkingStroke } from '../../InkingStroke';
+import requestPromise = require('request-promise');
library.add(faEdit);
library.add(faSmile, faTextHeight, faUpload);
@@ -199,22 +200,28 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
const curProto = Cast(Cast(this.dataDoc.proto, Doc, null)?.[this.fieldKey], RichTextField, null); // the default text inherited from a prototype
const curLayout = this.rootDoc !== this.layoutDoc ? Cast(this.layoutDoc[this.fieldKey], RichTextField, null) : undefined; // the default text stored in a layout template
const json = JSON.stringify(state.toJSON());
- if (!this._applyingChange && json.replace(/"selection":.*/, "") !== curProto?.Data.replace(/"selection":.*/, "")) {
- this._applyingChange = true;
- this.dataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now()));
- if ((!curTemp && !curProto) || curText || curLayout?.Data.includes("dash")) { // if no template, or there's text that didn't come from the layout template, write it to the document. (if this is driven by a template, then this overwrites the template text which is intended)
- if (json !== curLayout?.Data) {
- !curText && tx.storedMarks?.map(m => m.type.name === "pFontSize" && (Doc.UserDoc().fontSize = this.layoutDoc._fontSize = m.attrs.fontSize));
- !curText && tx.storedMarks?.map(m => m.type.name === "pFontFamily" && (Doc.UserDoc().fontFamily = this.layoutDoc._fontFamily = m.attrs.fontFamily));
- this.dataDoc[this.props.fieldKey] = new RichTextField(json, curText);
- this.dataDoc[this.props.fieldKey + "-noTemplate"] = (curTemp?.Text || "") !== curText; // mark the data field as being split from the template if it has been edited
+ if (!this.dataDoc[AclSym]) {
+ if (!this._applyingChange && json.replace(/"selection":.*/, "") !== curProto?.Data.replace(/"selection":.*/, "")) {
+ this._applyingChange = true;
+ this.dataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now()));
+ if ((!curTemp && !curProto) || curText || curLayout?.Data.includes("dash")) { // if no template, or there's text that didn't come from the layout template, write it to the document. (if this is driven by a template, then this overwrites the template text which is intended)
+ if (json !== curLayout?.Data) {
+ !curText && tx.storedMarks?.map(m => m.type.name === "pFontSize" && (Doc.UserDoc().fontSize = this.layoutDoc._fontSize = m.attrs.fontSize));
+ !curText && tx.storedMarks?.map(m => m.type.name === "pFontFamily" && (Doc.UserDoc().fontFamily = this.layoutDoc._fontFamily = m.attrs.fontFamily));
+ this.dataDoc[this.props.fieldKey] = new RichTextField(json, curText);
+ this.dataDoc[this.props.fieldKey + "-noTemplate"] = (curTemp?.Text || "") !== curText; // mark the data field as being split from the template if it has been edited
+ }
+ } else { // if we've deleted all the text in a note driven by a template, then restore the template data
+ this.dataDoc[this.props.fieldKey] = undefined;
+ this._editorView.updateState(EditorState.fromJSON(this.config, JSON.parse((curProto || curTemp).Data)));
+ this.dataDoc[this.props.fieldKey + "-noTemplate"] = undefined; // mark the data field as not being split from any template it might have
}
- } else { // if we've deleted all the text in a note driven by a template, then restore the template data
- this.dataDoc[this.props.fieldKey] = undefined;
- this._editorView.updateState(EditorState.fromJSON(this.config, JSON.parse((curProto || curTemp).Data)));
- this.dataDoc[this.props.fieldKey + "-noTemplate"] = undefined; // mark the data field as not being split from any template it might have
+ this._applyingChange = false;
}
- this._applyingChange = false;
+ } else {
+ const json = JSON.parse(Cast(this.dataDoc[this.fieldKey], RichTextField)?.Data!);
+ json.selection = state.toJSON().selection;
+ this._editorView.updateState(EditorState.fromJSON(this.config, json));
}
this.updateTitle();
this.tryUpdateHeight();
@@ -484,6 +491,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
});
changeItems.push({ description: "FreeForm", event: () => DocUtils.makeCustomViewClicked(this.rootDoc, Docs.Create.FreeformDocument, "freeform"), icon: "eye" });
!change && cm.addItem({ description: "Change Perspective...", subitems: changeItems, icon: "external-link-alt" });
+ this._downX = this._downY = Number.NaN;
}
recordDictation = () => {
@@ -599,7 +607,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
tr = tr.addMark(pos, pos + node.nodeSize, link);
}
});
+ OVERRIDE_ACL(true);
this._editorView!.dispatch(tr.removeMark(sel.from, sel.to, splitter));
+ OVERRIDE_ACL(false);
}
}
componentDidMount() {
@@ -914,6 +924,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
clipboardTextSerializer: this.clipboardTextSerializer,
handlePaste: this.handlePaste,
});
+ // applyDevTools.applyDevTools(this._editorView);
const startupText = !rtfField && this._editorView && Field.toString(this.dataDoc[fieldKey] as Field);
if (startupText) {
const { state: { tr }, dispatch } = this._editorView;
@@ -989,15 +1000,19 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
if (!FormattedTextBox._downEvent) return;
FormattedTextBox._downEvent = false;
if (!(e.nativeEvent as any).formattedHandled) {
+ const editor = this._editorView!;
FormattedTextBoxComment.textBox = this;
- FormattedTextBoxComment.update(this._editorView!, undefined, (e.target as any)?.className === "prosemirror-dropdownlink" ? (e.target as any).href : "");
+ const pcords = editor.posAtCoords({ left: e.clientX, top: e.clientY });
+ const node = pcords && editor.state.doc.nodeAt(pcords.pos); // get what prosemirror thinks the clicked node is (if it's null, then we didn't click on any text)
+ !this.props.isSelected(true) && editor.dispatch(editor.state.tr.setSelection(node && pcords ?
+ new NodeSelection(editor.state.doc.resolve(pcords.pos)) : new TextSelection(editor.state.doc.resolve(pcords?.pos || 0))));
+ FormattedTextBoxComment.update(editor, undefined, (e.target as any)?.className === "prosemirror-dropdownlink" ? (e.target as any).href : "");
}
(e.nativeEvent as any).formattedHandled = true;
if (e.buttons === 1 && this.props.isSelected(true) && !e.altKey) {
e.stopPropagation();
}
- this._downX = this._downY = Number.NaN;
}
@action
@@ -1062,38 +1077,35 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
// this hackiness handles clicking on the list item bullets to do expand/collapse. the bullets are ::before pseudo elements so there's no real way to hit test against them.
- hitBulletTargets(x: number, y: number, select: boolean, highlightOnly: boolean) {
+ hitBulletTargets(x: number, y: number, collapse: boolean, highlightOnly: boolean) {
clearStyleSheetRules(FormattedTextBox._bulletStyleSheet);
- const pos = this._editorView!.posAtCoords({ left: x, top: y });
- if (pos && this.props.isSelected(true)) {
- // let beforeEle = document.querySelector("." + hit.className) as Element; // const before = hit ? window.getComputedStyle(hit, ':before') : undefined;
- //const node = this._editorView!.state.doc.nodeAt(pos.pos);
- const $pos = this._editorView!.state.doc.resolve(pos.pos);
- let list_node = $pos.node().type === schema.nodes.list_item ? $pos.node() : undefined;
- if ($pos.node().type === schema.nodes.ordered_list) {
- for (let off = 1; off < 100; off++) {
- const pos = this._editorView!.posAtCoords({ left: x + off, top: y });
- const node = pos && this._editorView!.state.doc.nodeAt(pos.pos);
- if (node?.type === schema.nodes.list_item) {
- list_node = node;
- break;
- }
+ const clickPos = this._editorView!.posAtCoords({ left: x, top: y });
+ let olistPos = clickPos?.pos;
+ if (clickPos && olistPos && this.props.isSelected(true)) {
+ const clickNode = this._editorView?.state.doc.nodeAt(olistPos);
+ let nodeBef = this._editorView?.state.doc.nodeAt(Math.max(0, olistPos - 1));
+ olistPos = nodeBef?.type === this._editorView?.state.schema.nodes.ordered_list ? olistPos - 1 : olistPos;
+ let $olistPos = this._editorView?.state.doc.resolve(olistPos);
+ let olistNode = (nodeBef !== null || clickNode?.type === this._editorView?.state.schema.nodes.list_item) && olistPos === clickPos?.pos ? clickNode : nodeBef;
+ if (olistNode?.type === this._editorView?.state.schema.nodes.list_item) {
+ if ($olistPos && ($olistPos as any).path.length > 3) {
+ olistNode = $olistPos.parent;
+ $olistPos = this._editorView?.state.doc.resolve(($olistPos as any).path[($olistPos as any).path.length - 4]);
}
}
- if (list_node && pos.inside >= 0 && this._editorView!.state.doc.nodeAt(pos.inside)!.attrs.bulletStyle === list_node.attrs.bulletStyle) {
- if (select) {
- const $olist_pos = this._editorView!.state.doc.resolve($pos.pos - $pos.parentOffset - 1);
+ const listNode = this._editorView?.state.doc.nodeAt(clickPos.pos!);
+ if (olistNode && olistNode.type === this._editorView?.state.schema.nodes.ordered_list) {
+ if (!collapse) {
if (!highlightOnly) {
- this._editorView!.dispatch(this._editorView!.state.tr.setSelection(new NodeSelection($olist_pos)));
+ this._editorView!.dispatch(this._editorView!.state.tr.setSelection(new NodeSelection($olistPos!)));
}
- addStyleSheetRule(FormattedTextBox._bulletStyleSheet, list_node.attrs.mapStyle + list_node.attrs.bulletStyle + ":hover:before", { background: "lightgray" });
- } else if (Math.abs(pos.pos - pos.inside) < 2) {
+ addStyleSheetRule(FormattedTextBox._bulletStyleSheet, olistNode.attrs.mapStyle + olistNode.attrs.bulletStyle + ":hover:before", { background: "lightgray" });
+ } else if (listNode && listNode.type === this._editorView.state.schema.nodes.list_item) {
if (!highlightOnly) {
- const offset = this._editorView!.state.doc.nodeAt(pos.inside)?.type === schema.nodes.ordered_list ? 1 : 0;
- this._editorView!.dispatch(this._editorView!.state.tr.setNodeMarkup(pos.inside + offset, list_node.type, { ...list_node.attrs, visibility: !list_node.attrs.visibility }));
- this._editorView!.dispatch(this._editorView!.state.tr.setSelection(TextSelection.create(this._editorView!.state.doc, pos.inside + offset)));
+ this._editorView!.dispatch(this._editorView!.state.tr.setNodeMarkup(clickPos.pos!, listNode.type, { ...listNode.attrs, visibility: !listNode.attrs.visibility }));
+ this._editorView!.dispatch(this._editorView!.state.tr.setSelection(TextSelection.create(this._editorView!.state.doc, clickPos.pos!)));
}
- addStyleSheetRule(FormattedTextBox._bulletStyleSheet, list_node.attrs.mapStyle + list_node.attrs.bulletStyle + ":hover:before", { background: "lightgray" });
+ addStyleSheetRule(FormattedTextBox._bulletStyleSheet, olistNode.attrs.mapStyle + olistNode.attrs.bulletStyle + ":hover:before", { background: "lightgray" });
}
}
}
@@ -1220,6 +1232,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
} else if (FormattedTextBoxComment.textBox === this) {
setTimeout(() => FormattedTextBoxComment.Hide(), 0);
}
+ const selPad = this.props.isSelected() ? -10 : 0;
+ const selclass = this.props.isSelected() ? "-selected" : ""
return (
<div className={"formattedTextBox-cont"} style={{
transform: `scale(${scale})`,
@@ -1260,12 +1274,13 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
})}
>
- <div className={`formattedTextBox-outer`} style={{ width: `calc(100% - ${this.sidebarWidthPercent})`, }} onScroll={this.onscrolled} ref={this._scrollRef}>
- <div className={`formattedTextBox-inner${rounded}`} ref={this.createDropTarget}
+ <div className={`formattedTextBox-outer`} style={{ width: `calc(100% - ${this.sidebarWidthPercent})`, pointerEvents: !this.props.isSelected() ? "none" : undefined }} onScroll={this.onscrolled} ref={this._scrollRef}>
+ <div className={`formattedTextBox-inner${rounded}${selclass}`} ref={this.createDropTarget}
style={{
- padding: `${NumCast(this.layoutDoc._yMargin, this.props.yMargin || 0)}px ${NumCast(this.layoutDoc._xMargin, this.props.xMargin || 0)}px`,
- pointerEvents: ((this.layoutDoc.isLinkButton || this.props.onClick) && !this.props.isSelected()) ? "none" : undefined
- }} />
+ padding: `${Math.max(0, NumCast(this.layoutDoc._yMargin, this.props.yMargin || 0) + selPad)}px ${NumCast(this.layoutDoc._xMargin, this.props.xMargin || 0) + selPad}px`,
+ pointerEvents: !this.props.isSelected() ? ((this.layoutDoc.isLinkButton || this.props.onClick) ? "none" : "all") : undefined
+ }}
+ />
</div>
{!this.layoutDoc._showSidebar ? (null) : this.sidebarWidthPercent === "0%" ?
<div className="formattedTextBox-sidebar-handle" onPointerDown={this.sidebarDown} /> :
diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
index 000b3c2e5..0d8e22251 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
@@ -4,7 +4,7 @@ import { EditorView } from "prosemirror-view";
import * as ReactDOM from 'react-dom';
import { Doc, DocCastAsync } from "../../../../fields/Doc";
import { Cast, FieldValue, NumCast } from "../../../../fields/Types";
-import { emptyFunction, returnEmptyString, returnFalse, Utils, emptyPath, returnZero, returnOne } from "../../../../Utils";
+import { emptyFunction, returnEmptyString, returnFalse, Utils, emptyPath, returnZero, returnOne, returnEmptyFilter } from "../../../../Utils";
import { DocServer } from "../../../DocServer";
import { DocumentManager } from "../../../util/DocumentManager";
import { schema } from "./schema_rts";
@@ -222,9 +222,10 @@ export class FormattedTextBoxComment {
addDocTab={returnFalse}
pinToPres={returnFalse}
dontRegisterView={true}
+ docFilters={returnEmptyFilter}
ContainingCollectionDoc={undefined}
ContainingCollectionView={undefined}
- renderDepth={1}
+ renderDepth={0}
PanelWidth={() => Math.min(350, NumCast(target._width, 350))}
PanelHeight={() => Math.min(250, NumCast(target._height, 250))}
focus={emptyFunction}
diff --git a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
index 0a4c52ef9..75cfe6bd1 100644
--- a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
+++ b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
@@ -16,16 +16,13 @@ const mac = typeof navigator !== "undefined" ? /Mac/.test(navigator.platform) :
export type KeyMap = { [key: string]: any };
-export let updateBullets = (tx2: Transaction, schema: Schema, mapStyle?: string) => {
- let fontSize: number | undefined = undefined;
+export let updateBullets = (tx2: Transaction, schema: Schema, mapStyle?: string, from?: number, to?: number) => {
tx2.doc.descendants((node: any, offset: any, index: any) => {
- if (node.type === schema.nodes.ordered_list || node.type === schema.nodes.list_item) {
+ if ((from === undefined || to === undefined || (from <= offset + node.nodeSize && to >= offset)) && (node.type === schema.nodes.ordered_list || node.type === schema.nodes.list_item)) {
const path = (tx2.doc.resolve(offset) as any).path;
let depth = Array.from(path).reduce((p: number, c: any) => p + (c.hasOwnProperty("type") && c.type === schema.nodes.ordered_list ? 1 : 0), 0);
if (node.type === schema.nodes.ordered_list) depth++;
- fontSize = depth === 1 && node.attrs.setFontSize ? Number(node.attrs.setFontSize) : fontSize;
- const fsize = fontSize && node.type === schema.nodes.ordered_list ? Math.max(6, fontSize - (depth - 1) * 4) : undefined;
- tx2.setNodeMarkup(offset, node.type, { ...node.attrs, mapStyle: mapStyle ? mapStyle : node.attrs.mapStyle, bulletStyle: depth, inheritedFontSize: fsize }, node.marks);
+ tx2.setNodeMarkup(offset, node.type, { ...node.attrs, mapStyle: mapStyle || node.attrs.mapStyle, bulletStyle: depth, }, node.marks);
}
});
return tx2;
@@ -62,7 +59,6 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, props: any
bind("Mod-U", toggleMark(schema.marks.underline));
//Commands for lists
- bind("Ctrl-.", wrapInList(schema.nodes.bullet_list));
bind("Ctrl-i", wrapInList(schema.nodes.ordered_list));
bind("Tab", (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => {
diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx
index 03d393cde..1e14b8237 100644
--- a/src/client/views/nodes/formattedText/RichTextMenu.tsx
+++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx
@@ -104,7 +104,7 @@ export default class RichTextMenu extends AntimodeMenu {
{ node: schema.nodes.ordered_list.create({ mapStyle: "bullet" }), title: "Set list type", label: ":", command: this.changeListType },
{ node: schema.nodes.ordered_list.create({ mapStyle: "decimal" }), title: "Set list type", label: "1.1", command: this.changeListType },
{ node: schema.nodes.ordered_list.create({ mapStyle: "multi" }), title: "Set list type", label: "1.A", command: this.changeListType },
- { node: undefined, title: "Set list type", label: "Remove", command: this.changeListType },
+ //{ node: undefined, title: "Set list type", label: "Remove", command: this.changeListType },
];
this.fontColors = [
@@ -189,9 +189,9 @@ export default class RichTextMenu extends AntimodeMenu {
const node = (state.selection as NodeSelection).node;
if (node?.type === schema.nodes.ordered_list) {
let attrs = node.attrs;
- if (mark.type === schema.marks.pFontFamily) attrs = { ...attrs, setFontFamily: mark.attrs.family };
- if (mark.type === schema.marks.pFontSize) attrs = { ...attrs, setFontSize: mark.attrs.fontSize };
- if (mark.type === schema.marks.pFontColor) attrs = { ...attrs, setFontColor: mark.attrs.color };
+ if (mark.type === schema.marks.pFontFamily) attrs = { ...attrs, fontFamily: mark.attrs.family };
+ if (mark.type === schema.marks.pFontSize) attrs = { ...attrs, fontSize: `${mark.attrs.fontSize}px` };
+ if (mark.type === schema.marks.pFontColor) attrs = { ...attrs, fontColor: mark.attrs.color };
const tr = updateBullets(state.tr.setNodeMarkup(state.selection.from, node.type, attrs), state.schema);
dispatch(tr.setSelection(new NodeSelection(tr.doc.resolve(state.selection.from))));
} else {
@@ -378,26 +378,24 @@ export default class RichTextMenu extends AntimodeMenu {
// TODO: remove doesn't work
//remove all node type and apply the passed-in one to the selected text
- changeListType = (nodeType: NodeType | undefined) => {
+ changeListType = (nodeType: Node | undefined) => {
if (!this.view) return;
- if (nodeType === schema.nodes.bullet_list) {
- wrapInList(nodeType)(this.view.state, this.view.dispatch);
- } else {
- const marks = this.view.state.storedMarks || (this.view.state.selection.$to.parentOffset && this.view.state.selection.$from.marks());
- if (!wrapInList(schema.nodes.ordered_list)(this.view.state, (tx2: any) => {
- const tx3 = updateBullets(tx2, schema, nodeType && (nodeType as any).attrs.mapStyle);
- marks && tx3.ensureMarks([...marks]);
- marks && tx3.setStoredMarks([...marks]);
-
- this.view!.dispatch(tx2);
- })) {
- const tx2 = this.view.state.tr;
- const tx3 = updateBullets(tx2, schema, nodeType && (nodeType as any).attrs.mapStyle);
+ const marks = this.view.state.storedMarks || (this.view.state.selection.$to.parentOffset && this.view.state.selection.$from.marks());
+ if (!wrapInList(schema.nodes.ordered_list)(this.view.state, (tx2: any) => {
+ const tx3 = updateBullets(tx2, schema, nodeType && (nodeType as any).attrs.mapStyle, this.view!.state.selection.from - 1, this.view!.state.selection.to + 1);
+ marks && tx3.ensureMarks([...marks]);
+ marks && tx3.setStoredMarks([...marks]);
+
+ this.view!.dispatch(tx2);
+ })) {
+ const tx2 = this.view.state.tr;
+ if (nodeType && this.view.state.selection.$from.nodeAfter?.type === schema.nodes.ordered_list) {
+ const tx3 = updateBullets(tx2, schema, nodeType && (nodeType as any).attrs.mapStyle, this.view.state.selection.from, this.view.state.selection.to);
marks && tx3.ensureMarks([...marks]);
marks && tx3.setStoredMarks([...marks]);
- this.view.dispatch(tx3);
+ this.view.dispatch(tx3.setSelection(new NodeSelection(tx3.doc.resolve(this.view.state.selection.$from.pos))));
}
}
}
diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts
index 91187edf9..e442149d6 100644
--- a/src/client/views/nodes/formattedText/RichTextRules.ts
+++ b/src/client/views/nodes/formattedText/RichTextRules.ts
@@ -59,7 +59,7 @@ export class RichTextRules {
),
// * + - create bullet list
- wrappingInputRule(/^\s*([-+*])\s$/, schema.nodes.bullet_list),
+ wrappingInputRule(/^\s*([-+*])\s$/, schema.nodes.ordered_list),
// ``` create code block
textblockTypeInputRule(/^```$/, schema.nodes.code_block),
diff --git a/src/client/views/nodes/formattedText/RichTextSchema.tsx b/src/client/views/nodes/formattedText/RichTextSchema.tsx
index 05557e22a..a989abd6a 100644
--- a/src/client/views/nodes/formattedText/RichTextSchema.tsx
+++ b/src/client/views/nodes/formattedText/RichTextSchema.tsx
@@ -152,6 +152,7 @@ export class DashDocView {
whenActiveChanged={returnFalse}
bringToFront={emptyFunction}
dontRegisterView={false}
+ docFilters={this._textBox.props.docFilters}
ContainingCollectionView={this._textBox.props.ContainingCollectionView}
ContainingCollectionDoc={this._textBox.props.ContainingCollectionDoc}
ContentScaling={this.contentScaling}
diff --git a/src/client/views/nodes/formattedText/SummaryView.tsx b/src/client/views/nodes/formattedText/SummaryView.tsx
index 922285bd0..c017db034 100644
--- a/src/client/views/nodes/formattedText/SummaryView.tsx
+++ b/src/client/views/nodes/formattedText/SummaryView.tsx
@@ -14,7 +14,7 @@ export class SummaryView {
const self = this;
this._fieldWrapper = document.createElement("span");
this._fieldWrapper.className = this.className(node.attrs.visibility);
- this._fieldWrapper.onpointerdown = function (e: any) { self.onPointerDown(e, node, view, getPos); }
+ this._fieldWrapper.onpointerdown = function (e: any) { self.onPointerDown(e, node, view, getPos); };
this._fieldWrapper.onkeypress = function (e: any) { e.stopPropagation(); };
this._fieldWrapper.onkeydown = function (e: any) { e.stopPropagation(); };
this._fieldWrapper.onkeyup = function (e: any) { e.stopPropagation(); };
diff --git a/src/client/views/nodes/formattedText/marks_rts.ts b/src/client/views/nodes/formattedText/marks_rts.ts
index 49d5c96a4..1de211f28 100644
--- a/src/client/views/nodes/formattedText/marks_rts.ts
+++ b/src/client/views/nodes/formattedText/marks_rts.ts
@@ -53,21 +53,45 @@ export const marks: { [index: string]: MarkSpec } = {
}
},
+ /** FONT SIZES */
+ pFontSize: {
+ attrs: { fontSize: { default: 10 } },
+ parseDOM: [{
+ tag: "span", getAttrs(dom: any) {
+ return { fontSize: dom.style.fontSize ? Number(dom.style.fontSize.replace("px", "")) : "" };
+ }
+ }],
+ toDOM: (node) => node.attrs.fontSize ? ['span', { style: `font-size: ${node.attrs.fontSize}px;` }] : ['span', 0]
+ },
+ /* FONTS */
+ pFontFamily: {
+ attrs: { family: { default: "" } },
+ parseDOM: [{
+ tag: "span", getAttrs(dom: any) {
+ const cstyle = getComputedStyle(dom);
+ if (cstyle.font) {
+ if (cstyle.font.indexOf("Times New Roman") !== -1) return { family: "Times New Roman" };
+ if (cstyle.font.indexOf("Arial") !== -1) return { family: "Arial" };
+ if (cstyle.font.indexOf("Georgia") !== -1) return { family: "Georgia" };
+ if (cstyle.font.indexOf("Comic Sans") !== -1) return { family: "Comic Sans MS" };
+ if (cstyle.font.indexOf("Tahoma") !== -1) return { family: "Tahoma" };
+ if (cstyle.font.indexOf("Crimson") !== -1) return { family: "Crimson Text" };
+ }
+ }
+ }],
+ toDOM: (node) => node.attrs.family ? ['span', { style: `font-family: "${node.attrs.family}";` }] : ['span', 0]
+ },
// :: MarkSpec Coloring on text. Has `color` attribute that defined the color of the marked text.
pFontColor: {
- attrs: {
- color: { default: "#000" }
- },
+ attrs: { color: { default: "" } },
inclusive: true,
parseDOM: [{
tag: "span", getAttrs(dom: any) {
return { color: dom.getAttribute("color") };
}
}],
- toDOM(node: any) {
- return node.attrs.color ? ['span', { style: 'color:' + node.attrs.color }] : ['span', 0];
- }
+ toDOM: (node) => node.attrs.color ? ['span', { style: 'color:' + node.attrs.color }] : ['span', 0]
},
marker: {
@@ -277,38 +301,4 @@ export const marks: { [index: string]: MarkSpec } = {
parseDOM: [{ tag: "code" }],
toDOM() { return codeDOM; }
},
-
- /* FONTS */
- pFontFamily: {
- attrs: {
- family: { default: "Crimson Text" },
- },
- parseDOM: [{
- tag: "span", getAttrs(dom: any) {
- const cstyle = getComputedStyle(dom);
- if (cstyle.font) {
- if (cstyle.font.indexOf("Times New Roman") !== -1) return { family: "Times New Roman" };
- if (cstyle.font.indexOf("Arial") !== -1) return { family: "Arial" };
- if (cstyle.font.indexOf("Georgia") !== -1) return { family: "Georgia" };
- if (cstyle.font.indexOf("Comic Sans") !== -1) return { family: "Comic Sans MS" };
- if (cstyle.font.indexOf("Tahoma") !== -1) return { family: "Tahoma" };
- if (cstyle.font.indexOf("Crimson") !== -1) return { family: "Crimson Text" };
- }
- }
- }],
- toDOM: (node) => ['span', {
- style: `font-family: "${node.attrs.family}";`
- }]
- },
-
- /** FONT SIZES */
- pFontSize: {
- attrs: {
- fontSize: { default: 10 }
- },
- parseDOM: [{ style: 'font-size: 10px;' }],
- toDOM: (node) => ['span', {
- style: `font-size: ${node.attrs.fontSize}px;`
- }]
- },
};
diff --git a/src/client/views/nodes/formattedText/nodes_rts.ts b/src/client/views/nodes/formattedText/nodes_rts.ts
index af39ef9c7..b37e61d3f 100644
--- a/src/client/views/nodes/formattedText/nodes_rts.ts
+++ b/src/client/views/nodes/formattedText/nodes_rts.ts
@@ -218,48 +218,85 @@ export const nodes: { [index: string]: NodeSpec } = {
group: 'block',
attrs: {
bulletStyle: { default: 0 },
- mapStyle: { default: "decimal" },
- setFontSize: { default: undefined },
- setFontFamily: { default: "inherit" },
- setFontColor: { default: "inherit" },
- inheritedFontSize: { default: undefined },
+ mapStyle: { default: "decimal" },// "decimal", "multi", "bullet"
+ fontColor: { default: "inherit" },
+ fontSize: { default: undefined },
+ fontFamily: { default: undefined },
visibility: { default: true },
indent: { default: undefined }
},
+ parseDOM: [
+ {
+ tag: "ul", getAttrs(dom: any) {
+ return {
+ bulletStyle: dom.getAttribute("data-bulletStyle"),
+ mapStyle: dom.getAttribute("data-mapStyle"),
+ fontColor: dom.style.color,
+ fontSize: dom.style["font-size"],
+ fontFamily: dom.style["font-family"],
+ indent: dom.style["margin-left"]
+ };
+ }
+ },
+ {
+ style: 'list-style-type=disc', getAttrs(dom: any) {
+ return { mapStyle: "bullet" }
+ }
+ },
+ {
+ tag: "ol", getAttrs(dom: any) {
+ return {
+ bulletStyle: dom.getAttribute("data-bulletStyle"),
+ mapStyle: dom.getAttribute("data-mapStyle"),
+ fontColor: dom.style.color,
+ fontSize: dom.style["font-size"],
+ fontFamily: dom.style["font-family"],
+ indent: dom.style["margin-left"]
+ };
+ }
+ }],
toDOM(node: Node<any>) {
- if (node.attrs.mapStyle === "bullet") return ['ul', 0];
const map = node.attrs.bulletStyle ? node.attrs.mapStyle + node.attrs.bulletStyle : "";
- const fsize = node.attrs.setFontSize ? node.attrs.setFontSize : node.attrs.inheritedFontSize;
- const ffam = node.attrs.setFontFamily;
- const color = node.attrs.setFontColor;
+ const fsize = node.attrs.fontSize ? `font-size: ${node.attrs.fontSize};` : "";
+ const ffam = node.attrs.fontFamily ? `font-family:${node.attrs.fontFamily};` : "";
+ const fcol = node.attrs.fontColor ? `color: ${node.attrs.fontColor};` : "";
+ const marg = node.attrs.indent ? `margin-left: ${node.attrs.indent};` : "";
+ if (node.attrs.mapStyle === "bullet") {
+ return ['ul', {
+ "data-mapStyle": node.attrs.mapStyle,
+ "data-bulletStyle": node.attrs.bulletStyle,
+ style: `${fsize} ${ffam} ${fcol} ${marg}`
+ }, 0];
+ }
return node.attrs.visibility ?
- ['ol', { class: `${map}-ol`, style: `list-style: none; font-size: ${fsize}; font-family: ${ffam}; color:${color}; margin-left: ${node.attrs.indent}` }, 0] :
+ ['ol', {
+ class: `${map}-ol`,
+ "data-mapStyle": node.attrs.mapStyle,
+ "data-bulletStyle": node.attrs.bulletStyle,
+ style: `list-style: none; ${fsize} ${ffam} ${fcol} ${marg}`
+ }, 0] :
['ol', { class: `${map}-ol`, style: `list-style: none;` }];
}
},
- bullet_list: {
- ...bulletList,
- content: 'list_item+',
- group: 'block',
- // parseDOM: [{ tag: "ul" }, { style: 'list-style-type=disc' }],
- toDOM(node: Node<any>) {
- return ['ul', 0];
- }
- },
-
list_item: {
+ ...listItem,
attrs: {
bulletStyle: { default: 0 },
- mapStyle: { default: "decimal" },
+ mapStyle: { default: "decimal" }, // "decimal", "multi", "bullet"
visibility: { default: true }
},
- ...listItem,
content: 'paragraph block*',
+ parseDOM: [{
+ tag: "li", getAttrs(dom: any) {
+ return { mapStyle: dom.getAttribute("data-mapStyle"), bulletStyle: dom.getAttribute("data-bulletStyle") };
+ }
+ }],
toDOM(node: any) {
const map = node.attrs.bulletStyle ? node.attrs.mapStyle + node.attrs.bulletStyle : "";
- return node.attrs.visibility ? ["li", { class: `${map}` }, 0] : ["li", { class: `${map}` }, "..."];
- //return ["li", { class: `${map}` }, 0];
+ return node.attrs.visibility ?
+ ["li", { class: `${map}`, "data-mapStyle": node.attrs.mapStyle, "data-bulletStyle": node.attrs.bulletStyle }, 0] :
+ ["li", { class: `${map}`, "data-mapStyle": node.attrs.mapStyle, "data-bulletStyle": node.attrs.bulletStyle }, "..."];
}
},
}; \ No newline at end of file
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 57b7bceca..ce0ef1f3c 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -51,6 +51,7 @@ interface IViewerProps {
fieldKey: string;
Document: Doc;
DataDoc?: Doc;
+ docFilters: () => string[];
ContainingCollectionView: Opt<CollectionView>;
PanelWidth: () => number;
PanelHeight: () => number;
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index 793d4068f..6fd3455b6 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -194,6 +194,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
whenActiveChanged={returnFalse}
bringToFront={returnFalse}
opacity={returnOne}
+ docFilters={this.props.docFilters}
ContainingCollectionView={undefined}
ContainingCollectionDoc={undefined}
ContentScaling={returnOne}
diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx
index 24d6e9d6f..74262d81a 100644
--- a/src/client/views/search/SearchItem.tsx
+++ b/src/client/views/search/SearchItem.tsx
@@ -7,7 +7,7 @@ import { observer } from "mobx-react";
import { Doc } from "../../../fields/Doc";
import { Id } from "../../../fields/FieldSymbols";
import { Cast, NumCast, StrCast } from "../../../fields/Types";
-import { emptyFunction, emptyPath, returnFalse, Utils, returnTrue, returnOne, returnZero } from "../../../Utils";
+import { emptyFunction, emptyPath, returnFalse, Utils, returnTrue, returnOne, returnZero, returnEmptyString, returnEmptyFilter } from "../../../Utils";
import { DocumentType } from "../../documents/DocumentTypes";
import { DocumentManager } from "../../util/DocumentManager";
import { DragManager, SetupDrag } from "../../util/DragManager";
@@ -164,6 +164,7 @@ export class SearchItem extends React.Component<SearchItemProps> {
removeDocument={returnFalse}
addDocTab={returnFalse}
pinToPres={returnFalse}
+ docFilters={returnEmptyFilter}
ContainingCollectionDoc={undefined}
ContainingCollectionView={undefined}
ScreenToLocalTransform={Transform.Identity}
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 96587af44..8c8720179 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -134,7 +134,7 @@ export class Doc extends RefField {
has: (target, key) => target[AclSym] !== AclPrivate && key in target.__fields,
ownKeys: target => {
const obj = {} as any;
- (target[AclSym] !== AclPrivate) && Object.assign(obj, target.___fields);
+ if (target[AclSym] !== AclPrivate) Object.assign(obj, target.___fields);
runInAction(() => obj.__LAYOUT__ = target.__LAYOUT__);
return Object.keys(obj);
},
diff --git a/src/fields/RichTextUtils.ts b/src/fields/RichTextUtils.ts
index 66959882d..7c7bf3e12 100644
--- a/src/fields/RichTextUtils.ts
+++ b/src/fields/RichTextUtils.ts
@@ -256,7 +256,7 @@ export namespace RichTextUtils {
};
const list = (schema: any, items: Node[]): Node => {
- return schema.node("bullet_list", null, items);
+ return schema.node("ordered_list", { mapStyle: "bullet" }, items);
};
const paragraphNode = (schema: any, runs: docs_v1.Schema$TextRun[]): Node => {
diff --git a/src/fields/util.ts b/src/fields/util.ts
index 54e7eca28..ad7b6ea7a 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -101,12 +101,16 @@ export function makeReadOnly() {
export function makeEditable() {
_setter = _setterImpl;
}
+var _overrideAcl = false;
+export function OVERRIDE_ACL(val: boolean) {
+ _overrideAcl = val;
+}
const layoutProps = ["panX", "panY", "width", "height", "nativeWidth", "nativeHeight", "fitWidth", "fitToBox",
"LODdisable", "chromeStatus", "viewType", "gridGap", "xMargin", "yMargin", "autoHeight"];
export function setter(target: any, in_prop: string | symbol | number, value: any, receiver: any): boolean {
let prop = in_prop;
- if (target[AclSym]) return true;
+ if (target[AclSym] && !_overrideAcl) return true;
if (typeof prop === "string" && prop !== "__id" && prop !== "__fields" && (prop.startsWith("_") || layoutProps.includes(prop))) {
if (!prop.startsWith("_")) {
console.log(prop + " is deprecated - switch to _" + prop);
@@ -125,8 +129,8 @@ export function setter(target: any, in_prop: string | symbol | number, value: an
export function getter(target: any, in_prop: string | symbol | number, receiver: any): any {
let prop = in_prop;
- if (in_prop === AclSym) return target[AclSym];
- if (target[AclSym] === AclPrivate) return undefined;
+ if (in_prop === AclSym) return _overrideAcl ? undefined : target[AclSym];
+ if (target[AclSym] === AclPrivate && !_overrideAcl) return undefined;
if (prop === LayoutSym) {
return target.__LAYOUT__;
}
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index ceda74da2..a1719c015 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -9,13 +9,12 @@ import {
faThumbtack, faTree, faTv, faBook, faUndoAlt, faVideo, faAsterisk, faBrain, faImage, faPaintBrush, faTimes, faEye, faHome, faLongArrowAltLeft, faBars, faTh, faChevronLeft
} from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, observable } from 'mobx';
+import { action, computed, observable, reaction } from 'mobx';
import { observer } from 'mobx-react';
import * as rp from 'request-promise';
import { Doc, DocListCast } from '../fields/Doc';
-import { FieldValue, Cast } from '../fields/Types';
import { CurrentUserUtils } from '../client/util/CurrentUserUtils';
-import { emptyPath, emptyFunction, returnFalse, returnOne, returnTrue, returnZero, Utils } from '../Utils';
+import { emptyFunction, emptyPath, returnEmptyString, returnFalse, returnOne, returnTrue, returnZero, returnEmptyFilter } from '../Utils';
import { DocServer } from '../client/DocServer';
import { Docs, DocumentOptions } from '../client/documents/Documents';
import { Scripting } from '../client/util/Scripting';
@@ -37,10 +36,13 @@ import GestureOverlay from "../client/views/GestureOverlay";
import { ScriptField } from "../fields/ScriptField";
import InkOptionsMenu from "../client/views/collections/collectionFreeForm/InkOptionsMenu";
import { RadialMenu } from "../client/views/nodes/RadialMenu";
-import { UndoManager } from "../client/util/UndoManager";
+import { UndoManager, undoBatch } from "../client/util/UndoManager";
import { MainView } from "../client/views/MainView";
import { List } from "../fields/List";
import { AudioUpload } from "./AudioUpload";
+import { Cast, FieldValue } from '../fields/Types';
+import { CollectionView } from '../client/views/collections/CollectionView';
+import { InkingStroke } from '../client/views/InkingStroke';
library.add(faTasks, faFolderOpen, faAngleDoubleLeft, faExternalLinkSquareAlt, faMobile, faThLarge, faWindowClose, faEdit, faTrashAlt, faPalette, faAngleRight, faBell, faTrash, faCamera, faExpand, faCaretDown, faCaretLeft, faCaretRight, faCaretSquareDown, faCaretSquareRight, faArrowsAltH, faPlus, faMinus,
faTerminal, faToggleOn, fileSolid, faExternalLinkAlt, faLocationArrow, faSearch, faFileDownload, faStop, faCalculator, faWindowMaximize, faAddressCard,
@@ -215,6 +217,7 @@ export class MobileInterface extends React.Component {
parentActive={returnTrue}
whenActiveChanged={emptyFunction}
bringToFront={emptyFunction}
+ docFilters={returnEmptyFilter}
ContainingCollectionView={undefined}
ContainingCollectionDoc={undefined}
/>
@@ -236,6 +239,7 @@ export class MobileInterface extends React.Component {
* Navigates to the given doc and updates the sidebar.
* @param doc: doc for which the method is called
*/
+ @undoBatch
handleClick = async (doc: Doc) => {
const children = DocListCast(doc.data);
if (doc.type !== "collection" && this.sidebarActive) this.openFromSidebar(doc);
@@ -508,11 +512,12 @@ export class MobileInterface extends React.Component {
}
}
+
undo = () => {
if (this._activeDoc.type === "collection" && this._activeDoc !== this._homeDoc && this._activeDoc.title !== "WORKSPACES") {
return (<>
<div className="docButton"
- style={{ backgroundColor: "black", color: "white" }}
+ style={{ backgroundColor: "black", color: "white", fontSize: "60", opacity: UndoManager.CanUndo() ? "1" : "0.4", }}
id="undoButton"
title="undo"
onClick={(e: React.MouseEvent) => {
@@ -529,7 +534,7 @@ export class MobileInterface extends React.Component {
if (this._activeDoc.type === "collection" && this._activeDoc !== this._homeDoc && this._activeDoc.title !== "WORKSPACES") {
return (<>
<div className="docButton"
- style={{ backgroundColor: "black", color: "white" }}
+ style={{ backgroundColor: "black", color: "white", fontSize: "60", opacity: UndoManager.CanRedo() ? "1" : "0.4", }}
id="undoButton"
title="redo"
onClick={(e: React.MouseEvent) => {
@@ -831,8 +836,10 @@ export class MobileInterface extends React.Component {
-Scripting.addGlobal(function switchMobileView(doc: (userDoc: Doc) => Doc, renderView?: () => JSX.Element, onSwitch?: () => void) { return MobileInterface.Instance.switchCurrentView(doc, renderView, onSwitch); });
-Scripting.addGlobal(function openMobilePresentation() { return MobileInterface.Instance.setupDefaultPresentation(); });
+Scripting.addGlobal(function switchMobileView(doc: (userDoc: Doc) => Doc, renderView?: () => JSX.Element, onSwitch?: () => void) { return MobileInterface.Instance.switchCurrentView(doc, renderView, onSwitch); },
+ "changes the active document displayed on the mobile, (doc: any)");
+Scripting.addGlobal(function openMobilePresentation() { return MobileInterface.Instance.setupDefaultPresentation(); },
+ "opens the presentation on mobile");
Scripting.addGlobal(function toggleMobileSidebar() { return MobileInterface.Instance.toggleSidebar(); });
Scripting.addGlobal(function openMobileAudio() { return MobileInterface.Instance.toggleAudio(); });
Scripting.addGlobal(function openMobileSettings() { return SettingsManager.Instance.open(); });