aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections/CollectionSubView.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/collections/CollectionSubView.tsx')
-rw-r--r--src/client/views/collections/CollectionSubView.tsx145
1 files changed, 86 insertions, 59 deletions
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 1bfd408f8..c9eb08b45 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -1,14 +1,14 @@
import { action, computed, IReactionDisposer, reaction } from "mobx";
import { basename } from 'path';
-import CursorField from "../../../new_fields/CursorField";
-import { Doc, Opt } from "../../../new_fields/Doc";
-import { Id } from "../../../new_fields/FieldSymbols";
-import { List } from "../../../new_fields/List";
-import { listSpec } from "../../../new_fields/Schema";
-import { ScriptField } from "../../../new_fields/ScriptField";
-import { Cast } from "../../../new_fields/Types";
+import CursorField from "../../../fields/CursorField";
+import { Doc, Opt } from "../../../fields/Doc";
+import { Id } from "../../../fields/FieldSymbols";
+import { List } from "../../../fields/List";
+import { listSpec } from "../../../fields/Schema";
+import { ScriptField } from "../../../fields/ScriptField";
+import { Cast, ScriptCast } from "../../../fields/Types";
import { GestureUtils } from "../../../pen-gestures/GestureUtils";
-import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
+import { CurrentUserUtils } from "../../util/CurrentUserUtils";
import { Upload } from "../../../server/SharedMediaTypes";
import { Utils } from "../../../Utils";
import { GooglePhotos } from "../../apis/google_docs/GooglePhotosClientUtils";
@@ -16,7 +16,7 @@ import { DocServer } from "../../DocServer";
import { Docs, DocumentOptions } from "../../documents/Documents";
import { DocumentType } from "../../documents/DocumentTypes";
import { Networking } from "../../Network";
-import { DragManager } from "../../util/DragManager";
+import { DragManager, dropActionType } from "../../util/DragManager";
import { ImageUtils } from "../../util/Import & Export/ImageUtils";
import { InteractionUtils } from "../../util/InteractionUtils";
import { undoBatch, UndoManager } from "../../util/UndoManager";
@@ -27,9 +27,9 @@ import { CollectionView } from "./CollectionView";
import React = require("react");
export interface CollectionViewProps extends FieldViewProps {
- addDocument: (document: Doc) => boolean;
- removeDocument: (document: Doc) => boolean;
- moveDocument: (document: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean) => boolean;
+ addDocument: (document: Doc | Doc[]) => boolean;
+ removeDocument: (document: Doc | Doc[]) => boolean;
+ moveDocument: (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean;
PanelWidth: () => number;
PanelHeight: () => number;
VisibleHeight?: () => number;
@@ -43,6 +43,10 @@ export interface CollectionViewProps extends FieldViewProps {
export interface SubCollectionViewProps extends CollectionViewProps {
CollectionView: Opt<CollectionView>;
children?: never | (() => JSX.Element[]) | React.ReactNode;
+ ChildLayoutTemplate?: () => Doc;
+ ChildLayoutString?: string;
+ childClickScript?: ScriptField;
+ childDoubleClickScript?: ScriptField;
freezeChildDimensions?: boolean; // used by TimeView to coerce documents to treat their width height as their native width/height
overrideDocuments?: Doc[]; // used to override the documents shown by the sub collection to an explicit list (see LinkBox)
ignoreFields?: string[]; // used in TreeView to ignore specified fields (see LinkBox)
@@ -56,7 +60,6 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
private dropDisposer?: DragManager.DragDropDisposer;
private gestureDisposer?: GestureUtils.GestureEventDisposer;
protected multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
- private _childLayoutDisposer?: IReactionDisposer;
protected _mainCont?: HTMLDivElement;
protected createDashEventsTarget = (ele: HTMLDivElement) => { //used for stacking and masonry view
this.dropDisposer?.();
@@ -64,7 +67,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
this.multiTouchDisposer?.();
if (ele) {
this._mainCont = ele;
- this.dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc);
+ this.dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc, this.onInternalPreDrop.bind(this));
this.gestureDisposer = GestureUtils.MakeGestureTarget(ele, this.onGesture.bind(this));
this.multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(ele, this.onTouchStart.bind(this));
}
@@ -73,25 +76,9 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
this.createDashEventsTarget(ele);
}
- componentDidMount() {
- this._childLayoutDisposer = reaction(() => ({ childDocs: this.childDocs, childLayout: Cast(this.props.Document.childLayout, Doc) }),
- ({ childDocs, childLayout }) => {
- if (childLayout instanceof Doc) {
- childDocs.map(doc => {
- doc.layout_fromParent = childLayout;
- doc.layoutKey = "layout_fromParent";
- });
- }
- else if (!(childLayout instanceof Promise)) {
- childDocs.filter(d => !d.isTemplateForField).map(doc => doc.layoutKey === "layout_fromParent" && (doc.layoutKey = "layout"));
- }
- }, { fireImmediately: true });
-
- }
componentWillUnmount() {
this.gestureDisposer?.();
this.multiTouchDisposer?.();
- this._childLayoutDisposer?.();
}
@computed get dataDoc() {
@@ -108,7 +95,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
// to its children which may be templates.
// If 'annotationField' is specified, then all children exist on that field of the extension document, otherwise, they exist directly on the data document under 'fieldKey'
@computed get dataField() {
- return this.dataDoc[this.props.fieldKey + (this.props.annotationsKey ? "-" + this.props.annotationsKey : "")];
+ return this.dataDoc[this.props.annotationsKey || this.props.fieldKey];
}
get childLayoutPairs(): { layout: Doc; data: Doc; }[] {
@@ -208,34 +195,60 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
protected onGesture(e: Event, ge: GestureUtils.GestureEvent) {
}
+ protected onInternalPreDrop(e: Event, de: DragManager.DropEvent, targetAction: dropActionType) {
+ if (de.complete.docDragData) {
+ // if targetDropAction is, say 'alias', but we're just dragging within a collection, we want to ignore the targetAction.
+ // otherwise, the targetAction should become the actual action (which can still be overridden by the userDropAction -eg, shift/ctrl keys)
+ if (targetAction && !de.complete.docDragData.draggedDocuments.some(d => d.context === this.props.Document && this.childDocs.includes(d))) {
+ de.complete.docDragData.dropAction = targetAction;
+ }
+ e.stopPropagation();
+ }
+ }
+
+ addDocument = (doc: Doc | Doc[]) => this.props.addDocument(doc);
+
@undoBatch
@action
protected onInternalDrop(e: Event, de: DragManager.DropEvent): boolean {
const docDragData = de.complete.docDragData;
- (this.props.Document.dropConverter instanceof ScriptField) &&
- this.props.Document.dropConverter.script.run({ dragData: docDragData }); /// bcz: check this
+ ScriptCast(this.props.Document.dropConverter)?.script.run({ dragData: docDragData });
if (docDragData) {
let added = false;
if (docDragData.dropAction || docDragData.userDropAction) {
- added = docDragData.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d) || added, false);
+ added = this.addDocument(docDragData.droppedDocuments);
} else if (docDragData.moveDocument) {
- const movedDocs = docDragData.draggedDocuments;
- added = movedDocs.reduce((added: boolean, d, i) =>
- docDragData.droppedDocuments[i] !== d ? this.props.addDocument(docDragData.droppedDocuments[i]) :
- docDragData.moveDocument?.(d, this.props.Document, this.props.addDocument) || added, false);
+ const movedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] === d);
+ const addedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] !== d);
+ const res = addedDocs.length ? this.addDocument(addedDocs) : true;
+ added = movedDocs.length ? docDragData.moveDocument(movedDocs, this.props.Document, this.addDocument) : res;
} else {
- added = docDragData.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d) || added, false);
+ added = this.addDocument(docDragData.droppedDocuments);
}
e.stopPropagation();
return added;
}
else if (de.complete.annoDragData) {
e.stopPropagation();
- return this.props.addDocument(de.complete.annoDragData.dropDocument);
+ return this.addDocument(de.complete.annoDragData.dropDocument);
}
return false;
}
+ readUploadedFileAsText = (inputFile: File) => {
+ const temporaryFileReader = new FileReader();
+
+ return new Promise((resolve, reject) => {
+ temporaryFileReader.onerror = () => {
+ temporaryFileReader.abort();
+ reject(new DOMException("Problem parsing input file."));
+ };
+ temporaryFileReader.onload = () => {
+ resolve(temporaryFileReader.result);
+ };
+ temporaryFileReader.readAsText(inputFile);
+ });
+ }
@undoBatch
@action
protected async onExternalDrop(e: React.DragEvent, options: DocumentOptions, completed?: () => void) {
@@ -254,7 +267,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
e.stopPropagation();
e.preventDefault();
- const { addDocument } = this.props;
+ const { addDocument } = this;
if (!addDocument) {
alert("this.props.addDocument does not exist. Aborting drop operation.");
return;
@@ -332,23 +345,23 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
}));
return;
}
- let matches: RegExpExecArray | null;
- if ((matches = /(https:\/\/)?docs\.google\.com\/document\/d\/([^\\]+)\/edit/g.exec(text)) !== null) {
- const newBox = Docs.Create.TextDocument("", { ...options, _width: 400, _height: 200, title: "Awaiting title from Google Docs..." });
- const proto = newBox.proto!;
- const documentId = matches[2];
- proto[GoogleRef] = documentId;
- proto.data = "Please select this document and then click on its pull button to load its contents from from Google Docs...";
- proto.backgroundColor = "#eeeeff";
- addDocument(newBox);
- return;
- }
- if ((matches = /(https:\/\/)?photos\.google\.com\/(u\/3\/)?album\/([^\\]+)/g.exec(text)) !== null) {
- const albumId = matches[3];
- const mediaItems = await GooglePhotos.Query.AlbumSearch(albumId);
- console.log(mediaItems);
- return;
- }
+ // let matches: RegExpExecArray | null;
+ // if ((matches = /(https:\/\/)?docs\.google\.com\/document\/d\/([^\\]+)\/edit/g.exec(text)) !== null) {
+ // const newBox = Docs.Create.TextDocument("", { ...options, _width: 400, _height: 200, title: "Awaiting title from Google Docs..." });
+ // const proto = newBox.proto!;
+ // const documentId = matches[2];
+ // proto[GoogleRef] = documentId;
+ // proto.data = "Please select this document and then click on its pull button to load its contents from from Google Docs...";
+ // proto.backgroundColor = "#eeeeff";
+ // addDocument(newBox);
+ // return;
+ // }
+ // if ((matches = /(https:\/\/)?photos\.google\.com\/(u\/3\/)?album\/([^\\]+)/g.exec(text)) !== null) {
+ // const albumId = matches[3];
+ // const mediaItems = await GooglePhotos.Query.AlbumSearch(albumId);
+ // console.log(mediaItems);
+ // return;
+ // }
}
const { items } = e.dataTransfer;
@@ -373,7 +386,21 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
}
if (item.kind === "file") {
const file = item.getAsFile();
- file && file.type && files.push(file);
+ file?.type && files.push(file);
+
+ file?.type === "application/json" && this.readUploadedFileAsText(file).then(result => {
+ console.log(result);
+ const json = JSON.parse(result as string);
+ addDocument(Docs.Create.TreeDocument(
+ json["rectangular-puzzle"].crossword.clues[0].clue.map((c: any) => {
+ const label = Docs.Create.LabelDocument({ title: c["#text"], _width: 120, _height: 20 });
+ const proto = Doc.GetProto(label);
+ proto._width = 120;
+ proto._height = 20;
+ return proto;
+ }
+ ), { _width: 150, _height: 600, title: "across", backgroundColor: "white", _singleLine: true }));
+ });
}
}
for (const { source: { name, type }, result } of await Networking.UploadFilesToServer(files)) {