From d99f64efe9e69f2159f1ad8f851b24533a996ba5 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 26 Feb 2024 12:57:48 -0500 Subject: fixed some string types to be enumerations for dropAction. fixed bug in golden layout dragging where a stack's tabs could disappear. --- src/client/util/CurrentUserUtils.ts | 44 +++++++++++++++--------------- src/client/util/DragManager.ts | 54 ++++++++++++++++++++++++++----------- 2 files changed, 60 insertions(+), 38 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 714e33d25..d396ba815 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -14,7 +14,7 @@ import { SetCachedGroups, SharingPermissions } from "../../fields/util"; import { GestureUtils } from "../../pen-gestures/GestureUtils"; import { DocServer } from "../DocServer"; import { CollectionViewType, DocumentType } from "../documents/DocumentTypes"; -import { DocUtils, Docs, DocumentOptions, FInfo } from "../documents/Documents"; +import { DocUtils, Docs, DocumentOptions, FInfo, FInfoFieldType } from "../documents/Documents"; import { DashboardView } from "../views/DashboardView"; import { OverlayView } from "../views/OverlayView"; import { CollectionTreeView, TreeViewType } from "../views/collections/CollectionTreeView"; @@ -257,11 +257,11 @@ export class CurrentUserUtils { {key: "DataViz", creator: opts => Docs.Create.DataVizDocument("/users/rz/Downloads/addresses.csv", opts), opts: { _width: 300, _height: 300 }}, {key: "Header", creator: headerTemplate, opts: { _width: 300, _height: 70, _headerPointerEvents: "all", _headerHeight: 12, _headerFontSize: 9, _layout_autoHeight: true, treeView_HideUnrendered: true}}, {key: "ViewSlide", creator: slideView, opts: { _width: 400, _height: 300, _xMargin: 3, _yMargin: 3,}}, - {key: "Trail", creator: Docs.Create.PresDocument, opts: { _width: 400, _height: 30, _type_collection: CollectionViewType.Stacking, dropAction: "embed" as dropActionType, treeView_HideTitle: true, _layout_fitWidth:true, layout_boxShadow: "0 0" }}, + {key: "Trail", creator: Docs.Create.PresDocument, opts: { _width: 400, _height: 30, _type_collection: CollectionViewType.Stacking, dropAction: dropActionType.embed, treeView_HideTitle: true, _layout_fitWidth:true, layout_boxShadow: "0 0" }}, {key: "Tab", creator: opts => Docs.Create.FreeformDocument([], opts), opts: { _width: 500, _height: 800, _layout_fitWidth: true, _freeform_backgroundGrid: true, }}, {key: "Slide", creator: opts => Docs.Create.TreeDocument([], opts), opts: { _width: 300, _height: 200, _type_collection: CollectionViewType.Tree, treeView_HasOverlay: true, _text_fontSize: "20px", _layout_autoHeight: true, - dropAction:'move', treeView_Type: TreeViewType.outline, + dropAction:dropActionType.move, treeView_Type: TreeViewType.outline, backgroundColor: "white", _xMargin: 0, _yMargin: 0, _createDocOnCR: true }, funcs: {title: 'this.text?.Text'}}, ]; @@ -311,7 +311,7 @@ export class CurrentUserUtils { const reqdOpts:DocumentOptions = { title: "Document Creators", _layout_showTitle: "title", _xMargin: 0, _dragOnlyWithinContainer: true, _layout_hideContextMenu: true, _chromeHidden: true, isSystem: true, _layout_autoHeight: true, _width: 500, _height: 300, _layout_fitWidth: true, _columnWidth: 40, ignoreClick: true, _lockedPosition: true, _forceActive: true, - childDragAction: 'embed' + childDragAction: dropActionType.embed }; const reqdScripts = { dropConverter: "convertToButtons(dragData)" }; return DocUtils.AssignScripts(DocUtils.AssignOpts(dragCreatorDoc, reqdOpts, creatorBtns) ?? Docs.Create.MasonryDocument(creatorBtns, reqdOpts), reqdScripts); @@ -353,7 +353,7 @@ export class CurrentUserUtils { }); const reqdStackOpts:DocumentOptions ={ - title: "menuItemPanel", childDragAction: "same", layout_boxShadow: "rgba(0,0,0,0)", dontRegisterView: true, ignoreClick: true, + title: "menuItemPanel", childDragAction: dropActionType.same, layout_boxShadow: "rgba(0,0,0,0)", dontRegisterView: true, ignoreClick: true, _chromeHidden: true, _gridGap: 0, _yMargin: 0, _xMargin: 0, _layout_autoHeight: false, _width: 60, _columnWidth: 60, _lockedPosition: true, isSystem: true, }; return DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.StackingDocument(items??[], opts), reqdStackOpts, menuBtns, { dropConverter: "convertToButtons(dragData)" }); @@ -436,7 +436,7 @@ export class CurrentUserUtils { /// Search option on the left side button panel static setupSearcher(doc: Doc, field:string) { return DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.SearchDocument(opts), { - dontRegisterView: true, backgroundColor: "dimgray", ignoreClick: true, title: "Search Panel", isSystem: true, childDragAction: "embed", + dontRegisterView: true, backgroundColor: "dimgray", ignoreClick: true, title: "Search Panel", isSystem: true, childDragAction: dropActionType.embed, _lockedPosition: true, _type_collection: CollectionViewType.Schema }); } @@ -476,8 +476,8 @@ export class CurrentUserUtils { const childContextMenuIcons = ["tv", "camera", "users", "times", "trash"]; // entries must be kept in synch with childContextMenuScripts, childContextMenuLabels, and childContextMenuFilters const reqdOpts:DocumentOptions = { title: "My Dashboards", childHideLinkButton: true, treeView_FreezeChildren: "remove|add", treeView_HideTitle: true, layout_boxShadow: "0 0", childDontRegisterViews: true, - dropAction: "inSame", treeView_Type: TreeViewType.fileSystem, isFolder: true, isSystem: true, treeView_TruncateTitleWidth: 350, ignoreClick: true, - layout_headerButton: newDashboardButton, childDragAction: "inSame", + dropAction: dropActionType.inPlace, treeView_Type: TreeViewType.fileSystem, isFolder: true, isSystem: true, treeView_TruncateTitleWidth: 350, ignoreClick: true, + layout_headerButton: newDashboardButton, childDragAction: dropActionType.inPlace, _layout_showTitle: "title", _height: 400, _gridGap: 5, _forceActive: true, _lockedPosition: true, contextMenuLabels:new List(contextMenuLabels), contextMenuIcons:new List(contextMenuIcons), @@ -510,9 +510,9 @@ export class CurrentUserUtils { const newFolderButton = DocUtils.AssignScripts(DocUtils.AssignOpts(DocCast(myFilesystem?.layout_headerButton), newFolderOpts) ?? Docs.Create.FontIconDocument(newFolderOpts), newFolderScript); const reqdOpts:DocumentOptions = { _layout_showTitle: "title", _height: 100, _forceActive: true, - title: "My Documents", layout_headerButton: newFolderButton, treeView_HideTitle: true, dropAction: 'add', isSystem: true, + title: "My Documents", layout_headerButton: newFolderButton, treeView_HideTitle: true, dropAction: dropActionType.add, isSystem: true, isFolder: true, treeView_Type: TreeViewType.fileSystem, childHideLinkButton: true, layout_boxShadow: "0 0", childDontRegisterViews: true, - treeView_TruncateTitleWidth: 350, ignoreClick: true, childDragAction: "embed", + treeView_TruncateTitleWidth: 350, ignoreClick: true, childDragAction: dropActionType.embed, layout_explainer: "This is your file manager where you can create folders to keep track of documents independently of your dashboard." }; const fileFolders = new Set(DocListCast(DocCast(doc[field])?.data)); @@ -522,8 +522,8 @@ export class CurrentUserUtils { /// initializes the panel displaying docs that have been recently closed static setupRecentlyClosed(doc: Doc, field:string) { const reqdOpts:DocumentOptions = { _layout_showTitle: "title", _lockedPosition: true, _gridGap: 5, _forceActive: true, isFolder: true, - title: "My Recently Closed", childHideLinkButton: true, treeView_HideTitle: true, childDragAction: "move", isSystem: true, - treeView_TruncateTitleWidth: 350, ignoreClick: true, layout_boxShadow: "0 0", childDontRegisterViews: true, dropAction: "same", + title: "My Recently Closed", childHideLinkButton: true, treeView_HideTitle: true, childDragAction: dropActionType.move, isSystem: true, + treeView_TruncateTitleWidth: 350, ignoreClick: true, layout_boxShadow: "0 0", childDontRegisterViews: true, dropAction: dropActionType.same, contextMenuLabels: new List(["Empty recently closed"]), contextMenuIcons:new List(["trash"]), layout_explainer: "Recently closed documents appear in this menu. They will only be deleted if you explicity empty this list." @@ -546,7 +546,7 @@ export class CurrentUserUtils { static setupUserDocView(doc: Doc, field:string) { const reqdOpts:DocumentOptions = { _lockedPosition: true, _gridGap: 5, _forceActive: true, title: Doc.CurrentUserEmail +"-view", - layout_boxShadow: "0 0", childDontRegisterViews: true, dropAction: "same", ignoreClick: true, isSystem: true, + layout_boxShadow: "0 0", childDontRegisterViews: true, dropAction: dropActionType.same, ignoreClick: true, isSystem: true, treeView_HideTitle: true, treeView_TruncateTitleWidth: 350 }; if (!doc[field]) DocUtils.AssignOpts(doc, {treeView_Open: true, treeView_ExpandedView: "fields" }); @@ -587,7 +587,7 @@ export class CurrentUserUtils { ]; const btns = btnDescs.map(desc => dockBtn({_width: 30, _height: 30, defaultDoubleClick: 'ignore', undoIgnoreFields: new List(['opacity']), _dragOnlyWithinContainer: true, ...desc.opts}, desc.scripts)); const dockBtnsReqdOpts:DocumentOptions = { - title: "docked buttons", _height: 40, flexGap: 0, layout_boxShadow: "standard", childDragAction: 'move', + title: "docked buttons", _height: 40, flexGap: 0, layout_boxShadow: "standard", childDragAction: dropActionType.move, childDontRegisterViews: true, linearView_IsOpen: true, linearView_Expandable: true, ignoreClick: true }; reaction(() => UndoManager.redoStack.slice(), () => Doc.GetProto(btns.find(btn => btn.title === "Redo")!).opacity = UndoManager.CanRedo() ? 1 : 0.4, { fireImmediately: true }); @@ -743,7 +743,7 @@ export class CurrentUserUtils { /// Initializes all the default buttons for the top bar context menu static setupContextMenuButtons(doc: Doc, field="myContextMenuBtns") { - const reqdCtxtOpts:DocumentOptions = { title: "context menu buttons", undoIgnoreFields:new List(['width', "linearView_IsOpen"]), flexGap: 0, childDragAction: 'embed', childDontRegisterViews: true, linearView_IsOpen: true, ignoreClick: true, linearView_Expandable: false, _height: 35 }; + const reqdCtxtOpts:DocumentOptions = { title: "context menu buttons", undoIgnoreFields:new List(['width', "linearView_IsOpen"]), flexGap: 0, childDragAction: dropActionType.embed, childDontRegisterViews: true, linearView_IsOpen: true, ignoreClick: true, linearView_Expandable: false, _height: 35 }; const ctxtMenuBtnsDoc = DocUtils.AssignDocField(doc, field, (opts, items) => this.linearButtonList(opts, items??[]), reqdCtxtOpts, undefined); const ctxtMenuBtns = CurrentUserUtils.contextMenuTools().map(params => this.setupContextMenuBtn(params, ctxtMenuBtnsDoc) ); return DocUtils.AssignOpts(ctxtMenuBtnsDoc, reqdCtxtOpts, ctxtMenuBtns); @@ -769,7 +769,7 @@ export class CurrentUserUtils { ]; const btns = btnDescs.map(desc => dockBtn({_width: desc.opts.width??30, _height: 30, defaultDoubleClick: 'ignore', undoIgnoreFields: new List(['opacity']), _dragOnlyWithinContainer: true, ...desc.opts}, desc.scripts, desc.funcs)); const dockBtnsReqdOpts:DocumentOptions = { - title: "docked buttons", _height: 40, flexGap: 0, layout_boxShadow: "standard", childDragAction: 'move', + title: "docked buttons", _height: 40, flexGap: 0, layout_boxShadow: "standard", childDragAction: dropActionType.move, childDontRegisterViews: true, linearView_IsOpen: true, linearView_Expandable: false, ignoreClick: true }; return DocUtils.AssignDocField(doc, field, (opts, items) => this.linearButtonList(opts, items??[]), dockBtnsReqdOpts, btns); @@ -809,7 +809,7 @@ export class CurrentUserUtils { // childContextMenuLabels: new List(["Add to Dashboards",]), // childContextMenuIcons: new List(["user-plus",]), "acl-Guest": SharingPermissions.Augment, "_acl-Guest": SharingPermissions.Augment, - childDragAction: "embed", isSystem: true, childContentPointerEvents: "none", childLimitHeight: 0, _yMargin: 0, _gridGap: 15, childDontRegisterViews:true, + childDragAction: dropActionType.embed, isSystem: true, childContentPointerEvents: "none", childLimitHeight: 0, _yMargin: 0, _gridGap: 15, childDontRegisterViews:true, // NOTE: treeView_HideTitle & _layout_showTitle is for a TreeView's editable title, _layout_showTitle is for DocumentViews title bar _layout_showTitle: "title", treeView_HideTitle: true, ignoreClick: true, _lockedPosition: true, layout_boxShadow: "0 0", _chromeHidden: true, dontRegisterView: true, layout_explainer: "This is where documents or dashboards that other users have shared with you will appear. To share a document or dashboard right click and select 'Share'" @@ -824,7 +824,7 @@ export class CurrentUserUtils { const reqdOpts:DocumentOptions = { title: "My Imports", _forceActive: true, _layout_showTitle: "title", childLayoutString: ImportElementBox.LayoutString('data'), _dragOnlyWithinContainer: true, _layout_hideContextMenu: true, childLimitHeight: 0, onClickScriptDisable:"never", - childDragAction: "copy", _layout_autoHeight: true, _yMargin: 50, _gridGap: 15, layout_boxShadow: "0 0", _lockedPosition: true, isSystem: true, _chromeHidden: true, + childDragAction: dropActionType.copy, _layout_autoHeight: true, _yMargin: 50, _gridGap: 15, layout_boxShadow: "0 0", _lockedPosition: true, isSystem: true, _chromeHidden: true, dontRegisterView: true, layout_explainer: "This is where documents that are Imported into Dash will go." }; const myImports = DocUtils.AssignDocField(doc, field, (opts) => Docs.Create.MasonryDocument([], opts), reqdOpts, undefined, {onClick: "deselectAll()"}); @@ -886,7 +886,7 @@ export class CurrentUserUtils { this.setupDocTemplates(doc); // sets up the template menu of templates //this.setupFieldInfos(doc); // sets up the collection of field info descriptions for each possible DocumentOption DocUtils.AssignDocField(doc, "globalScriptDatabase", (opts) => Docs.Prototypes.MainScriptDocument(), {}); - DocUtils.AssignDocField(doc, "myHeaderBar", (opts) => Docs.Create.MulticolumnDocument([], opts), { title: "My Header Bar", isSystem: true, _chromeHidden:true, childLayoutFitWidth:false, childDocumentsActive:false, dropAction: 'move'}); // drop down panel at top of dashboard for stashing documents + DocUtils.AssignDocField(doc, "myHeaderBar", (opts) => Docs.Create.MulticolumnDocument([], opts), { title: "My Header Bar", isSystem: true, _chromeHidden:true, childLayoutFitWidth:false, childDocumentsActive:false, dropAction: dropActionType.move}); // drop down panel at top of dashboard for stashing documents Doc.AddDocToList(Doc.MyFilesystem, undefined, Doc.MyDashboards) Doc.AddDocToList(Doc.MyFilesystem, undefined, Doc.MySharedDocs) @@ -909,9 +909,9 @@ export class CurrentUserUtils { const options = pair[1] as FInfo; const opts:DocumentOptions = { isSystem: true, title: pair[0], ...OmitKeys(options, ["values"]).omit, fieldIsLayout: pair[0].startsWith("_")}; switch (options.fieldType) { - case "boolean": opts.fieldValues = new List(options.values as any); break; - case "number": opts.fieldValues = new List(options.values as any); break; - case Doc.name: opts.fieldValues = new List(options.values as any); break; + case FInfoFieldType.boolean: opts.fieldValues = new List(options.values as any); break; + case FInfoFieldType.number: opts.fieldValues = new List(options.values as any); break; + case FInfoFieldType.Doc: opts.fieldValues = new List(options.values as any); break; default: opts.fieldValues = new List(options.values as any); break;// string, pointerEvents, dimUnit, dropActionType } DocUtils.AssignDocField(infos, pair[0], opts => Doc.assign(new Doc(), OmitKeys(opts,["values"]).omit), opts); diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 1f093a33c..f6af6196f 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -1,10 +1,24 @@ +/** + * The DragManager handles all dragging interactions that occur entirely within Dash (as opposed to external drag operations from the file system, etc) + * + * Events are generated for + * a pause in the drag movement (dashDragMovePause) as a Doc(s) is dragged, + * just before (dashPreDrop) a Doc(s) is dropped, + * and just after (dashDropEvent) a Doc(s) is dropped + * If the document is dragged and paused over the golden layout header tabs, the + * drag interaction will switch to a golden layout tab drag. + * + * All drag operations can be aborted by hitting the Esc key + * + */ + import { action, observable, runInAction } from 'mobx'; import { DateField } from '../../fields/DateField'; import { Doc, Field, Opt, StrListCast } from '../../fields/Doc'; import { List } from '../../fields/List'; import { PrefetchProxy } from '../../fields/Proxy'; import { ScriptField } from '../../fields/ScriptField'; -import { ScriptCast, StrCast } from '../../fields/Types'; +import { ScriptCast } from '../../fields/Types'; import { emptyFunction, Utils } from '../../Utils'; import { Docs, DocUtils } from '../documents/Documents'; import { CollectionFreeFormDocumentView } from '../views/nodes/CollectionFreeFormDocumentView'; @@ -16,7 +30,15 @@ import { UndoManager } from './UndoManager'; import { DocData } from '../../fields/DocSymbols'; const { default : { contextMenuZindex } } = require('../views/global/globalCssVariables.module.scss'); // prettier-ignore -export type dropActionType = 'embed' | 'copy' | 'move' | 'add' | 'same' | 'inSame' | 'proto' | 'none' | undefined; // undefined = move, "same" = move but don't call dropPropertiesToRemove +export enum dropActionType { + embed = 'embed', // create a new embedding of the dragged document for the new location + copy = 'copy', // copy the dragged document + move = 'move', // move the dragged document to the drop location after removing it from where it was + add = 'add', // add the dragged document to the drop location without removing it from where it was + same = 'same', // only allow drop within same collection (or same hierarchical tree collection) + inPlace = 'inSame', // keep document in place (unless overridden by a drag modifier) + proto = 'proto', +} // undefined = move, same = move but doesn't call dropPropertiesToRemove /** * Initialize drag @@ -129,9 +151,9 @@ export namespace DragManager { treeViewDoc?: Doc; offset: number[]; canEmbed?: boolean; - userDropAction: dropActionType; // the user requested drop action -- this will be honored as specified by modifier keys + userDropAction?: dropActionType; // the user requested drop action -- this will be honored as specified by modifier keys defaultDropAction?: dropActionType; // an optionally specified default drop action when there is no user drop actionl - this will be honored if there is no user drop action - dropAction: dropActionType; // a drop action request by the initiating code. the actual drop action may be different -- eg, if the request is 'embed', but the document is dropped within the same collection, the drop action will be switched to 'move' + dropAction?: dropActionType; // a drop action request by the initiating code. the actual drop action may be different -- eg, if the request is 'embed', but the document is dropped within the same collection, the drop action will be switched to 'move' dropPropertiesToRemove?: string[]; moveDocument?: MoveFunction; removeDocument?: RemoveFunction; @@ -170,8 +192,8 @@ export namespace DragManager { dropDocCreator: (annotationOn: Doc | undefined) => Doc; dropDocument?: Doc; offset: number[]; - dropAction: dropActionType; - userDropAction: dropActionType; + dropAction?: dropActionType; + userDropAction?: dropActionType; } let defaultPreDropFunc = (e: Event, de: DragManager.DropEvent, targetAction: dropActionType) => { @@ -189,7 +211,7 @@ export namespace DragManager { const handler = (e: Event) => dropFunc(e, (e as CustomEvent).detail); const preDropHandler = (e: Event) => { const de = (e as CustomEvent).detail; - (preDropFunc ?? defaultPreDropFunc)(e, de, StrCast(doc.dropAction) as dropActionType); + (preDropFunc ?? defaultPreDropFunc)(e, de, doc.dropAction as any as dropActionType); }; element.addEventListener('dashOnDrop', handler); element.addEventListener('dashPreDrop', preDropHandler); @@ -218,19 +240,19 @@ export namespace DragManager { dragData.draggedDocuments.map(async d => !dragData.isDocDecorationMove && !dragData.userDropAction && ScriptCast(d.onDragStart) ? addAudioTag(ScriptCast(d.onDragStart).script.run({ this: d }).result) - : docDragData.dropAction === 'embed' + : docDragData.dropAction === dropActionType.embed ? Doc.BestEmbedding(d) - : docDragData.dropAction === 'add' + : docDragData.dropAction === dropActionType.add ? d - : docDragData.dropAction === 'proto' + : docDragData.dropAction === dropActionType.proto ? d[DocData] - : docDragData.dropAction === 'copy' + : docDragData.dropAction === dropActionType.copy ? (await Doc.MakeClone(d)).clone : d ) ) ).filter(d => d); - !['same', 'proto'].includes(docDragData.dropAction as any) && + ![dropActionType.same, dropActionType.proto].includes(docDragData.dropAction as any) && docDragData.droppedDocuments // .filter(drop => !drop.dragOnlyWithinContainer || ['embed', 'copy'].includes(docDragData.dropAction as any)) .forEach((drop: Doc, i: number) => { @@ -504,7 +526,7 @@ export namespace DragManager { const moveHandler = (e: PointerEvent) => { e.preventDefault(); // required or dragging text menu link item ends up dragging the link button as native drag/drop if (dragData instanceof DocumentDragData) { - dragData.userDropAction = e.ctrlKey && e.altKey ? 'copy' : e.shiftKey ? 'move' : e.ctrlKey ? 'embed' : dragData.defaultDropAction; + dragData.userDropAction = e.ctrlKey && e.altKey ? dropActionType.copy : e.shiftKey ? dropActionType.move : e.ctrlKey ? dropActionType.embed : dragData.defaultDropAction; } if (['lm_tab', 'lm_title_wrap', 'lm_tabs', 'lm_header'].includes(typeof (e.target as any).className === 'string' ? (e.target as any)?.className : '') && dragData.draggedDocuments.length === 1) { if (!startWindowDragTimer) { @@ -530,7 +552,7 @@ export namespace DragManager { if (target && !Doc.UserDoc()._noAutoscroll && !options?.noAutoscroll && !dragData.draggedDocuments?.some((d: any) => d._freeform_noAutoPan)) { const autoScrollHandler = () => { target.dispatchEvent( - new CustomEvent('dashDragAutoScroll', { + new CustomEvent('dashDragMovePause', { bubbles: true, detail: { shiftKey: e.shiftKey, @@ -552,7 +574,7 @@ export namespace DragManager { screenY: e.screenY, detail: e.detail, view: e.view ? e.view : (new Window() as any), - nativeEvent: new DragEvent('dashDragAutoScroll'), + nativeEvent: new DragEvent('dashDragMovePause'), currentTarget: target, target: target, bubbles: true, @@ -566,7 +588,7 @@ export namespace DragManager { isPropagationStopped: () => ('not implemented for this event' ? false : false), persist: emptyFunction, timeStamp: e.timeStamp, - type: 'dashDragAutoScroll', + type: 'dashDragMovePause', }, }) ); -- cgit v1.2.3-70-g09d2 From 86726ad1b7ef40ac374b53f9d5902441537df7bd Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 28 Feb 2024 10:38:54 -0500 Subject: changed multirow view to support a maxShown flag so that headerBar doesn't take forever to load with a lot of closed tabs. --- src/client/documents/Documents.ts | 1 + src/client/util/CurrentUserUtils.ts | 2 +- src/client/util/DragManager.ts | 2 - src/client/views/FilterPanel.tsx | 4 +- src/client/views/OverlayView.tsx | 4 +- .../CollectionMulticolumnView.tsx | 58 +++++++++++++++------- .../CollectionMultirowView.tsx | 1 - 7 files changed, 48 insertions(+), 24 deletions(-) (limited to 'src/client/util') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 8a13395c3..9b17901ca 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -267,6 +267,7 @@ export class DocumentOptions { _layout_reflowVertical?: BOOLt = new BoolInfo('native height can be changed independent of width by dragging decoration resizers'); _layout_reflowHorizontal?: BOOLt = new BoolInfo('whether a doc with a native size can be horizonally resized, causing some form of reflow'); layout_boxShadow?: string; // box-shadow css string OR "standard" to use dash standard box shadow + layout_maxShown?: NUMt = new NumInfo('maximum number of children to display at one time (see multicolumnview)'); _layout_autoHeight?: BOOLt = new BoolInfo('whether document automatically resizes vertically to display contents'); _layout_curPage?: NUMt = new NumInfo('current page of a PDF or other? paginated document', false); _layout_currentTimecode?: NUMt = new NumInfo('the current timecode of a time-based document (e.g., current time of a video) value is in seconds', false); diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index d396ba815..289384be0 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -886,7 +886,7 @@ export class CurrentUserUtils { this.setupDocTemplates(doc); // sets up the template menu of templates //this.setupFieldInfos(doc); // sets up the collection of field info descriptions for each possible DocumentOption DocUtils.AssignDocField(doc, "globalScriptDatabase", (opts) => Docs.Prototypes.MainScriptDocument(), {}); - DocUtils.AssignDocField(doc, "myHeaderBar", (opts) => Docs.Create.MulticolumnDocument([], opts), { title: "My Header Bar", isSystem: true, _chromeHidden:true, childLayoutFitWidth:false, childDocumentsActive:false, dropAction: dropActionType.move}); // drop down panel at top of dashboard for stashing documents + DocUtils.AssignDocField(doc, "myHeaderBar", (opts) => Docs.Create.MulticolumnDocument([], opts), { title: "My Header Bar", isSystem: true, _chromeHidden:true, layout_maxShown: 10, childLayoutFitWidth:false, childDocumentsActive:false, dropAction: dropActionType.move}); // drop down panel at top of dashboard for stashing documents Doc.AddDocToList(Doc.MyFilesystem, undefined, Doc.MyDashboards) Doc.AddDocToList(Doc.MyFilesystem, undefined, Doc.MySharedDocs) diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index f6af6196f..aa0f77c72 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -101,8 +101,6 @@ export namespace DragManager { export interface DragOptions { dragComplete?: (e: DragCompleteEvent) => void; // function to invoke when drag has completed hideSource?: boolean; // hide source document during drag - offsetX?: number; // offset of top left of source drag visual from cursor - offsetY?: number; noAutoscroll?: boolean; } diff --git a/src/client/views/FilterPanel.tsx b/src/client/views/FilterPanel.tsx index 818c81c9a..455801422 100644 --- a/src/client/views/FilterPanel.tsx +++ b/src/client/views/FilterPanel.tsx @@ -121,11 +121,13 @@ export class FilterPanel extends ObservableReactComponent { const valueSet = new Set(childFilters.map(filter => filter.split(Doc.FilterSep)[1])); let rtFields = 0; let subDocs = childDocs; + let gatheredDocs = [] as Doc[]; if (subDocs.length > 0) { let newarray: Doc[] = []; while (subDocs.length > 0) { newarray = []; subDocs.forEach(t => { + gatheredDocs.push(t); const facetVal = t[facetKey]; if (facetVal instanceof RichTextField || typeof facetVal === 'string') rtFields++; facetVal !== undefined && valueSet.add(Field.toString(facetVal as Field)); @@ -135,7 +137,7 @@ export class FilterPanel extends ObservableReactComponent { DocListCast(t[annos ? fieldKey + '_annotations' : fieldKey]).forEach(newdoc => newarray.push(newdoc)); annos && DocListCast(t[fieldKey + '_sidebar']).forEach(newdoc => newarray.push(newdoc)); }); - subDocs = newarray; + subDocs = newarray.filter(d => !gatheredDocs.includes(d)); } } // } diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx index 20dc6c9fa..15b1f0275 100644 --- a/src/client/views/OverlayView.tsx +++ b/src/client/views/OverlayView.tsx @@ -9,7 +9,7 @@ import { Height, Width } from '../../fields/DocSymbols'; import { Id } from '../../fields/FieldSymbols'; import { NumCast } from '../../fields/Types'; import { DocumentType } from '../documents/DocumentTypes'; -import { DragManager } from '../util/DragManager'; +import { DragManager, dropActionType } from '../util/DragManager'; import { Transform } from '../util/Transform'; import { LightboxView } from './LightboxView'; import { ObservableReactComponent } from './ObservableReactComponent'; @@ -196,7 +196,7 @@ export class OverlayView extends ObservableReactComponent<{}> { if (e.metaKey) { const dragData = new DragManager.DocumentDragData([d]); dragData.offset = [-offsetx, -offsety]; - dragData.dropAction = 'move'; + dragData.dropAction = dropActionType.move; dragData.removeDocument = this.removeOverlayDoc; dragData.moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean): boolean => { return dragData.removeDocument!(doc) ? addDocument(doc) : false; diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index b181b59ce..85fe7c896 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -1,10 +1,10 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; -import { Button } from 'browndash-components'; -import { action, computed, makeObservable } from 'mobx'; +import { Button, IconButton } from 'browndash-components'; +import { action, computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { emptyFunction, returnFalse } from '../../../../Utils'; +import { FaChevronRight } from 'react-icons/fa'; import { Doc, DocListCast } from '../../../../fields/Doc'; import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; import { DragManager, dropActionType } from '../../../util/DragManager'; @@ -37,6 +37,8 @@ const resizerWidth = 8; @observer export class CollectionMulticolumnView extends CollectionSubView() { + @observable _startIndex = 0; + constructor(props: any) { super(props); makeObservable(this); @@ -48,7 +50,7 @@ export class CollectionMulticolumnView extends CollectionSubView() { */ @computed private get ratioDefinedDocs() { - return this.childLayoutPairs.map(pair => pair.layout).filter(layout => StrCast(layout._dimUnit, '*') === DimUnit.Ratio); + return this.childLayouts.filter(layout => StrCast(layout._dimUnit, '*') === DimUnit.Ratio); } @computed @@ -57,6 +59,15 @@ export class CollectionMulticolumnView extends CollectionSubView() { return ratioDocs.length ? Math.min(...ratioDocs.map(layout => NumCast(layout._dimMagnitude))) : 1; } + @computed get maxShown() { + return NumCast(this.layoutDoc.layout_maxShown); + } + + @computed + private get childLayouts() { + return (this.maxShown ? this.childLayoutPairs.slice(this._startIndex, this._startIndex + this.maxShown) : this.childLayoutPairs).map(pair => pair.layout); + } + /** * This loops through all childLayoutPairs and extracts the values for _dimUnit * and _dimMagnitude, ignoring any that are malformed. Additionally, it then @@ -69,9 +80,9 @@ export class CollectionMulticolumnView extends CollectionSubView() { private get resolvedLayoutInformation(): LayoutData { let starSum = 0; const widthSpecifiers: WidthSpecifier[] = []; - this.childLayoutPairs.map(pair => { - const unit = StrCast(pair.layout._dimUnit, '*'); - const magnitude = NumCast(pair.layout._dimMagnitude, this.minimumDim); + this.childLayouts.map(layout => { + const unit = StrCast(layout._dimUnit, '*'); + const magnitude = NumCast(layout._dimMagnitude, this.minimumDim); if (unit && magnitude && magnitude > 0 && resolvedUnits.includes(unit)) { unit === DimUnit.Ratio && (starSum += magnitude); widthSpecifiers.push({ magnitude, unit }); @@ -90,7 +101,7 @@ export class CollectionMulticolumnView extends CollectionSubView() { */ // setTimeout(() => { // const { ratioDefinedDocs } = this; - // if (this.childLayoutPairs.length) { + // if (this.childPairs.length) { // const minimum = this.minimumDim; // if (minimum !== 0) { // ratioDefinedDocs.forEach(layout => layout._dimMagnitude = NumCast(layout._dimMagnitude, 1) / minimum, 1); @@ -187,13 +198,14 @@ export class CollectionMulticolumnView extends CollectionSubView() { return Transform.Identity(); // we're still waiting on promises to resolve } let offset = 0; - for (const { layout: candidate } of this.childLayoutPairs) { + var xf = Transform.Identity(); + this.childLayouts.map(candidate => { if (candidate === layout) { - return this.ScreenToLocalBoxXf().translate(-offset / (this._props.NativeDimScaling?.() || 1), 0); + return (xf = this.ScreenToLocalBoxXf().translate(-offset / (this._props.NativeDimScaling?.() || 1), 0)); } offset += this.lookupPixels(candidate) + resizerWidth; - } - return Transform.Identity(); // type coersion, this case should never be hit + }); + return xf; }; @undoBatch @@ -297,10 +309,8 @@ export class CollectionMulticolumnView extends CollectionSubView() { */ @computed private get contents(): JSX.Element[] | null { - const { childLayoutPairs } = this; const collector: JSX.Element[] = []; - for (let i = 0; i < childLayoutPairs.length; i++) { - const { layout } = childLayoutPairs[i]; + this.childLayouts.forEach((layout, i) => { collector.push(
@@ -317,10 +327,10 @@ export class CollectionMulticolumnView extends CollectionSubView() { select={this._props.select} columnUnitLength={this.getColumnUnitLength} toLeft={layout} - toRight={childLayoutPairs[i + 1]?.layout} + toRight={this.childLayouts[i + 1]} /> ); - } + }); collector.pop(); // removes the final extraneous resize bar return collector; } @@ -339,6 +349,20 @@ export class CollectionMulticolumnView extends CollectionSubView() { marginBottom: NumCast(this.Document._yMargin), }}> {this.contents} + {!this._startIndex ? null : ( + +
(this._startIndex = Math.min(this.childLayoutPairs.length - 1, this._startIndex + this.maxShown)))}> +
+
+ )} + {this._startIndex > this.childLayoutPairs.length - 1 ? null : ( + +
(this._startIndex = Math.min(this.childLayoutPairs.length - 1, this._startIndex + this.maxShown)))}> + } color={SettingsManager.userColor} /> +
+
+ )}
); } diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx index 659f7ccdc..17bf3e50c 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx @@ -1,7 +1,6 @@ import { action, computed, makeObservable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { emptyFunction, returnFalse } from '../../../../Utils'; import { Doc, DocListCast } from '../../../../fields/Doc'; import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; import { DragManager, dropActionType } from '../../../util/DragManager'; -- cgit v1.2.3-70-g09d2 From 4cce99ec8d0bb2a45e19dd967dbbb8348c68abe8 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 28 Feb 2024 22:46:23 -0500 Subject: fixed double click of some icons to make them persist (circle, rectangle, fitall). --- src/client/util/CurrentUserUtils.ts | 4 +--- src/client/views/global/globalScripts.ts | 12 ++++++------ src/client/views/nodes/FontIconBox/FontIconBox.tsx | 10 ++++++++-- 3 files changed, 15 insertions(+), 11 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 289384be0..84bed08fa 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -611,9 +611,7 @@ export class CurrentUserUtils { return [ { title: "Snap", icon: "th", toolTip: "Show Snap Lines", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"snaplines", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform { title: "Grid", icon: "border-all", toolTip: "Show Grid", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"grid", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform - { title: "View All", icon: "object-group", toolTip: "Keep all Docs in View",btnType: ButtonType.ToggleButton, ignoreClick:true, expertMode: false, toolType:"viewAll", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform - // want the same style as toggle button, but don't want it to act as an actual toggle, so set disableToggle to true, - { title: "Fit All", icon: "arrows-left-right", toolTip: "Fit Docs to View (once)",btnType: ButtonType.ClickButton,ignoreClick:false,expertMode: false, toolType:"fitOnce", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform + { title: "Fit All", icon: "object-group", toolTip: "Fit Docs to View (double click to make sticky)",btnType: ButtonType.ToggleButton, ignoreClick:true, expertMode: false, toolType:"viewAll", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}', onDoubleClick: '{ return showFreeform(this.toolType, _readOnly_, true);}'}}, // Only when floating document is selected in freeform { title: "Clusters", icon: "braille", toolTip: "Show Doc Clusters", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"clusters", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform { title: "Cards", icon: "brain", toolTip: "Flashcards", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"flashcards", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform { title: "Arrange", icon:"arrow-down-short-wide",toolTip:"Toggle Auto Arrange", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"arrange", funcs: {hidden: 'IsNoviceMode()'}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts index e73ab25b5..33704e8fe 100644 --- a/src/client/views/global/globalScripts.ts +++ b/src/client/views/global/globalScripts.ts @@ -98,7 +98,7 @@ ScriptingGlobals.add(function toggleOverlay(checkResult?: boolean) { selected ? selected.CollectionFreeFormDocumentView?.float() : console.log('[FontIconBox.tsx] toggleOverlay failed'); }); -ScriptingGlobals.add(function showFreeform(attr: 'flashcards' | 'center' | 'grid' | 'snaplines' | 'clusters' | 'arrange' | 'viewAll' | 'fitOnce', checkResult?: boolean) { +ScriptingGlobals.add(function showFreeform(attr: 'flashcards' | 'center' | 'grid' | 'snaplines' | 'clusters' | 'arrange' | 'viewAll' | 'fitOnce', checkResult?: boolean, persist?: boolean) { const selected = SelectionManager.Docs.lastElement(); // prettier-ignore const map: Map<'flashcards' | 'center' |'grid' | 'snaplines' | 'clusters' | 'arrange'| 'viewAll' | 'fitOnce', { waitForRender?: boolean, checkResult: (doc:Doc) => any; setDoc: (doc:Doc, dv:DocumentView) => void;}> = new Map([ @@ -112,16 +112,16 @@ ScriptingGlobals.add(function showFreeform(attr: 'flashcards' | 'center' | 'grid }], ['viewAll', { checkResult: (doc:Doc) => BoolCast(doc?._freeform_fitContentsToBox, false), - setDoc: (doc:Doc,dv:DocumentView) => doc._freeform_fitContentsToBox = !doc._freeform_fitContentsToBox, + setDoc: (doc:Doc,dv:DocumentView) => { + if (persist) doc._freeform_fitContentsToBox = !doc._freeform_fitContentsToBox; + else if (doc._freeform_fitContentsToBox) doc._freeform_fitContentsToBox = undefined; + else (dv.ComponentView as CollectionFreeFormView)?.fitContentOnce(); + }, }], ['center', { checkResult: (doc:Doc) => BoolCast(doc?._stacking_alignCenter, false), setDoc: (doc:Doc,dv:DocumentView) => doc._stacking_alignCenter = !doc._stacking_alignCenter, }], - ['fitOnce', { - checkResult: (doc:Doc) => false, - setDoc: (doc:Doc, dv:DocumentView) => (dv.ComponentView as CollectionFreeFormView)?.fitContentOnce() - }], ['clusters', { waitForRender: true, // flags that undo batch should terminate after a re-render giving the script the chance to fire checkResult: (doc:Doc) => BoolCast(doc?._freeform_useClusters, false), diff --git a/src/client/views/nodes/FontIconBox/FontIconBox.tsx b/src/client/views/nodes/FontIconBox/FontIconBox.tsx index 3577cc8d9..91b6de80b 100644 --- a/src/client/views/nodes/FontIconBox/FontIconBox.tsx +++ b/src/client/views/nodes/FontIconBox/FontIconBox.tsx @@ -7,7 +7,7 @@ import * as React from 'react'; import { Doc, DocListCast, StrListCast } from '../../../../fields/Doc'; import { ScriptField } from '../../../../fields/ScriptField'; import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; -import { emptyFunction, setupMoveUpEvents, Utils } from '../../../../Utils'; +import { emptyFunction, returnTrue, setupMoveUpEvents, Utils } from '../../../../Utils'; import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes'; import { SelectionManager } from '../../../util/SelectionManager'; import { SettingsManager } from '../../../util/SettingsManager'; @@ -314,6 +314,7 @@ export class FontIconBox extends ViewBoxBaseComponent() { const tooltip = StrCast(this.Document.toolTip); const script = ScriptCast(this.Document.onClick); + const double = ScriptCast(this.Document.onDoubleClick); const toggleStatus = script ? script.script.run({ this: this.Document, self: this.Document, value: undefined, _readOnly_: true }).result : false; // Colors const color = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color); @@ -330,7 +331,12 @@ export class FontIconBox extends ViewBoxBaseComponent() { //background={SettingsManager.userBackgroundColor} icon={this.Icon(color)!} label={this.label} - onPointerDown={() => script.script.run({ this: this.Document, self: this.Document, value: !toggleStatus, _readOnly_: false })} + onPointerDown={e => + setupMoveUpEvents(this, e, returnTrue, emptyFunction, (e, doubleTap) => { + !doubleTap && script.script.run({ this: this.Document, self: this.Document, value: !toggleStatus, _readOnly_: false }); + doubleTap && double.script.run({ this: this.Document, self: this.Document, value: !toggleStatus, _readOnly_: false }); + }) + } /> ); } -- cgit v1.2.3-70-g09d2 From 26cd21b5148d07e0be39cd6997723b34a70ebab6 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 5 Mar 2024 12:16:53 -0500 Subject: added mermaid and poltly to tools list --- src/client/util/CurrentUserUtils.ts | 99 +++++++++++++++++++++++++++++++- src/client/views/nodes/ComparisonBox.tsx | 4 +- 2 files changed, 98 insertions(+), 5 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 84bed08fa..3a928d0af 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -2,6 +2,7 @@ import { observable, reaction, runInAction } from "mobx"; import * as rp from 'request-promise'; import { OmitKeys, Utils } from "../../Utils"; import { Doc, DocListCast, DocListCastAsync, Opt } from "../../fields/Doc"; +import { DocData } from "../../fields/DocSymbols"; import { InkTool } from "../../fields/InkField"; import { List } from "../../fields/List"; import { PrefetchProxy } from "../../fields/Proxy"; @@ -234,6 +235,95 @@ export class CurrentUserUtils { MakeTemplate(Doc.GetProto(slide), true, "Untitled Slide View"); return slide; } + const plotlyView = (opts:DocumentOptions) => { + var plotly = Doc.MyPublishedDocs.find(doc => doc.title === "@plotly"); + if (!plotly) { + const plotly = Docs.Create.TextDocument( + `await import("https://cdn.plot.ly/plotly-2.27.0.min.js"); + Plotly.newPlot(dashDiv.id, [ --DOCDATA-- ])` + , {title: "@plotly", title_custom: true, _width:300,_height:400}); + Doc.AddToMyPublished(plotly); + } + const rtfield = new RichTextField(JSON.stringify( + {doc: {type:"doc",content:[ + {type:"code_block",content:[ + {type:"text",text:"^@plotly"}, + {type:"text",text:"\n"}, + {type:"text",text:"\n{"}, + {type:"text",text:"\n x: [1,2,3,5,19],"}, + {type:"text",text:"\n y: [1, 9, 15, 12,3],"}, + {type:"text",text:"\n mode: 'lines+markers', "}, + {type:"text",text:"\n type: 'scatter'"}, + {type:"text",text:"\n}"} + ]} + ]}, + selection:{type:"text",anchor:2,head:2}}), + `^@plotly + { + x: [1,2,3,5,19], + y: [1, 9, 15, 12,3], + mode: 'lines+markers', + type: 'scatter' + }`); + const slide = Docs.Create.TextDocument("", opts); + slide[DocData].text = rtfield; + slide[DocData].layout_textPainted = ``; + slide[DocData]._type_collection = CollectionViewType.Freeform; + slide.onPaint = ScriptField.MakeScript(`toggleDetail(documentView, "textPainted", "")`); + return slide; + } + const mermaidsView = (opts:DocumentOptions) => { + var mermaids = Doc.MyPublishedDocs.find(doc => doc.title === "@mermaids"); + if (!mermaids) { + const mermaids = Docs.Create.TextDocument( + `const mdef = (await import("https://cdn.jsdelivr.net/npm/mermaid\@10.8.0/dist/mermaid.esm.min.mjs")).default; + window["callb"] = (x) => { + alert(x); + } + mdef.initialize({ + securityLevel : "loose", + startOnLoad: true, + flowchart: { useMaxWidth: true, htmlLabels: true, curve: 'cardinal' }, + }); + const mermaid = async (str) => (await mdef.render("graph"+Date.now(),str)); + const {svg, bindFunctions} = await mermaid(\`--DOCDATA--\`); + dashDiv.innerHTML = svg; + if (bindFunctions) { + bindFunctions(dashDiv); + }` + , {title: "@mermaids", title_custom: true, _width:300,_height:400}); + Doc.AddToMyPublished(mermaids); + } + const rtfield = new RichTextField(JSON.stringify( + {doc: {type:"doc",content:[ + {type:"code_block",content:[ + {type:"text",text:"^@mermaids"}, + {type:"text",text:"\n\n"}, + {type:"text",text:"pie "}, + {type:"text",text:"title"}, + {type:"text",text:" "}, + {type:"text",text:"Minerals in my tap water"}, + {type:"text",text:"\n \"Calcium\" : "}, + {type:"dashField",attrs:{fieldKey:"calcium",docId:"","hideKey":false,editable:true}}, + {type:"text",text:"\n \"Potassium\" : "}, + {type:"dashField",attrs:{fieldKey:"pot",docId:"",hideKey:false,editable:true}}, + {type:"text",text:"\n \"Magnesium\" : 10.01"} + ]} + ]}, + selection:{type:"text",anchor:109,head:109} + }), + `^@mermaids +pie title Minerals in my tap water + "Calcium" : 42.96 + "Potassium" : 50 + "Magnesium" : 10.01`); + const slide = Docs.Create.TextDocument("", opts); + slide[DocData].text = rtfield; + slide[DocData].layout_textPainted = ``; + slide[DocData]._type_collection = CollectionViewType.Freeform; + slide.onPaint = ScriptField.MakeScript(`toggleDetail(documentView, "textPainted", "")`); + return slide; + } const emptyThings:{key:string, // the field name where the empty thing will be stored opts:DocumentOptions, // the document options that are required for the empty thing funcs?:{[key:string]: any}, // computed fields that are rquired for the empth thing @@ -264,7 +354,9 @@ export class CurrentUserUtils { dropAction:dropActionType.move, treeView_Type: TreeViewType.outline, backgroundColor: "white", _xMargin: 0, _yMargin: 0, _createDocOnCR: true }, funcs: {title: 'this.text?.Text'}}, - ]; + {key: "Mermaids", creator: mermaidsView, opts: { _width: 300, _height: 300, }}, + {key: "Plotly", creator: plotlyView, opts: { _width: 300, _height: 300, }}, + ]; emptyThings.forEach(thing => DocUtils.AssignDocField(doc, "empty"+thing.key, (opts) => thing.creator(opts), {...standardOps(thing.key), ...thing.opts}, undefined, thing.scripts, thing.funcs)); @@ -272,6 +364,8 @@ export class CurrentUserUtils { { toolTip: "Tap or drag to create a note", title: "Note", icon: "sticky-note", dragFactory: doc.emptyNote as Doc, clickFactory: DocCast(doc.emptyNote)}, { toolTip: "Tap or drag to create a flashcard", title: "Flashcard", icon: "id-card", dragFactory: doc.emptyFlashcard as Doc, clickFactory: DocCast(doc.emptyFlashcard)}, { toolTip: "Tap or drag to create an equation", title: "Math", icon: "calculator", dragFactory: doc.emptyEquation as Doc, clickFactory: DocCast(doc.emptyEquation)}, + { toolTip: "Tap or drag to create a mermaid node", title: "Mermaids", icon: "rocket", dragFactory: doc.emptyMermaids as Doc, clickFactory: DocCast(doc.emptyMermaids)}, + { toolTip: "Tap or drag to create a plotly node", title: "Plotly", icon: "rocket", dragFactory: doc.emptyPlotly as Doc, clickFactory: DocCast(doc.emptyMermaids)}, { toolTip: "Tap or drag to create a physics simulation",title: "Simulation", icon: "rocket",dragFactory: doc.emptySimulation as Doc, clickFactory: DocCast(doc.emptySimulation), funcs: { hidden: "IsNoviceMode()"}}, { toolTip: "Tap or drag to create a note board", title: "Notes", icon: "folder", dragFactory: doc.emptyNoteboard as Doc, clickFactory: DocCast(doc.emptyNoteboard)}, { toolTip: "Tap or drag to create a collection", title: "Col", icon: "folder", dragFactory: doc.emptyCollection as Doc, clickFactory: DocCast(doc.emptyTab)}, @@ -442,8 +536,7 @@ export class CurrentUserUtils { /// Initializes the panel of draggable tools that is opened from the left sidebar. static setupToolsBtnPanel(doc: Doc, field:string) { - const myTools = DocCast(doc[field]); - const allTools = DocListCast(myTools?.data); + const allTools = DocListCast(DocCast(doc[field])?.data); const creatorBtns = CurrentUserUtils.setupCreatorButtons(doc, allTools?.length ? allTools[0]:undefined); const userTools = allTools && allTools?.length > 1 ? allTools[1]:undefined; const userBtns = CurrentUserUtils.setupUserDocumentCreatorButtons(doc, userTools); diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index 116dc48a6..ef8c045cc 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -6,7 +6,7 @@ import { emptyFunction, returnFalse, returnNone, returnZero, setupMoveUpEvents } import { Doc, Opt } from '../../../fields/Doc'; import { DocCast, NumCast, StrCast } from '../../../fields/Types'; import { DocUtils, Docs } from '../../documents/Documents'; -import { DragManager } from '../../util/DragManager'; +import { DragManager, dropActionType } from '../../util/DragManager'; import { undoBatch } from '../../util/UndoManager'; import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent'; import { StyleProp } from '../StyleProvider'; @@ -135,7 +135,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent() this, e, e => { - const de = new DragManager.DocumentDragData([DocCast(this.dataDoc[which])], 'move'); + const de = new DragManager.DocumentDragData([DocCast(this.dataDoc[which])], dropActionType.move); de.moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean): boolean => { this.clearDoc(which); return addDocument(doc); -- cgit v1.2.3-70-g09d2 From 1dd5944ab430a57d105e649a218ca0d9f2f0a060 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 5 Mar 2024 12:26:23 -0500 Subject: from last --- src/client/util/CurrentUserUtils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/client/util') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 3a928d0af..d75c717c9 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -241,7 +241,7 @@ export class CurrentUserUtils { const plotly = Docs.Create.TextDocument( `await import("https://cdn.plot.ly/plotly-2.27.0.min.js"); Plotly.newPlot(dashDiv.id, [ --DOCDATA-- ])` - , {title: "@plotly", title_custom: true, _width:300,_height:400}); + , {title: "@plotly", title_custom: true, _layout_showTitle:"title", _width:300,_height:400}); Doc.AddToMyPublished(plotly); } const rtfield = new RichTextField(JSON.stringify( @@ -291,7 +291,7 @@ export class CurrentUserUtils { if (bindFunctions) { bindFunctions(dashDiv); }` - , {title: "@mermaids", title_custom: true, _width:300,_height:400}); + , {title: "@mermaids", title_custom: true, _layout_showTitle:"title", _width:300,_height:400}); Doc.AddToMyPublished(mermaids); } const rtfield = new RichTextField(JSON.stringify( -- cgit v1.2.3-70-g09d2