From c23d9ba83c87511a626bfe8d1da5dd981e311262 Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 23 Jan 2020 18:24:38 -0500 Subject: got rid of extension docs. changed layout-specific keys to start with "_" which flags them to be written to the current layout document --- src/client/views/nodes/AudioBox.tsx | 101 +++++++++++++++++------------------- 1 file changed, 49 insertions(+), 52 deletions(-) (limited to 'src/client/views/nodes/AudioBox.tsx') diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 95c765e8a..8ede79edc 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -68,7 +68,7 @@ export class AudioBox extends DocExtendableComponent AudioBox._scrubTime, timeInMillisecondsFrom1970 => { - const start = this.extensionDoc && DateCast(this.extensionDoc.recordingStart); + const start = DateCast(this.dataDoc[this.props.fieldKey + "-recordingStart"]); start && this.playFrom((timeInMillisecondsFrom1970 - start.date.getTime()) / 1000); }); } @@ -128,13 +128,12 @@ export class AudioBox extends DocExtendableComponent { let gumStream: any; const self = this; - const extensionDoc = this.extensionDoc; - extensionDoc && navigator.mediaDevices.getUserMedia({ + navigator.mediaDevices.getUserMedia({ audio: true }).then(function (stream) { gumStream = stream; self._recorder = new MediaRecorder(stream); - extensionDoc.recordingStart = new DateField(new Date()); + self.dataDoc[self.props.fieldKey + "-recordingStart"] = new DateField(new Date()); AudioBox.ActiveRecordings.push(self.props.Document); self._recorder.ondataavailable = async function (e: any) { const formData = new FormData(); @@ -213,55 +212,53 @@ export class AudioBox extends DocExtendableComponent -
- {!this.path ? - : -
-
-
-
-
e.stopPropagation()} - onPointerDown={e => { - if (e.button === 0 && !e.ctrlKey) { - const rect = (e.target as any).getBoundingClientRect(); - this._ele!.currentTime = this.Document.currentTimecode = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration); - this.pause(); - e.stopPropagation(); - } - }} > - {DocListCast(this.dataDoc.links).map((l, i) => { - let la1 = l.anchor1 as Doc; - let la2 = l.anchor2 as Doc; - let linkTime = NumCast(l.anchor2Timecode); - if (Doc.AreProtosEqual(la1, this.dataDoc)) { - la1 = l.anchor2 as Doc; - la2 = l.anchor1 as Doc; - linkTime = NumCast(l.anchor1Timecode); - } - return !linkTime ? (null) : -
-
- -
-
Doc.linkFollowHighlight(la1)} - onPointerDown={e => { if (e.button === 0 && !e.ctrlKey) { this.playFrom(linkTime); e.stopPropagation(); } }} - onClick={e => { if (e.button === 0 && !e.ctrlKey) { this.pause(); e.stopPropagation(); } }} /> -
; - })} -
- {this.audio} -
+ return
+
+ {!this.path ? + : +
+
+
+
+
e.stopPropagation()} + onPointerDown={e => { + if (e.button === 0 && !e.ctrlKey) { + const rect = (e.target as any).getBoundingClientRect(); + this._ele!.currentTime = this.Document.currentTimecode = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration); + this.pause(); + e.stopPropagation(); + } + }} > + {DocListCast(this.dataDoc.links).map((l, i) => { + let la1 = l.anchor1 as Doc; + let la2 = l.anchor2 as Doc; + let linkTime = NumCast(l.anchor2Timecode); + if (Doc.AreProtosEqual(la1, this.dataDoc)) { + la1 = l.anchor2 as Doc; + la2 = l.anchor1 as Doc; + linkTime = NumCast(l.anchor1Timecode); + } + return !linkTime ? (null) : +
+
+ +
+
Doc.linkFollowHighlight(la1)} + onPointerDown={e => { if (e.button === 0 && !e.ctrlKey) { this.playFrom(linkTime); e.stopPropagation(); } }} + onClick={e => { if (e.button === 0 && !e.ctrlKey) { this.pause(); e.stopPropagation(); } }} /> +
; + })} +
+ {this.audio}
- } -
- ); +
+ } +
; } } \ No newline at end of file -- cgit v1.2.3-70-g09d2 From c5d618538d4fd9669476dc7eb66ddd45783e5fa6 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Mon, 27 Jan 2020 05:50:15 -0500 Subject: nativewidth and nativeheight extension key fix and implemented UI to manually download a remotely hosted image --- .../util/Import & Export/DirectoryImportBox.tsx | 4 ++-- src/client/util/Import & Export/ImageUtils.ts | 4 ++-- src/client/views/DocComponent.tsx | 2 +- src/client/views/collections/CollectionSubView.tsx | 2 +- src/client/views/nodes/AudioBox.tsx | 2 +- src/client/views/nodes/ImageBox.scss | 24 ++++++++++++++----- src/client/views/nodes/ImageBox.tsx | 28 +++++++++++++++++++++- src/mobile/ImageUpload.tsx | 2 +- src/server/ApiManagers/UploadManager.ts | 14 ++++++++++- src/server/DashUploadUtils.ts | 12 +++------- 10 files changed, 69 insertions(+), 25 deletions(-) (limited to 'src/client/views/nodes/AudioBox.tsx') diff --git a/src/client/util/Import & Export/DirectoryImportBox.tsx b/src/client/util/Import & Export/DirectoryImportBox.tsx index c7c94abed..071015193 100644 --- a/src/client/util/Import & Export/DirectoryImportBox.tsx +++ b/src/client/util/Import & Export/DirectoryImportBox.tsx @@ -116,13 +116,13 @@ export default class DirectoryImportBox extends React.Component formData.append(Utils.GenerateGuid(), file); }); - collector.push(...(await Networking.PostFormDataToServer("/upload", formData))); + collector.push(...(await Networking.PostFormDataToServer("/uploadFormData", formData))); runInAction(() => this.completed += batch.length); }); await Promise.all(uploads.map(async ({ name, type, clientAccessPath, exifData }) => { const path = Utils.prepend(clientAccessPath); - const document = await Docs.Get.DocumentFromType(type, path, { width: 300, title: name }); + const document = await Docs.Get.DocumentFromType(type, path, { _width: 300, title: name }); const { data, error } = exifData; if (document) { Doc.GetProto(document).exif = error || Docs.Get.DocumentHierarchyFromJson(data); diff --git a/src/client/util/Import & Export/ImageUtils.ts b/src/client/util/Import & Export/ImageUtils.ts index 2f4db0e17..ff909cc6b 100644 --- a/src/client/util/Import & Export/ImageUtils.ts +++ b/src/client/util/Import & Export/ImageUtils.ts @@ -22,8 +22,8 @@ export namespace ImageUtils { } = await Networking.PostToServer("/inspectImage", { source }); document.exif = error || Docs.Get.DocumentHierarchyFromJson(data); const proto = Doc.GetProto(document); - proto.nativeWidth = nativeWidth; - proto.nativeHeight = nativeHeight; + proto["data-nativeWidth"] = nativeWidth; + proto["data-nativeHeight"] = nativeHeight; proto.contentSize = contentSize; return data !== undefined; }; diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index d98301cf6..6f3eb6808 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -61,7 +61,7 @@ export function DocAnnotatableComponent

(schema _annotationKey: string = "annotations"; public set annotationKey(val: string) { this._annotationKey = val; } - public get annotationKey() { return this._annotationKey } + public get annotationKey() { return this._annotationKey; } @action.bound removeDocument(doc: Doc): boolean { diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index b96b86929..80fcc33aa 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -324,7 +324,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { formData.append('file', file); const dropFileName = file ? file.name : "-empty-"; - promises.push(Networking.PostFormDataToServer("/upload", formData).then(results => { + promises.push(Networking.PostFormDataToServer("/uploadFormData", formData).then(results => { results.map(action((result: any) => { const { clientAccessPath, nativeWidth, nativeHeight, contentSize } = result; const full = { ...options, _width: 300, title: dropFileName }; diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 8ede79edc..62a479b2a 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -138,7 +138,7 @@ export class AudioBox extends DocExtendableComponent); } + @computed + private get considerDownloadIcon() { + const data = this.dataDoc[this.props.fieldKey]; + if (!(data instanceof ImageField)) { + return (null); + } + const primary = data.url.href; + if (primary.includes(window.location.origin)) { + return (null); + } + return ( + { + const { dataDoc } = this; + const [{ clientAccessPath }] = await Networking.PostToServer("/uploadRemoteImage", { sources: [primary] }); + dataDoc.originalUrl = primary; + dataDoc[this.props.fieldKey] = new ImageField(Utils.prepend(clientAccessPath)); + }} + /> + ); + } + @computed get nativeSize() { const pw = typeof this.props.PanelWidth === "function" ? this.props.PanelWidth() : typeof this.props.PanelWidth === "number" ? (this.props.PanelWidth as any) as number : 50; const nativeWidth = NumCast(this.dataDoc[this.props.fieldKey + "-nativeWidth"], pw); @@ -347,6 +372,7 @@ export class ImageBox extends DocAnnotatableComponent

+ {this.considerDownloadIcon} {this.considerGooglePhotosLink()}
; diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx index dab4de110..1583e3d5d 100644 --- a/src/mobile/ImageUpload.tsx +++ b/src/mobile/ImageUpload.tsx @@ -45,7 +45,7 @@ class Uploader extends React.Component { const formData = new FormData(); formData.append("file", files[0]); - const upload = window.location.origin + "/upload"; + const upload = window.location.origin + "/uploadFormData"; this.status = "uploading image"; const res = await fetch(upload, { method: 'POST', diff --git a/src/server/ApiManagers/UploadManager.ts b/src/server/ApiManagers/UploadManager.ts index 583eaa59b..a92b613b7 100644 --- a/src/server/ApiManagers/UploadManager.ts +++ b/src/server/ApiManagers/UploadManager.ts @@ -40,7 +40,7 @@ export default class UploadManager extends ApiManager { register({ method: Method.POST, - subscription: "/upload", + subscription: "/uploadFormData", secureHandler: async ({ req, res }) => { const form = new formidable.IncomingForm(); form.uploadDir = pathToDirectory(Directory.parsed_files); @@ -59,6 +59,18 @@ export default class UploadManager extends ApiManager { } }); + register({ + method: Method.POST, + subscription: "/uploadRemoteImage", + secureHandler: async ({ req, res }) => { + const { sources } = req.body; + if (Array.isArray(sources)) { + return res.send(await Promise.all(sources.map(url => DashUploadUtils.UploadImage(url)))); + } + res.send(); + } + }); + register({ method: Method.POST, subscription: "/uploadDoc", diff --git a/src/server/DashUploadUtils.ts b/src/server/DashUploadUtils.ts index b826b4882..cb7104757 100644 --- a/src/server/DashUploadUtils.ts +++ b/src/server/DashUploadUtils.ts @@ -108,13 +108,7 @@ export namespace DashUploadUtils { return MoveParsedFile(absolutePath, Directory.pdfs); } - const generate = (prefix: string, url: string) => `${prefix}upload_${Utils.GenerateGuid()}${sanitizeExtension(url)}`; - const sanitizeExtension = (source: string) => { - let extension = path.extname(source); - extension = extension.toLowerCase(); - extension = extension.split("?")[0]; - return extension; - }; + const generate = (prefix: string, extension: string) => `${prefix}upload_${Utils.GenerateGuid()}.${extension}`; /** * Uploads an image specified by the @param source to Dash's /public/files/ @@ -209,8 +203,8 @@ export namespace DashUploadUtils { export const UploadInspectedImage = async (metadata: InspectionResults, filename?: string, format?: string, prefix = ""): Promise => { const { requestable, source, ...remaining } = metadata; - const resolved = filename || generate(prefix, requestable); - const extension = format || sanitizeExtension(requestable || resolved); + const extension = remaining.contentType.toLowerCase().split("/")[1]; //format || sanitizeExtension(requestable || resolved); + const resolved = filename || generate(prefix, extension); const information: ImageUploadInformation = { clientAccessPath: clientPathToFile(Directory.images, resolved), serverAccessPaths: {}, -- cgit v1.2.3-70-g09d2