aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/documents/Documents.ts23
-rw-r--r--src/client/util/CurrentUserUtils.ts12
-rw-r--r--src/client/util/ScrollBox.tsx24
-rw-r--r--src/client/views/TouchScrollableMenu.tsx63
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx2
-rw-r--r--src/client/views/nodes/DocumentView.tsx116
6 files changed, 66 insertions, 174 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index a0870ba43..ee3bf0d82 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -59,6 +59,7 @@ import { WebBox } from '../views/nodes/WebBox';
import { SearchBox } from '../views/search/SearchBox';
import { CollectionViewType, DocumentType } from './DocumentTypes';
import { CalendarBox } from '../views/nodes/calendarBox/CalendarBox';
+import { OpenWhere } from '../views/nodes/DocumentView';
const { default: { DFLT_IMAGE_NATIVE_DIM } } = require('../views/global/globalCssVariables.module.scss'); // prettier-ignore
const defaultNativeImageDim = Number(DFLT_IMAGE_NATIVE_DIM.replace('px', ''));
@@ -407,7 +408,7 @@ export class DocumentOptions {
onChildClick?: ScriptField; // script given to children of a collection to execute when they are clicked
onChildDoubleClick?: ScriptField; // script given to children of a collection to execute when they are double clicked
onClickScriptDisable?: STRt = new StrInfo('"always" disable click script, "never" disable click script, or default');
- defaultDoubleClick?: 'ignore' | 'default'; // ignore double clicks, or deafult (undefined) means open document full screen
+ defaultDoubleClick?: 'ignore' | 'default'; // ignore double clicks, or default (undefined) means open document full screen
waitForDoubleClickToClick?: 'always' | 'never' | 'default'; // whether a click function wait for double click to expire. 'default' undefined = wait only if there's a click handler, "never" = never wait, "always" = alway wait
onPointerDown?: ScriptField;
onPointerUp?: ScriptField;
@@ -1102,7 +1103,7 @@ export namespace Docs {
I.stroke_isInkMask = isInkMask;
I.text_align = 'center';
I.rotation = 0;
- I.defaultDoubleClick = 'click';
+ I.defaultDoubleClick = 'ignore';
I.author_date = new DateField();
I['acl-Guest'] = Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.View;
//I['acl-Override'] = SharingPermissions.Unset;
@@ -1796,6 +1797,24 @@ export namespace DocUtils {
return newCollection;
}
}
+ export function makeIntoPortal(doc: Doc, layoutDoc: Doc, allLinks: Doc[]) {
+ const portalLink = allLinks.find(d => d.link_anchor_1 === doc && d.link_relationship === 'portal to:portal from');
+ if (!portalLink) {
+ DocUtils.MakeLink(
+ doc,
+ Docs.Create.FreeformDocument([], {
+ _width: NumCast(layoutDoc._width) + 10,
+ _height: Math.max(NumCast(layoutDoc._height), NumCast(layoutDoc._width) + 10),
+ _isLightbox: true,
+ _layout_fitWidth: true,
+ title: StrCast(doc.title) + ' [Portal]',
+ }),
+ { link_relationship: 'portal to:portal from' }
+ );
+ }
+ doc.followLinkLocation = OpenWhere.lightbox;
+ doc.onClick = FollowLinkScript();
+ }
export function LeavePushpin(doc: Doc, annotationField: string) {
if (doc.followLinkToggle) return undefined;
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 07ee777cd..6ddb65941 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -604,12 +604,12 @@ export class CurrentUserUtils {
CurrentUserUtils.createToolButton(opts), scripts, funcs);
const btnDescs = [// setup reactions to change the highlights on the undo/redo buttons -- would be better to encode this in the undo/redo buttons, but the undo/redo stacks are not wired up that way yet
- { scripts: { onClick: "undo()"}, opts: { title: "Undo", icon: "undo-alt", toolTip: "Undo ⌘Z" }},
- { scripts: { onClick: "redo()"}, opts: { title: "Redo", icon: "redo-alt", toolTip: "Redo ⌘⇧Z" }},
- { scripts: { }, opts: { title: "undoStack", layout: "<UndoStack>", toolTip: "Undo/Redo Stack"}}, // note: layout fields are hacks -- they don't actually run through the JSX parser (yet)
- { scripts: { }, opts: { title: "linker", layout: "<LinkingUI>", toolTip: "link started"}},
- { scripts: { }, opts: { title: "currently playing", layout: "<CurrentlyPlayingUI>", toolTip: "currently playing media"}},
- { scripts: { }, opts: { title: "Branching", layout: "<Branching>", toolTip: "Branch, baby!"}}
+ { scripts: { onClick: "undo()"}, opts: { title: "Undo", icon: "undo-alt", toolTip: "Undo ⌘Z" }},
+ { scripts: { onClick: "redo()"}, opts: { title: "Redo", icon: "redo-alt", toolTip: "Redo ⌘⇧Z" }},
+ { scripts: { }, opts: { title: "undoStack", layout: "<UndoStack>", toolTip: "Undo/Redo Stack"}}, // note: layout fields are hacks -- they don't actually run through the JSX parser (yet)
+ { scripts: { }, opts: { title: "linker", layout: "<LinkingUI>", toolTip: "link started"}},
+ { scripts: { }, opts: { title: "currently playing", layout: "<CurrentlyPlayingUI>", toolTip: "currently playing media"}},
+ { scripts: { }, opts: { title: "Branching", layout: "<Branching>", toolTip: "Branch, baby!"}}
];
const btns = btnDescs.map(desc => dockBtn({_width: 30, _height: 30, defaultDoubleClick: 'ignore', undoIgnoreFields: new List<string>(['opacity']), _dragOnlyWithinContainer: true, ...desc.opts}, desc.scripts));
const dockBtnsReqdOpts:DocumentOptions = {
diff --git a/src/client/util/ScrollBox.tsx b/src/client/util/ScrollBox.tsx
deleted file mode 100644
index 785526ab3..000000000
--- a/src/client/util/ScrollBox.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import * as React from 'react';
-
-export class ScrollBox extends React.Component<React.PropsWithChildren<{}>> {
- onWheel = (e: React.WheelEvent) => {
- if (e.currentTarget.scrollHeight > e.currentTarget.clientHeight) {
- // If the element has a scroll bar, then we don't want the containing collection to zoom
- e.stopPropagation();
- }
- };
-
- render() {
- return (
- <div
- style={{
- overflow: 'auto',
- width: '100%',
- height: '100%',
- }}
- onWheel={this.onWheel}>
- {this.props.children}
- </div>
- );
- }
-}
diff --git a/src/client/views/TouchScrollableMenu.tsx b/src/client/views/TouchScrollableMenu.tsx
deleted file mode 100644
index 530c693a7..000000000
--- a/src/client/views/TouchScrollableMenu.tsx
+++ /dev/null
@@ -1,63 +0,0 @@
-import * as React from 'react';
-import { computed } from 'mobx';
-import { observer } from 'mobx-react';
-
-export interface TouchScrollableMenuProps {
- options: JSX.Element[];
- bounds: {
- right: number;
- left: number;
- bottom: number;
- top: number;
- width: number;
- height: number;
- };
- selectedIndex: number;
- x: number;
- y: number;
-}
-
-export interface TouchScrollableMenuItemProps {
- text: string;
- onClick: () => any;
-}
-
-@observer
-export default class TouchScrollableMenu extends React.Component<TouchScrollableMenuProps> {
- @computed
- private get possibilities() {
- return this.props.options;
- }
-
- @computed
- private get selectedIndex() {
- return this.props.selectedIndex;
- }
-
- render() {
- return (
- <div
- className="inkToTextDoc-cont"
- style={{
- transform: `translate(${this.props.x}px, ${this.props.y}px)`,
- width: 300,
- height: this.possibilities.length * 25,
- }}>
- <div className="inkToTextDoc-scroller" style={{ transform: `translate(0, ${-this.selectedIndex * 25}px)` }}>
- {this.possibilities}
- </div>
- <div className="shadow" style={{ height: `calc(100% - 25px - ${this.selectedIndex * 25}px)` }}></div>
- </div>
- );
- }
-}
-
-export class TouchScrollableMenuItem extends React.Component<TouchScrollableMenuItemProps> {
- render() {
- return (
- <div className="menuItem-cont" onClick={this.props.onClick}>
- {this.props.text}
- </div>
- );
- }
-}
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index c2f8232c6..a9910c2a8 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -219,7 +219,7 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps
const scrollMode = e.altKey ? (Doc.UserDoc().freeformScrollMode === freeformScrollMode.Pan ? freeformScrollMode.Zoom : freeformScrollMode.Pan) : Doc.UserDoc().freeformScrollMode;
// allow marquee if right drag/meta drag, or pan mode
- if (e.button === 2 || e.metaKey || scrollMode === freeformScrollMode.Pan) {
+ if (e.button === 2 || e.metaKey || (this._props.isContentActive() && scrollMode === freeformScrollMode.Pan)) {
this.setPreviewCursor(e.clientX, e.clientY, true, false, this._props.Document);
e.preventDefault();
} else PreviewCursor.Instance.Visible = false;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 8eb354e1e..a82580ddb 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -236,16 +236,15 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
runInAction(() => (this._mounted = true));
this.setupHandlers();
this._disposers.contentActive = reaction(
- () => {
+ () =>
// true - if the document has been activated directly or indirectly (by having its children selected)
// false - if its pointer events are explicitly turned off or if it's container tells it that it's inactive
// undefined - it is not active, but it should be responsive to actions that might activate it or its contents (eg clicking)
- return this._props.isContentActive() === false || this._props.pointerEvents?.() === 'none'
+ this._props.isContentActive() === false || this._props.pointerEvents?.() === 'none'
? false
: Doc.ActiveTool !== InkTool.None || SnappingManager.CanEmbed || this.rootSelected() || this.Document.forceActive || this._componentView?.isAnyChildContentActive?.() || this._props.isContentActive()
? true
- : undefined;
- },
+ : undefined,
active => (this._isContentActive = active),
{ fireImmediately: true }
);
@@ -312,20 +311,23 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
let stopPropagate = true;
let preventDefault = true;
!this.layoutDoc._keepZWhenDragged && this._props.bringToFront?.(this.Document);
+ const scriptProps = {
+ this: this.Document,
+ _readOnly_: false,
+ scriptContext: this._props.scriptContext,
+ documentView,
+ clientX: e.clientX,
+ clientY: e.clientY,
+ shiftKey: e.shiftKey,
+ altKey: e.altKey,
+ metaKey: e.metaKey,
+ value: undefined,
+ };
if (this._doubleTap) {
const defaultDblclick = this._props.defaultDoubleClick?.() || this.Document.defaultDoubleClick;
if (this.onDoubleClickHandler?.script) {
- const { clientX, clientY, shiftKey, altKey, ctrlKey } = e; // or we could call e.persist() to capture variables
- // prettier-ignore
- const func = () => this.onDoubleClickHandler.script.run( {
- this: this.Document,
- scriptContext: this._props.scriptContext,
- documentView,
- clientX, clientY, altKey, shiftKey, ctrlKey,
- value: undefined,
- }, console.log );
- UndoManager.RunInBatch(() => (func().result?.select === true ? this._props.select(false) : ''), 'on double click');
- } else if (!Doc.IsSystem(this.Document) && (defaultDblclick === undefined || defaultDblclick === 'default')) {
+ UndoManager.RunInBatch(() => this.onDoubleClickHandler.script.run(scriptProps, console.log).result?.select && this._props.select(false), 'on double click: ' + this.Document.title);
+ } else if (!Doc.IsSystem(this.Document) && defaultDblclick !== 'ignore') {
UndoManager.RunInBatch(() => LightboxView.Instance.AddDocTab(this.Document, OpenWhere.lightbox), 'double tap');
SelectionManager.DeselectAll();
Doc.UnBrushDoc(this.Document);
@@ -338,33 +340,14 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
} else {
let clickFunc: undefined | (() => any);
if (!this.disableClickScriptFunc && this.onClickHandler?.script) {
- const { clientX, clientY, shiftKey, altKey, metaKey } = e;
- const func = () => {
- // replace default add doc func with this view's add doc func.
- // to allow override behaviors for how to display links to undisplayed documents.
- // e.g., if this document is part of a labeled 'lightbox' container, then documents will be shown in place
- // instead of in the global lightbox
+ clickFunc = undoable(() => {
+ // use this view's add doc func to override method for following links to undisplayed documents.
+ // e.g., if this document is part of a labeled 'lightbox' container, then documents will be shown in this container of in the global lightbox
const oldFunc = DocumentViewInternal.addDocTabFunc;
DocumentViewInternal.addDocTabFunc = this._props.addDocTab;
- this.onClickHandler?.script.run(
- {
- this: this.Document,
- _readOnly_: false,
- scriptContext: this._props.scriptContext,
- documentView,
- clientX,
- clientY,
- shiftKey,
- altKey,
- metaKey,
- },
- console.log
- ).result?.select === true
- ? this._props.select(false)
- : '';
+ this.onClickHandler?.script.run(scriptProps, console.log).result?.select && this._props.select(false);
DocumentViewInternal.addDocTabFunc = oldFunc;
- };
- clickFunc = () => UndoManager.RunInBatch(func, 'click ' + this.Document.title);
+ }, 'click ' + this.Document.title);
} else {
// onDragStart implies a button doc that we don't want to select when clicking. RootDocument & isTemplateForField implies we're clicking on part of a template instance and we want to select the whole template, not the part
if ((this.layoutDoc.onDragStart || this._props.TemplateDataDocument) && !(e.ctrlKey || e.button > 0)) {
@@ -412,10 +395,9 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
!Doc.IsInMyOverlay(this.layoutDoc)
) {
e.stopPropagation();
- // don't preventDefault anymore. Goldenlayout, PDF text selection and RTF text selection all need it to go though
- //if (this._props.isSelected(true) && this.Document.type !== DocumentType.PDF && this.layoutDoc._type_collection !== CollectionViewType.Docking) e.preventDefault();
+ // don't preventDefault. Goldenlayout, PDF text selection and RTF text selection all need it to go though
- // listen to move events if document content isn't active or document is draggable
+ // listen to move events when document content isn't active or document is always draggable
if (!this.layoutDoc._lockedPosition && (!this.isContentActive() || BoolCast(this.layoutDoc._dragWhenActive, this._props.dragWhenActive))) {
document.addEventListener('pointermove', this.onPointerMove);
}
@@ -489,26 +471,24 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
if (this.Document === Doc.ActiveDashboard) {
e.stopPropagation();
e.preventDefault();
- alert(
- (e.target as any)?.closest?.('*.lm_content')
- ? "You can't perform this move most likely because you didn't drag the document's title bar to enable embedding in a different document."
- : 'Linking to document tabs not yet supported. Drop link on document content.'
- );
+ alert((e.target as any)?.closest?.('*.lm_content') ? "You can't perform this move most likely because you didn't drag the document's title bar to enable embedding in a different document." : 'Linking to document tabs not yet supported.');
return true;
}
- const linkdrag = de.complete.annoDragData ?? de.complete.linkDragData;
+ const annoData = de.complete.annoDragData;
+ const linkdrag = annoData ?? de.complete.linkDragData;
if (linkdrag) {
linkdrag.linkSourceDoc = linkdrag.linkSourceGetAnchor();
if (linkdrag.linkSourceDoc && linkdrag.linkSourceDoc !== this.Document) {
- if (de.complete.annoDragData && !de.complete.annoDragData.dropDocument) {
- de.complete.annoDragData.dropDocument = de.complete.annoDragData.dropDocCreator(undefined);
+ if (annoData && !annoData.dropDocument) {
+ annoData.dropDocument = annoData.dropDocCreator(undefined);
}
- if (de.complete.annoDragData || this.Document !== linkdrag.linkSourceDoc.embedContainer) {
- const dropDoc = de.complete.annoDragData?.dropDocument ?? this._componentView?.getAnchor?.(true) ?? this.Document;
- de.complete.linkDocument = DocUtils.MakeLink(linkdrag.linkSourceDoc, dropDoc, {}, undefined, [de.x, de.y - 50]);
- if (de.complete.linkDocument) {
- de.complete.linkDocument.layout_isSvg = true;
- this._docView?.CollectionFreeFormView?.addDocument(de.complete.linkDocument);
+ if (annoData || this.Document !== linkdrag.linkSourceDoc.embedContainer) {
+ const dropDoc = annoData?.dropDocument ?? this._componentView?.getAnchor?.(true) ?? this.Document;
+ const linkDoc = DocUtils.MakeLink(linkdrag.linkSourceDoc, dropDoc, {}, undefined, [de.x, de.y - 50]);
+ if (linkDoc) {
+ de.complete.linkDocument = linkDoc;
+ linkDoc.layout_isSvg = true;
+ this._docView?.CollectionFreeFormView?.addDocument(linkDoc);
}
}
e.stopPropagation();
@@ -518,25 +498,6 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
return false;
}, 'drop doc');
- makeIntoPortal = undoable(() => {
- const portalLink = this._allLinks.find(d => d.link_anchor_1 === this.Document && d.link_relationship === 'portal to:portal from');
- if (!portalLink) {
- DocUtils.MakeLink(
- this.Document,
- Docs.Create.FreeformDocument([], {
- _width: NumCast(this.layoutDoc._width) + 10,
- _height: Math.max(NumCast(this.layoutDoc._height), NumCast(this.layoutDoc._width) + 10),
- _isLightbox: true,
- _layout_fitWidth: true,
- title: StrCast(this.Document.title) + ' [Portal]',
- }),
- { link_relationship: 'portal to:portal from' }
- );
- }
- this.Document.followLinkLocation = OpenWhere.lightbox;
- this.Document.onClick = FollowLinkScript();
- }, 'make into portal');
-
importDocument = () => {
const input = document.createElement('input');
input.type = 'file';
@@ -627,7 +588,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
const existingOnClick = cm.findByDescription('OnClick...');
const onClicks: ContextMenuProps[] = existingOnClick && 'subitems' in existingOnClick ? existingOnClick.subitems : [];
- onClicks.push({ description: 'Enter Portal', event: this.makeIntoPortal, icon: 'window-restore' });
+ onClicks.push({ description: 'Enter Portal', event: undoable(e => DocUtils.makeIntoPortal(this.Document, this.layoutDoc, this._allLinks), 'make into portal'), icon: 'window-restore' });
!Doc.noviceMode && onClicks.push({ description: 'Toggle Detail', event: this.setToggleDetail, icon: 'concierge-bell' });
if (!this.Document.annotationOn) {
@@ -818,7 +779,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
rootSelected={this.rootSelected}
onClickScript={this.onClickFunc}
setTitleFocus={this.setTitleFocus}
- hideClickBehaviors={BoolCast(this.layoutDoc.hideClickBehaviors)}
+ hideClickBehaviors={BoolCast(this.Document.hideClickBehaviors)}
/>
{this.layoutDoc.layout_hideAllLinks ? null : this.allLinkEndpoints()}
</div>
@@ -1254,7 +1215,6 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
this.layoutDoc._viewTransition = undefined;
};
public noOnClick = () => this._docViewInternal?.noOnClick();
- public makeIntoPortal = () => this._docViewInternal?.makeIntoPortal();
public toggleFollowLink = (zoom?: boolean, setTargetToggle?: boolean): void => this._docViewInternal?.toggleFollowLink(zoom, setTargetToggle);
public setToggleDetail = () => this._docViewInternal?.setToggleDetail();
public onContextMenu = (e?: React.MouseEvent, pageX?: number, pageY?: number) => this._docViewInternal?.onContextMenu?.(e, pageX, pageY);