aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/apis/google_docs/GooglePhotosClientUtils.ts23
-rw-r--r--src/client/views/collections/CollectionSubView.tsx26
-rw-r--r--src/client/views/collections/CollectionView.scss2
-rw-r--r--src/client/views/collections/CollectionView.tsx54
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx101
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx13
6 files changed, 123 insertions, 96 deletions
diff --git a/src/client/apis/google_docs/GooglePhotosClientUtils.ts b/src/client/apis/google_docs/GooglePhotosClientUtils.ts
index ff471853a..1e4c120bc 100644
--- a/src/client/apis/google_docs/GooglePhotosClientUtils.ts
+++ b/src/client/apis/google_docs/GooglePhotosClientUtils.ts
@@ -153,21 +153,20 @@ export namespace GooglePhotos {
}
const tagMapping = new Map<string, string>();
const images = (await DocListCastAsync(collection.data))!.map(Doc.GetProto);
- images && images.forEach(image => tagMapping.set(image[Id], ContentCategories.NONE));
- const values = Object.values(ContentCategories);
+ images?.forEach(image => tagMapping.set(image[Id], ContentCategories.NONE));
+ const values = Object.values(ContentCategories).filter(value => value !== ContentCategories.NONE);
for (const value of values) {
- if (value === ContentCategories.NONE) {
- continue;
- }
- for (const id of (await ContentSearch({ included: [value] }))?.mediaItems?.map(({ id }) => id)) {
+ const searched = (await ContentSearch({ included: [value] }))?.mediaItems?.map(({ id }) => id);
+ console.log("Searching " + value);
+ console.log(searched);
+ searched?.forEach(async id => {
const image = await Cast(idMapping[id], Doc);
- if (!image) {
- continue;
+ if (image) {
+ const key = image[Id];
+ const tags = tagMapping.get(key);
+ !tags?.includes(value) && tagMapping.set(key, tags + delimiter + value);
}
- const key = image[Id];
- const tags = tagMapping.get(key);
- !tags?.includes(value) && tagMapping.set(key, tags + delimiter + value);
- }
+ });
}
images?.forEach(image => {
const concatenated = tagMapping.get(image[Id])!;
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 8c78e568c..250c9b3b0 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -6,7 +6,7 @@ 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 { Cast, ScriptCast } from "../../../new_fields/Types";
import { GestureUtils } from "../../../pen-gestures/GestureUtils";
import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
import { Upload } from "../../../server/SharedMediaTypes";
@@ -208,19 +208,18 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
@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.props.addDocument(docDragData.droppedDocuments as any as Doc);
} 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.props.addDocument(addedDocs as any as Doc) : true;
+ added = movedDocs.length ? docDragData.moveDocument(movedDocs as any as Doc, this.props.Document, this.props.addDocument) : res;
} else {
- added = docDragData.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d) || added, false);
+ added = this.props.addDocument(docDragData.droppedDocuments as any as Doc);
}
e.stopPropagation();
return added;
@@ -389,8 +388,13 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
console.log(result);
const json = JSON.parse(result as string) as any;
addDocument(Docs.Create.TreeDocument(
- json["rectangular-puzzle"].crossword.clues[0].clue.map((c: any) =>
- Docs.Create.LabelDocument({ title: c["#text"], _width: 120, _height: 20 })
+ 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 }));
});
}
diff --git a/src/client/views/collections/CollectionView.scss b/src/client/views/collections/CollectionView.scss
index d43dd387a..7877fe155 100644
--- a/src/client/views/collections/CollectionView.scss
+++ b/src/client/views/collections/CollectionView.scss
@@ -70,7 +70,7 @@
height: 30px;
position: absolute;
bottom: 15px;
- left: 15px;
+ right: 15px;
border: 2px solid black;
border-radius: 50%;
padding: 3px;
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 43da1c44f..ccfc660cc 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -15,9 +15,7 @@ import { ImageField } from '../../../new_fields/URLField';
import { TraceMobx } from '../../../new_fields/util';
import { Utils, setupMoveUpEvents, returnFalse, returnZero, emptyPath, emptyFunction, returnOne } from '../../../Utils';
import { DocumentType } from '../../documents/DocumentTypes';
-import { DocumentManager } from '../../util/DocumentManager';
import { ImageUtils } from '../../util/Import & Export/ImageUtils';
-import { SelectionManager } from '../../util/SelectionManager';
import { ContextMenu } from "../ContextMenu";
import { FieldView, FieldViewProps } from '../nodes/FieldView';
import { ScriptBox } from '../ScriptBox';
@@ -45,7 +43,6 @@ import { ScriptField, ComputedField } from '../../../new_fields/ScriptField';
import { InteractionUtils } from '../../util/InteractionUtils';
import { ObjectField } from '../../../new_fields/ObjectField';
import CollectionMapView from './CollectionMapView';
-import { Transform } from 'prosemirror-transform';
import { CollectionPileView } from './CollectionPileView';
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
@@ -119,35 +116,32 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
whenActiveChanged = (isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive);
@action.bound
- addDocument(doc: Doc): boolean {
- if (this.props.filterAddDocument?.(doc) === false) {
- return false;
+ addDocument = (doc: Doc): boolean => {
+ if (doc instanceof Doc) {
+ if (this.props.filterAddDocument?.(doc) === false) {
+ return false;
+ }
}
-
+ const docs = doc instanceof Doc ? [doc] : doc as any as Doc[];
const targetDataDoc = this.props.Document[DataSym];
const docList = DocListCast(targetDataDoc[this.props.fieldKey]);
- !docList.includes(doc) && (targetDataDoc[this.props.fieldKey] = new List<Doc>([...docList, doc])); // DocAddToList may write to targetdataDoc's parent ... we don't want this. should really change GetProto to GetDataDoc and test for resolvedDataDoc there
- // Doc.AddDocToList(targetDataDoc, this.props.fieldKey, doc);
- targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now()));
- doc.context = this.props.Document;
- Doc.GetProto(doc).lastOpened = new DateField;
+ const added = docs.filter(d => !docList.includes(d));
+ if (added.length) {
+ added.map(doc => doc.context = this.props.Document);
+ targetDataDoc[this.props.fieldKey] = new List<Doc>([...docList, ...added]);
+ targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now()));
+ }
return true;
}
@action.bound
- removeDocument(doc: Doc): boolean {
+ removeDocument = (doc: any): boolean => {
+ const docs = doc instanceof Doc ? [doc] : doc as Doc[];
const targetDataDoc = this.props.Document[DataSym];
- const docView = DocumentManager.Instance.getDocumentView(doc, this.props.ContainingCollectionView);
- docView && SelectionManager.DeselectDoc(docView);
const value = DocListCast(targetDataDoc[this.props.fieldKey]);
- let index = value.reduce((p, v, i) => (v instanceof Doc && v === doc) ? i : p, -1);
- index = index !== -1 ? index : value.reduce((p, v, i) => (v instanceof Doc && Doc.AreProtosEqual(v, doc)) ? i : p, -1);
-
- doc.context = undefined;
- ContextMenu.Instance?.clearItems();
- if (index !== -1) {
- value.splice(index, 1);
- targetDataDoc[this.props.fieldKey] = new List<Doc>(value);
+ const result = value.filter(v => !docs.includes(v));
+ if (result.length !== value.length) {
+ targetDataDoc[this.props.fieldKey] = new List<Doc>(result);
return true;
}
return false;
@@ -158,7 +152,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
// otherwise, the document being moved must be able to be removed from its container before
// moving it into the target.
@action.bound
- moveDocument(doc: Doc, targetCollection: Doc | undefined, addDocument: (doc: Doc) => boolean): boolean {
+ moveDocument = (doc: Doc, targetCollection: Doc | undefined, addDocument: (doc: Doc) => boolean): boolean => {
if (Doc.AreProtosEqual(this.props.Document, targetCollection)) {
return true;
}
@@ -166,10 +160,14 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
}
showIsTagged = () => {
- const children = DocListCast(this.props.Document[this.props.fieldKey]);
- const imageProtos = children.filter(doc => Cast(doc.data, ImageField)).map(Doc.GetProto);
- const allTagged = imageProtos.length > 0 && imageProtos.every(image => image.googlePhotosTags);
- return !allTagged ? (null) : <img id={"google-tags"} src={"/assets/google_tags.png"} />;
+ return (null);
+ // this section would display an icon in the bototm right of a collection to indicate that all
+ // photos had been processed through Google's content analysis API and Google's tags had been
+ // assigned to the documents googlePhotosTags field.
+ // const children = DocListCast(this.props.Document[this.props.fieldKey]);
+ // const imageProtos = children.filter(doc => Cast(doc.data, ImageField)).map(Doc.GetProto);
+ // const allTagged = imageProtos.length > 0 && imageProtos.every(image => image.googlePhotosTags);
+ // return !allTagged ? (null) : <img id={"google-tags"} src={"/assets/google_tags.png"} />;
}
private SubViewHelper = (type: CollectionViewType, renderProps: CollectionRenderProps) => {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 37957b0f6..6011d5f9c 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -124,10 +124,15 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
this.addDocument(newBox);
}
private addDocument = (newBox: Doc) => {
- const added = this.props.addDocument(newBox);
- added && this.bringToFront(newBox);
- added && this.updateCluster(newBox);
- return added;
+ if (newBox instanceof Doc) {
+ const added = this.props.addDocument(newBox);
+ added && this.bringToFront(newBox);
+ added && this.updateCluster(newBox);
+ return added;
+ } else {
+ return this.props.addDocument(newBox);
+ // bcz: deal with clusters
+ }
}
private selectDocuments = (docs: Doc[]) => {
SelectionManager.DeselectAll();
@@ -153,6 +158,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
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 (super.onInternalDrop(e, de)) {
if (de.complete.docDragData) {
if (de.complete.docDragData.droppedDocuments.length) {
@@ -162,20 +168,25 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
const y = (z ? ypo : yp) - de.complete.docDragData.offset[1];
const dropX = NumCast(firstDoc.x);
const dropY = NumCast(firstDoc.y);
- de.complete.docDragData.droppedDocuments.forEach(action((d: Doc) => {
- const layoutDoc = Doc.Layout(d);
- 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;
+ 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);
+ 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);
}
- d.isBackground === undefined && this.bringToFront(d);
- }));
+ });
(de.complete.docDragData.droppedDocuments.length === 1 || de.shiftKey) && this.updateClusterDocs(de.complete.docDragData.droppedDocuments);
}
@@ -760,20 +771,21 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
}
}
- bringToFront = (doc: Doc, sendToBack?: boolean) => {
+ bringToFront = action((doc: Doc, sendToBack?: boolean) => {
if (sendToBack || doc.isBackground) {
doc.zIndex = 0;
}
else {
const docs = this.childLayoutPairs.map(pair => pair.layout);
- docs.slice().sort((doc1, doc2) => {
- if (doc1 === doc) return 1;
- if (doc2 === doc) return -1;
- return NumCast(doc1.zIndex) - NumCast(doc2.zIndex);
- }).forEach((doc, index) => doc.zIndex = index + 1);
- doc.zIndex = docs.length + 1;
+ docs.slice().sort((doc1, doc2) => NumCast(doc1.zIndex) - NumCast(doc2.zIndex));
+ let zlast = docs.length ? NumCast(docs[docs.length - 1].zIndex) : 1;
+ if (zlast - docs.length > 100) {
+ for (let i = 0; i < docs.length; i++) doc.zIndex = i + 1;
+ zlast = docs.length + 1;
+ }
+ doc.zIndex = zlast + 1;
}
- }
+ })
scaleAtPt(docpt: number[], scale: number) {
const screenXY = this.getTransform().inverse().transformPoint(docpt[0], docpt[1]);
@@ -895,14 +907,22 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
addDocTab = action((doc: Doc, where: string) => {
if (where === "inParent") {
- const pt = this.getTransform().transformPoint(NumCast(doc.x), NumCast(doc.y));
- doc.x = pt[0];
- doc.y = pt[1];
- this.props.addDocument(doc);
- return true;
+ if (doc instanceof Doc) {
+ const pt = this.getTransform().transformPoint(NumCast(doc.x), NumCast(doc.y));
+ doc.x = pt[0];
+ doc.y = pt[1];
+ return this.props.addDocument(doc);
+ } else {
+ (doc as any as Doc[]).forEach(doc => {
+ const pt = this.getTransform().transformPoint(NumCast(doc.x), NumCast(doc.y));
+ doc.x = pt[0];
+ doc.y = pt[1];
+ });
+ return this.props.addDocument(doc);
+ }
}
if (where === "inPlace" && this.layoutDoc.isInPlaceContainer) {
- this.dataDoc[this.props.fieldKey] = new List<Doc>([doc]);
+ this.dataDoc[this.props.fieldKey] = doc instanceof Doc ? doc : new List<Doc>(doc as any as Doc[]);
return true;
}
return this.props.addDocTab(doc, where);
@@ -1002,8 +1022,10 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
get doLayoutComputation() {
const { newPool, computedElementData } = this.doInternalLayoutComputation;
- runInAction(() =>
- Array.from(newPool.entries()).map(entry => {
+ const array = Array.from(newPool.entries());
+ runInAction(() => {
+ for (let i = 0; i < array.length; i++) {
+ const entry = array[i];
const lastPos = this._cachedPool.get(entry[0]); // last computed pos
const newPos = entry[1];
if (!lastPos || newPos.x !== lastPos.x || newPos.y !== lastPos.y || newPos.z !== lastPos.z || newPos.zIndex !== lastPos.zIndex) {
@@ -1012,7 +1034,8 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
if (!lastPos || newPos.height !== lastPos.height || newPos.width !== lastPos.width) {
this._layoutSizeData.set(entry[0], { width: newPos.width, height: newPos.height });
}
- }));
+ }
+ });
this._cachedPool.clear();
Array.from(newPool.entries()).forEach(k => this._cachedPool.set(k[0], k[1]));
const elements: ViewDefResult[] = computedElementData.slice();
@@ -1058,12 +1081,13 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
}
promoteCollection = undoBatch(action(() => {
- this.childDocs.forEach(doc => {
+ const childDocs = this.childDocs.slice();
+ childDocs.forEach(doc => {
const scr = this.getTransform().inverse().transformPoint(NumCast(doc.x), NumCast(doc.y));
doc.x = scr?.[0];
doc.y = scr?.[1];
- this.props.addDocTab(doc, "inParent") && this.props.removeDocument(doc);
});
+ this.props.addDocTab(childDocs as any as Doc, "inParent");
this.props.ContainingCollectionView?.removeDocument(this.props.Document);
}));
layoutDocsInGrid = () => {
@@ -1148,6 +1172,11 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
@action
setupDragLines = () => {
+ const activeDocs = this.getActiveDocuments();
+ if (activeDocs.length > 50) {
+ DragManager.SetSnapLines([], []);
+ return;
+ }
const size = this.props.ScreenToLocalTransform().transformDirection(this.props.PanelWidth(), this.props.PanelHeight());
const selRect = { left: this.panX() - size[0] / 2, top: this.panY() - size[1] / 2, width: size[0], height: size[1] };
const docDims = (doc: Doc) => ({ left: NumCast(doc.x), top: NumCast(doc.y), width: NumCast(doc._width), height: NumCast(doc._height) });
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 5bac075b4..43d4203ad 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -198,7 +198,6 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
@action
onPointerUp = (e: PointerEvent): void => {
- if (!this.props.active(true)) this.props.selectDocuments([this.props.Document], []);
if (this._visible) {
const mselect = this.marqueeSelect();
if (!e.shiftKey) {
@@ -300,10 +299,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
@action
delete = () => {
- this.marqueeSelect(false).map(d => this.props.removeDocument(d));
- if (this.ink) {
- // this.marqueeInkDelete(this.ink.inkData);
- }
+ this.props.removeDocument(this.marqueeSelect(false) as any as Doc);
SelectionManager.DeselectAll();
this.cleanupInteractions(false);
MarqueeOptionsMenu.Instance.fadeOut(true);
@@ -349,13 +345,14 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
const bounds = this.Bounds;
const selected = this.marqueeSelect(false);
if (e instanceof KeyboardEvent ? e.key === "c" : true) {
- selected.map(d => {
- this.props.removeDocument(d);
+ selected.map(action(d => {
+ //this.props.removeDocument(d);
d.x = NumCast(d.x) - bounds.left - bounds.width / 2;
d.y = NumCast(d.y) - bounds.top - bounds.height / 2;
d.displayTimecode = undefined; // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection
return d;
- });
+ }));
+ this.props.removeDocument(selected as any as Doc);
}
const newCollection = this.getCollection(selected, (e as KeyboardEvent)?.key === "t" ? Docs.Create.StackingDocument : undefined);
this.props.addDocument(newCollection);