From 0664b26916f656e2b898af4edab13c7b6d5a1dcc Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 21 Apr 2022 15:00:31 -0400 Subject: fixed issues with pile view - dragging, burst size, rendering within grid/non-freeform views, fixed timeView filtering to not keep making redundant filters, --- src/client/views/collections/collectionGrid/CollectionGridView.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/client/views/collections/collectionGrid/CollectionGridView.tsx') diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx index 58ea7410d..da102fe18 100644 --- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx +++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx @@ -166,7 +166,7 @@ export class CollectionGridView extends CollectionSubView() { ScreenToLocalTransform={dxf} onClick={this.onChildClickHandler} renderDepth={this.props.renderDepth + 1} - dontCenter={"y"} + dontCenter={this.props.Document.centerY ? "" : "y"} />; } @@ -283,6 +283,7 @@ export class CollectionGridView extends CollectionSubView() { onContextMenu = () => { const displayOptionsMenu: ContextMenuProps[] = []; displayOptionsMenu.push({ description: "Toggle Content Display Style", event: () => this.props.Document.display = this.props.Document.display ? undefined : "contents", icon: "copy" }); + displayOptionsMenu.push({ description: "Toggle Vertical Centering", event: () => this.props.Document.centerY = !this.props.Document.centerY, icon: "copy" }); ContextMenu.Instance.addItem({ description: "Display", subitems: displayOptionsMenu, icon: "tv" }); } @@ -293,7 +294,7 @@ export class CollectionGridView extends CollectionSubView() { if (this.props.isContentActive(true)) { setupMoveUpEvents(this, e, returnFalse, returnFalse, (e: PointerEvent, doubleTap?: boolean) => { - if (doubleTap) { + if (doubleTap && !e.button) { undoBatch(action(() => { const text = Docs.Create.TextDocument("", { _width: 150, _height: 50 }); FormattedTextBox.SelectOnLoad = text[Id];// track the new text box so we can give it a prop that tells it to focus itself when it's displayed -- cgit v1.2.3-70-g09d2 From 0dd3bbfc119d48bd2c32f8e55b7051e3ddc530c3 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 21 Jun 2022 14:40:04 -0400 Subject: restored experimental templates. fixed (enabled) pointer events on nested column/row views when container is active. got rid of freezeDimensions which wasn't needed and introduced artifacts for views that set it (timeView, GridView) --- src/client/documents/Documents.ts | 1 + src/client/util/CurrentUserUtils.ts | 74 +++++++++++----------- src/client/util/DragManager.ts | 11 ++-- src/client/views/PropertiesView.tsx | 1 - .../views/collections/CollectionStackingView.tsx | 1 - .../views/collections/CollectionTimeView.tsx | 5 +- src/client/views/collections/CollectionView.tsx | 1 - .../collectionFreeForm/CollectionFreeFormView.tsx | 1 - .../collectionGrid/CollectionGridView.tsx | 1 - .../CollectionMulticolumnView.tsx | 14 ++-- .../CollectionMultirowView.tsx | 6 +- .../collectionSchema/CollectionSchemaView.tsx | 1 - .../collections/collectionSchema/SchemaTable.tsx | 1 - src/client/views/nodes/DocumentContentsView.tsx | 1 - src/client/views/nodes/DocumentView.tsx | 7 +- src/client/views/nodes/button/FontIconBox.tsx | 4 +- 16 files changed, 61 insertions(+), 69 deletions(-) (limited to 'src/client/views/collections/collectionGrid/CollectionGridView.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 73b756a8d..59391d150 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -194,6 +194,7 @@ export class DocumentOptions { childLimitHeight?: number; // whether to limit the height of collection children. 0 - means height can be no bigger than width childLayoutTemplate?: Doc; // template for collection to use to render its children (see PresBox layout in tree view) childLayoutString?: string; // template string for collection to use to render its children + childDocumentsActive?: boolean; // whether child documents are active when parent is document active childDontRegisterViews?: boolean; childHideLinkButton?: boolean; // hide link buttons on all children childContextMenuFilters?: List; diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 9b5fc5b98..e80fe6776 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -1,6 +1,6 @@ import { computed, observable, reaction } from "mobx"; import * as rp from 'request-promise'; -import { DataSym, Doc, DocListCast, DocListCastAsync, StrListCast } from "../../fields/Doc"; +import { DataSym, Doc, DocListCast, DocListCastAsync, Opt, StrListCast } from "../../fields/Doc"; import { Id } from "../../fields/FieldSymbols"; import { InkTool } from "../../fields/InkField"; import { List } from "../../fields/List"; @@ -109,40 +109,43 @@ export class CurrentUserUtils { } // initializes experimental advanced template views - slideView, headerView - static setupExperimentalTemplateButtons(doc: Doc, field="template-experimental-buttons") { - const tempDocs = DocCast(doc[field]); - const requiredTypeNameFields:{opts:DocumentOptions, template:() => Doc}[] = [ + static setupExperimentalTemplateButtons(doc: Doc, tempDocs?:Doc) { + const requiredTypeNameFields:{btnOpts:DocumentOptions, templateOpts:DocumentOptions, template:(opts:DocumentOptions) => Doc}[] = [ { - opts:{type: "slide", icon: "address-card"}, template: () => Docs.Create.MultirowDocument( + btnOpts: { title: "slide", icon: "address-card" }, + templateOpts: { _width: 400, _height: 300, title: "slideView", childDocumentsActive: true, _xMargin: 3, _yMargin: 3, system: true }, + template: (opts:DocumentOptions) => Docs.Create.MultirowDocument( [ - Docs.Create.MulticolumnDocument([], { title: "data", _height: 200, system: true }), - Docs.Create.TextDocument("", { title: "text", _height: 100, system: true, _fontFamily: StrCast(Doc.UserDoc()._fontFamily), _fontSize: StrCast(Doc.UserDoc()._fontSize) }) - ], - { _width: 400, _height: 300, title: "slideView", _xMargin: 3, _yMargin: 3, system: true } - ) + Docs.Create.MulticolumnDocument([], { title: "data", _height: 200, system: true }), + Docs.Create.TextDocument("", { title: "text", _fitWidth:true, _height: 100, system: true, _fontFamily: StrCast(Doc.UserDoc()._fontFamily), _fontSize: StrCast(Doc.UserDoc()._fontSize) }) + ], opts) }, { - opts:{type: "mobile", icon: "mobile"}, template: () => this.mobileButton({ title: "NEW MOBILE BUTTON", onClick: undefined, }, - [this.createToolButton({ ignoreClick: true, icon: "mobile", backgroundColor: "transparent" }), - this.mobileTextContainer({}, - [this.mobileButtonText({}, "NEW MOBILE BUTTON"), this.mobileButtonInfo({}, "You can customize this button and make it your own.")]) - ] + btnOpts: { title: "mobile", icon: "mobile" }, + templateOpts: { title: "NEW MOBILE BUTTON", onClick: undefined, }, + template: (opts:DocumentOptions) => this.mobileButton(opts, + [this.createToolButton({ ignoreClick: true, icon: "mobile", backgroundColor: "transparent" }), + this.mobileTextContainer({}, + [this.mobileButtonText({}, "NEW MOBILE BUTTON"), this.mobileButtonInfo({}, "You can customize this button and make it your own.")]) + ] ) }, ]; - const requiredTypes = requiredTypeNameFields.map(({ opts, template }) => { - const docType = DocListCast(tempDocs?.data)?.find(doc => doc.title === opts.type); - const reqdOpts = { - dragFactory: template(), - title: opts.type, - icon: opts.icon + const requiredTypes = requiredTypeNameFields.map(({ btnOpts, template, templateOpts }) => { + const tempBtn = DocListCast(tempDocs?.data)?.find(doc => doc.title === btnOpts.title); + const reqdScripts = { onDragStart: '{ return copyDragFactory(this.dragFactory); }' }; + const assignBtnAndTempOpts = (templateBtn:Opt, btnOpts:DocumentOptions, templateOptions:DocumentOptions) => { + if (templateBtn) { + this.AssignOpts(templateBtn,btnOpts); + this.AssignOpts(DocCast(templateBtn.dragFactory), templateOptions) ?? (templateBtn.dragFactory = template(templateOpts)); + } + return templateBtn; }; - const reqdScripts = {onDragStart: 'copyDragFactory(this.dragFactory)'}; const makeTemp = (doc:Doc) => { doc.isTemplateDoc = makeTemplate(doc); return doc; } - return this.AssignScripts(!docType ? makeTemp(CurrentUserUtils.createToolButton(reqdOpts)) : this.AssignOpts(docType, reqdOpts)!, reqdScripts)!; + return this.AssignScripts(assignBtnAndTempOpts(tempBtn, btnOpts, templateOpts) ?? CurrentUserUtils.createToolButton( {...btnOpts, dragFactory: makeTemp(template(templateOpts))}), reqdScripts); }); const reqdOpts = { @@ -150,12 +153,9 @@ export class CurrentUserUtils { _stayInCollection: true, _hideContextMenu: true, _forceActive: true, system: true, _autoHeight: true, _width: 500, _height: 300, _fitWidth: true, _columnWidth: 35, ignoreClick: true, _lockedPosition: true, }; - const reqdScripts = {dropConverter : "convertToButtons(dragData)"}; - const reqdFuncs = {hidden: "IsNoviceMode()"} - return this.AssignScripts(!tempDocs ? - (doc[field] = Docs.Create.MasonryDocument(requiredTypes, reqdOpts)) : - this.AssignOpts(tempDocs, reqdOpts, requiredTypes)!, - reqdScripts, reqdFuncs); + const reqdScripts = { dropConverter : "convertToButtons(dragData)" }; + const reqdFuncs = { hidden: "IsNoviceMode()" }; + return this.AssignScripts(this.AssignOpts(tempDocs, reqdOpts, requiredTypes) ?? Docs.Create.MasonryDocument(requiredTypes, reqdOpts), reqdScripts, reqdFuncs); } /// Initializes templates that can be applied to notes @@ -525,12 +525,12 @@ export class CurrentUserUtils { static setupToolsBtnPanel(doc: Doc, field:string) { const myTools = DocCast(doc[field]); const creatorBtns = CurrentUserUtils.setupCreatorButtons(doc, DocListCast(myTools?.data)?.length ? DocListCast(myTools.data)[0]:undefined); - //const templateBtns = CurrentUserUtils.setupExperimentalTemplateButtons(doc); + const templateBtns = CurrentUserUtils.setupExperimentalTemplateButtons(doc,DocListCast(myTools?.data)?.length > 1 ? DocListCast(myTools.data)[1]:undefined); const reqdToolOps:DocumentOptions = { title: "My Tools", system: true, ignoreClick: true, boxShadow: "0 0", _showTitle: "title", _width: 500, _yMargin: 20, _lockedPosition: true, _forceActive: true, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, }; - this.AssignOpts(myTools, reqdToolOps, [creatorBtns, /*templateBtns*/]) ?? (doc[field] = Docs.Create.StackingDocument([creatorBtns, /*templateBtns*/], reqdToolOps)); + this.AssignOpts(myTools, reqdToolOps, [creatorBtns, templateBtns]) ?? (doc[field] = Docs.Create.StackingDocument([creatorBtns, templateBtns], reqdToolOps)); } /// initializes the left sidebar dashboard pane @@ -749,7 +749,7 @@ export class CurrentUserUtils { } static schemaTools():Button[] { - return [{ title: "Show preview", toolTip: "Show preview of selected document", btnType: ButtonType.ToggleButton, buttonText: "Show Preview", icon: "eye", scripts:{onClick:'toggleSchemaPreview(_readOnly_)'}, }]; + return [{ title: "Show preview", toolTip: "Show preview of selected document", btnType: ButtonType.ToggleButton, buttonText: "Show Preview", icon: "eye", scripts:{ onClick: '{return toggleSchemaPreview(_readOnly_);}'}, }]; } static webTools() { @@ -774,9 +774,9 @@ export class CurrentUserUtils { }, // Always show { title: "Back", toolTip: "Prev Animation Frame", width: 20, btnType: ButtonType.ClickButton,icon: "chevron-left", scripts:{onClick: 'prevKeyFrame(_readOnly_)'}, funcs: {hidden: 'IsNoviceMode()'} }, { title: "Fwd", toolTip: "Next Animation Frame", width: 20, btnType: ButtonType.ClickButton, icon: "chevron-right", scripts:{onClick: 'nextKeyFrame(_readOnly_)'}, funcs: {hidden: 'IsNoviceMode()'}}, - { title: "Fill", toolTip: "Background Fill Color", width: 20, btnType: ButtonType.ColorButton, ignoreClick: true, icon: "fill-drip", scripts: { script: "setBackgroundColor(value, _readOnly_)"}, funcs:{ hidden: 'selectedDocumentType()' }}, // Only when a document is selected - { title: "Header", toolTip: "Header Color", btnType: ButtonType.ColorButton, ignoreClick: true, icon: "heading", scripts: {script: "setHeaderColor(value, _readOnly_)"}, funcs : {hidden: 'selectedDocumentType()'} }, - { title: "Overlay", toolTip: "Overlay", btnType: ButtonType.ToggleButton, icon: "layer-group", scripts: {onClick : 'toggleOverlay(_readOnly_)'}, funcs: {hidden: 'selectedDocumentType(undefined, "freeform", true)'} }, // Only when floating document is selected in freeform + { title: "Fill", toolTip: "Background Fill Color", width: 20, btnType: ButtonType.ColorButton, ignoreClick: true, icon: "fill-drip", scripts: { script: "setBackgroundColor(value, _readOnly_)"}, funcs:{ hidden: '!selectedDocumentType()' }}, // Only when a document is selected + { title: "Header", toolTip: "Header Color", btnType: ButtonType.ColorButton, ignoreClick: true, icon: "heading", scripts: {script: "setHeaderColor(value, _readOnly_)"}, funcs : {hidden: '!selectedDocumentType()'} }, + { title: "Overlay", toolTip: "Overlay", btnType: ButtonType.ToggleButton, icon: "layer-group", scripts: {onClick : 'toggleOverlay(_readOnly_)'}, funcs: {hidden: '!selectedDocumentType(undefined, "freeform", true)'} }, // Only when floating document is selected in freeform // { title: "Alias", btnType: ButtonType.ClickButton, icon: "copy", hidden: 'selectedDocumentType()' }, // Only when a document is selected { title: "Text", icon: "text", subMenu: CurrentUserUtils.textTools(), funcs: { linearViewIsExpanded: `selectedDocumentType("${DocumentType.RTF}")`} }, // Always available { title: "Ink", icon: "ink", subMenu: CurrentUserUtils.inkTools(), funcs: { linearViewIsExpanded: `selectedDocumentType("${DocumentType.INK}")`} }, // Always available @@ -983,7 +983,6 @@ export class CurrentUserUtils { doc.savedFilters ?? (doc.savedFilters = new List()); doc.filterDocCount = 0; doc.freezeChildren = "remove|add"; - doc.myHeaderBar ?? (doc.myHeaderBar = Docs.Create.MulticolumnDocument([], { title: "header bar", system: true })); // drop down panel at top of dashboard for stashing documents await this.setupLinkDocs(doc, linkDatabaseId); await this.setupSharedDocs(doc, sharingDocumentId); // sets up the right sidebar collection for mobile upload documents and sharing this.setupDefaultIconTemplates(doc); // creates a set of icon templates triggered by the document deoration icon @@ -995,7 +994,8 @@ export class CurrentUserUtils { this.setupLeftSidebarMenu(doc); // the left-side column of buttons that open their contents in a flyout panel on the left this.setupDocTemplates(doc); // sets up the template menu of templates doc.globalScriptDatabase ?? ( doc.globalScriptDatabase = Docs.Prototypes.MainScriptDocument()); - + doc.myHeaderBar ?? (doc.myHeaderBar = Docs.Create.MulticolumnDocument([], { title: "header bar", system: true })); // drop down panel at top of dashboard for stashing documents + setTimeout(() => DocServer.UPDATE_SERVER_CACHE(), 2500); doc.fieldInfos = await Docs.setupFieldInfos(); if (doc.activeDashboard instanceof Doc) { diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 2b62945af..09b463c2f 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -223,10 +223,13 @@ export namespace DragManager { if (docDragData && !docDragData.droppedDocuments.length) { docDragData.dropAction = dragData.userDropAction || dragData.dropAction; docDragData.droppedDocuments = - await Promise.all(dragData.draggedDocuments.map(async d => !dragData.isDocDecorationMove && !dragData.userDropAction && ScriptCast(d.onDragStart) ? addAudioTag(ScriptCast(d.onDragStart).script.run({ this: d }).result) : - docDragData.dropAction === "alias" ? Doc.MakeAlias(d) : - docDragData.dropAction === "proto" ? Doc.GetProto(d) : - docDragData.dropAction === "copy" ? (await Doc.MakeClone(d)).clone : d)); + await Promise.all(dragData.draggedDocuments.map(async d => + !dragData.isDocDecorationMove && !dragData.userDropAction && ScriptCast(d.onDragStart) ? + addAudioTag(ScriptCast(d.onDragStart).script.run({ this: d }).result) : + docDragData.dropAction === "alias" ? Doc.MakeAlias(d) : + docDragData.dropAction === "proto" ? Doc.GetProto(d) : + docDragData.dropAction === "copy" ? + (await Doc.MakeClone(d)).clone : d)); !["same", "proto"].includes(docDragData.dropAction as any) && docDragData.droppedDocuments.forEach((drop: Doc, i: number) => { const dragProps = Cast(dragData.draggedDocuments[i].removeDropProperties, listSpec("string"), []); const remProps = (dragData?.removeDropProperties || []).concat(Array.from(dragProps)); diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index 90c86fa18..faab2ed26 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -304,7 +304,6 @@ export class PropertiesView extends React.Component { rootSelected={returnFalse} styleProvider={DefaultStyleProvider} docViewPath={returnEmptyDoclist} - freezeDimensions={true} dontCenter={"y"} isDocumentActive={returnFalse} isContentActive={emptyFunction} diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 277fcd59c..684c919bd 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -250,7 +250,6 @@ export class CollectionStackingView extends CollectionSubView { - this._childClickedScript = ScriptField.MakeScript("openInLightbox(self, shiftKey)", { this: Doc.name, shiftKey: "boolean" });//, { detailView: detailView! }); + this._childClickedScript = ScriptField.MakeScript("openInLightbox(self)", { this: Doc.name }); this._viewDefDivClick = ScriptField.MakeScript("pivotColumnClick(this,payload)", { payload: "any" }); }); } @@ -138,8 +138,7 @@ export class CollectionTimeView extends CollectionSubView() { fitContentsToBox={returnTrue} childClickScript={this._childClickedScript} viewDefDivClick={this._viewDefDivClick} - childFreezeDimensions={true} - dontScaleFilter={this.dontScaleFilter} + //dontScaleFilter={this.dontScaleFilter} layoutEngine={this.layoutEngine} /> ; } diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 63616263e..b432104a1 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -75,7 +75,6 @@ export interface CollectionViewProps extends FieldViewProps { childHideResizeHandles?: () => boolean; childLayoutTemplate?: () => (Doc | undefined);// specify a layout Doc template to use for children of the collection childLayoutString?: string; - childFreezeDimensions?: boolean; // used by TimeView to coerce documents to treat their width height as their native width/height childIgnoreNativeSize?: boolean; childClickScript?: ScriptField; childDoubleClickScript?: ScriptField; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 99eec7892..542b1fce1 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1265,7 +1265,6 @@ export class CollectionFreeFormView extends CollectionSubView this.props.isSelected() || this.props.isContentActive(); - isChildContentActive = () => this.props.isSelected() || this.props.isAnyChildContentActive() ? true : false; + isChildContentActive = () => ((this.props.childDocumentsActive?.() || this.Document._childDocumentsActive) && this.props.isDocumentActive?.() && SnappingManager.GetIsDragging()) || this.props.isSelected() || this.props.isAnyChildContentActive() ? true : false; getDisplayDoc = (layout: Doc, dxf: () => Transform, width: () => number, height: () => number) => { return this.props.isSelected() || this.props.isContentActive(); - isChildContentActive = () => this.props.isSelected() || this.props.isAnyChildContentActive() ? true : false; + isChildContentActive = () => ((this.props.childDocumentsActive?.() || this.Document._childDocumentsActive) && this.props.isDocumentActive?.() && SnappingManager.GetIsDragging()) || this.props.isSelected() || this.props.isAnyChildContentActive() ? true : false; getDisplayDoc = (layout: Doc, dxf: () => Transform, width: () => number, height: () => number) => { return { DataDoc={this._showDataDoc} styleProvider={DefaultStyleProvider} docViewPath={returnEmptyDoclist} - freezeDimensions={true} focus={DocUtils.DefaultFocus} renderDepth={this.props.renderDepth} rootSelected={returnFalse} diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 70732e74c..db076c069 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -143,7 +143,6 @@ export class DocumentContentsView extends React.Component, onInput: Opt): JsxBindings { const docOnlyProps = [ // these are the properties in DocumentViewProps that need to be removed to pass on only DocumentSharedViewProps to the FieldViews - "freezeDimensions", "hideResizeHandles", "hideTitle", "treeViewDoc", diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 89096c948..263e1dc4c 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -160,7 +160,6 @@ export interface DocumentViewSharedProps { // these props are specific to DocuentViews export interface DocumentViewProps extends DocumentViewSharedProps { // properties specific to DocumentViews but not to FieldView - freezeDimensions?: boolean; hideResizeHandles?: boolean; // whether to suppress DocumentDecorations when this document is selected hideTitle?: boolean; // forces suppression of title. e.g, treeView document labels suppress titles in case they are globally active via settings hideDecorationTitle?: boolean; // forces suppression of title. e.g, treeView document labels suppress titles in case they are globally active via settings @@ -1220,11 +1219,11 @@ export class DocumentView extends React.Component { @computed get layoutDoc() { return Doc.Layout(this.Document, this.props.LayoutTemplate?.()); } @computed get nativeWidth() { return this.docView?._componentView?.reverseNativeScaling?.() ? 0 : - returnVal(this.props.NativeWidth?.(), Doc.NativeWidth(this.layoutDoc, this.props.DataDoc, this.props.freezeDimensions)); + returnVal(this.props.NativeWidth?.(), Doc.NativeWidth(this.layoutDoc, this.props.DataDoc, !this.fitWidth)); } @computed get nativeHeight() { return this.docView?._componentView?.reverseNativeScaling?.() ? 0 : - returnVal(this.props.NativeHeight?.(), Doc.NativeHeight(this.layoutDoc, this.props.DataDoc, this.props.freezeDimensions)); + returnVal(this.props.NativeHeight?.(), Doc.NativeHeight(this.layoutDoc, this.props.DataDoc, !this.fitWidth)); } @computed get shouldNotScale() { return (this.fitWidth && !this.nativeWidth) || @@ -1312,8 +1311,6 @@ export class DocumentView extends React.Component { ContentScale = () => this.nativeScaling; selfView = () => this; screenToLocalTransform = () => { - const oshift = this.fitWidth && this.ComponentView instanceof FormattedTextBox; - const shift = oshift ? -(this.props.PanelHeight() - this.rootDoc[HeightSym]()) / 2 : 0; return this.props.ScreenToLocalTransform().translate(-this.centeringX, -this.centeringY).translate(0, shift).scale(1 / this.nativeScaling); } componentDidMount() { diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx index 1b37e729b..85efc67a5 100644 --- a/src/client/views/nodes/button/FontIconBox.tsx +++ b/src/client/views/nodes/button/FontIconBox.tsx @@ -903,9 +903,9 @@ ScriptingGlobals.add(function toggleSchemaPreview(checkResult?: boolean) { } else if (selected) { if (NumCast(selected.schemaPreviewWidth) > 0) { - selected.schemaPreviewWidth = 200; - } else { selected.schemaPreviewWidth = 0; + } else { + selected.schemaPreviewWidth = 200; } } }); -- cgit v1.2.3-70-g09d2 From cd409364ec3ec40e2c060ede7b8d7610777483d6 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 26 Jul 2022 12:29:41 -0400 Subject: fixed dragging webBoxes within a gridView to not marquee select. --- .../collectionGrid/CollectionGridView.tsx | 278 +++++++++++++-------- 1 file changed, 170 insertions(+), 108 deletions(-) (limited to 'src/client/views/collections/collectionGrid/CollectionGridView.tsx') diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx index 4e4c33446..9468c5f06 100644 --- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx +++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx @@ -1,6 +1,6 @@ import { action, computed, Lambda, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; -import * as React from "react"; +import * as React from 'react'; import { Doc, Opt } from '../../../../fields/Doc'; import { Id } from '../../../../fields/FieldSymbols'; import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; @@ -15,8 +15,8 @@ import { ContextMenuProps } from '../../ContextMenuItem'; import { DocumentView } from '../../nodes/DocumentView'; import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; import { CollectionSubView } from '../CollectionSubView'; -import "./CollectionGridView.scss"; -import Grid, { Layout } from "./Grid"; +import './CollectionGridView.scss'; +import Grid, { Layout } from './Grid'; @observer export class CollectionGridView extends CollectionSubView() { @@ -29,50 +29,76 @@ export class CollectionGridView extends CollectionSubView() { onChildClickHandler = () => ScriptCast(this.Document.onChildClick); - @computed get numCols() { return NumCast(this.props.Document.gridNumCols, 10); } - @computed get rowHeight() { return this._rowHeight === undefined ? NumCast(this.props.Document.gridRowHeight, 100) : this._rowHeight; } - // sets the default width and height of the grid nodes - @computed get defaultW() { return NumCast(this.props.Document.gridDefaultW, 2); } - @computed get defaultH() { return NumCast(this.props.Document.gridDefaultH, 2); } + @computed get numCols() { + return NumCast(this.props.Document.gridNumCols, 10); + } + @computed get rowHeight() { + return this._rowHeight === undefined ? NumCast(this.props.Document.gridRowHeight, 100) : this._rowHeight; + } + // sets the default width and height of the grid nodes + @computed get defaultW() { + return NumCast(this.props.Document.gridDefaultW, 2); + } + @computed get defaultH() { + return NumCast(this.props.Document.gridDefaultH, 2); + } - @computed get colWidthPlusGap() { return (this.props.PanelWidth() - this.margin) / this.numCols; } - @computed get rowHeightPlusGap() { return this.rowHeight + this.margin; } + @computed get colWidthPlusGap() { + return (this.props.PanelWidth() - this.margin) / this.numCols; + } + @computed get rowHeightPlusGap() { + return this.rowHeight + this.margin; + } - @computed get margin() { return NumCast(this.props.Document.margin, 10); } // sets the margin between grid nodes + @computed get margin() { + return NumCast(this.props.Document.margin, 10); + } // sets the margin between grid nodes - @computed get flexGrid() { return BoolCast(this.props.Document.gridFlex, true); } // is grid static/flexible i.e. whether nodes be moved around and resized - @computed get compaction() { return StrCast(this.props.Document.gridStartCompaction, StrCast(this.props.Document.gridCompaction, "vertical")); } // is grid static/flexible i.e. whether nodes be moved around and resized + @computed get flexGrid() { + return BoolCast(this.props.Document.gridFlex, true); + } // is grid static/flexible i.e. whether nodes be moved around and resized + @computed get compaction() { + return StrCast(this.props.Document.gridStartCompaction, StrCast(this.props.Document.gridCompaction, 'vertical')); + } // is grid static/flexible i.e. whether nodes be moved around and resized /** * Sets up the listeners for the list of documents and the reset button. */ componentDidMount() { - this._changeListenerDisposer = reaction(() => this.childLayoutPairs, (pairs) => { - const newLayouts: Layout[] = []; - const oldLayouts = this.savedLayoutList; - pairs.forEach((pair, i) => { - const existing = oldLayouts.find(l => l.i === pair.layout[Id]); - if (existing) newLayouts.push(existing); - else { - if (Object.keys(this.dropLocation).length) { // external drop - this.addLayoutItem(newLayouts, this.makeLayoutItem(pair.layout, this.dropLocation as { x: number, y: number }, !this.flexGrid)); - this.dropLocation = {}; - } - else { // internal drop - this.addLayoutItem(newLayouts, this.makeLayoutItem(pair.layout, this.unflexedPosition(i), !this.flexGrid)); + this._changeListenerDisposer = reaction( + () => this.childLayoutPairs, + pairs => { + const newLayouts: Layout[] = []; + const oldLayouts = this.savedLayoutList; + pairs.forEach((pair, i) => { + const existing = oldLayouts.find(l => l.i === pair.layout[Id]); + if (existing) newLayouts.push(existing); + else { + if (Object.keys(this.dropLocation).length) { + // external drop + this.addLayoutItem(newLayouts, this.makeLayoutItem(pair.layout, this.dropLocation as { x: number; y: number }, !this.flexGrid)); + this.dropLocation = {}; + } else { + // internal drop + this.addLayoutItem(newLayouts, this.makeLayoutItem(pair.layout, this.unflexedPosition(i), !this.flexGrid)); + } } - } - }); - pairs?.length && this.setLayoutList(newLayouts); - }, { fireImmediately: true }); + }); + pairs?.length && this.setLayoutList(newLayouts); + }, + { fireImmediately: true } + ); // updates the layouts if the reset button has been clicked - this._resetListenerDisposer = reaction(() => this.props.Document.gridResetLayout, (reset) => { - if (reset && this.flexGrid) { - this.setLayout(this.childLayoutPairs.map((pair, index) => this.makeLayoutItem(pair.layout, this.unflexedPosition(index)))); + this._resetListenerDisposer = reaction( + () => this.props.Document.gridResetLayout, + reset => { + if (reset && this.flexGrid) { + this.setLayout(this.childLayoutPairs.map((pair, index) => this.makeLayoutItem(pair.layout, this.unflexedPosition(index)))); + } + this.props.Document.gridResetLayout = false; } - this.props.Document.gridResetLayout = false; - }); + ); } /** @@ -85,15 +111,15 @@ export class CollectionGridView extends CollectionSubView() { /** * @returns the default location of the grid node (i.e. when the grid is static) - * @param index + * @param index */ - unflexedPosition(index: number): Omit { + unflexedPosition(index: number): Omit { return { x: (index % (Math.floor(this.numCols / this.defaultW) || 1)) * this.defaultW, y: Math.floor(index / (Math.floor(this.numCols / this.defaultH) || 1)) * this.defaultH, w: this.defaultW, h: this.defaultH, - static: true + static: true, }; } @@ -110,9 +136,9 @@ export class CollectionGridView extends CollectionSubView() { /** * Creates a layout object for a grid item */ - makeLayoutItem = (doc: Doc, pos: { x: number, y: number }, Static: boolean = false, w: number = this.defaultW, h: number = this.defaultH) => { - return ({ i: doc[Id], w, h, x: pos.x, y: pos.y, static: Static }); - } + makeLayoutItem = (doc: Doc, pos: { x: number; y: number }, Static: boolean = false, w: number = this.defaultW, h: number = this.defaultH) => { + return { i: doc[Id], w, h, x: pos.x, y: pos.y, static: Static }; + }; /** * Adds a layout to the list of layouts. @@ -122,16 +148,16 @@ export class CollectionGridView extends CollectionSubView() { f !== -1 && layouts.splice(f, 1); layouts.push(layout); return layouts; - } + }; /** - * @returns the transform that will correctly place the document decorations box. + * @returns the transform that will correctly place the document decorations box. */ private lookupIndividualTransform = (layout: Layout) => { const xypos = this.flexGrid ? layout : this.unflexedPosition(this.renderedLayoutList.findIndex(l => l.i === layout.i)); const pos = { x: xypos.x * this.colWidthPlusGap + this.margin, y: xypos.y * this.rowHeightPlusGap + this.margin - this._scroll }; return this.props.ScreenToLocalTransform().translate(-pos.x, -pos.y); - } + }; /** * @returns the layout list converted from JSON @@ -147,26 +173,32 @@ export class CollectionGridView extends CollectionSubView() { this.props.Document.gridLayoutString = JSON.stringify(layouts); } + isContentActive = () => this.props.isSelected() || this.props.isContentActive(); + isChildContentActive = () => (this.props.isDocumentActive?.() && (this.props.childDocumentsActive?.() || BoolCast(this.rootDoc.childDocumentsActive)) ? true : undefined); /** - * - * @param layout + * + * @param layout * @param dxf the x- and y-translations of the decorations box as a transform i.e. this.lookupIndividualTransform - * @param width - * @param height + * @param width + * @param height * @returns the `ContentFittingDocumentView` of the node */ getDisplayDoc(layout: Doc, dxf: () => Transform, width: () => number, height: () => number) { - return ; + return ( + + ); } /** @@ -176,7 +208,7 @@ export class CollectionGridView extends CollectionSubView() { @action setLayout = (layoutArray: Layout[]) => { // for every child in the collection, check to see if there's a corresponding grid layout object and - // updated layout object. If both exist, which they should, update the grid layout object from the updated object + // updated layout object. If both exist, which they should, update the grid layout object from the updated object if (this.flexGrid) { const savedLayouts = this.savedLayoutList; this.childLayoutPairs.forEach(({ layout: doc }) => { @@ -194,7 +226,7 @@ export class CollectionGridView extends CollectionSubView() { undoBatch(() => this.setLayoutList(savedLayouts))(); } } - } + }; /** * @returns a list of `ContentFittingDocumentView`s inside wrapper divs. @@ -209,11 +241,12 @@ export class CollectionGridView extends CollectionSubView() { const dxf = () => this.lookupIndividualTransform(l); const width = () => (this.flexGrid ? l.w : this.defaultW) * this.colWidthPlusGap - this.margin; const height = () => (this.flexGrid ? l.h : this.defaultH) * this.rowHeightPlusGap - this.margin; - child && collector.push( -
- {this.getDisplayDoc(child.layout, dxf, width, height)} -
- ); + child && + collector.push( +
+ {this.getDisplayDoc(child.layout, dxf, width, height)} +
+ ); }); } return collector; @@ -223,14 +256,19 @@ export class CollectionGridView extends CollectionSubView() { * @returns a list of `Layout` objects with attributes depending on whether the grid is flexible or static */ @computed get renderedLayoutList(): Layout[] { - return this.flexGrid ? - this.savedLayoutList.map(({ i, x, y, w, h }) => ({ - i, y, h, - x: x + w > this.numCols ? 0 : x, // handles wrapping around of nodes when numCols decreases - w: Math.min(w, this.numCols), // reduces width if greater than numCols - static: BoolCast(this.childLayoutPairs.find(({ layout }) => layout[Id] === i)?.layout._lockedPosition, false) // checks if the lock position item has been selected in the context menu - })) : - this.savedLayoutList.map((layout, index) => { Object.assign(layout, this.unflexedPosition(index)); return layout; }); + return this.flexGrid + ? this.savedLayoutList.map(({ i, x, y, w, h }) => ({ + i, + y, + h, + x: x + w > this.numCols ? 0 : x, // handles wrapping around of nodes when numCols decreases + w: Math.min(w, this.numCols), // reduces width if greater than numCols + static: BoolCast(this.childLayoutPairs.find(({ layout }) => layout[Id] === i)?.layout._lockedPosition, false), // checks if the lock position item has been selected in the context menu + })) + : this.savedLayoutList.map((layout, index) => { + Object.assign(layout, this.unflexedPosition(index)); + return layout; + }); } /** @@ -246,7 +284,7 @@ export class CollectionGridView extends CollectionSubView() { return true; } return false; - } + }; /** * Handles external drop of images/PDFs etc from outside Dash. @@ -255,7 +293,7 @@ export class CollectionGridView extends CollectionSubView() { onExternalDrop = async (e: React.DragEvent): Promise => { this.dropLocation = this.screenToCell(e.clientX, e.clientY); super.onExternalDrop(e, {}); - } + }; /** * Handles the change in the value of the rowHeight slider. @@ -263,65 +301,83 @@ export class CollectionGridView extends CollectionSubView() { @action onSliderChange = (event: React.ChangeEvent) => { this._rowHeight = event.currentTarget.valueAsNumber; - } + }; /** * Handles the user clicking on the slider. */ @action onSliderDown = (e: React.PointerEvent) => { this._rowHeight = this.rowHeight; // uses _rowHeight during dragging and sets doc's rowHeight when finished so that operation is undoable - setupMoveUpEvents(this, e, returnFalse, action(() => { - undoBatch(() => this.props.Document.gridRowHeight = this._rowHeight)(); - this._rowHeight = undefined; - }), emptyFunction, false, false); + setupMoveUpEvents( + this, + e, + returnFalse, + action(() => { + undoBatch(() => (this.props.Document.gridRowHeight = this._rowHeight))(); + this._rowHeight = undefined; + }), + emptyFunction, + false, + false + ); e.stopPropagation(); - } + }; /** * Adds the display option to change the css display attribute of the `ContentFittingDocumentView`s */ onContextMenu = () => { const displayOptionsMenu: ContextMenuProps[] = []; - displayOptionsMenu.push({ description: "Toggle Content Display Style", event: () => this.props.Document.display = this.props.Document.display ? undefined : "contents", icon: "copy" }); - displayOptionsMenu.push({ description: "Toggle Vertical Centering", event: () => this.props.Document.centerY = !this.props.Document.centerY, icon: "copy" }); - ContextMenu.Instance.addItem({ description: "Display", subitems: displayOptionsMenu, icon: "tv" }); - } + displayOptionsMenu.push({ description: 'Toggle Content Display Style', event: () => (this.props.Document.display = this.props.Document.display ? undefined : 'contents'), icon: 'copy' }); + displayOptionsMenu.push({ description: 'Toggle Vertical Centering', event: () => (this.props.Document.centerY = !this.props.Document.centerY), icon: 'copy' }); + ContextMenu.Instance.addItem({ description: 'Display', subitems: displayOptionsMenu, icon: 'tv' }); + }; /** * Handles text document creation on double click. */ onPointerDown = (e: React.PointerEvent) => { if (this.props.isContentActive(true)) { - setupMoveUpEvents(this, e, returnFalse, returnFalse, + setupMoveUpEvents( + this, + e, + returnFalse, + returnFalse, (e: PointerEvent, doubleTap?: boolean) => { if (doubleTap && !e.button) { - undoBatch(action(() => { - const text = Docs.Create.TextDocument("", { _width: 150, _height: 50 }); - FormattedTextBox.SelectOnLoad = text[Id];// track the new text box so we can give it a prop that tells it to focus itself when it's displayed - Doc.AddDocToList(this.props.Document, this.props.fieldKey, text); - this.setLayoutList(this.addLayoutItem(this.savedLayoutList, this.makeLayoutItem(text, this.screenToCell(e.clientX, e.clientY)))); - }))(); + undoBatch( + action(() => { + const text = Docs.Create.TextDocument('', { _width: 150, _height: 50 }); + FormattedTextBox.SelectOnLoad = text[Id]; // track the new text box so we can give it a prop that tells it to focus itself when it's displayed + Doc.AddDocToList(this.props.Document, this.props.fieldKey, text); + this.setLayoutList(this.addLayoutItem(this.savedLayoutList, this.makeLayoutItem(text, this.screenToCell(e.clientX, e.clientY)))); + }) + )(); } }, - false); + false + ); if (this.props.isSelected(true)) e.stopPropagation(); } - } + }; render() { return ( -
-
+
e.stopPropagation()} onScroll={action(e => { if (!this.props.isSelected()) e.currentTarget.scrollTop = this._scroll; else this._scroll = e.currentTarget.scrollTop; - })} > + })}> - + min={1} + value={this.rowHeight} + max={this.props.PanelHeight() - 30} + onPointerDown={this.onSliderDown} + onChange={this.onSliderChange} + />
-
+
); } -} \ No newline at end of file +} -- cgit v1.2.3-70-g09d2