diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/util/DocumentManager.ts | 4 | ||||
-rw-r--r-- | src/client/views/collections/CollectionPileView.tsx | 135 | ||||
-rw-r--r-- | src/client/views/collections/CollectionView.tsx | 1 | ||||
-rw-r--r-- | src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 1 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 12 | ||||
-rw-r--r-- | src/client/views/nodes/ImageBox.scss | 18 | ||||
-rw-r--r-- | src/client/views/nodes/ImageBox.tsx | 4 |
7 files changed, 91 insertions, 84 deletions
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 519f75dbd..9336717c0 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -190,7 +190,7 @@ export class DocumentManager { finalTargetDoc.hidden && (finalTargetDoc.hidden = undefined); !noSelect && docView?.select(false); if (originatingDoc?.followLinkAudio) { - const anno = Cast(finalTargetDoc[Doc.LayoutFieldKey(finalTargetDoc) + '-audioAnnotations'], listSpec(AudioField), null).lastElement(); + const anno = Cast(finalTargetDoc[Doc.LayoutFieldKey(finalTargetDoc) + '-audioAnnotations'], listSpec(AudioField), null)?.lastElement(); if (anno) { if (anno instanceof AudioField) { new Howl({ @@ -326,7 +326,7 @@ export class DocumentManager { docContext, linkDoc, true /* if target not found, get rid of context just created */, - undefined, + originatingDoc, finished, originalTarget ) diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx index 4489601db..38e240ac6 100644 --- a/src/client/views/collections/CollectionPileView.tsx +++ b/src/client/views/collections/CollectionPileView.tsx @@ -1,33 +1,35 @@ -import { action, computed, IReactionDisposer, reaction } from "mobx"; -import { observer } from "mobx-react"; -import { Doc, HeightSym, WidthSym } from "../../../fields/Doc"; -import { NumCast, StrCast } from "../../../fields/Types"; -import { emptyFunction, returnFalse, returnTrue, setupMoveUpEvents } from "../../../Utils"; -import { DocUtils } from "../../documents/Documents"; -import { SelectionManager } from "../../util/SelectionManager"; -import { SnappingManager } from "../../util/SnappingManager"; -import { undoBatch, UndoManager } from "../../util/UndoManager"; -import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; -import "./CollectionPileView.scss"; -import { CollectionSubView } from "./CollectionSubView"; -import React = require("react"); -import { ScriptField } from "../../../fields/ScriptField"; +import { action, computed, IReactionDisposer, reaction } from 'mobx'; +import { observer } from 'mobx-react'; +import { Doc, HeightSym, WidthSym } from '../../../fields/Doc'; +import { NumCast, StrCast } from '../../../fields/Types'; +import { emptyFunction, returnFalse, returnTrue, setupMoveUpEvents } from '../../../Utils'; +import { DocUtils } from '../../documents/Documents'; +import { SelectionManager } from '../../util/SelectionManager'; +import { SnappingManager } from '../../util/SnappingManager'; +import { undoBatch, UndoManager } from '../../util/UndoManager'; +import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; +import './CollectionPileView.scss'; +import { CollectionSubView } from './CollectionSubView'; +import React = require('react'); +import { ScriptField } from '../../../fields/ScriptField'; @observer export class CollectionPileView extends CollectionSubView() { - _originalChrome: any = ""; + _originalChrome: any = ''; _disposers: { [name: string]: IReactionDisposer } = {}; componentDidMount() { - if (this.layoutEngine() !== "pass" && this.layoutEngine() !== "starburst") { - this.Document._pileLayoutEngine = "pass"; + if (this.layoutEngine() !== 'pass' && this.layoutEngine() !== 'starburst') { + this.Document._pileLayoutEngine = 'pass'; } this._originalChrome = this.layoutDoc._chromeHidden; this.layoutDoc._chromeHidden = true; - // pileups are designed to go away when they are empty. - this._disposers.selected = reaction(() => this.childDocs.length, - (num) => !num && this.props.ContainingCollectionView?.removeDocument(this.props.Document)); + // pileups are designed to go away when they are empty. + this._disposers.selected = reaction( + () => this.childDocs.length, + num => !num && this.props.ContainingCollectionView?.removeDocument(this.props.Document) + ); } componentWillUnmount() { this.layoutDoc._chromeHidden = this._originalChrome; @@ -38,32 +40,36 @@ export class CollectionPileView extends CollectionSubView() { @undoBatch addPileDoc = (doc: Doc | Doc[]) => { - (doc instanceof Doc ? [doc] : doc).map((d) => DocUtils.iconify(d)); + (doc instanceof Doc ? [doc] : doc).map(d => DocUtils.iconify(d)); return this.props.addDocument?.(doc) || false; - } + }; @undoBatch removePileDoc = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => { - (doc instanceof Doc ? [doc] : doc).map(undoBatch((d) => Doc.deiconifyView(d))); + (doc instanceof Doc ? [doc] : doc).map(undoBatch(d => Doc.deiconifyView(d))); return this.props.moveDocument?.(doc, targetCollection, addDoc) || false; - } + }; toggleIcon = () => { - return ScriptField.MakeScript("documentView.iconify()", { documentView: "any" }); - } + return ScriptField.MakeScript('documentView.iconify()', { documentView: 'any' }); + }; // returns the contents of the pileup in a CollectionFreeFormView @computed get contents() { - const isStarburst = this.layoutEngine() === "starburst"; - return <div className="collectionPileView-innards" - style={{ pointerEvents: isStarburst || SnappingManager.GetIsDragging() ? undefined : "none" }} > - <CollectionFreeFormView {...this.props} - layoutEngine={this.layoutEngine} - childDocumentsActive={isStarburst ? returnTrue : undefined} - addDocument={this.addPileDoc} - childClickScript={this.toggleIcon()} - moveDocument={this.removePileDoc} /> - </div>; + const isStarburst = this.layoutEngine() === 'starburst'; + return ( + <div className="collectionPileView-innards" style={{ pointerEvents: isStarburst || SnappingManager.GetIsDragging() ? undefined : 'none' }}> + <CollectionFreeFormView + {...this.props} + layoutEngine={this.layoutEngine} + childDocumentsActive={isStarburst ? returnTrue : undefined} + addDocument={this.addPileDoc} + childCanEmbedOnDrag={true} + childClickScript={this.toggleIcon()} + moveDocument={this.removePileDoc} + /> + </div> + ); } // toggles the pileup between starburst to compact @@ -99,27 +105,35 @@ export class CollectionPileView extends CollectionSubView() { pointerDown = (e: React.PointerEvent) => { let dist = 0; SnappingManager.SetIsDragging(true); - setupMoveUpEvents(this, e, (e: PointerEvent, down: number[], delta: number[]) => { - if (this.layoutEngine() === "pass" && this.childDocs.length && e.shiftKey) { - dist += Math.sqrt(delta[0] * delta[0] + delta[1] * delta[1]); - if (dist > 100) { - if (!this._undoBatch) { - this._undoBatch = UndoManager.StartBatch("layout pile"); + setupMoveUpEvents( + this, + e, + (e: PointerEvent, down: number[], delta: number[]) => { + if (this.layoutEngine() === 'pass' && this.childDocs.length && e.shiftKey) { + dist += Math.sqrt(delta[0] * delta[0] + delta[1] * delta[1]); + if (dist > 100) { + if (!this._undoBatch) { + this._undoBatch = UndoManager.StartBatch('layout pile'); + } + const doc = this.childDocs[0]; + doc.x = e.clientX; + doc.y = e.clientY; + this.props.addDocTab(doc, 'inParent') && (this.props.removeDocument?.(doc) || false); + dist = 0; } - const doc = this.childDocs[0]; - doc.x = e.clientX; - doc.y = e.clientY; - this.props.addDocTab(doc, "inParent") && (this.props.removeDocument?.(doc) || false); - dist = 0; } - } - return false; - }, () => { - this._undoBatch?.end(); - this._undoBatch = undefined; - SnappingManager.SetIsDragging(false); - }, emptyFunction, e.shiftKey && this.layoutEngine() === "pass", this.layoutEngine() === "pass" && e.shiftKey); // this sets _doubleTap - } + return false; + }, + () => { + this._undoBatch?.end(); + this._undoBatch = undefined; + SnappingManager.SetIsDragging(false); + }, + emptyFunction, + e.shiftKey && this.layoutEngine() === 'pass', + this.layoutEngine() === 'pass' && e.shiftKey + ); // this sets _doubleTap + }; // onClick for toggling the pileup view @undoBatch @@ -130,12 +144,13 @@ export class CollectionPileView extends CollectionSubView() { this.toggleStarburst(); e.stopPropagation(); } - } + }; render() { - return <div className={`collectionPileView`} onClick={this.onClick} onPointerDown={this.pointerDown} - style={{ width: this.props.PanelWidth(), height: "100%" }}> - {this.contents} - </div>; + return ( + <div className={`collectionPileView`} onClick={this.onClick} onPointerDown={this.pointerDown} style={{ width: this.props.PanelWidth(), height: '100%' }}> + {this.contents} + </div> + ); } } diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 9f63a11aa..625d4e9e5 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -54,6 +54,7 @@ interface CollectionViewProps_ extends FieldViewProps { childHideDecorationTitle?: () => boolean; childHideResizeHandles?: () => boolean; childLayoutTemplate?: () => Doc | undefined; // specify a layout Doc template to use for children of the collection + childCanEmbedOnDrag?: boolean; childXPadding?: number; childYPadding?: number; childLayoutString?: string; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 8fe5ad63f..932bd789d 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1314,6 +1314,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged} docViewPath={this.props.docViewPath} styleProvider={this.getClusterColor} + canEmbedOnDrag={this.props.childCanEmbedOnDrag} dataProvider={this.childDataProvider} sizeProvider={this.childSizeProvider} dropAction={StrCast(this.props.Document.childDropAction) as dropActionType} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 76d6d3532..84cacd919 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -147,6 +147,7 @@ export interface DocumentViewSharedProps { pinToPres: (document: Doc) => void; ScreenToLocalTransform: () => Transform; bringToFront: (doc: Doc, sendToBack?: boolean) => void; + canEmbedOnDrag?: boolean; xPadding?: number; yPadding?: number; dropAction?: dropActionType; @@ -505,6 +506,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps dragData.treeViewDoc = this.props.treeViewDoc; dragData.removeDocument = this.props.removeDocument; dragData.moveDocument = this.props.moveDocument; + dragData.canEmbed = this.props.canEmbedOnDrag; //dragData.dimSource : // dragEffects field, set dim // add kv pairs to a doc, swap properties with the node while dragging, and then swap when dropping @@ -525,7 +527,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps e.preventDefault(); if (e.key === '†' || e.key === 't') { if (!StrCast(this.layoutDoc._showTitle)) this.layoutDoc._showTitle = 'title'; - if (!this._titleRef.current) setTimeout(() => this._titleRef.current?.setIsFocused(true), 0); + if (!this._titleRef.current) setTimeout(() => this._titleRef.current?.setIsFocused(true)); else if (!this._titleRef.current.setIsFocused(true)) { // if focus didn't change, focus on interior text... this._titleRef.current?.setIsFocused(false); @@ -540,12 +542,10 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps // copying over VIEW fields immediately allows the view type to switch to create the right _componentView Array.from(Object.keys(Doc.GetProto(anchor))) .filter(key => key.startsWith(ViewSpecPrefix)) - .forEach(spec => { - this.layoutDoc[spec.replace(ViewSpecPrefix, '')] = (field => (field instanceof ObjectField ? ObjectField.MakeCopy(field) : field))(anchor[spec]); - }); - // after a timeout, the right _componentView should have been created, so call it to update its view spec values + .forEach(spec => (this.layoutDoc[spec.replace(ViewSpecPrefix, '')] = (field => (field instanceof ObjectField ? ObjectField.MakeCopy(field) : field))(anchor[spec]))); + // after a render the general viewSpec should have created the right _componentView, so after a timeout, call the componentview to update its specific view specs setTimeout(() => this._componentView?.setViewSpec?.(anchor, LinkDocPreview.LinkInfo ? true : false)); - const focusSpeed = this._componentView?.scrollFocus?.(anchor, options?.instant === false || !LinkDocPreview.LinkInfo); // bcz: smooth parameter should really be passed into focus() instead of inferred here + const focusSpeed = this._componentView?.scrollFocus?.(anchor, options?.instant === false || !LinkDocPreview.LinkInfo); const endFocus = focusSpeed === undefined ? options?.afterFocus : async (moved: boolean) => options?.afterFocus?.(true) ?? ViewAdjustment.doNothing; this.props.focus(options?.docTransform ? anchor : this.rootDoc, { ...options, diff --git a/src/client/views/nodes/ImageBox.scss b/src/client/views/nodes/ImageBox.scss index cd2b23f02..6359a9491 100644 --- a/src/client/views/nodes/ImageBox.scss +++ b/src/client/views/nodes/ImageBox.scss @@ -5,7 +5,6 @@ position: relative; transform-origin: top left; - .imageBox-annotationLayer { position: absolute; transform-origin: left top; @@ -95,7 +94,6 @@ height: 100%; } - .imageBox-fader { position: relative; width: 100%; @@ -103,7 +101,8 @@ display: flex; height: 100%; - .imageBox-fadeBlocker, .imageBox-fadeBlocker-hover{ + .imageBox-fadeBlocker, + .imageBox-fadeBlocker-hover { width: 100%; height: 100%; position: absolute; @@ -126,17 +125,6 @@ left: 0; } -.imageBox-fadeBlocker { - -webkit-transition: opacity 1s ease-in-out; - -moz-transition: opacity 1s ease-in-out; - -o-transition: opacity 1s ease-in-out; - transition: opacity 1s ease-in-out; -} - .imageBox-fadeBlocker-hover { - -webkit-transition: opacity 1s ease-in-out; - -moz-transition: opacity 1s ease-in-out; - -o-transition: opacity 1s ease-in-out; - transition: opacity 1s ease-in-out; opacity: 0; -}
\ No newline at end of file +} diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 8ecd8104a..76ba7765c 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -377,7 +377,9 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp <div className="imageBox-fader" style={{ overflow: Array.from(this.props.docViewPath?.()).slice(-1)[0].fitWidth ? 'auto' : undefined }}> <img key="paths" src={srcpath} style={{ transform, transformOrigin }} draggable={false} width={nativeWidth} /> {fadepath === srcpath ? null : ( - <div className={`imageBox-fadeBlocker${(this.props.isHovering?.() && this.layoutDoc[this.fieldKey + '-useAlt'] === undefined) || BoolCast(this.layoutDoc[this.fieldKey + '-useAlt']) ? '-hover' : ''}`}> + <div + className={`imageBox-fadeBlocker${(this.props.isHovering?.() && this.layoutDoc[this.fieldKey + '-useAlt'] === undefined) || BoolCast(this.layoutDoc[this.fieldKey + '-useAlt']) ? '-hover' : ''}`} + style={{ transition: StrCast(this.layoutDoc.viewTransition, 'opacity 1000 ms') }}> <img className="imageBox-fadeaway" key="fadeaway" src={fadepath} style={{ transform, transformOrigin }} draggable={false} width={nativeWidth} /> </div> )} |