From b6ce0dca4f5c32edffe0f271ce3f5e3676040cae Mon Sep 17 00:00:00 2001 From: Melissa Zhang Date: Thu, 16 Apr 2020 15:44:55 -0700 Subject: added ComparisonBox document --- src/client/views/nodes/ComparisonBox.scss | 8 + src/client/views/nodes/ComparisonBox.tsx | 121 ++++++++ src/client/views/nodes/TestBox.tsx | 467 ++++++++++++++++++++++++++++++ 3 files changed, 596 insertions(+) create mode 100644 src/client/views/nodes/ComparisonBox.scss create mode 100644 src/client/views/nodes/ComparisonBox.tsx create mode 100644 src/client/views/nodes/TestBox.tsx (limited to 'src/client') diff --git a/src/client/views/nodes/ComparisonBox.scss b/src/client/views/nodes/ComparisonBox.scss new file mode 100644 index 000000000..32ced3463 --- /dev/null +++ b/src/client/views/nodes/ComparisonBox.scss @@ -0,0 +1,8 @@ +.comparisonBox { + pointer-events: all; + border-radius: inherit; + width: 100%; + height: 100%; + position: absolute; + transform-origin: top left; +} \ No newline at end of file diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx new file mode 100644 index 000000000..167000821 --- /dev/null +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -0,0 +1,121 @@ +import { library } from '@fortawesome/fontawesome-svg-core'; +import { faEye } from '@fortawesome/free-regular-svg-icons'; +import { faAsterisk, faBrain, faFileAudio, faImage, faPaintBrush } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { action, computed, observable, runInAction } from 'mobx'; +import { observer } from "mobx-react"; +import { DataSym, Doc, DocListCast, HeightSym, WidthSym } from '../../../new_fields/Doc'; +import { documentSchema } from '../../../new_fields/documentSchemas'; +import { Id } from '../../../new_fields/FieldSymbols'; +import { List } from '../../../new_fields/List'; +import { ObjectField } from '../../../new_fields/ObjectField'; +import { createSchema, listSpec, makeInterface } from '../../../new_fields/Schema'; +import { ComputedField } from '../../../new_fields/ScriptField'; +import { Cast, NumCast, StrCast } from '../../../new_fields/Types'; +import { AudioField, ImageField } from '../../../new_fields/URLField'; +import { TraceMobx } from '../../../new_fields/util'; +import { emptyFunction, returnOne, Utils, returnZero } from '../../../Utils'; +import { CognitiveServices, Confidence, Service, Tag } from '../../cognitive_services/CognitiveServices'; +import { Docs } from '../../documents/Documents'; +import { DragManager } from '../../util/DragManager'; +import { SelectionManager } from '../../util/SelectionManager'; +import { undoBatch } from '../../util/UndoManager'; +import { ContextMenu } from "../ContextMenu"; +import { ContextMenuProps } from '../ContextMenuItem'; +import { ViewBoxAnnotatableComponent } from '../DocComponent'; +import { FieldView, FieldViewProps } from './FieldView'; +import "./ComparisonBox.scss"; +import React = require("react"); +import { ContentFittingDocumentView } from './ContentFittingDocumentView'; + +library.add(faImage, faEye as any, faPaintBrush, faBrain); +library.add(faFileAudio, faAsterisk); + + +export const pageSchema = createSchema({ + beforeDoc: "string", + afterDoc: "string" +}); + +type ComparisonDocument = makeInterface<[typeof pageSchema, typeof documentSchema]>; +const ComparisonDocument = makeInterface(pageSchema, documentSchema); + + +@observer +export class ComparisonBox extends ViewBoxAnnotatableComponent(ComparisonDocument) { + protected multiTouchDisposer?: import("../../util/InteractionUtils").InteractionUtils.MultiTouchEventDisposer | undefined; + protected beforeDoc: Doc | undefined; + protected afterDoc: Doc | undefined; + + public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ComparisonBox, fieldKey); } + + private _beforeDropDisposer?: DragManager.DragDropDisposer; + private _afterDropDisposer?: DragManager.DragDropDisposer; + + protected createBeforeDropTarget = (ele: HTMLDivElement) => { + this._beforeDropDisposer && this._beforeDropDisposer(); + ele && (this._beforeDropDisposer = DragManager.MakeDropTarget(ele, (event, dropEvent) => { + this.beforeDoc = dropEvent.complete.docDragData.droppedDocuments[0]; + })); + } + + protected createAfterDropTarget = (ele: HTMLDivElement) => { + this._afterDropDisposer && this._afterDropDisposer(); + ele && (this._afterDropDisposer = DragManager.MakeDropTarget(ele, (event, dropEvent) => { + this.afterDoc = dropEvent.complete.docDragData.droppedDocuments[0]; + })); + // this.afterDropHandler(this._afterDropDisposer); + } + + beforeDropHandler = (ele: any) => { + + } + + afterDropHandler = (ele: any) => { + + } + + clearBeforeDoc = (e: PointerEvent) => { + e.stopPropagation; + this.beforeDoc = undefined; + } + + clearAfterDoc = (e: PointerEvent) => { + e.stopPropagation; + this.afterDoc = undefined; + } + + get fieldKey() { + return this.props.fieldKey.startsWith("@") ? StrCast(this.props.Document[this.props.fieldKey]) : this.props.fieldKey; + } + + render() { + TraceMobx(); + const dragging = !SelectionManager.GetIsDragging() ? "" : "-dragging"; + const beforeDoc = this.props.Document.beforeDoc as Doc; + return ( +
+ { + beforeDoc ? +
+ +
: null + } + + {/* { + beforeDoc ? +
+ +
: null + } +
+ +
*/} +
); + } +} \ No newline at end of file diff --git a/src/client/views/nodes/TestBox.tsx b/src/client/views/nodes/TestBox.tsx new file mode 100644 index 000000000..de1640027 --- /dev/null +++ b/src/client/views/nodes/TestBox.tsx @@ -0,0 +1,467 @@ +import { library } from '@fortawesome/fontawesome-svg-core'; +import { faEye } from '@fortawesome/free-regular-svg-icons'; +import { faAsterisk, faBrain, faFileAudio, faImage, faPaintBrush } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { action, computed, observable, runInAction } from 'mobx'; +import { observer } from "mobx-react"; +import { DataSym, Doc, DocListCast, HeightSym, WidthSym } from '../../../new_fields/Doc'; +import { documentSchema } from '../../../new_fields/documentSchemas'; +import { Id } from '../../../new_fields/FieldSymbols'; +import { List } from '../../../new_fields/List'; +import { ObjectField } from '../../../new_fields/ObjectField'; +import { createSchema, listSpec, makeInterface } from '../../../new_fields/Schema'; +import { ComputedField } from '../../../new_fields/ScriptField'; +import { Cast, NumCast, StrCast } from '../../../new_fields/Types'; +import { AudioField, ImageField } from '../../../new_fields/URLField'; +import { TraceMobx } from '../../../new_fields/util'; +import { emptyFunction, returnOne, Utils, returnZero } from '../../../Utils'; +import { CognitiveServices, Confidence, Service, Tag } from '../../cognitive_services/CognitiveServices'; +import { Docs } from '../../documents/Documents'; +import { Networking } from '../../Network'; +import { DragManager } from '../../util/DragManager'; +import { SelectionManager } from '../../util/SelectionManager'; +import { undoBatch } from '../../util/UndoManager'; +import { ContextMenu } from "../../views/ContextMenu"; +import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; +import { ContextMenuProps } from '../ContextMenuItem'; +import { ViewBoxAnnotatableComponent } from '../DocComponent'; +import FaceRectangles from './FaceRectangles'; +import { FieldView, FieldViewProps } from './FieldView'; +import "./ImageBox.scss"; +import React = require("react"); +const requestImageSize = require('../../util/request-image-size'); +const path = require('path'); +const { Howl } = require('howler'); + + +library.add(faImage, faEye as any, faPaintBrush, faBrain); +library.add(faFileAudio, faAsterisk); + + +export const pageSchema = createSchema({ + curPage: "number", + fitWidth: "boolean", + googlePhotosUrl: "string", + googlePhotosTags: "string" +}); + +interface Window { + MediaRecorder: MediaRecorder; +} + +declare class MediaRecorder { + // whatever MediaRecorder has + constructor(e: any); +} + +type ImageDocument = makeInterface<[typeof pageSchema, typeof documentSchema]>; +const ImageDocument = makeInterface(pageSchema, documentSchema); + +const uploadIcons = { + idle: "downarrow.png", + loading: "loading.gif", + success: "greencheck.png", + failure: "redx.png" +}; + +@observer +export class ImageBox extends ViewBoxAnnotatableComponent(ImageDocument) { + protected multiTouchDisposer?: import("../../util/InteractionUtils").InteractionUtils.MultiTouchEventDisposer | undefined; + public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ImageBox, fieldKey); } + private _imgRef: React.RefObject = React.createRef(); + private _dropDisposer?: DragManager.DragDropDisposer; + @observable private _audioState = 0; + @observable static _showControls: boolean; + @observable uploadIcon = uploadIcons.idle; + + protected createDropTarget = (ele: HTMLDivElement) => { + this._dropDisposer && this._dropDisposer(); + ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this))); + } + + @undoBatch + @action + drop = (e: Event, de: DragManager.DropEvent) => { + if (de.complete.docDragData) { + if (de.metaKey) { + de.complete.docDragData.droppedDocuments.forEach(action((drop: Doc) => { + Doc.AddDocToList(this.dataDoc, this.fieldKey + "-alternates", drop); + e.stopPropagation(); + })); + } else if (de.altKey || !this.dataDoc[this.fieldKey]) { + const layoutDoc = de.complete.docDragData?.draggedDocuments[0]; + const targetField = Doc.LayoutFieldKey(layoutDoc); + const targetDoc = layoutDoc[DataSym]; + if (targetDoc[targetField] instanceof ImageField) { + this.dataDoc[this.fieldKey] = ObjectField.MakeCopy(targetDoc[targetField] as ImageField); + this.dataDoc[this.fieldKey + "-nativeWidth"] = NumCast(targetDoc[targetField + "-nativeWidth"]); + this.dataDoc[this.fieldKey + "-nativeHeight"] = NumCast(targetDoc[targetField + "-nativeHeight"]); + e.stopPropagation(); + } + } + } + } + + recordAudioAnnotation = () => { + let gumStream: any; + let recorder: any; + const self = this; + navigator.mediaDevices.getUserMedia({ + audio: true + }).then(function (stream) { + gumStream = stream; + recorder = new MediaRecorder(stream); + recorder.ondataavailable = async function (e: any) { + const formData = new FormData(); + formData.append("file", e.data); + const res = await fetch(Utils.prepend("/uploadFormData"), { + method: 'POST', + body: formData + }); + const files = await res.json(); + const url = Utils.prepend(files[0].path); + // upload to server with known URL + const audioDoc = Docs.Create.AudioDocument(url, { title: "audio test", _width: 200, _height: 32 }); + audioDoc.treeViewExpandedView = "layout"; + const audioAnnos = Cast(this.dataDoc[this.fieldKey + "-audioAnnotations"], listSpec(Doc)); + if (audioAnnos === undefined) { + this.dataDoc[this.fieldKey + "-audioAnnotations"] = new List([audioDoc]); + } else { + audioAnnos.push(audioDoc); + } + }; + runInAction(() => self._audioState = 2); + recorder.start(); + setTimeout(() => { + recorder.stop(); + runInAction(() => self._audioState = 0); + gumStream.getAudioTracks()[0].stop(); + }, 5000); + }); + } + + @undoBatch + rotate = action(() => { + const nw = NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"]); + const nh = NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"]); + const w = this.layoutDoc._width; + const h = this.layoutDoc._height; + this.dataDoc[this.fieldKey + "-rotation"] = (NumCast(this.dataDoc[this.fieldKey + "-rotation"]) + 90) % 360; + this.dataDoc[this.fieldKey + "-nativeWidth"] = nh; + this.dataDoc[this.fieldKey + "-nativeHeight"] = nw; + this.layoutDoc._width = h; + this.layoutDoc._height = w; + }); + + specificContextMenu = (e: React.MouseEvent): void => { + const field = Cast(this.dataDoc[this.fieldKey], ImageField); + if (field) { + const funcs: ContextMenuProps[] = []; + funcs.push({ description: "Copy path", event: () => Utils.CopyText(field.url.href), icon: "expand-arrows-alt" }); + funcs.push({ description: "Rotate", event: this.rotate, icon: "expand-arrows-alt" }); + funcs.push({ + description: "Reset Native Dimensions", event: action(async () => { + const curNW = NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"]); + const curNH = NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"]); + if (this.props.PanelWidth() / this.props.PanelHeight() > curNW / curNH) { + this.dataDoc[this.fieldKey + "-nativeWidth"] = this.props.PanelHeight() * curNW / curNH; + this.dataDoc[this.fieldKey + "-nativeHeight"] = this.props.PanelHeight(); + } else { + this.dataDoc[this.fieldKey + "-nativeWidth"] = this.props.PanelWidth(); + this.dataDoc[this.fieldKey + "-nativeHeight"] = this.props.PanelWidth() * curNH / curNW; + } + }), icon: "expand-arrows-alt" + }); + + const existingAnalyze = ContextMenu.Instance.findByDescription("Analyzers..."); + const modes: ContextMenuProps[] = existingAnalyze && "subitems" in existingAnalyze ? existingAnalyze.subitems : []; + modes.push({ description: "Generate Tags", event: this.generateMetadata, icon: "tag" }); + modes.push({ description: "Find Faces", event: this.extractFaces, icon: "camera" }); + //modes.push({ description: "Recommend", event: this.extractText, icon: "brain" }); + !existingAnalyze && ContextMenu.Instance.addItem({ description: "Analyzers...", subitems: modes, icon: "hand-point-right" }); + + ContextMenu.Instance.addItem({ description: "Image Funcs...", subitems: funcs, icon: "asterisk" }); + } + } + + extractFaces = () => { + const converter = (results: any) => { + return results.map((face: CognitiveServices.Image.Face) => Docs.Get.FromJson({ data: face, title: `Face: ${face.faceId}` })!); + }; + this.url && CognitiveServices.Image.Appliers.ProcessImage(this.dataDoc, [this.fieldKey + "-faces"], this.url, Service.Face, converter); + } + + generateMetadata = (threshold: Confidence = Confidence.Excellent) => { + const converter = (results: any) => { + const tagDoc = new Doc; + const tagsList = new List(); + results.tags.map((tag: Tag) => { + tagsList.push(tag.name); + const sanitized = tag.name.replace(" ", "_"); + tagDoc[sanitized] = ComputedField.MakeFunction(`(${tag.confidence} >= this.confidence) ? ${tag.confidence} : "${ComputedField.undefined}"`); + }); + this.dataDoc[this.fieldKey + "-generatedTags"] = tagsList; + tagDoc.title = "Generated Tags Doc"; + tagDoc.confidence = threshold; + return tagDoc; + }; + this.url && CognitiveServices.Image.Appliers.ProcessImage(this.dataDoc, [this.fieldKey + "-generatedTagsDoc"], this.url, Service.ComputerVision, converter); + } + + @computed private get url() { + const data = Cast(this.dataDoc[this.fieldKey], ImageField); + return data ? data.url.href : undefined; + } + + choosePath(url: URL) { + const lower = url.href.toLowerCase(); + if (url.protocol === "data") { + return url.href; + } else if (url.href.indexOf(window.location.origin) === -1) { + return Utils.CorsProxy(url.href); + } else if (!/\.(png|jpg|jpeg|gif|webp)$/.test(lower)) { + return url.href;//Why is this here + } + const ext = path.extname(url.href); + const suffix = this.props.renderDepth < 1 ? "_o" : this._curSuffix; + return url.href.replace(ext, suffix + ext); + } + + @observable _smallRetryCount = 1; + @observable _mediumRetryCount = 1; + @observable _largeRetryCount = 1; + @action retryPath = () => { + if (this._curSuffix === "_s") this._smallRetryCount++; + if (this._curSuffix === "_m") this._mediumRetryCount++; + if (this._curSuffix === "_l") this._largeRetryCount++; + } + @action onError = (error: any) => { + const timeout = this._curSuffix === "_s" ? this._smallRetryCount : this._curSuffix === "_m" ? this._mediumRetryCount : this._largeRetryCount; + if (timeout < 5) { + setTimeout(this.retryPath, 500); + } else { + const original = StrCast(this.dataDoc[this.fieldKey + "-originalUrl"]); + if (error.type === "error" && original) { + this.dataDoc[this.fieldKey] = new ImageField(original); + } + } + } + _curSuffix = "_m"; + + resize = (imgPath: string) => { + const cachedNativeSize = { + width: NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"]), + height: NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"]) + }; + const docAspect = this.layoutDoc[HeightSym]() / this.layoutDoc[WidthSym](); + const cachedAspect = cachedNativeSize.height / cachedNativeSize.width; + if (!cachedNativeSize.width || !cachedNativeSize.height || Math.abs(NumCast(this.layoutDoc._width) / NumCast(this.layoutDoc._height) - cachedNativeSize.width / cachedNativeSize.height) > 0.05) { + if (!this.layoutDoc.isTemplateDoc || this.dataDoc !== this.layoutDoc) { + requestImageSize(imgPath).then((inquiredSize: any) => { + const rotation = NumCast(this.dataDoc[this.fieldKey + "-rotation"]) % 180; + const rotatedNativeSize = rotation === 90 || rotation === 270 ? { height: inquiredSize.width, width: inquiredSize.height } : inquiredSize; + const rotatedAspect = rotatedNativeSize.height / rotatedNativeSize.width; + setTimeout(action(() => { + if (this.layoutDoc[WidthSym]() && (!cachedNativeSize.width || !cachedNativeSize.height || Math.abs(1 - docAspect / rotatedAspect) > 0.1)) { + this.layoutDoc._height = this.layoutDoc[WidthSym]() * rotatedAspect; + this.dataDoc[this.fieldKey + "-nativeWidth"] = this.layoutDoc._nativeWidth = rotatedNativeSize.width; + this.dataDoc[this.fieldKey + "-nativeHeight"] = this.layoutDoc._nativeHeight = rotatedNativeSize.height; + } + }), 0); + }).catch((err: any) => console.log(err)); + } else if (Math.abs(1 - docAspect / cachedAspect) > 0.1) { + this.layoutDoc._width = this.layoutDoc[WidthSym]() || cachedNativeSize.width; + this.layoutDoc._height = this.layoutDoc[WidthSym]() * cachedAspect; + } + } else if (this.layoutDoc._nativeWidth !== cachedNativeSize.width || this.layoutDoc._nativeHeight !== cachedNativeSize.height) { + !(this.layoutDoc[StrCast(this.layoutDoc.layoutKey)] instanceof Doc) && setTimeout(() => { + if (!(this.layoutDoc[StrCast(this.layoutDoc.layoutKey)] instanceof Doc)) { + this.layoutDoc._nativeWidth = cachedNativeSize.width; + this.layoutDoc._nativeHeight = cachedNativeSize.height; + } + }, 0); + } + } + + @action + onPointerEnter = () => { + const self = this; + const audioAnnos = DocListCast(this.dataDoc[this.fieldKey + "-audioAnnotations"]); + if (audioAnnos && audioAnnos.length && this._audioState === 0) { + const anno = audioAnnos[Math.floor(Math.random() * audioAnnos.length)]; + anno.data instanceof AudioField && new Howl({ + src: [anno.data.url.href], + format: ["mp3"], + autoplay: true, + loop: false, + volume: 0.5, + onend: function () { + runInAction(() => self._audioState = 0); + } + }); + this._audioState = 1; + } + } + + audioDown = () => this.recordAudioAnnotation(); + + considerGooglePhotosLink = () => { + const remoteUrl = this.dataDoc.googlePhotosUrl; + return !remoteUrl ? (null) : ( window.open(remoteUrl)} + />); + } + + considerGooglePhotosTags = () => { + const tags = this.dataDoc.googlePhotosTags; + return !tags ? (null) : (); + } + + @computed + private get considerDownloadIcon() { + const data = this.dataDoc[this.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 { success, failure, idle, loading } = uploadIcons; + runInAction(() => this.uploadIcon = loading); + const [{ accessPaths }] = await Networking.PostToServer("/uploadRemoteImage", { sources: [primary] }); + dataDoc[this.props.fieldKey + "-originalUrl"] = primary; + let succeeded = true; + let data: ImageField | undefined; + try { + data = new ImageField(Utils.prepend(accessPaths.agnostic.client)); + } catch { + succeeded = false; + } + runInAction(() => this.uploadIcon = succeeded ? success : failure); + setTimeout(action(() => { + this.uploadIcon = idle; + if (data) { + dataDoc[this.fieldKey] = data; + } + }), 2000); + }} + /> + ); + } + + @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.fieldKey + "-nativeWidth"], pw); + const nativeHeight = NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"], 1); + return { nativeWidth, nativeHeight }; + } + + // this._curSuffix = ""; + // if (w > 20) { + // if (w < 100 && this._smallRetryCount < 10) this._curSuffix = "_s"; + // else if (w < 600 && this._mediumRetryCount < 10) this._curSuffix = "_m"; + // else if (this._largeRetryCount < 10) this._curSuffix = "_l"; + @computed get paths() { + const field = Cast(this.dataDoc[this.fieldKey], ImageField, null); // retrieve the primary image URL that is being rendered from the data doc + const alts = DocListCast(this.dataDoc[this.fieldKey + "-alternates"]); // retrieve alternate documents that may be rendered as alternate images + const altpaths = alts.map(doc => Cast(doc[Doc.LayoutFieldKey(doc)], ImageField, null)?.url.href).filter(url => url); // access the primary layout data of the alternate documents + const paths = field ? [this.choosePath(field.url), ...altpaths] : altpaths; + return paths.length ? paths : [Utils.CorsProxy("http://www.cs.brown.edu/~bcz/noImage.png")]; + } + + @computed get content() { + TraceMobx(); + + const srcpath = this.paths[0]; + const fadepath = this.paths[Math.min(1, this.paths.length - 1)]; + const { nativeWidth, nativeHeight } = this.nativeSize; + const rotation = NumCast(this.dataDoc[this.fieldKey + "-rotation"]); + const aspect = (rotation % 180) ? nativeHeight / nativeWidth : 1; + const pwidth = this.props.PanelWidth(); + const pheight = this.props.PanelHeight(); + const shift = (rotation % 180) ? (pheight - pwidth) / aspect / 2 + (pheight - pwidth) / 2 : 0; + + this.resize(srcpath); + + return
+
+ + {fadepath === srcpath ? (null) :
+
} +
+ {!this.layoutDoc._showAudio ? (null) : +
+ +
} + {this.considerDownloadIcon} + {this.considerGooglePhotosLink()} + +
; + } + + contentFunc = () => [this.content]; + render() { + TraceMobx(); + const dragging = !SelectionManager.GetIsDragging() ? "" : "-dragging"; + return (
+ + {this.contentFunc} + +
); + } +} \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 1e24f26454aada5afbf9daad4d5ed339083f364c Mon Sep 17 00:00:00 2001 From: Melissa Zhang Date: Thu, 16 Apr 2020 17:20:07 -0700 Subject: fixed image drag and drop --- src/client/documents/DocumentTypes.ts | 1 + src/client/documents/Documents.ts | 9 +- src/client/views/nodes/ComparisonBox.scss | 7 +- src/client/views/nodes/ComparisonBox.tsx | 97 ++++++++++------------ src/client/views/nodes/DocumentContentsView.tsx | 3 +- .../authentication/models/current_user_utils.ts | 1 + 6 files changed, 62 insertions(+), 56 deletions(-) (limited to 'src/client') diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts index de366763b..06d35038a 100644 --- a/src/client/documents/DocumentTypes.ts +++ b/src/client/documents/DocumentTypes.ts @@ -31,6 +31,7 @@ export enum DocumentType { COLOR = "color", // color picker (view of a color picker for a color string) YOUTUBE = "youtube", // youtube directory (view of you tube search results) DOCHOLDER = "docholder", // nested document (view of a document) + COMPARISON = "comparison", // before/after view with slider (view of 2 images) LINKDB = "linkdb", // database of links ??? why do we have this RECOMMENDATION = "recommendation", // view of a recommendation diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 43e379125..a2e59b238 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -49,8 +49,8 @@ import { ContextMenuProps } from "../views/ContextMenuItem"; import { ContextMenu } from "../views/ContextMenu"; import { LinkBox } from "../views/nodes/LinkBox"; import { ScreenshotBox } from "../views/nodes/ScreenshotBox"; +import { ComparisonBox } from "../views/nodes/ComparisonBox"; import CollectionMapView from "../views/collections/CollectionMapView"; -import LocationField, { LocationData } from "../../new_fields/LocationField"; const requestImageSize = require('../util/request-image-size'); const path = require('path'); @@ -280,6 +280,9 @@ export namespace Docs { [DocumentType.SCREENSHOT, { layout: { view: ScreenshotBox, dataField: data }, }], + [DocumentType.COMPARISON, { + layout: { view: ComparisonBox, dataField: data }, + }], ]); // All document prototypes are initialized with at least these values @@ -535,6 +538,10 @@ export namespace Docs { return InstanceFromProto(Prototypes.get(DocumentType.SCREENSHOT), "", options); } + export function ComparisonDocument(options: DocumentOptions = {}) { + return InstanceFromProto(Prototypes.get(DocumentType.COMPARISON), "", options); + } + export function AudioDocument(url: string, options: DocumentOptions = {}) { const instance = InstanceFromProto(Prototypes.get(DocumentType.AUDIO), new AudioField(new URL(url)), options); Doc.GetProto(instance).backgroundColor = ComputedField.MakeFunction("this._audioState === 'playing' ? 'green':'gray'"); diff --git a/src/client/views/nodes/ComparisonBox.scss b/src/client/views/nodes/ComparisonBox.scss index 32ced3463..57c680d55 100644 --- a/src/client/views/nodes/ComparisonBox.scss +++ b/src/client/views/nodes/ComparisonBox.scss @@ -3,6 +3,9 @@ border-radius: inherit; width: 100%; height: 100%; - position: absolute; - transform-origin: top left; + + .beforeBox-cont { + width: 100%; + height: 100%; + } } \ No newline at end of file diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index 167000821..9120daa6c 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -4,7 +4,7 @@ import { faAsterisk, faBrain, faFileAudio, faImage, faPaintBrush } from '@fortaw import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable, runInAction } from 'mobx'; import { observer } from "mobx-react"; -import { DataSym, Doc, DocListCast, HeightSym, WidthSym } from '../../../new_fields/Doc'; +import { Doc } from '../../../new_fields/Doc'; import { documentSchema } from '../../../new_fields/documentSchemas'; import { Id } from '../../../new_fields/FieldSymbols'; import { List } from '../../../new_fields/List'; @@ -12,16 +12,9 @@ import { ObjectField } from '../../../new_fields/ObjectField'; import { createSchema, listSpec, makeInterface } from '../../../new_fields/Schema'; import { ComputedField } from '../../../new_fields/ScriptField'; import { Cast, NumCast, StrCast } from '../../../new_fields/Types'; -import { AudioField, ImageField } from '../../../new_fields/URLField'; -import { TraceMobx } from '../../../new_fields/util'; import { emptyFunction, returnOne, Utils, returnZero } from '../../../Utils'; -import { CognitiveServices, Confidence, Service, Tag } from '../../cognitive_services/CognitiveServices'; import { Docs } from '../../documents/Documents'; import { DragManager } from '../../util/DragManager'; -import { SelectionManager } from '../../util/SelectionManager'; -import { undoBatch } from '../../util/UndoManager'; -import { ContextMenu } from "../ContextMenu"; -import { ContextMenuProps } from '../ContextMenuItem'; import { ViewBoxAnnotatableComponent } from '../DocComponent'; import { FieldView, FieldViewProps } from './FieldView'; import "./ComparisonBox.scss"; @@ -44,45 +37,33 @@ const ComparisonDocument = makeInterface(pageSchema, documentSchema); @observer export class ComparisonBox extends ViewBoxAnnotatableComponent(ComparisonDocument) { protected multiTouchDisposer?: import("../../util/InteractionUtils").InteractionUtils.MultiTouchEventDisposer | undefined; - protected beforeDoc: Doc | undefined; - protected afterDoc: Doc | undefined; public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ComparisonBox, fieldKey); } private _beforeDropDisposer?: DragManager.DragDropDisposer; private _afterDropDisposer?: DragManager.DragDropDisposer; - protected createBeforeDropTarget = (ele: HTMLDivElement) => { - this._beforeDropDisposer && this._beforeDropDisposer(); - ele && (this._beforeDropDisposer = DragManager.MakeDropTarget(ele, (event, dropEvent) => { - this.beforeDoc = dropEvent.complete.docDragData.droppedDocuments[0]; - })); + protected createDropTarget = (ele: HTMLDivElement | null, fieldKey: string) => { + if (ele) { + return DragManager.MakeDropTarget(ele, (event, dropEvent) => this.dropHandler(event, dropEvent, fieldKey)); + } } - protected createAfterDropTarget = (ele: HTMLDivElement) => { - this._afterDropDisposer && this._afterDropDisposer(); - ele && (this._afterDropDisposer = DragManager.MakeDropTarget(ele, (event, dropEvent) => { - this.afterDoc = dropEvent.complete.docDragData.droppedDocuments[0]; - })); - // this.afterDropHandler(this._afterDropDisposer); - } - - beforeDropHandler = (ele: any) => { - - } - - afterDropHandler = (ele: any) => { - + private dropHandler = (event: Event, dropEvent: DragManager.DropEvent, fieldKey: string) => { + const droppedDocs = dropEvent.complete.docDragData?.droppedDocuments; + if (droppedDocs?.length) { + this.props.Document[fieldKey] = Doc.MakeAlias(droppedDocs[0]); + } } clearBeforeDoc = (e: PointerEvent) => { e.stopPropagation; - this.beforeDoc = undefined; + delete this.props.Document.beforeDoc; } clearAfterDoc = (e: PointerEvent) => { e.stopPropagation; - this.afterDoc = undefined; + delete this.props.Document.afterDoc; } get fieldKey() { @@ -90,32 +71,44 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent - { - beforeDoc ? -
+
+
{ + this._beforeDropDisposer && this._beforeDropDisposer(); + this._beforeDropDisposer = this.createDropTarget(ele, "beforeDoc"); + }} + style={{ backgroundColor: "red" }} + > + { + beforeDoc ? -
: null - } - - {/* { - beforeDoc ? -
- -
: null - } -
- -
*/} + : null + } +
+
{ + this._afterDropDisposer && this._afterDropDisposer(); + this._afterDropDisposer = this.createDropTarget(ele, "afterDoc"); + }} + style={{ backgroundColor: "orange" }} + > + { + afterDoc ? + + : null + } +
); } } \ No newline at end of file diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 7522af3a3..831bce22f 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -30,6 +30,7 @@ import { DashWebRTCVideo } from "../webcam/DashWebRTCVideo"; import { LinkAnchorBox } from "./LinkAnchorBox"; import { PresElementBox } from "../presentationview/PresElementBox"; import { ScreenshotBox } from "./ScreenshotBox"; +import { ComparisonBox } from "./ComparisonBox"; import { VideoBox } from "./VideoBox"; import { WebBox } from "./WebBox"; import { InkingStroke } from "../InkingStroke"; @@ -113,7 +114,7 @@ export class DocumentContentsView extends React.Component Date: Sat, 18 Apr 2020 16:16:41 -0700 Subject: set up overlapping images and slider bar --- src/client/views/nodes/ComparisonBox.scss | 32 ++++++++++++++++++++-- src/client/views/nodes/ComparisonBox.tsx | 45 ++++++++++++++++++------------- 2 files changed, 56 insertions(+), 21 deletions(-) (limited to 'src/client') diff --git a/src/client/views/nodes/ComparisonBox.scss b/src/client/views/nodes/ComparisonBox.scss index 57c680d55..2c907a010 100644 --- a/src/client/views/nodes/ComparisonBox.scss +++ b/src/client/views/nodes/ComparisonBox.scss @@ -4,8 +4,36 @@ width: 100%; height: 100%; - .beforeBox-cont { - width: 100%; + .clip-div { + position: absolute; + top: 0; + left: 0; + width: 50%; height: 100%; + overflow: hidden; + z-index: 999; + + .beforeBox-cont { + height: 100%; + width: 300px; + } + + .slide-bar { + position: absolute; + width: 5px; + height: 100%; + top: 0; + right: 0; + background-color: black; + cursor: ew-resize; + } + } + + .afterBox-cont { + position: absolute; + top: 0; + right: 0; + height: 100%; + width: 300px; } } \ No newline at end of file diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index 9120daa6c..5c44b3068 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -58,11 +58,13 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent { e.stopPropagation; + e.preventDefault; delete this.props.Document.beforeDoc; } clearAfterDoc = (e: PointerEvent) => { e.stopPropagation; + e.preventDefault; delete this.props.Document.afterDoc; } @@ -75,22 +77,25 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent -
{ - this._beforeDropDisposer && this._beforeDropDisposer(); - this._beforeDropDisposer = this.createDropTarget(ele, "beforeDoc"); - }} - style={{ backgroundColor: "red" }} - > - { - beforeDoc ? - - : null - } +
+
{ + this._beforeDropDisposer && this._beforeDropDisposer(); + this._beforeDropDisposer = this.createDropTarget(ele, "beforeDoc"); + }} + style={{ backgroundColor: "red" }}> + { + beforeDoc ? + + : +
upload before image!
+ } +
+
+ style={{ backgroundColor: "orange" }}> { afterDoc ? - : null + : +
+ upload after image! +
}
); -- cgit v1.2.3-70-g09d2 From 1f68dae9485294f642bdb842347c53e5fab604d0 Mon Sep 17 00:00:00 2001 From: Melissa Zhang Date: Sun, 19 Apr 2020 01:12:15 -0700 Subject: added slider bar functionality for sliding between two images --- src/client/views/nodes/ComparisonBox.scss | 22 ++++++++++- src/client/views/nodes/ComparisonBox.tsx | 64 ++++++++++++++++++++++++------- 2 files changed, 71 insertions(+), 15 deletions(-) (limited to 'src/client') diff --git a/src/client/views/nodes/ComparisonBox.scss b/src/client/views/nodes/ComparisonBox.scss index 2c907a010..5112ed4b8 100644 --- a/src/client/views/nodes/ComparisonBox.scss +++ b/src/client/views/nodes/ComparisonBox.scss @@ -15,7 +15,7 @@ .beforeBox-cont { height: 100%; - width: 300px; + background-color: red; } .slide-bar { @@ -34,6 +34,24 @@ top: 0; right: 0; height: 100%; - width: 300px; + width: 100%; + background-color: orange; + } + + .clear-button { + position: absolute; + top: 0; + height: 25px; + width: 25px; + background-color: white; + border-radius: 50%; + } + + .clear-button.before { + left: 0; + } + + .clear-button.after { + right: 0; } } \ No newline at end of file diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index 5c44b3068..fe3f47e2a 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -24,7 +24,6 @@ import { ContentFittingDocumentView } from './ContentFittingDocumentView'; library.add(faImage, faEye as any, faPaintBrush, faBrain); library.add(faFileAudio, faAsterisk); - export const pageSchema = createSchema({ beforeDoc: "string", afterDoc: "string" @@ -56,13 +55,41 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent { + @action + private registerSliding = (e: React.PointerEvent) => { + e.stopPropagation(); + e.preventDefault(); + window.removeEventListener("pointermove", this.onPointerMove); + window.removeEventListener("pointerup", this.onPointerUp); + window.addEventListener("pointermove", this.onPointerMove); + window.addEventListener("pointerup", this.onPointerUp); + } + + componentDidMount() { + const initialWidth = this.props.PanelWidth() / 2; + this.props.Document.clipWidth = initialWidth; + } + + private onPointerMove = ({ movementX }: PointerEvent) => { + const width = this.props.Document.clipWidth + movementX; + if (width && width > 0 && width < this.props.PanelWidth()) { + this.props.Document.clipWidth = width; + } + } + + @action + private onPointerUp = () => { + window.removeEventListener("pointermove", this.onPointerMove); + window.removeEventListener("pointerup", this.onPointerUp); + } + + clearBeforeDoc = (e: React.MouseEvent) => { e.stopPropagation; e.preventDefault; delete this.props.Document.beforeDoc; } - clearAfterDoc = (e: PointerEvent) => { + clearAfterDoc = (e: React.MouseEvent) => { e.stopPropagation; e.preventDefault; delete this.props.Document.afterDoc; @@ -75,9 +102,11 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent -
+
+ {/* wraps around before image and slider bar */} +
+ style={{ width: this.props.PanelWidth() }}> { beforeDoc ? - +
this.clearBeforeDoc(e)} + /> : -
upload before image!
+
+ upload before image! +
}
-
+
this.registerSliding(e)} />
{ this._afterDropDisposer && this._afterDropDisposer(); this._afterDropDisposer = this.createDropTarget(ele, "afterDoc"); - }} - style={{ backgroundColor: "orange" }}> + }}> { afterDoc ? - +
this.clearAfterDoc(e)} + /> : -
+
upload after image!
} -- cgit v1.2.3-70-g09d2 From 13f182c2f138c25b0b57169dc94ecbfdd59483ef Mon Sep 17 00:00:00 2001 From: Melissa Zhang Date: Wed, 22 Apr 2020 23:24:14 -0700 Subject: icons for clear buttons --- src/client/views/nodes/ComparisonBox.scss | 14 ++++++------ src/client/views/nodes/ComparisonBox.tsx | 38 ++++++++++++++++--------------- 2 files changed, 27 insertions(+), 25 deletions(-) (limited to 'src/client') diff --git a/src/client/views/nodes/ComparisonBox.scss b/src/client/views/nodes/ComparisonBox.scss index 5112ed4b8..38d3a04e9 100644 --- a/src/client/views/nodes/ComparisonBox.scss +++ b/src/client/views/nodes/ComparisonBox.scss @@ -40,18 +40,18 @@ .clear-button { position: absolute; - top: 0; - height: 25px; - width: 25px; - background-color: white; - border-radius: 50%; + opacity: 1; + pointer-events: all; + cursor: pointer; } .clear-button.before { - left: 0; + top: 3px; + left: 3px; } .clear-button.after { - right: 0; + top: 3px; + right: 3px; } } \ No newline at end of file diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index fe3f47e2a..15ba8d8f2 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -1,6 +1,6 @@ import { library } from '@fortawesome/fontawesome-svg-core'; import { faEye } from '@fortawesome/free-regular-svg-icons'; -import { faAsterisk, faBrain, faFileAudio, faImage, faPaintBrush } from '@fortawesome/free-solid-svg-icons'; +import { faAsterisk, faBrain, faFileAudio, faImage, faPaintBrush, faTimes } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable, runInAction } from 'mobx'; import { observer } from "mobx-react"; @@ -71,8 +71,8 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent { - const width = this.props.Document.clipWidth + movementX; - if (width && width > 0 && width < this.props.PanelWidth()) { + const width = NumCast(this.props.Document.clipWidth) + movementX; //is it ok to use NumCast + if (width && width > 5 && width < this.props.PanelWidth()) { this.props.Document.clipWidth = width; } } @@ -117,13 +117,14 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent { beforeDoc ? - <> -
this.clearBeforeDoc(e)} - /> + <> + +
this.clearBeforeDoc(e)}> + +
+ :
upload before image! @@ -141,15 +142,16 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent { afterDoc ? - <> -
this.clearAfterDoc(e)} - /> + <> + +
this.clearAfterDoc(e)}> + +
+ : -
+
upload after image!
} -- cgit v1.2.3-70-g09d2 From eebb7712c5f55c9dd49f0433acaf50a289fbdf08 Mon Sep 17 00:00:00 2001 From: Melissa Zhang Date: Thu, 23 Apr 2020 01:50:49 -0700 Subject: re-position slider bar when resized --- src/client/views/nodes/ComparisonBox.scss | 2 +- src/client/views/nodes/ComparisonBox.tsx | 25 +++++++++++++++++++++---- 2 files changed, 22 insertions(+), 5 deletions(-) (limited to 'src/client') diff --git a/src/client/views/nodes/ComparisonBox.scss b/src/client/views/nodes/ComparisonBox.scss index 38d3a04e9..e2852c5f1 100644 --- a/src/client/views/nodes/ComparisonBox.scss +++ b/src/client/views/nodes/ComparisonBox.scss @@ -24,7 +24,7 @@ height: 100%; top: 0; right: 0; - background-color: black; + background-color: white; cursor: ew-resize; } } diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index 15ba8d8f2..88a6e62d1 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -2,7 +2,7 @@ import { library } from '@fortawesome/fontawesome-svg-core'; import { faEye } from '@fortawesome/free-regular-svg-icons'; import { faAsterisk, faBrain, faFileAudio, faImage, faPaintBrush, faTimes } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, observable, runInAction } from 'mobx'; +import { action, computed, observable, runInAction, Lambda } from 'mobx'; import { observer } from "mobx-react"; import { Doc } from '../../../new_fields/Doc'; import { documentSchema } from '../../../new_fields/documentSchemas'; @@ -32,7 +32,6 @@ export const pageSchema = createSchema({ type ComparisonDocument = makeInterface<[typeof pageSchema, typeof documentSchema]>; const ComparisonDocument = makeInterface(pageSchema, documentSchema); - @observer export class ComparisonBox extends ViewBoxAnnotatableComponent(ComparisonDocument) { protected multiTouchDisposer?: import("../../util/InteractionUtils").InteractionUtils.MultiTouchEventDisposer | undefined; @@ -65,9 +64,15 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent this.props.PanelWidth()).observe(({ oldValue, newValue }) => + this.props.Document.clipWidth = NumCast(this.props.Document.clipWidth) / NumCast(oldValue) * newValue + ); } private onPointerMove = ({ movementX }: PointerEvent) => { @@ -95,16 +100,28 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent { + console.log("native height: " + this.props.NativeHeight()); + console.log("native width: " + this.props.NativeWidth()); + console.log("panel height: " + this.props.PanelHeight()); + console.log("panel width: " + this.props.PanelWidth()); + console.log("scaling: " + this.props.ContentScaling()); + console.log("transform: " + this.props.ScreenToLocalTransform()); + } + + private resizeUpdater: Lambda; + get fieldKey() { return this.props.fieldKey.startsWith("@") ? StrCast(this.props.Document[this.props.fieldKey]) : this.props.fieldKey; } render() { + console.log("scaling?? " + this.props.ContentScaling()); const beforeDoc = this.props.Document.beforeDoc as Doc; const afterDoc = this.props.Document.afterDoc as Doc; const clipWidth = this.props.Document.clipWidth as Number; return ( -
+
this.onResize()}> {/* wraps around before image and slider bar */}
Date: Thu, 23 Apr 2020 13:58:57 -0700 Subject: scaled slider bar movement --- src/client/views/nodes/ComparisonBox.tsx | 35 +++++++++++--------------------- 1 file changed, 12 insertions(+), 23 deletions(-) (limited to 'src/client') diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index 88a6e62d1..dbaad360b 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -7,13 +7,9 @@ import { observer } from "mobx-react"; import { Doc } from '../../../new_fields/Doc'; import { documentSchema } from '../../../new_fields/documentSchemas'; import { Id } from '../../../new_fields/FieldSymbols'; -import { List } from '../../../new_fields/List'; -import { ObjectField } from '../../../new_fields/ObjectField'; import { createSchema, listSpec, makeInterface } from '../../../new_fields/Schema'; import { ComputedField } from '../../../new_fields/ScriptField'; import { Cast, NumCast, StrCast } from '../../../new_fields/Types'; -import { emptyFunction, returnOne, Utils, returnZero } from '../../../Utils'; -import { Docs } from '../../documents/Documents'; import { DragManager } from '../../util/DragManager'; import { ViewBoxAnnotatableComponent } from '../DocComponent'; import { FieldView, FieldViewProps } from './FieldView'; @@ -64,19 +60,24 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent { }; + componentWillMount() { - const initialWidth = this.props.PanelWidth() / 2; - this.props.Document.clipWidth = initialWidth; + this.props.Document.clipWidth = this.props.PanelWidth() / 2; - //when resized, use current position and old value to infer the new bar position - computed(() => this.props.PanelWidth()).observe(({ oldValue, newValue }) => + //preserve before/after ratio during resizing + this.resizeUpdater = computed(() => this.props.PanelWidth()).observe(({ oldValue, newValue }) => this.props.Document.clipWidth = NumCast(this.props.Document.clipWidth) / NumCast(oldValue) * newValue ); } + componentWillUnmount() { + this.resizeUpdater(); + } + private onPointerMove = ({ movementX }: PointerEvent) => { - const width = NumCast(this.props.Document.clipWidth) + movementX; //is it ok to use NumCast + //is it ok to use NumCast + const width = movementX * this.props.ScreenToLocalTransform().Scale + NumCast(this.props.Document.clipWidth); if (width && width > 5 && width < this.props.PanelWidth()) { this.props.Document.clipWidth = width; } @@ -100,28 +101,16 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent { - console.log("native height: " + this.props.NativeHeight()); - console.log("native width: " + this.props.NativeWidth()); - console.log("panel height: " + this.props.PanelHeight()); - console.log("panel width: " + this.props.PanelWidth()); - console.log("scaling: " + this.props.ContentScaling()); - console.log("transform: " + this.props.ScreenToLocalTransform()); - } - - private resizeUpdater: Lambda; - get fieldKey() { return this.props.fieldKey.startsWith("@") ? StrCast(this.props.Document[this.props.fieldKey]) : this.props.fieldKey; } render() { - console.log("scaling?? " + this.props.ContentScaling()); const beforeDoc = this.props.Document.beforeDoc as Doc; const afterDoc = this.props.Document.afterDoc as Doc; const clipWidth = this.props.Document.clipWidth as Number; return ( -
this.onResize()}> +
{/* wraps around before image and slider bar */}
Date: Thu, 23 Apr 2020 15:16:04 -0700 Subject: added upload icon, changed background colours --- src/client/views/nodes/ComparisonBox.scss | 24 +++++++++++++++++++----- src/client/views/nodes/ComparisonBox.tsx | 10 +++++----- 2 files changed, 24 insertions(+), 10 deletions(-) (limited to 'src/client') diff --git a/src/client/views/nodes/ComparisonBox.scss b/src/client/views/nodes/ComparisonBox.scss index e2852c5f1..74e80236d 100644 --- a/src/client/views/nodes/ComparisonBox.scss +++ b/src/client/views/nodes/ComparisonBox.scss @@ -15,7 +15,8 @@ .beforeBox-cont { height: 100%; - background-color: red; + overflow: auto; + background-color: rgb(230, 230, 230); } .slide-bar { @@ -35,23 +36,36 @@ right: 0; height: 100%; width: 100%; - background-color: orange; + overflow: auto; + background-color: rgb(200, 200, 200); } .clear-button { position: absolute; - opacity: 1; + top: 3px; + opacity: 0.8; pointer-events: all; cursor: pointer; } .clear-button.before { - top: 3px; left: 3px; } .clear-button.after { - top: 3px; right: 3px; } + + .placeholder { + width: 50%; + height: 50%; + margin-top: 25%; + margin-left: 25%; + + .upload-icon { + width: 100%; + height: 100%; + opacity: 0.5; + } + } } \ No newline at end of file diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index dbaad360b..6ca0397e2 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -1,6 +1,6 @@ import { library } from '@fortawesome/fontawesome-svg-core'; import { faEye } from '@fortawesome/free-regular-svg-icons'; -import { faAsterisk, faBrain, faFileAudio, faImage, faPaintBrush, faTimes } from '@fortawesome/free-solid-svg-icons'; +import { faAsterisk, faBrain, faFileAudio, faImage, faPaintBrush, faTimes, faCloudUploadAlt } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable, runInAction, Lambda } from 'mobx'; import { observer } from "mobx-react"; @@ -133,7 +133,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent :
- upload before image! +
}
@@ -157,11 +157,11 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent : -
- upload after image! +
+
}
-
); +
); } } \ No newline at end of file -- cgit v1.2.3-70-g09d2 From fbd1f11cbd1aef4ea5fefa868662a66ab41ba62b Mon Sep 17 00:00:00 2001 From: Melissa Zhang Date: Sun, 26 Apr 2020 12:18:10 -0700 Subject: set new icon --- src/client/views/MainView.tsx | 3 ++- src/client/views/nodes/ComparisonBox.scss | 2 +- src/client/views/nodes/ComparisonBox.tsx | 6 ++---- src/server/authentication/models/current_user_utils.ts | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) (limited to 'src/client') diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 8fb67c435..da60549ab 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -1,5 +1,5 @@ import { library } from '@fortawesome/fontawesome-svg-core'; -import { faTerminal, faCalculator, faWindowMaximize, faAddressCard, faQuestionCircle, faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt, faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter, faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote, faThumbtack, faTree, faTv, faUndoAlt, faVideo } from '@fortawesome/free-solid-svg-icons'; +import { faColumns, faTerminal, faCalculator, faWindowMaximize, faAddressCard, faQuestionCircle, faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt, faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter, faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote, faThumbtack, faTree, faTv, faUndoAlt, faVideo } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, configure, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; @@ -102,6 +102,7 @@ export class MainView extends React.Component { } } + library.add(faColumns); library.add(faTerminal); library.add(faCalculator); library.add(faWindowMaximize); diff --git a/src/client/views/nodes/ComparisonBox.scss b/src/client/views/nodes/ComparisonBox.scss index 74e80236d..5449cd145 100644 --- a/src/client/views/nodes/ComparisonBox.scss +++ b/src/client/views/nodes/ComparisonBox.scss @@ -36,7 +36,7 @@ right: 0; height: 100%; width: 100%; - overflow: auto; + overflow: hidden; background-color: rgb(200, 200, 200); } diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index 6ca0397e2..09590aff7 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -60,8 +60,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent { }; - + private resizeUpdater: Lambda | undefined; componentWillMount() { this.props.Document.clipWidth = this.props.PanelWidth() / 2; @@ -72,11 +71,10 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent { - //is it ok to use NumCast const width = movementX * this.props.ScreenToLocalTransform().Scale + NumCast(this.props.Document.clipWidth); if (width && width > 5 && width < this.props.PanelWidth()) { this.props.Document.clipWidth = width; diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 4cddbb347..54e20f3c5 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -189,7 +189,7 @@ export class CurrentUserUtils { { _nativeWidth: undefined, _nativeHeight: undefined, _LODdisable: true, _width: 150, _height: 100, title: "freeform" }); } return [ - { title: "Drag a comparison box", label: "Comparison", icon: "cat", ignoreClick: true, drag: 'Docs.Create.ComparisonDocument()' }, + { title: "Drag a comparison box", label: "Comp", icon: "columns", ignoreClick: true, drag: 'Docs.Create.ComparisonDocument()' }, { title: "Drag a collection", label: "Col", icon: "folder", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyCollection as Doc }, { title: "Drag a web page", label: "Web", icon: "globe-asia", ignoreClick: true, drag: 'Docs.Create.WebDocument("", { title: "New Webpage" })' }, { title: "Drag a cat image", label: "Img", icon: "cat", ignoreClick: true, drag: 'Docs.Create.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { _width: 250, _nativeWidth:250, title: "an image of a cat" })' }, -- cgit v1.2.3-70-g09d2 From bb170fe119eb1831e96ebc1ae10553334398cf45 Mon Sep 17 00:00:00 2001 From: Melissa Zhang Date: Mon, 27 Apr 2020 00:14:14 -0700 Subject: set drap & dropped document to snap back to its original position --- src/client/views/nodes/ComparisonBox.tsx | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'src/client') diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index 09590aff7..e8368e12d 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -20,10 +20,7 @@ import { ContentFittingDocumentView } from './ContentFittingDocumentView'; library.add(faImage, faEye as any, faPaintBrush, faBrain); library.add(faFileAudio, faAsterisk); -export const pageSchema = createSchema({ - beforeDoc: "string", - afterDoc: "string" -}); +export const pageSchema = createSchema({}); type ComparisonDocument = makeInterface<[typeof pageSchema, typeof documentSchema]>; const ComparisonDocument = makeInterface(pageSchema, documentSchema); @@ -39,14 +36,16 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent { if (ele) { - return DragManager.MakeDropTarget(ele, (event, dropEvent) => this.dropHandler(event, dropEvent, fieldKey)); + this.props.Document.targetDropAction = "alias"; + return DragManager.MakeDropTarget(ele, (event, dropEvent) => this.dropHandler(event, dropEvent, fieldKey), this.props.Document); } } private dropHandler = (event: Event, dropEvent: DragManager.DropEvent, fieldKey: string) => { + event.stopPropagation(); const droppedDocs = dropEvent.complete.docDragData?.droppedDocuments; if (droppedDocs?.length) { - this.props.Document[fieldKey] = Doc.MakeAlias(droppedDocs[0]); + this.props.Document[fieldKey] = droppedDocs[0]; } } -- cgit v1.2.3-70-g09d2 From 26abe109bdb556d86a2a3fe39377a080a2a902f1 Mon Sep 17 00:00:00 2001 From: Melissa Zhang Date: Tue, 28 Apr 2020 21:58:10 -0700 Subject: fixed bug where user cannot select comparison box when images and box are the same size --- src/client/views/nodes/ComparisonBox.scss | 104 ++++++++++++++++-------------- src/client/views/nodes/ComparisonBox.tsx | 77 +++++++++++----------- 2 files changed, 95 insertions(+), 86 deletions(-) (limited to 'src/client') diff --git a/src/client/views/nodes/ComparisonBox.scss b/src/client/views/nodes/ComparisonBox.scss index 5449cd145..f3ad2b8b9 100644 --- a/src/client/views/nodes/ComparisonBox.scss +++ b/src/client/views/nodes/ComparisonBox.scss @@ -3,69 +3,77 @@ border-radius: inherit; width: 100%; height: 100%; + background-color: grey; - .clip-div { + .content-wrapper { position: absolute; - top: 0; - left: 0; - width: 50%; - height: 100%; - overflow: hidden; - z-index: 999; + bottom: 0; + width: 100%; + height: 95%; - .beforeBox-cont { + .clip-div { + position: absolute; + top: 0; + left: 0; + width: 50%; height: 100%; - overflow: auto; - background-color: rgb(230, 230, 230); + overflow: hidden; + z-index: 999; + + .beforeBox-cont { + height: 100%; + overflow: auto; + background-color: rgb(240, 240, 240); + } + + .slide-bar { + position: absolute; + width: 5px; + height: 100%; + top: 0; + right: 0; + background-color: grey; + cursor: ew-resize; + } } - .slide-bar { + .afterBox-cont { position: absolute; - width: 5px; - height: 100%; top: 0; right: 0; - background-color: white; - cursor: ew-resize; + height: 100%; + width: 100%; + overflow: hidden; + background-color: lightgray; } - } - .afterBox-cont { - position: absolute; - top: 0; - right: 0; - height: 100%; - width: 100%; - overflow: hidden; - background-color: rgb(200, 200, 200); - } - - .clear-button { - position: absolute; - top: 3px; - opacity: 0.8; - pointer-events: all; - cursor: pointer; - } + .clear-button { + position: absolute; + top: 3px; + opacity: 0.8; + pointer-events: all; + cursor: pointer; + } - .clear-button.before { - left: 3px; - } + .clear-button.before { + left: 3px; + } - .clear-button.after { - right: 3px; - } + .clear-button.after { + right: 3px; + } - .placeholder { - width: 50%; - height: 50%; - margin-top: 25%; - margin-left: 25%; + .placeholder { + width: 50%; + height: 50%; + margin-top: 25%; + margin-left: 25%; - .upload-icon { - width: 100%; - height: 100%; - opacity: 0.5; + .upload-icon { + width: 100%; + height: 100%; + opacity: 0.5; + } } } } \ No newline at end of file diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index e8368e12d..6968d5a88 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -7,9 +7,8 @@ import { observer } from "mobx-react"; import { Doc } from '../../../new_fields/Doc'; import { documentSchema } from '../../../new_fields/documentSchemas'; import { Id } from '../../../new_fields/FieldSymbols'; -import { createSchema, listSpec, makeInterface } from '../../../new_fields/Schema'; -import { ComputedField } from '../../../new_fields/ScriptField'; -import { Cast, NumCast, StrCast } from '../../../new_fields/Types'; +import { createSchema, makeInterface } from '../../../new_fields/Schema'; +import { NumCast, StrCast } from '../../../new_fields/Types'; import { DragManager } from '../../util/DragManager'; import { ViewBoxAnnotatableComponent } from '../DocComponent'; import { FieldView, FieldViewProps } from './FieldView'; @@ -108,24 +107,50 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent - {/* wraps around before image and slider bar */} -
+
+
+ {/* wraps around before image and slider bar */} +
{ + this._beforeDropDisposer && this._beforeDropDisposer(); + this._beforeDropDisposer = this.createDropTarget(ele, "beforeDoc"); + }} + style={{ width: this.props.PanelWidth() }}> + { + beforeDoc ? + <> + +
this.clearBeforeDoc(e)}> + +
+ + : +
+ +
+ } +
+
this.registerSliding(e)} /> +
{ - this._beforeDropDisposer && this._beforeDropDisposer(); - this._beforeDropDisposer = this.createDropTarget(ele, "beforeDoc"); - }} - style={{ width: this.props.PanelWidth() }}> + this._afterDropDisposer && this._afterDropDisposer(); + this._afterDropDisposer = this.createDropTarget(ele, "afterDoc"); + }}> { - beforeDoc ? + afterDoc ? <> -
this.clearBeforeDoc(e)}> - +
this.clearAfterDoc(e)}> +
: @@ -134,30 +159,6 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent }
-
this.registerSliding(e)} /> -
-
{ - this._afterDropDisposer && this._afterDropDisposer(); - this._afterDropDisposer = this.createDropTarget(ele, "afterDoc"); - }}> - { - afterDoc ? - <> - -
this.clearAfterDoc(e)}> - -
- - : -
- -
- }
); } -- cgit v1.2.3-70-g09d2 From b95f29de5002c78868fd6f21564505d4c09aec6a Mon Sep 17 00:00:00 2001 From: Melissa Zhang Date: Wed, 29 Apr 2020 11:47:53 -0700 Subject: fixed undo functionality --- src/client/views/nodes/ComparisonBox.tsx | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/client') diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index 6968d5a88..7b35b2811 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -15,6 +15,7 @@ import { FieldView, FieldViewProps } from './FieldView'; import "./ComparisonBox.scss"; import React = require("react"); import { ContentFittingDocumentView } from './ContentFittingDocumentView'; +import { undoBatch } from '../../util/UndoManager'; library.add(faImage, faEye as any, faPaintBrush, faBrain); library.add(faFileAudio, faAsterisk); @@ -40,6 +41,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent { event.stopPropagation(); const droppedDocs = dropEvent.complete.docDragData?.droppedDocuments; @@ -85,12 +87,14 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent { e.stopPropagation; e.preventDefault; delete this.props.Document.beforeDoc; } + @undoBatch clearAfterDoc = (e: React.MouseEvent) => { e.stopPropagation; e.preventDefault; -- cgit v1.2.3-70-g09d2 From 36c01920e3874e1484222a7012745b581405f67d Mon Sep 17 00:00:00 2001 From: Melissa Zhang Date: Wed, 29 Apr 2020 11:54:36 -0700 Subject: minor styling changes --- src/client/views/nodes/ComparisonBox.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/client') diff --git a/src/client/views/nodes/ComparisonBox.scss b/src/client/views/nodes/ComparisonBox.scss index f3ad2b8b9..b874f96b6 100644 --- a/src/client/views/nodes/ComparisonBox.scss +++ b/src/client/views/nodes/ComparisonBox.scss @@ -9,7 +9,7 @@ position: absolute; bottom: 0; width: 100%; - height: 95%; + height: calc(100% - 15px); .clip-div { position: absolute; @@ -22,7 +22,7 @@ .beforeBox-cont { height: 100%; - overflow: auto; + overflow: hidden; background-color: rgb(240, 240, 240); } -- cgit v1.2.3-70-g09d2 From 408c8beb55e774f466abe455bb1296c89fe0c256 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 13 May 2020 11:40:58 -0400 Subject: fixed presentations to not find items in the presentation list. cleaned up webbox css --- src/client/util/DocumentManager.ts | 40 +++++++---------- .../views/collections/CollectionStackingView.tsx | 1 + .../collectionFreeForm/CollectionFreeFormView.tsx | 1 + src/client/views/nodes/PresBox.tsx | 1 + src/client/views/nodes/WebBox.scss | 52 +++++++++++++--------- src/client/views/nodes/WebBox.tsx | 7 +-- 6 files changed, 53 insertions(+), 49 deletions(-) (limited to 'src/client') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 1ba6f0248..99d85125a 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -94,37 +94,29 @@ export class DocumentManager { // heuristic to return the "best" documents first: // choose an exact match over an alias match // choose documents that have a PanelWidth() over those that don't (the treeview documents have no panelWidth) - docViews.map(view => !view.props.Document.presBox && view.props.PanelWidth() > 1 && view.props.Document === toFind && toReturn.push(view)); - docViews.map(view => !view.props.Document.presBox && view.props.PanelWidth() <= 1 && view.props.Document === toFind && toReturn.push(view)); - docViews.map(view => !view.props.Document.presBox && view.props.PanelWidth() > 1 && view.props.Document !== toFind && Doc.AreProtosEqual(view.props.Document, toFind) && toReturn.push(view)); - docViews.map(view => !view.props.Document.presBox && view.props.PanelWidth() <= 1 && view.props.Document !== toFind && Doc.AreProtosEqual(view.props.Document, toFind) && toReturn.push(view)); + docViews.map(view => view.props.PanelWidth() > 1 && view.props.Document === toFind && toReturn.push(view)); + docViews.map(view => view.props.PanelWidth() <= 1 && view.props.Document === toFind && toReturn.push(view)); + docViews.map(view => view.props.PanelWidth() > 1 && view.props.Document !== toFind && Doc.AreProtosEqual(view.props.Document, toFind) && toReturn.push(view)); + docViews.map(view => view.props.PanelWidth() <= 1 && view.props.Document !== toFind && Doc.AreProtosEqual(view.props.Document, toFind) && toReturn.push(view)); return toReturn; } @computed public get LinkedDocumentViews() { - const pairs = DocumentManager.Instance.DocumentViews - //.filter(dv => (dv.isSelected() || Doc.IsBrushed(dv.props.Document))) // draw links from DocumentViews that are selected or brushed OR - // || DocumentManager.Instance.DocumentViews.some(dv2 => { // Documentviews which - // const rest = DocListCast(dv2.props.Document.links).some(l => Doc.AreProtosEqual(l, dv.props.Document));// are link doc anchors - // const init = (dv2.isSelected() || Doc.IsBrushed(dv2.props.Document)) && dv2.Document.type !== DocumentType.AUDIO; // on a view that is selected or brushed - // return init && rest; - // } - // ) - .reduce((pairs, dv) => { - const linksList = LinkManager.Instance.getAllRelatedLinks(dv.props.Document); - pairs.push(...linksList.reduce((pairs, link) => { - const linkToDoc = link && LinkManager.Instance.getOppositeAnchor(link, dv.props.Document); - linkToDoc && DocumentManager.Instance.getDocumentViews(linkToDoc).map(docView1 => { - if (dv.props.Document.type !== DocumentType.LINK || dv.props.LayoutTemplateString !== docView1.props.LayoutTemplateString) { - pairs.push({ a: dv, b: docView1, l: link }); - } - }); - return pairs; - }, [] as { a: DocumentView, b: DocumentView, l: Doc }[])); + const pairs = DocumentManager.Instance.DocumentViews.reduce((pairs, dv) => { + const linksList = LinkManager.Instance.getAllRelatedLinks(dv.props.Document); + pairs.push(...linksList.reduce((pairs, link) => { + const linkToDoc = link && LinkManager.Instance.getOppositeAnchor(link, dv.props.Document); + linkToDoc && DocumentManager.Instance.getDocumentViews(linkToDoc).map(docView1 => { + if (dv.props.Document.type !== DocumentType.LINK || dv.props.LayoutTemplateString !== docView1.props.LayoutTemplateString) { + pairs.push({ a: dv, b: docView1, l: link }); + } + }); return pairs; - }, [] as { a: DocumentView, b: DocumentView, l: Doc }[]); + }, [] as { a: DocumentView, b: DocumentView, l: Doc }[])); + return pairs; + }, [] as { a: DocumentView, b: DocumentView, l: Doc }[]); return pairs; } diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 821a6d476..d97f26daf 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -207,6 +207,7 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument) NativeHeight={returnZero} NativeWidth={returnZero} fitToBox={false} + dontRegisterView={this.props.dontRegisterView} rootSelected={this.rootSelected} dropAction={StrCast(this.props.Document.childDropAction) as dropActionType} onClick={this.onChildClickHandler} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 6caee960d..cfa1a046f 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -893,6 +893,7 @@ export class CollectionFreeFormView extends CollectionSubView childLayoutTemplate={this.childLayoutTemplate} filterAddDocument={this.addDocumentFilter} removeDocument={returnFalse} + dontRegisterView={true} focus={this.selectElement} ScreenToLocalTransform={this.getTransform} /> : (null) diff --git a/src/client/views/nodes/WebBox.scss b/src/client/views/nodes/WebBox.scss index 4c05d4627..4623444b9 100644 --- a/src/client/views/nodes/WebBox.scss +++ b/src/client/views/nodes/WebBox.scss @@ -5,6 +5,36 @@ transform-origin: top left; width: 100%; height: 100%; + + .webBox-htmlSpan { + position: absolute; + top: 0; + left: 0; + } + .webBox-cont { + pointer-events: none; + } + .webBox-cont, .webBox-cont-interactive { + padding: 0vw; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + transform-origin: top left; + overflow: auto; + .webBox-iframe { + width: 100%; + height: 100%; + position: absolute; + top:0; + } + } + .webBox-cont-interactive { + span { + user-select: text !important; + } + } .webBox-outerContent { width: 100%; height: 100%; @@ -20,29 +50,7 @@ display:none; } } -.webBox-cont { - padding: 0vw; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - transform-origin: top left; - overflow: auto; - pointer-events: none; -} - -.webBox-cont-interactive { - span { - user-select: text !important; - } -} -#webBox-htmlSpan { - position: absolute; - top: 0; - left: 0; -} .webBox-overlay { width: 100%; diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 384a6e8a5..b0abb2479 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -308,18 +308,19 @@ export class WebBox extends ViewBoxAnnotatableComponent; + view = ; } else if (field instanceof WebField) { const url = this.layoutDoc.UseCors ? Utils.CorsProxy(field.url.href) : field.url.href; - view =