From 74e4909a77ac143ecdb1d038ad182aae9c710129 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Wed, 3 Jul 2019 22:15:25 -0400 Subject: implemented directory import routine --- src/client/views/collections/CollectionSubView.tsx | 46 +--------------------- 1 file changed, 2 insertions(+), 44 deletions(-) (limited to 'src/client/views/collections/CollectionSubView.tsx') diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 3b3bbdbd9..e886ad84a 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -102,47 +102,6 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { return false; } - protected async getDocumentFromType(type: string, path: string, options: DocumentOptions): Promise> { - let ctor: ((path: string, options: DocumentOptions) => (Doc | Promise)) | undefined = undefined; - if (type.indexOf("image") !== -1) { - ctor = Docs.ImageDocument; - } - if (type.indexOf("video") !== -1) { - ctor = Docs.VideoDocument; - } - if (type.indexOf("audio") !== -1) { - ctor = Docs.AudioDocument; - } - if (type.indexOf("pdf") !== -1) { - ctor = Docs.PdfDocument; - options.nativeWidth = 1200; - } - if (type.indexOf("excel") !== -1) { - ctor = Docs.DBDocument; - options.dropAction = "copy"; - } - if (type.indexOf("html") !== -1) { - if (path.includes(window.location.hostname)) { - let s = path.split('/'); - let id = s[s.length - 1]; - DocServer.GetRefField(id).then(field => { - if (field instanceof Doc) { - let alias = Doc.MakeAlias(field); - alias.x = options.x || 0; - alias.y = options.y || 0; - alias.width = options.width || 300; - alias.height = options.height || options.width || 300; - this.props.addDocument(alias, false); - } - }); - return undefined; - } - ctor = Docs.WebDocument; - options = { height: options.width, ...options, title: path, nativeWidth: undefined }; - } - return ctor ? ctor(path, options) : undefined; - } - @undoBatch @action protected onDrop(e: React.DragEvent, options: DocumentOptions): void { @@ -223,7 +182,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { .then(result => { let type = result["content-type"]; if (type) { - this.getDocumentFromType(type, str, { ...options, width: 300, nativeWidth: 300 }) + Docs.getDocumentFromType(type, str, { ...options, width: 300, nativeWidth: 300 }, this.props.addDocument) .then(doc => doc && this.props.addDocument(doc, false)); } }); @@ -245,8 +204,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { }).then(async (res: Response) => { (await res.json()).map(action((file: any) => { let path = window.location.origin + file; - let docPromise = this.getDocumentFromType(type, path, { ...options, nativeWidth: 300, width: 300, title: dropFileName }); - + let docPromise = Docs.getDocumentFromType(type, path, { ...options, nativeWidth: 300, width: 300, title: dropFileName }, this.props.addDocument); docPromise.then(doc => doc && this.props.addDocument(doc)); })); }); -- cgit v1.2.3-70-g09d2 From d236da11dcd635440eecb897a195df8ade4ca7b0 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 4 Jul 2019 18:20:54 -0400 Subject: added dropping and reordering within Stacking views. needs GUI feedback. --- src/client/util/DragManager.ts | 2 +- .../views/collections/CollectionStackingView.tsx | 58 +++++++++++++++++++++- src/client/views/collections/CollectionSubView.tsx | 9 +++- src/client/views/nodes/ImageBox.tsx | 4 +- 4 files changed, 68 insertions(+), 5 deletions(-) (limited to 'src/client/views/collections/CollectionSubView.tsx') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index d4b1bc8f4..ce1f9d890 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -448,7 +448,7 @@ export namespace DragManager { x: e.x, y: e.y, data: dragData, - mods: e.altKey ? "AltKey" : "" + mods: e.altKey ? "AltKey" : e.ctrlKey ? "CtrlKey" : "" } }) ); diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index b10907937..6b4eddec9 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -11,6 +11,8 @@ import { CollectionSchemaPreview } from "./CollectionSchemaView"; import "./CollectionStackingView.scss"; import { CollectionSubView } from "./CollectionSubView"; import { resolve } from "bluebird"; +import { undoBatch } from "../../util/UndoManager"; +import { DragManager } from "../../util/DragManager"; @observer export class CollectionStackingView extends CollectionSubView(doc => doc) { @@ -96,8 +98,10 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { ; }); } + docXfs: any[] = [] @computed get children() { + this.docXfs.length = 0; return this.childDocs.filter(d => !d.isMinimized).map((d, i) => { let aspect = d.nativeHeight ? NumCast(d.nativeWidth) / NumCast(d.nativeHeight) : undefined; let dref = React.createRef(); @@ -105,6 +109,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { let width = () => d.nativeWidth ? Math.min(d[WidthSym](), this.columnWidth) : this.columnWidth; let height = () => aspect ? width() / aspect : d[HeightSym](); let rowSpan = Math.ceil((height() + this.gridGap) / (this._gridSize + this.gridGap)); + this.docXfs.push({ dxf: dxf, width: width, height: height }); return (
doc) { }); } } + + @undoBatch + @action + drop = (e: Event, de: DragManager.DropEvent) => { + let targInd = -1; + let where = [de.x, de.y]; + if (de.data instanceof DragManager.DocumentDragData) { + this.docXfs.map((cd, i) => { + let pos = cd.dxf().inverse().transformPoint(-2 * this.gridGap, -2 * this.gridGap); + let pos1 = cd.dxf().inverse().transformPoint(cd.width(), cd.height()); + if (where[0] > pos[0] && where[0] < pos1[0] && where[1] > pos[1] && where[1] < pos1[1]) { + targInd = i; + } + }) + } + if (super.drop(e, de)) { + if (targInd !== -1) { + let newDoc = de.data.droppedDocuments[0]; + let docs = this.childDocList; + if (docs) { + let srcInd = docs.indexOf(newDoc); + docs.splice(srcInd, 1); + docs.splice(targInd > srcInd ? targInd - 1 : targInd, 0, newDoc); + } + } + } + return false; + } + @undoBatch + @action + onDrop = (e: React.DragEvent): void => { + let where = [e.clientX, e.clientY]; + let targInd = -1; + this.docXfs.map((cd, i) => { + let pos = cd.dxf().inverse().transformPoint(-2 * this.gridGap, -2 * this.gridGap); + let pos1 = cd.dxf().inverse().transformPoint(cd.width(), cd.height()); + if (where[0] > pos[0] && where[0] < pos1[0] && where[1] > pos[1] && where[1] < pos1[1]) { + targInd = i; + } + }) + super.onDrop(e, {}, () => { + if (targInd !== -1) { + let newDoc = this.childDocs[this.childDocs.length - 1]; + let docs = this.childDocList; + if (docs) { + docs.splice(docs.length - 1, 1); + docs.splice(targInd, 0, newDoc); + } + } + }); + } render() { let cols = this.singleColumn ? 1 : Math.max(1, Math.min(this.childDocs.filter(d => !d.isMinimized).length, Math.floor((this.props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + this.gridGap)))); let templatecols = ""; for (let i = 0; i < cols; i++) templatecols += `${this.columnWidth}px `; return ( -
e.stopPropagation()} > +
e.stopPropagation()} >
(schemaCtor: (doc: Doc) => T) { //This linter error can't be fixed because of how js arguments work, so don't switch this to filter(FieldValue) return DocListCast((BoolCast(this.props.Document.isTemplate) ? this.extensionDoc : this.props.Document)[this.props.fieldExt ? this.props.fieldExt : this.props.fieldKey]); } + get childDocList() { + //TODO tfs: This might not be what we want? + //This linter error can't be fixed because of how js arguments work, so don't switch this to filter(FieldValue) + return Cast((BoolCast(this.props.Document.isTemplate) ? this.extensionDoc : this.props.Document)[this.props.fieldExt ? this.props.fieldExt : this.props.fieldKey], listSpec(Doc)); + } @action protected async setCursorPosition(position: [number, number]) { @@ -145,7 +150,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { @undoBatch @action - protected onDrop(e: React.DragEvent, options: DocumentOptions): void { + protected onDrop(e: React.DragEvent, options: DocumentOptions, completed?: () => void) { if (e.ctrlKey) { e.stopPropagation(); // bcz: this is a hack to stop propagation when dropping an image on a text document with shift+ctrl return; @@ -255,7 +260,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { } if (promises.length) { - Promise.all(promises).finally(() => batch.end()); + Promise.all(promises).finally(() => { completed && completed(); batch.end(); }); } else { batch.end(); } diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 06bf65f73..dd4e4262d 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -73,7 +73,7 @@ export class ImageBox extends DocComponent(ImageD if (de.mods === "AltKey" && /*this.dataDoc !== this.props.Document &&*/ drop.data instanceof ImageField) { Doc.GetProto(this.dataDoc)[this.props.fieldKey] = new ImageField(drop.data.url); e.stopPropagation(); - } else { + } else if (de.mods === "CtrlKey") { if (this.extensionDoc !== this.dataDoc) { let layout = StrCast(drop.backgroundLayout); if (layout.indexOf(ImageBox.name) !== -1) { @@ -205,6 +205,8 @@ export class ImageBox extends DocComponent(ImageD requestImageSize(window.origin + RouteStore.corsProxy + "/" + srcpath) .then((size: any) => { let aspect = size.height / size.width; + let rotation = NumCast(this.dataDoc.rotation) % 180; + if (rotation === 90 || rotation === 270) aspect = 1 / aspect; if (Math.abs(layoutdoc[HeightSym]() / layoutdoc[WidthSym]() - aspect) > 0.01) { setTimeout(action(() => { layoutdoc.height = layoutdoc[WidthSym]() * aspect; -- cgit v1.2.3-70-g09d2 From aedd283fb9f9eff4145e27658bc6647982256032 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Fri, 5 Jul 2019 00:34:19 -0400 Subject: beginning implementation of key value tags for all imported documents --- src/client/documents/Documents.ts | 12 +- .../util/Import & Export/DirectoryImportBox.scss | 0 .../util/Import & Export/DirectoryImportBox.tsx | 181 +++++++++++++++++++++ src/client/util/Import & Export/ImageImporter.tsx | 67 -------- src/client/util/Import & Export/ImportBox.tsx | 134 --------------- src/client/util/request-image-size.js | 6 +- src/client/views/MainView.tsx | 1 - src/client/views/collections/CollectionSubView.tsx | 4 +- src/client/views/nodes/DocumentContentsView.tsx | 4 +- src/client/views/nodes/ImageBox.tsx | 4 +- 10 files changed, 198 insertions(+), 215 deletions(-) create mode 100644 src/client/util/Import & Export/DirectoryImportBox.scss create mode 100644 src/client/util/Import & Export/DirectoryImportBox.tsx delete mode 100644 src/client/util/Import & Export/ImageImporter.tsx delete mode 100644 src/client/util/Import & Export/ImportBox.tsx (limited to 'src/client/views/collections/CollectionSubView.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 5d637dd3a..26b5498a2 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -36,7 +36,7 @@ import { UndoManager } from "../util/UndoManager"; import { RouteStore } from "../../server/RouteStore"; import { LinkManager } from "../util/LinkManager"; import { DocumentManager } from "../util/DocumentManager"; -import ImportBox from "../util/Import & Export/ImportBox"; +import DirectoryImportBox from "../util/Import & Export/DirectoryImportBox"; var requestImageSize = require('../util/request-image-size'); var path = require('path'); @@ -180,7 +180,7 @@ export namespace Docs { } function CreateImportPrototype(): Doc { - let importProto = setupPrototypeOptions(importProtoId, "IMPORT_PROTO", ImportBox.LayoutString(), { x: 0, y: 0, width: 600, height: 600, type: DocTypes.IMPORT }); + let importProto = setupPrototypeOptions(importProtoId, "IMPORT_PROTO", DirectoryImportBox.LayoutString(), { x: 0, y: 0, width: 600, height: 600, type: DocTypes.IMPORT }); return importProto; } @@ -347,7 +347,7 @@ export namespace Docs { return CreateInstance(collProto, new List(documents), { ...options, viewType: CollectionViewType.Docking, dockingConfig: config }, id); } - export async function getDocumentFromType(type: string, path: string, options: DocumentOptions, addDocument?: (document: Doc, allowDuplicates?: boolean) => boolean): Promise> { + export async function getDocumentFromType(type: string, path: string, options: DocumentOptions): Promise> { let ctor: ((path: string, options: DocumentOptions) => (Doc | Promise)) | undefined = undefined; if (type.indexOf("image") !== -1) { ctor = Docs.ImageDocument; @@ -370,17 +370,17 @@ export namespace Docs { if (path.includes(window.location.hostname)) { let s = path.split('/'); let id = s[s.length - 1]; - DocServer.GetRefField(id).then(field => { + return DocServer.GetRefField(id).then(field => { if (field instanceof Doc) { let alias = Doc.MakeAlias(field); alias.x = options.x || 0; alias.y = options.y || 0; alias.width = options.width || 300; alias.height = options.height || options.width || 300; - addDocument && addDocument(alias, false); + return alias; } + return undefined; }); - return undefined; } ctor = Docs.WebDocument; options = { height: options.width, ...options, title: path, nativeWidth: undefined }; diff --git a/src/client/util/Import & Export/DirectoryImportBox.scss b/src/client/util/Import & Export/DirectoryImportBox.scss new file mode 100644 index 000000000..e69de29bb diff --git a/src/client/util/Import & Export/DirectoryImportBox.tsx b/src/client/util/Import & Export/DirectoryImportBox.tsx new file mode 100644 index 000000000..2d77f6ae6 --- /dev/null +++ b/src/client/util/Import & Export/DirectoryImportBox.tsx @@ -0,0 +1,181 @@ +import "fs"; +import React = require("react"); +import { Doc } from "../../../new_fields/Doc"; +import { DocServer } from "../../DocServer"; +import { RouteStore } from "../../../server/RouteStore"; +import { action, observable, runInAction } from "mobx"; +import { FieldViewProps, FieldView } from "../../views/nodes/FieldView"; +import Measure, { ContentRect } from "react-measure"; +import { library } from '@fortawesome/fontawesome-svg-core'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faArrowUp, faTag, faFileExcel } from '@fortawesome/free-solid-svg-icons'; +import { Docs, DocumentOptions } from "../../documents/Documents"; +import { EditableView } from "../../views/EditableView"; + +export default class DirectoryImportBox extends React.Component { + private selector = React.createRef(); + @observable private top = 0; + @observable private left = 0; + private dimensions = 50; + + @observable private key = "Key"; + @observable private value = "Value"; + + public static LayoutString() { return FieldView.LayoutString(DirectoryImportBox); } + + constructor(props: FieldViewProps) { + super(props); + library.add(faArrowUp, faTag); + } + + updateKey = (newKey: string) => { + runInAction(() => this.key = newKey); + console.log("KEY ", this.key); + return true; + } + + updateValue = (newValue: string) => { + runInAction(() => this.value = newValue); + console.log("VALUE ", this.value); + return true; + } + + handleSelection = async (e: React.ChangeEvent) => { + let promises: Promise[] = []; + let docs: Doc[] = []; + + let files = e.target.files; + if (!files || files.length === 0) return; + + let directory = (files.item(0) as any).webkitRelativePath.split("/", 1); + + for (let i = 0; i < files.length; i++) { + let uploaded_file = files.item(i); + + if (!uploaded_file) { + continue; + } + + let formData = new FormData(); + formData.append('file', uploaded_file); + let dropFileName = uploaded_file ? uploaded_file.name : "-empty-"; + let type = uploaded_file.type; + + let prom = fetch(DocServer.prepend(RouteStore.upload), { + method: 'POST', + body: formData + }).then(async (res: Response) => { + (await res.json()).map(action((file: any) => { + let path = DocServer.prepend(file); + console.log(path); + let docPromise = Docs.getDocumentFromType(type, path, { nativeWidth: 300, width: 300, title: dropFileName }); + docPromise.then(doc => doc && docs.push(doc)); + })); + }); + promises.push(prom); + } + + await Promise.all(promises); + + let doc = this.props.Document; + let options: DocumentOptions = { title: `Import of ${directory}`, width: 500, height: 500, x: Doc.GetT(doc, "x", "number"), y: Doc.GetT(doc, "y", "number") }; + let parent = this.props.ContainingCollectionView; + if (parent) { + let importContainer = Docs.StackingDocument(docs, options); + Doc.AddDocToList(Doc.GetProto(parent.props.Document), "data", importContainer); + this.props.removeDocument && this.props.removeDocument(doc); + } + } + + componentDidMount() { + this.selector.current!.setAttribute("directory", ""); + this.selector.current!.setAttribute("webkitdirectory", ""); + } + + @action + preserveCentering = (rect: ContentRect) => { + let bounds = rect.offset!; + if (bounds.width === 0 || bounds.height === 0) { + return; + } + let offset = this.dimensions / 2; + this.left = bounds.width / 2 - offset; + this.top = bounds.height / 2 - offset; + } + + render() { + let dimensions = 50; + let keyValueStyle = { paddingLeft: 5, width: "50%" }; + return ( + + {({ measureRef }) => +
+ +