From 510f9145fa1bffd72aaee1c861e2013a0cad42ca Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 21 Sep 2022 12:06:07 -0400
Subject: fixed following links to toggle alias if it's displayed when actual
 target isn't.  changed cropping images to leave behind an outline not, a
 solid rectangle.  double clicking on link buttons no longer opens them in
 lightbox view.

---
 src/client/views/nodes/ImageBox.tsx | 1 +
 1 file changed, 1 insertion(+)

(limited to 'src/client/views/nodes/ImageBox.tsx')

diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 9590bcb15..11f221448 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -136,6 +136,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
     crop = (region: Doc | undefined, addCrop?: boolean) => {
         if (!region) return;
         const cropping = Doc.MakeCopy(region, true);
+        Doc.GetProto(region).backgroundColor = 'transparent';
         Doc.GetProto(region).lockedPosition = true;
         Doc.GetProto(region).title = 'region:' + this.rootDoc.title;
         Doc.GetProto(region).isPushpin = true;
-- 
cgit v1.2.3-70-g09d2


From 0046f6eab6ec28b509398b5184922296014a66d0 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 21 Sep 2022 13:24:02 -0400
Subject:  added cropping for videos.  made images render at full res when
 selected.

---
 src/client/views/nodes/ImageBox.tsx |  2 +-
 src/client/views/nodes/VideoBox.tsx | 53 +++++++++++++++++++++++++++++++++++--
 2 files changed, 52 insertions(+), 3 deletions(-)

(limited to 'src/client/views/nodes/ImageBox.tsx')

diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 11f221448..d3d68d835 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -74,7 +74,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                 scrSize: this.props.ScreenToLocalTransform().inverse().transformDirection(this.nativeSize.nativeWidth, this.nativeSize.nativeHeight)[0] / this.nativeSize.nativeWidth,
                 selected: this.props.isSelected(),
             }),
-            ({ forceFull, scrSize, selected }) => (this._curSuffix = this.fieldKey === 'icon' ? '_m' : forceFull ? '_o' : scrSize < 0.25 ? '_s' : scrSize < 0.5 ? '_m' : scrSize < 0.8 || !selected ? '_l' : '_o'),
+            ({ forceFull, scrSize, selected }) => (this._curSuffix = selected ? '_o' : this.fieldKey === 'icon' ? '_m' : forceFull ? '_o' : scrSize < 0.25 ? '_s' : scrSize < 0.5 ? '_m' : scrSize < 0.8 ? '_l' : '_o'),
             { fireImmediately: true, delay: 1000 }
         );
         this._disposers.path = reaction(
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index b45ee7f6e..ac472aa89 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -30,6 +30,7 @@ import { StyleProp } from '../StyleProvider';
 import { FieldView, FieldViewProps } from './FieldView';
 import { RecordingBox } from './RecordingBox';
 import './VideoBox.scss';
+import { ObjectField } from '../../../fields/ObjectField';
 const path = require('path');
 
 /**
@@ -397,7 +398,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
     // sets video info on load
     videoLoad = action(() => {
         const aspect = this.player!.videoWidth / (this.player!.videoHeight || 1);
-        if (aspect) {
+        if (aspect && !this.dataDoc.viewScaleMin) {
             Doc.SetNativeWidth(this.dataDoc, this.player!.videoWidth);
             Doc.SetNativeHeight(this.dataDoc, this.player!.videoHeight);
             this.layoutDoc._height = NumCast(this.layoutDoc._width) / aspect;
@@ -570,7 +571,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                         key="video"
                         autoPlay={this._screenCapture}
                         ref={this.setVideoRef}
-                        style={this._fullScreen ? this.fullScreenSize() : {}}
+                        style={this._fullScreen ? this.fullScreenSize() : this.dataDoc.viewScaleMin ? { width: 'max-content', height: 'max-content', transform: `scale(${1 / NumCast(this.rootDoc._viewScale)})`, transformOrigin: 'top left' } : {}}
                         onCanPlay={this.videoLoad}
                         controls={VideoBox._nativeControls}
                         onPlay={() => this.Play()}
@@ -986,6 +987,53 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         return <div className="videoBox-annotationLayer" style={{ transition: this.transition, height: `${this.heightPercent}%` }} ref={this._annotationLayer} />;
     }
 
+    crop = (region: Doc | undefined, addCrop?: boolean) => {
+        if (!region) return;
+        const cropping = Doc.MakeCopy(region, true);
+        Doc.GetProto(region).backgroundColor = 'transparent';
+        Doc.GetProto(region).lockedPosition = true;
+        Doc.GetProto(region).title = 'region:' + this.rootDoc.title;
+        Doc.GetProto(region).isPushpin = true;
+        region._timecodeToHide = region._timecodeToShow;
+        this.addDocument(region);
+        const anchx = NumCast(cropping.x);
+        const anchy = NumCast(cropping.y);
+        const anchw = NumCast(cropping._width);
+        const anchh = NumCast(cropping._height);
+        const viewScale = NumCast(this.rootDoc[this.fieldKey + '-nativeWidth']) / anchw;
+        cropping.title = 'crop: ' + this.rootDoc.title;
+        cropping.x = NumCast(this.rootDoc.x) + NumCast(this.rootDoc._width);
+        cropping.y = NumCast(this.rootDoc.y);
+        cropping._width = anchw * (this.props.NativeDimScaling?.() || 1);
+        cropping._height = anchh * (this.props.NativeDimScaling?.() || 1);
+        cropping.timecodeToHide = undefined;
+        cropping.timecodeToShow = undefined;
+        cropping.isLinkButton = undefined;
+        const croppingProto = Doc.GetProto(cropping);
+        croppingProto.annotationOn = undefined;
+        croppingProto.isPrototype = true;
+        croppingProto.proto = Cast(this.rootDoc.proto, Doc, null)?.proto; // set proto of cropping's data doc to be IMAGE_PROTO
+        croppingProto.type = DocumentType.VID;
+        croppingProto.layout = VideoBox.LayoutString('data');
+        croppingProto.data = ObjectField.MakeCopy(this.rootDoc[this.fieldKey] as ObjectField);
+        croppingProto['data-nativeWidth'] = anchw;
+        croppingProto['data-nativeHeight'] = anchh;
+        croppingProto.currentTimecode = this.layoutDoc._currentTimecode;
+        croppingProto.viewScale = viewScale;
+        croppingProto.viewScaleMin = viewScale;
+        croppingProto.panX = anchx / viewScale;
+        croppingProto.panY = anchy / viewScale;
+        croppingProto.panXMin = anchx / viewScale;
+        croppingProto.panXMax = anchw / viewScale;
+        croppingProto.panYMin = anchy / viewScale;
+        croppingProto.panYMax = anchh / viewScale;
+        if (addCrop) {
+            DocUtils.MakeLink({ doc: region }, { doc: cropping }, 'cropped image', '');
+        }
+        this.props.bringToFront(cropping);
+        return cropping;
+    };
+
     savedAnnotations = () => this._savedAnnotations;
     render() {
         const borderRad = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BorderRounding);
@@ -1048,6 +1096,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                             savedAnnotations={this.savedAnnotations}
                             annotationLayer={this._annotationLayer.current}
                             mainCont={this._mainCont.current}
+                            anchorMenuCrop={this.crop}
                         />
                     )}
                     {this.renderTimeline}
-- 
cgit v1.2.3-70-g09d2


From 604b3e566eaf762ede05f4a31c459c20d0df020b Mon Sep 17 00:00:00 2001
From: Geireann Lindfield Roberts <60007097+geireann@users.noreply.github.com>
Date: Thu, 22 Sep 2022 13:10:56 -0400
Subject: added more things to novice mode

---
 src/client/views/nodes/ImageBox.tsx              | 2 +-
 src/client/views/nodes/trails/PresElementBox.tsx | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

(limited to 'src/client/views/nodes/ImageBox.tsx')

diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index d3d68d835..486c9c48c 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -340,7 +340,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                         </div>
                     )}
                 </div>
-                {this.considerDownloadIcon}
+                {!Doc.noviceMode && this.considerDownloadIcon}
                 {this.considerGooglePhotosLink()}
                 <FaceRectangles document={this.dataDoc} color={'#0000FF'} backgroundColor={'#0000FF'} />
             </div>
diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx
index e3f93c637..e6d08cd53 100644
--- a/src/client/views/nodes/trails/PresElementBox.tsx
+++ b/src/client/views/nodes/trails/PresElementBox.tsx
@@ -511,11 +511,11 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
                                     V
                                 </div>
                             </Tooltip>
-                            <Tooltip title={<div className="dash-tooltip">{this.recordingIsInOverlay ? 'Hide Recording' : `${PresElementBox.videoIsRecorded(activeItem) ? 'Show' : 'Start'} recording`}</div>}>
+                            {!Doc.noviceMode && <Tooltip title={<div className="dash-tooltip">{this.recordingIsInOverlay ? 'Hide Recording' : `${PresElementBox.videoIsRecorded(activeItem) ? 'Show' : 'Start'} recording`}</div>}>
                                 <div className="slideButton" onClick={e => (this.recordingIsInOverlay ? this.hideRecording(e, true) : this.startRecording(e, activeItem))} style={{ fontWeight: 700 }}>
                                     <FontAwesomeIcon icon={`video${this.recordingIsInOverlay ? '-slash' : ''}`} onPointerDown={e => e.stopPropagation()} />
                                 </div>
-                            </Tooltip>
+                            </Tooltip>}
                             <Tooltip title={<div className="dash-tooltip">{activeItem.groupWithUp ? 'Ungroup' : 'Group with up'}</div>}>
                                 <div
                                     className="slideButton"
-- 
cgit v1.2.3-70-g09d2


From e8c7c942fa19922b476573ad664b2bfc87191b44 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 5 Oct 2022 14:06:34 -0400
Subject: fixed uploading tif and other unsupported images to generate an error
 quickly with a better erorr message.

---
 deploy/assets/unknown-file-icon-hi.png | Bin 0 -> 32861 bytes
 src/client/util/request-image-size.js  |  26 ++++++++++++++------------
 src/client/views/nodes/ImageBox.tsx    |   2 +-
 src/server/DashUploadUtils.ts          |  11 ++++++-----
 4 files changed, 21 insertions(+), 18 deletions(-)
 create mode 100644 deploy/assets/unknown-file-icon-hi.png

(limited to 'src/client/views/nodes/ImageBox.tsx')

diff --git a/deploy/assets/unknown-file-icon-hi.png b/deploy/assets/unknown-file-icon-hi.png
new file mode 100644
index 000000000..be8a5ece0
Binary files /dev/null and b/deploy/assets/unknown-file-icon-hi.png differ
diff --git a/src/client/util/request-image-size.js b/src/client/util/request-image-size.js
index beb030635..502e0fbac 100644
--- a/src/client/util/request-image-size.js
+++ b/src/client/util/request-image-size.js
@@ -15,15 +15,18 @@ const HttpError = require('standard-http-error');
 
 module.exports = function requestImageSize(options) {
     let opts = {
-        encoding: null
+        encoding: null,
     };
 
     if (options && typeof options === 'object') {
         opts = Object.assign(options, opts);
     } else if (options && typeof options === 'string') {
-        opts = Object.assign({
-            uri: options
-        }, opts);
+        opts = Object.assign(
+            {
+                uri: options,
+            },
+            opts
+        );
     } else {
         return Promise.reject(new Error('You should provide an URI string or a "request" options object.'));
     }
@@ -38,9 +41,8 @@ module.exports = function requestImageSize(options) {
                 return reject(new HttpError(res.statusCode, res.statusMessage));
             }
 
-            let buffer = new Buffer.from([]);
+            let buffer = Buffer.from([]);
             let size;
-            let imageSizeError;
 
             res.on('data', chunk => {
                 buffer = Buffer.concat([buffer, chunk]);
@@ -48,8 +50,8 @@ module.exports = function requestImageSize(options) {
                 try {
                     size = imageSize(buffer);
                 } catch (err) {
-                    imageSizeError = err;
-                    return;
+                    reject(err);
+                    return req.abort();
                 }
 
                 if (size) {
@@ -58,11 +60,11 @@ module.exports = function requestImageSize(options) {
                 }
             });
 
-            res.on('error', err => reject(err));
+            res.on('error', reject);
 
             res.on('end', () => {
                 if (!size) {
-                    return reject(imageSizeError);
+                    return reject(new Error('Image has no size'));
                 }
 
                 size.downloaded = buffer.length;
@@ -70,6 +72,6 @@ module.exports = function requestImageSize(options) {
             });
         });
 
-        req.on('error', err => reject(err));
+        req.on('error', reject);
     });
-};
\ No newline at end of file
+};
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 486c9c48c..959c641a8 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -231,7 +231,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         const lower = url.href.toLowerCase();
         if (url.protocol === 'data') return url.href;
         if (url.href.indexOf(window.location.origin) === -1) return Utils.CorsProxy(url.href);
-        if (!/\.(png|jpg|jpeg|gif|webp)$/.test(lower)) return url.href; //Why is this here
+        if (!/\.(png|jpg|jpeg|gif|webp)$/.test(lower)) return `/assets/unknown-file-icon-hi.png`;
 
         const ext = extname(url.href);
         return url.href.replace(ext, this._curSuffix + ext);
diff --git a/src/server/DashUploadUtils.ts b/src/server/DashUploadUtils.ts
index 58ec6558b..baf2989fd 100644
--- a/src/server/DashUploadUtils.ts
+++ b/src/server/DashUploadUtils.ts
@@ -2,7 +2,7 @@ import { green, red } from 'colors';
 import { ExifImage } from 'exif';
 import * as exifr from 'exifr';
 import { File } from 'formidable';
-import { createReadStream, createWriteStream, exists, existsSync, readFileSync, rename, unlinkSync, writeFile } from 'fs';
+import { createReadStream, createWriteStream, existsSync, readFileSync, rename, unlinkSync, writeFile } from 'fs';
 import * as path from 'path';
 import { basename } from 'path';
 import * as sharp from 'sharp';
@@ -17,7 +17,6 @@ import { resolvedServerUrl } from './server_Initialization';
 import { AcceptableMedia, Upload } from './SharedMediaTypes';
 import request = require('request-promise');
 import formidable = require('formidable');
-import { NoEmitOnErrorsPlugin } from 'webpack';
 const spawn = require('child_process').spawn;
 const { exec } = require('child_process');
 const parse = require('pdf-parse');
@@ -315,7 +314,7 @@ export namespace DashUploadUtils {
     export const UploadImage = async (source: string, filename?: string, prefix: string = ''): Promise<Upload.ImageInformation | Error> => {
         const metadata = await InspectImage(source);
         if (metadata instanceof Error) {
-            return metadata;
+            return { name: metadata.name, message: metadata.message };
         }
         return UploadInspectedImage(metadata, filename || metadata.filename, prefix);
     };
@@ -395,10 +394,12 @@ export namespace DashUploadUtils {
             exifData,
             requestable: resolvedUrl,
         };
+
         // Use the request library to parse out file level image information in the headers
         const { headers } = await new Promise<any>((resolve, reject) => {
-            request.head(resolvedUrl, (error, res) => (error ? reject(error) : resolve(res)));
-        }).catch(console.error);
+            return request.head(resolvedUrl, (error, res) => (error ? reject(error) : resolve(res)));
+        }).catch(reject);
+
         try {
             // Compute the native width and height ofthe image with an npm module
             const { width: nativeWidth, height: nativeHeight } = await requestImageSize(resolvedUrl);
-- 
cgit v1.2.3-70-g09d2

