aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/documents/Documents.ts1
-rw-r--r--src/client/views/DocumentDecorations.scss5
-rw-r--r--src/client/views/DocumentDecorations.tsx4
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx5
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx137
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx2
-rw-r--r--src/client/views/nodes/DocumentView.tsx18
-rw-r--r--src/fields/Doc.ts25
8 files changed, 109 insertions, 88 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 5b32bf76a..38fe04534 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -514,6 +514,7 @@ export namespace Docs {
const dataDoc = MakeDataDelegate(proto, protoProps, data, fieldKey);
const viewDoc = Doc.MakeDelegate(dataDoc, delegId);
+ viewDoc.author = Doc.CurrentUserEmail;
viewDoc.type !== DocumentType.LINK && DocUtils.MakeLinkToActiveAudio(viewDoc);
return Doc.assign(viewDoc, delegateProps, true);
diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss
index a4d4af2f0..0a96b058b 100644
--- a/src/client/views/DocumentDecorations.scss
+++ b/src/client/views/DocumentDecorations.scss
@@ -152,6 +152,11 @@ $linkGap : 3px;
text-align: center;
display: flex;
border-bottom: solid 1px;
+ margin-left:10px;
+ width: calc(100% - 10px);
+ }
+ .focus-visible {
+ margin-left:0px;
}
.publishBox {
width: 20px;
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 04f02c683..e7a237e62 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -466,7 +466,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
const titleArea = this._edtingTitle ?
<>
- <input ref={this._keyinput} className="documentDecorations-title" type="text" name="dynbox" autoComplete="on" value={this._accumulatedTitle} style={{ width: minimal ? "100%" : "calc(100% - 20px)" }}
+ <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 => {
@@ -485,7 +485,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
<FontAwesomeIcon size="lg" icon="cog" />
</div>}
<div className="documentDecorations-title" key="title" onPointerDown={this.onTitleDown} >
- <span style={{ width: "calc(100% - 25px)", display: "inline-block" }}>{`${this.selectionTitle}`}</span>
+ <span style={{ width: "100%", display: "inline-block" }}>{`${this.selectionTitle}`}</span>
</div>
</>;
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 7fd19a23c..bd48d1727 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -474,7 +474,10 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument)
width: `${1 / this.scaling * 100}%`,
transformOrigin: "top left",
}}
- onScroll={action((e: React.UIEvent<HTMLDivElement>) => this._scroll = e.currentTarget.scrollTop)}
+ onScroll={action(e => {
+ if (!this.props.isSelected()) e.currentTarget.scrollTop = this._scroll;
+ else this._scroll = e.currentTarget.scrollTop;
+ })}
onDrop={this.onExternalDrop.bind(this)}
onContextMenu={this.onContextMenu}
onWheel={e => this.props.active() && e.stopPropagation()} >
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index c753a703d..fc5e61026 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -46,7 +46,6 @@ import React = require("react");
import { CollectionViewType } from "../CollectionView";
import { Timeline } from "../../animationtimeline/Timeline";
import { SnappingManager } from "../../../util/SnappingManager";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
library.add(faEye as any, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt, faCompass, faUpload, faBraille, faChalkboard, faFileUpload);
@@ -119,10 +118,12 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
this.Document.scale || 1)
@computed get cachedCenteringShiftX(): number {
- return !this.isAnnotationOverlay ? this.props.PanelWidth() / 2 / this.parentScaling / this.contentScaling : 0; // shift so pan position is at center of window for non-overlay collections
+ const scaling = this.fitToContent ? 1 : this.contentScaling;
+ return !this.isAnnotationOverlay ? this.props.PanelWidth() / 2 / this.parentScaling / scaling : 0; // shift so pan position is at center of window for non-overlay collections
}
@computed get cachedCenteringShiftY(): number {
- return !this.isAnnotationOverlay ? this.props.PanelHeight() / 2 / this.parentScaling / this.contentScaling : 0;// shift so pan position is at center of window for non-overlay collections
+ const scaling = this.fitToContent ? 1 : this.contentScaling;
+ return !this.isAnnotationOverlay ? this.props.PanelHeight() / 2 / this.parentScaling / scaling : 0;// shift so pan position is at center of window for non-overlay collections
}
@computed get cachedGetLocalTransform(): Transform {
return Transform.Identity().scale(1 / this.zoomScaling()).translate(this.panX(), this.panY());
@@ -188,79 +189,76 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
return this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map(pair => pair.layout);
}
+ onExternalDrop = (e: React.DragEvent) => {
+ return (pt => super.onExternalDrop(e, { x: pt[0], y: pt[1] }))(this.getTransform().transformPoint(e.pageX, e.pageY));
+ }
+
+ @undoBatch
+ @action
+ internalDocDrop(e: Event, de: DragManager.DropEvent, docDragData: DragManager.DocumentDragData, xp: number, yp: number) {
+ if (!super.onInternalDrop(e, de)) return false;
+ const [xpo, ypo] = this.getTransformOverlay().transformPoint(de.x, de.y);
+ const z = NumCast(docDragData.droppedDocuments[0].z);
+ const x = (z ? xpo : xp) - docDragData.offset[0];
+ const y = (z ? ypo : yp) - docDragData.offset[1];
+ const zsorted = this.childLayoutPairs.map(pair => pair.layout).slice().sort((doc1, doc2) => NumCast(doc1.zIndex) - NumCast(doc2.zIndex));
+ zsorted.forEach((doc, index) => doc.zIndex = index + 1);
+ const dropPos = [NumCast(docDragData.droppedDocuments[0].x), NumCast(docDragData.droppedDocuments[0].y)];
+ for (let i = 0; i < docDragData.droppedDocuments.length; i++) {
+ const d = docDragData.droppedDocuments[i];
+ const layoutDoc = Doc.Layout(d);
+ if (this.Document.currentFrame !== undefined && !this.props.isAnnotationOverlay) {
+ const vals = CollectionFreeFormDocumentView.getValues(d, NumCast(d.activeFrame, 1000));
+ CollectionFreeFormDocumentView.setValues(this.Document.currentFrame, d, x + vals.x - dropPos[0], y + vals.y - dropPos[1], vals.opacity);
+ } else {
+ d.x = x + NumCast(d.x) - dropPos[0];
+ d.y = y + NumCast(d.y) - dropPos[1];
+ }
+ const nd = [NumCast(layoutDoc._nativeWidth), NumCast(layoutDoc._nativeHeight)];
+ layoutDoc._width = NumCast(layoutDoc._width, 300);
+ layoutDoc._height = NumCast(layoutDoc._height, nd[0] && nd[1] ? nd[1] / nd[0] * NumCast(layoutDoc._width) : 300);
+ d.isBackground === undefined && (d.zIndex = zsorted.length + 1 + i); // bringToFront
+ }
+
+ (docDragData.droppedDocuments.length === 1 || de.shiftKey) && this.updateClusterDocs(docDragData.droppedDocuments);
+ return true;
+ }
+
+ @undoBatch
@action
- onExternalDrop = (e: React.DragEvent): Promise<void> => {
- const pt = this.getTransform().transformPoint(e.pageX, e.pageY);
- return super.onExternalDrop(e, { x: pt[0], y: pt[1] });
+ internalPdfAnnoDrop(e: Event, annoDragData: DragManager.PdfAnnoDragData, xp: number, yp: number) {
+ const dragDoc = annoDragData.dropDocument;
+ const dropPos = [NumCast(dragDoc.x), NumCast(dragDoc.y)];
+ dragDoc.x = xp - annoDragData.offset[0] + (NumCast(dragDoc.x) - dropPos[0]);
+ dragDoc.y = yp - annoDragData.offset[1] + (NumCast(dragDoc.y) - dropPos[1]);
+ annoDragData.targetContext = this.props.Document; // dropped a PDF annotation, so we need to set the targetContext on the dragData which the PDF view uses at the end of the drop operation
+ this.bringToFront(dragDoc);
+ return true;
}
@undoBatch
@action
+ internalLinkDrop(e: Event, de: DragManager.DropEvent, linkDragData: DragManager.LinkDragData, xp: number, yp: number) {
+ if (linkDragData.linkSourceDocument === this.props.Document) 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
+ e.stopPropagation();
+ return true;
+ }
+
+ @action
onInternalDrop = (e: Event, de: DragManager.DropEvent) => {
// if (this.props.Document.isBackground) return false;
- const xf = this.getTransform();
- const xfo = this.getTransformOverlay();
- const [xp, yp] = xf.transformPoint(de.x, de.y);
- const [xpo, ypo] = xfo.transformPoint(de.x, de.y);
- const zsorted = this.childLayoutPairs.map(pair => pair.layout).slice().sort((doc1, doc2) => NumCast(doc1.zIndex) - NumCast(doc2.zIndex));
- if (!this.isAnnotationOverlay && de.complete.linkDragData && de.complete.linkDragData.linkSourceDocument !== this.props.Document) {
- const source = Docs.Create.TextDocument("", { _width: 200, _height: 75, x: xp, y: yp, title: "dropped annotation" });
- this.props.addDocument(source);
- (de.complete.linkDragData.linkDocument = DocUtils.MakeLink({ doc: source }, { doc: de.complete.linkDragData.linkSourceDocument },
- "doc annotation")); // TODODO this is where in text links get passed
- e.stopPropagation();
+ const [xp, yp] = this.getTransform().transformPoint(de.x, de.y);
+ if (this.isAnnotationOverlay !== true && de.complete.linkDragData)
+ return this.internalLinkDrop(e, de, de.complete.linkDragData, xp, yp);
+ if (de.complete.annoDragData?.dropDocument && super.onInternalDrop(e, de))
+ return this.internalPdfAnnoDrop(e, de.complete.annoDragData, xp, yp);
+ if (de.complete.docDragData?.droppedDocuments.length && this.internalDocDrop(e, de, de.complete.docDragData, xp, yp)) {
return true;
- }
- if (super.onInternalDrop(e, de)) {
- if (de.complete.docDragData) {
- if (de.complete.docDragData.droppedDocuments.length) {
- const firstDoc = de.complete.docDragData.droppedDocuments[0];
- const z = NumCast(firstDoc.z);
- const x = (z ? xpo : xp) - de.complete.docDragData.offset[0];
- const y = (z ? ypo : yp) - de.complete.docDragData.offset[1];
- const dropX = NumCast(firstDoc.x);
- const dropY = NumCast(firstDoc.y);
- const droppedDocs = de.complete.docDragData.droppedDocuments;
- runInAction(() => {
- zsorted.forEach((doc, index) => doc.zIndex = index + 1);
- for (let i = 0; i < droppedDocs.length; i++) {
- const d = droppedDocs[i];
- const layoutDoc = Doc.Layout(d);
- if (this.Document.currentFrame !== undefined && !this.props.isAnnotationOverlay) {
- const vals = CollectionFreeFormDocumentView.getValues(d, NumCast(d.activeFrame, 1000));
- CollectionFreeFormDocumentView.setValues(this.Document.currentFrame, d, x + vals.x - dropX, y + vals.y - dropY, vals.opacity);
- } else {
- d.x = x + NumCast(d.x) - dropX;
- d.y = y + NumCast(d.y) - dropY;
- }
- if (!NumCast(layoutDoc._width)) {
- layoutDoc._width = 300;
- }
- if (!NumCast(layoutDoc._height)) {
- const nw = NumCast(layoutDoc._nativeWidth);
- const nh = NumCast(layoutDoc._nativeHeight);
- layoutDoc._height = nw && nh ? nh / nw * NumCast(layoutDoc._width) : 300;
- }
- d.isBackground === undefined && (d.zIndex = zsorted.length + 1 + i); // bringToFront
- }
- });
-
- (de.complete.docDragData.droppedDocuments.length === 1 || de.shiftKey) && this.updateClusterDocs(de.complete.docDragData.droppedDocuments);
- }
- }
- else if (de.complete.annoDragData) {
- if (de.complete.annoDragData.dropDocument) {
- const dragDoc = de.complete.annoDragData.dropDocument;
- const x = xp - de.complete.annoDragData.offset[0];
- const y = yp - de.complete.annoDragData.offset[1];
- const dropX = NumCast(dragDoc.x);
- const dropY = NumCast(dragDoc.y);
- dragDoc.x = x + NumCast(dragDoc.x) - dropX;
- dragDoc.y = y + NumCast(dragDoc.y) - dropY;
- de.complete.annoDragData.targetContext = this.props.Document; // dropped a PDF annotation, so we need to set the targetContext on the dragData which the PDF view uses at the end of the drop operation
- this.bringToFront(dragDoc);
- }
- }
+ } else {
+ UndoManager.Undo();
}
return false;
}
@@ -1346,7 +1344,6 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
<CollectionFreeFormViewPannableContents
centeringShiftX={this.centeringShiftX}
centeringShiftY={this.centeringShiftY}
- shifted={!this.nativeHeight && !this.isAnnotationOverlay}
easing={this.easing}
transition={Cast(this.layoutDoc.transition, "string", null)}
viewDefDivClick={this.props.viewDefDivClick}
@@ -1432,7 +1429,6 @@ interface CollectionFreeFormViewPannableContentsProps {
easing: () => boolean;
viewDefDivClick?: ScriptField;
children: () => JSX.Element[];
- shifted: boolean;
transition?: string;
}
@@ -1447,7 +1443,6 @@ class CollectionFreeFormViewPannableContents extends React.Component<CollectionF
const zoom = this.props.zoomScaling();
return <div className={freeformclass}
style={{
- width: this.props.shifted ? 0 : undefined, height: this.props.shifted ? 0 : undefined,
transform: `translate(${cenx}px, ${ceny}px) scale(${zoom}) translate(${panx}px, ${pany}px)`,
transition: this.props.transition
}}>
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index cdfeeaa6b..46804c848 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -607,7 +607,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
@computed
get marqueeDiv() {
- const p: [number, number] = this._visible ? this.props.getContainerTransform().transformPoint(this._downX < this._lastX ? this._downX : this._lastX, this._downY < this._lastY ? this._downY : this._lastY) : [0, 0];
+ const p = this._visible ? this.props.getContainerTransform().transformPoint(this._downX < this._lastX ? this._downX : this._lastX, this._downY < this._lastY ? this._downY : this._lastY) : [0, 0];
const v = this.props.getContainerTransform().transformDirection(this._lastX - this._downX, this._lastY - this._downY);
/**
* @RE - The commented out span below
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index e245e045c..d132f0b3b 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -44,6 +44,7 @@ import "./DocumentView.scss";
import { LinkAnchorBox } from './LinkAnchorBox';
import { RadialMenu } from './RadialMenu';
import React = require("react");
+import { undo } from 'prosemirror-history';
library.add(fa.faEdit, fa.faTrash, fa.faShare, fa.faDownload, fa.faExpandArrowsAlt, fa.faCompressArrowsAlt, fa.faLayerGroup, fa.faExternalLinkAlt, fa.faAlignCenter, fa.faCaretSquareRight,
fa.faSquare, fa.faConciergeBell, fa.faWindowRestore, fa.faFolder, fa.faMapPin, fa.faLink, fa.faFingerprint, fa.faCrosshairs, fa.faDesktop, fa.faUnlock, fa.faLock, fa.faLaptopCode, fa.faMale,
@@ -682,6 +683,17 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
this.Document.lockedPosition = this.Document.lockedPosition ? undefined : true;
}
+ @undoBatch
+ @action
+ setAcl = (acl: "readOnly" | "addOnly" | "ownerOnly") => {
+ this.layoutDoc.ACL = this.dataDoc.ACL = acl;
+ DocListCast(this.dataDoc[Doc.LayoutFieldKey(this.dataDoc)]).map(d => {
+ if (d.author === Doc.CurrentUserEmail) d.ACL = acl;
+ const data = d[DataSym];
+ if (data && data.author === Doc.CurrentUserEmail) data.ACL = acl;
+ });
+ }
+
@action
onContextMenu = async (e: React.MouseEvent | Touch): Promise<void> => {
// the touch onContextMenu is button 0, the pointer onContextMenu is button 2
@@ -742,9 +754,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
const more = cm.findByDescription("More...");
const moreItems: ContextMenuProps[] = more && "subitems" in more ? more.subitems : [];
- moreItems.push({ description: "Make Add Only", event: () => this.dataDoc.ACL = this.layoutDoc.ACL = "addOnly", icon: "concierge-bell" });
- moreItems.push({ description: "Make Read Only", event: () => this.dataDoc.ACL = this.layoutDoc.ACL = "readOnly", icon: "concierge-bell" });
- moreItems.push({ description: "Make Private", event: () => this.dataDoc.ACL = this.layoutDoc.ACL = "noAccess", icon: "concierge-bell" });
+ moreItems.push({ description: "Make Add Only", event: () => this.setAcl("addOnly"), icon: "concierge-bell" });
+ moreItems.push({ description: "Make Read Only", event: () => this.setAcl("readOnly"), icon: "concierge-bell" });
+ moreItems.push({ description: "Make Private", event: () => this.setAcl("ownerOnly"), icon: "concierge-bell" });
moreItems.push({ description: "Make View of Metadata Field", event: () => Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.DataDoc), icon: "concierge-bell" });
moreItems.push({ description: `${this.Document._chromeStatus !== "disabled" ? "Hide" : "Show"} Chrome`, event: () => this.Document._chromeStatus = (this.Document._chromeStatus !== "disabled" ? "disabled" : "enabled"), icon: "project-diagram" });
moreItems.push({ description: this.Document.lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.Document.lockedPosition) ? "unlock" : "lock" });
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 6891bf652..e46acd16d 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -94,7 +94,7 @@ export const HeightSym = Symbol("Height");
export const DataSym = Symbol("Data");
export const LayoutSym = Symbol("Layout");
export const AclSym = Symbol("Acl");
-export const AclPrivate = Symbol("AclNoAccess");
+export const AclPrivate = Symbol("AclOwnerOnly");
export const AclReadonly = Symbol("AclReadOnly");
export const AclAddonly = Symbol("AclAddonly");
export const UpdatingFromServer = Symbol("UpdatingFromServer");
@@ -103,13 +103,17 @@ const CachedUpdates = Symbol("Cached updates");
function fetchProto(doc: Doc) {
if (doc.author !== Doc.CurrentUserEmail) {
- if (doc.ACL === "noAccess") {
- doc[AclSym] = AclPrivate;
- return undefined;
- } else if (doc.ACL === "readOnly") {
- doc[AclSym] = AclReadonly;
- } else if (doc.ACL === "addOnly") {
- doc[AclSym] = AclAddonly;
+ const acl = Doc.Get(doc, "ACL", true);
+ switch (acl) {
+ case "ownerOnly":
+ doc[AclSym] = AclPrivate;
+ return undefined;
+ case "readOnly":
+ doc[AclSym] = AclReadonly;
+ break;
+ case "addOnly":
+ doc[AclSym] = AclAddonly;
+ break;
}
}
@@ -117,7 +121,7 @@ function fetchProto(doc: Doc) {
if (proto instanceof Promise) {
proto.then(proto => {
if (proto.author !== Doc.CurrentUserEmail) {
- if (proto.ACL === "noAccess") {
+ if (proto.ACL === "ownerOnly") {
proto[AclSym] = doc[AclSym] = AclPrivate;
return undefined;
} else if (proto.ACL === "readOnly") {
@@ -484,6 +488,7 @@ export namespace Doc {
}
alias.aliasOf = doc;
alias.title = ComputedField.MakeFunction(`renameAlias(this, ${Doc.GetProto(doc).aliasNumber = NumCast(Doc.GetProto(doc).aliasNumber) + 1})`);
+ alias.author = Doc.CurrentUserEmail;
return alias;
}
@@ -614,7 +619,7 @@ export namespace Doc {
}
}
});
-
+ copy["author"] = Doc.CurrentUserEmail;
return copy;
}