From 08f125f5880247280c02633feeb31a8df1912b97 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 31 Jul 2023 00:06:16 -0400 Subject: fixed dictation into text boxes to stop when component unmounts. fixed some icons. fixed multiToggle for alignments. added link docs to user cache. fixed background color for tab stack buttons. added a bunch of @computeds to try to help performacne with lots of docs. chnaged text boxes to no expand/contract padding when selected. --- src/client/DocServer.ts | 3 +- src/client/documents/Documents.ts | 4 +- src/client/util/CurrentUserUtils.ts | 58 +++++++++-------- src/client/util/RTFMarkup.tsx | 2 +- src/client/views/PropertiesButtons.tsx | 4 +- .../views/collections/CollectionDockingView.scss | 1 + .../collectionFreeForm/CollectionFreeFormView.tsx | 20 +++--- .../collectionLinear/CollectionLinearView.tsx | 33 +++++----- .../collectionSchema/CollectionSchemaView.tsx | 1 - src/client/views/global/globalScripts.ts | 52 ++++++++-------- src/client/views/nodes/DocumentView.tsx | 55 ++++++++++------- src/client/views/nodes/FontIconBox/FontIconBox.tsx | 72 ++++++++++++---------- .../nodes/formattedText/FormattedTextBox.scss | 20 +----- .../views/nodes/formattedText/FormattedTextBox.tsx | 48 +++++++++------ src/fields/Doc.ts | 2 +- src/fields/List.ts | 46 +++++++------- 16 files changed, 218 insertions(+), 203 deletions(-) (limited to 'src') diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index ba59a9f50..ad5a73598 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -49,7 +49,8 @@ export namespace DocServer { } const filtered = Array.from(Object.keys(_cache)).filter(key => { const doc = _cache[key] as Doc; - if (!(StrCast(doc.author).includes('.edu') || StrCast(doc.author).includes('.com')) || doc.author == Doc.CurrentUserEmail) return true; + return true; + if (!(StrCast(doc.author).includes('.edu') || StrCast(doc.author).includes('.com')) || doc.author === Doc.CurrentUserEmail) return true; return false; }); if (filtered.length === lastCacheUpdate) return; diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index f22fa9f17..d38e2292c 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -636,7 +636,7 @@ export namespace Docs { DocumentType.CONFIG, { layout: { view: CollectionView, dataField: defaultDataKey }, - options: { layout_hideLinkButton: true, pointerEvents: 'none', layout_unrendered: true }, + options: { layout_hideLinkButton: true, layout_unrendered: true }, }, ], [ @@ -854,7 +854,7 @@ export namespace Docs { dataProps.author_date = new DateField(); if (fieldKey) { dataProps[`${fieldKey}_modificationDate`] = new DateField(); - dataProps[fieldKey] = data; + dataProps[fieldKey] = options.data ?? data; // so that the list of annotations is already initialised, prevents issues in addonly. // without this, if a doc has no annotations but the user has AddOnly privileges, they won't be able to add an annotation because they would have needed to create the field's list which they don't have permissions to do. diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index a86011042..8e91bf83f 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -586,6 +586,11 @@ export class CurrentUserUtils { dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), _lockedPosition: true, isSystem: true, flexDirection: "row" }) + static multiToggleList = (opts: DocumentOptions, docs: Doc[]) => Docs.Create.FontIconDocument({ + ...opts, data:docs, _gridGap: 0, _xMargin: 5, _yMargin: 5, layout_boxShadow: "0 0", _forceActive: true, + dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), + _lockedPosition: true, isSystem: true, flexDirection: "row" + }) static createToolButton = (opts: DocumentOptions) => Docs.Create.FontIconDocument({ btnType: ButtonType.ToolButton, _forceActive: true, _layout_hideContextMenu: true, @@ -640,17 +645,17 @@ export class CurrentUserUtils { btnList: new List(["Roboto", "Roboto Mono", "Nunito", "Times New Roman", "Arial", "Georgia", "Comic Sans MS", "Tahoma", "Impact", "Crimson Text"]) }, { title: "Font Size",toolTip: "Font size (%size)", btnType: ButtonType.NumberDropdownButton, toolType:"fontSize", ignoreClick: true, scripts: {script: '{ return setFontAttr(self.toolType, value, _readOnly_);}'}, numBtnMax: 200, numBtnMin: 6 }, { title: "Color", toolTip: "Font color (%color)", btnType: ButtonType.ColorButton, icon: "font", toolType:"fontColor",ignoreClick: true, scripts: {script: '{ return setFontAttr(self.toolType, value, _readOnly_);}'}}, - { title: "Highlight",toolTip:"Font highlight", btnType: ButtonType.ColorButton, icon: "highlighter", toolType:"highlight",ignoreClick: true, scripts: {script: '{ return setFontAttr(self.toolType, value, _readOnly_);}'},funcs: {hidden: "IsNoviceMode()"} }, + { title: "Highlight",toolTip: "Font highlight", btnType: ButtonType.ColorButton, icon: "highlighter", toolType:"highlight",ignoreClick: true, scripts: {script: '{ return setFontAttr(self.toolType, value, _readOnly_);}'},funcs: {hidden: "IsNoviceMode()"} }, { title: "Bold", toolTip: "Bold (Ctrl+B)", btnType: ButtonType.ToggleButton, icon: "bold", toolType:"bold", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, { title: "Italic", toolTip: "Italic (Ctrl+I)", btnType: ButtonType.ToggleButton, icon: "italic", toolType:"italics", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, { title: "Under", toolTip: "Underline (Ctrl+U)", btnType: ButtonType.ToggleButton, icon: "underline", toolType:"underline",ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, { title: "Bullets", toolTip: "Bullet List", btnType: ButtonType.ToggleButton, icon: "list", toolType:"bullet", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, { title: "#", toolTip: "Number List", btnType: ButtonType.ToggleButton, icon: "list-ol", toolType:"decimal", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, - { title: "Alignment",toolTip: "Alignment", btnType: ButtonType.MultiToggleButton, toolType:"alignment", ignoreClick: true, + { title: "Align", toolTip: "Alignment", btnType: ButtonType.MultiToggleButton, toolType:"alignment", ignoreClick: true, subMenu: [ - { title: "Left", toolTip: "Left align (Cmd-[)", btnType: ButtonType.ToggleButton, icon: "align-left", toolType:"left", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}' }}, - { title: "Center", toolTip: "Center align (Cmd-\\)",btnType: ButtonType.ToggleButton, icon: "align-center",toolType:"center",ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, - { title: "Right", toolTip: "Right align (Cmd-])", btnType: ButtonType.ToggleButton, icon: "align-right", toolType:"right", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, + { title: "Left", toolTip: "Left align (Cmd-[)", btnType: ButtonType.ToggleButton, icon: "align-left", toolType:"left", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}' }}, + { title: "Center", toolTip: "Center align (Cmd-\\)",btnType: ButtonType.ToggleButton, icon: "align-center",toolType:"center",ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, + { title: "Right", toolTip: "Right align (Cmd-])", btnType: ButtonType.ToggleButton, icon: "align-right", toolType:"right", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, ] }, { title: "Dictate", toolTip: "Dictate", btnType: ButtonType.ToggleButton, icon: "microphone", toolType:"dictation", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'}}, @@ -730,32 +735,31 @@ export class CurrentUserUtils { return DocUtils.AssignScripts(DocUtils.AssignOpts(btnDoc, reqdOpts) ?? Docs.Create.FontIconDocument(reqdOpts), params.scripts, reqdFuncs); } + static setupContextMenuBtn(params:Button, menuDoc:Doc):Doc { + const menuBtnDoc = DocListCast(menuDoc?.data).find(doc => doc.title === params.title); + if (!params.subMenu) { // button does not have a sub menu + return this.setupContextMenuButton(params, menuBtnDoc); + } + // linear view + const reqdSubMenuOpts = { ...OmitKeys(params, ["scripts", "funcs", "subMenu"]).omit, undoIgnoreFields: new List(['width', "linearView_IsOpen"]), + childDontRegisterViews: true, flexGap: 0, _height: 30, ignoreClick: params.scripts?.onClick ? false : true, + linearView_SubMenu: true, linearView_Expandable: params.btnType !== ButtonType.MultiToggleButton}; + + const items = !menuBtnDoc ? [] : params.subMenu?.map(sub => this.setupContextMenuBtn(sub, menuBtnDoc) ); + if (params.btnType === ButtonType.MultiToggleButton) { + const list = DocUtils.AssignScripts( DocUtils.AssignDocField(menuDoc, StrCast(params.title), + (opts) => this.multiToggleList(opts, items??[]), reqdSubMenuOpts, items), params.scripts); + return list; + } + return DocUtils.AssignScripts( + DocUtils.AssignDocField(menuDoc, StrCast(params.title), (opts) => this.linearButtonList(opts, items??[]), reqdSubMenuOpts, items), params.scripts, params.funcs); + } + /// 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 ctxtMenuBtnsDoc = DocUtils.AssignDocField(doc, field, (opts, items) => this.linearButtonList(opts, items??[]), reqdCtxtOpts, undefined); - const ctxtMenuBtns = CurrentUserUtils.contextMenuTools().map(params => { - const menuBtnDoc = DocListCast(ctxtMenuBtnsDoc?.data).find(doc => doc.title === params.title); - if (!params.subMenu) { // button does not have a sub menu - return this.setupContextMenuButton(params, menuBtnDoc); - } else { // linear view - let reqdSubMenuOpts; - if (params.btnType === ButtonType.MultiToggleButton) { - reqdSubMenuOpts = { ...OmitKeys(params, ["scripts", "funcs", "subMenu"]).omit, undoIgnoreFields: new List(['width', "linearView_IsOpen"]), - childDontRegisterViews: true, flexGap: 0, _height: 30, ignoreClick: params.scripts?.onClick ? false : true, - linearView_SubMenu: true, linearView_Dropdown: true, }; - } else { - reqdSubMenuOpts = { ...OmitKeys(params, ["scripts", "funcs", "subMenu"]).omit, undoIgnoreFields: new List(['width', "linearView_IsOpen"]), - childDontRegisterViews: true, flexGap: 0, _height: 30, ignoreClick: params.scripts?.onClick ? false : true, - linearView_SubMenu: true, linearView_Expandable: true, }; - } - const items = params.subMenu?.map(sub => - this.setupContextMenuButton(sub, DocListCast(menuBtnDoc?.data).find(doc => doc.title === sub.title)) - ); - return DocUtils.AssignScripts( - DocUtils.AssignDocField(ctxtMenuBtnsDoc, StrCast(params.title), (opts) => this.linearButtonList(opts, items??[]), reqdSubMenuOpts, items), params.scripts, params.funcs); - } - }); + const ctxtMenuBtns = CurrentUserUtils.contextMenuTools().map(params => this.setupContextMenuBtn(params, ctxtMenuBtnsDoc) ); return DocUtils.AssignOpts(ctxtMenuBtnsDoc, reqdCtxtOpts, ctxtMenuBtns); } diff --git a/src/client/util/RTFMarkup.tsx b/src/client/util/RTFMarkup.tsx index b93d4f293..c2f121e1f 100644 --- a/src/client/util/RTFMarkup.tsx +++ b/src/client/util/RTFMarkup.tsx @@ -30,7 +30,7 @@ export class RTFMarkup extends React.Component<{}> { */ @computed get cheatSheet() { return ( -
+

{`wiki:phrase`} {` display wikipedia page for entered text (terminate with carriage return)`} diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx index 2e3668268..b74eabcc3 100644 --- a/src/client/views/PropertiesButtons.tsx +++ b/src/client/views/PropertiesButtons.tsx @@ -244,10 +244,10 @@ export class PropertiesButtons extends React.Component<{}, {}> { @computed get layout_autoHeightButton() { // store previous dimensions to store old values return this.propertyToggleBtn( - on => 'Auto\xA0Size', + on => (on ? 'AUTO\xA0SIZE' : 'FIXED SIZE'), '_layout_autoHeight', on => `Automatical vertical sizing to show all content`, - on => 'arrows-alt-v' + on => ); } diff --git a/src/client/views/collections/CollectionDockingView.scss b/src/client/views/collections/CollectionDockingView.scss index a4c5229aa..d93015506 100644 --- a/src/client/views/collections/CollectionDockingView.scss +++ b/src/client/views/collections/CollectionDockingView.scss @@ -176,6 +176,7 @@ display: flex; align-content: center; justify-content: center; + background: $dark-gray; } .lm_controls > li { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index ba31916a7..b5e9994dd 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1264,13 +1264,15 @@ export class CollectionFreeFormView extends CollectionSubView { + @computed get _pointerEvents() { const engine = this.props.layoutEngine?.() || StrCast(this.props.Document._layoutEngine); const pointerEvents = DocumentDecorations.Instance.Interacting ? 'none' : this.props.childPointerEvents ?? (this.props.viewDefDivClick || (engine === computePassLayout.name && !this.props.isSelected(true)) || this.isContentActive() === false ? 'none' : this.props.pointerEvents?.()); return pointerEvents; - }; + } + pointerEvents = () => this._pointerEvents; + childContentsActive = () => (this.props.childContentsActive ?? this.isContentActive() === false ? returnFalse : emptyFunction)(); getChildDocView(entry: PoolData) { const childLayout = entry.pair.layout; const childData = entry.pair.data; @@ -1299,7 +1301,7 @@ export class CollectionFreeFormView extends CollectionSubView { - return this._layoutPoolData.get(doc[Id] + (replica || '')); - }; + childPositionProviderUnmemoized = (doc: Doc, replica: string) => this._layoutPoolData.get(doc[Id] + (replica || '')); childDataProvider = computedFn( function childDataProvider(this: any, doc: Doc, replica: string) { - return this._layoutPoolData.get(doc[Id] + (replica || '')); + return this.childPositionProviderUnmemoized(doc, replica); }.bind(this) ); - childSizeProviderUnmemoized = (doc: Doc, replica: string) => { - return this._layoutSizeData.get(doc[Id] + (replica || '')); - }; + childSizeProviderUnmemoized = (doc: Doc, replica: string) => this._layoutSizeData.get(doc[Id] + (replica || '')); childSizeProvider = computedFn( function childSizeProvider(this: any, doc: Doc, replica: string) { - return this._layoutSizeData.get(doc[Id] + (replica || '')); + return this.childSizeProviderUnmemoized(doc, replica); }.bind(this) ); diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx index 56b8366d0..2254b2e5f 100644 --- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx +++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx @@ -204,7 +204,7 @@ export class CollectionLinearView extends CollectionSubView() { const menuOpener = ( } type={Type.TERT} color={StrCast(Doc.UserDoc().userVariantColor, Colors.MEDIUM_BLUE)} @@ -212,7 +212,7 @@ export class CollectionLinearView extends CollectionSubView() { toggleType={ToggleType.BUTTON} toggleStatus={BoolCast(this.layoutDoc.linearView_IsOpen)} onClick={() => { - this.layoutDoc.linearView_IsOpen = !isExpanded; + this.layoutDoc.linearView_IsOpen = !isExpanded; }} tooltip={isExpanded ? 'Close' : 'Open'} fillWidth={true} @@ -223,25 +223,22 @@ export class CollectionLinearView extends CollectionSubView() { return (

- {this.props.Document.linearView_Dropdown ? -
Hello World!
- : + { <> - {!this.props.Document.linearView_Expandable ? null : menuOpener} - {!this.layoutDoc.linearView_IsOpen ? null : ( -
- {this.childLayoutPairs.map(pair => this.getDisplayDoc(pair.layout))} -
- )} + {menuOpener} + {!this.layoutDoc.linearView_IsOpen ? null : ( +
+ {this.childLayoutPairs.map(pair => this.getDisplayDoc(pair.layout))} +
+ )} } -
); diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index ee5bf82ed..babe5c810 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -810,7 +810,6 @@ export class CollectionSchemaView extends CollectionSubView() { } @computed get sortedDocs() { - trace(); const field = StrCast(this.layoutDoc.sortField); const desc = BoolCast(this.layoutDoc.sortDesc); const docs = !field diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts index b906065a0..61920cdef 100644 --- a/src/client/views/global/globalScripts.ts +++ b/src/client/views/global/globalScripts.ts @@ -1,26 +1,28 @@ -import { Colors } from "browndash-components"; -import { runInAction, action } from "mobx"; -import { aggregateBounds } from "../../../Utils"; -import { Doc } from "../../../fields/Doc"; -import { Width, Height } from "../../../fields/DocSymbols"; -import { InkTool } from "../../../fields/InkField"; -import { Cast, StrCast, NumCast, BoolCast } from "../../../fields/Types"; -import { WebField } from "../../../fields/URLField"; -import { GestureUtils } from "../../../pen-gestures/GestureUtils"; -import { LinkManager } from "../../util/LinkManager"; -import { ScriptingGlobals } from "../../util/ScriptingGlobals"; -import { SelectionManager } from "../../util/SelectionManager"; -import { UndoManager } from "../../util/UndoManager"; -import { GestureOverlay } from "../GestureOverlay"; -import { InkTranscription } from "../InkTranscription"; -import { ActiveFillColor, SetActiveFillColor, ActiveIsInkMask, SetActiveIsInkMask, ActiveInkWidth, SetActiveInkWidth, ActiveInkColor, SetActiveInkColor } from "../InkingStroke"; -import { CollectionFreeFormView } from "../collections/collectionFreeForm"; -import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView"; -import { WebBox } from "../nodes/WebBox"; -import { RichTextMenu } from "../nodes/formattedText/RichTextMenu"; -import { DocumentType } from "../../documents/DocumentTypes"; +import { Colors } from 'browndash-components'; +import { runInAction, action } from 'mobx'; +import { aggregateBounds } from '../../../Utils'; +import { Doc } from '../../../fields/Doc'; +import { Width, Height } from '../../../fields/DocSymbols'; +import { InkTool } from '../../../fields/InkField'; +import { Cast, StrCast, NumCast, BoolCast } from '../../../fields/Types'; +import { WebField } from '../../../fields/URLField'; +import { GestureUtils } from '../../../pen-gestures/GestureUtils'; +import { LinkManager } from '../../util/LinkManager'; +import { ScriptingGlobals } from '../../util/ScriptingGlobals'; +import { SelectionManager } from '../../util/SelectionManager'; +import { undoable, UndoManager } from '../../util/UndoManager'; +import { GestureOverlay } from '../GestureOverlay'; +import { InkTranscription } from '../InkTranscription'; +import { ActiveFillColor, SetActiveFillColor, ActiveIsInkMask, SetActiveIsInkMask, ActiveInkWidth, SetActiveInkWidth, ActiveInkColor, SetActiveInkColor } from '../InkingStroke'; +import { CollectionFreeFormView } from '../collections/collectionFreeForm'; +import { CollectionFreeFormDocumentView } from '../nodes/CollectionFreeFormDocumentView'; +import { WebBox } from '../nodes/WebBox'; +import { RichTextMenu } from '../nodes/formattedText/RichTextMenu'; +import { DocumentType } from '../../documents/DocumentTypes'; -ScriptingGlobals.add(function IsNoneSelected() { return SelectionManager.Views().length <= 0; }, "are no document selected"); +ScriptingGlobals.add(function IsNoneSelected() { + return SelectionManager.Views().length <= 0; +}, 'are no document selected'); // toggle: Set overlay status of selected document ScriptingGlobals.add(function setView(view: string) { @@ -52,7 +54,7 @@ ScriptingGlobals.add(function setBackgroundColor(color?: string, checkResult?: b if (contentFrameNumber !== undefined) { CollectionFreeFormDocumentView.setStringValues(contentFrameNumber, dv.rootDoc, { fieldKey: color }); } else { - console.log('setting color to: ', color) + console.log('setting color to: ', color); dv.rootDoc['_' + fieldKey] = color; } }); @@ -119,7 +121,6 @@ ScriptingGlobals.add(function showFreeform(attr: 'flashcards' | 'grid' | 'snapli ]); if (checkResult) { - console.log(attr, map.get(attr)?.checkResult(selected)) return map.get(attr)?.checkResult(selected); } const batch = map.get(attr)?.waitForRender ? UndoManager.StartBatch('set freeform attribute') : { end: () => {} }; @@ -193,10 +194,9 @@ ScriptingGlobals.add(function toggleCharStyle(charStyle: attrname, checkResult?: const map = new Map(attrs.concat(alignments).concat(listings)); if (checkResult) { - console.log(charStyle, checkResult, map.get(charStyle)?.checkResult()); return map.get(charStyle)?.checkResult(); } - map.get(charStyle)?.toggle(); + undoable(() => map.get(charStyle)?.toggle(), 'toggle ' + charStyle)(); }); export function checkInksToGroup() { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 2990e2159..70d2f95ea 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1,5 +1,5 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; -import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx'; +import { action, computed, IReactionDisposer, observable, reaction, runInAction, trace } from 'mobx'; import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; import { Bounce, Fade, Flip, LightSpeed, Roll, Rotate, Zoom } from 'react-reveal'; @@ -314,7 +314,7 @@ export class DocumentViewInternal extends DocComponent this.props.isSelected(outsideReaction) || (this.props.Document.rootDocument && this.props.rootSelected?.(outsideReaction)) || false; + @computed get _rootSelected() { + return this.props.isSelected(false) || (this.props.Document.rootDocument && this.props.rootSelected?.(false)) || false; + } + rootSelected = (outsideReaction?: boolean) => this._rootSelected; panelHeight = () => this.props.PanelHeight() - this.headerMargin; screenToLocal = () => this.props.ScreenToLocalTransform().translate(0, -this.headerMargin); onClickFunc: any = () => (this.disableClickScriptFunc ? undefined : this.onClickHandler); setHeight = (height: number) => (this.layoutDoc._height = height); setContentView = action((view: { getAnchor?: (addAsAnnotation: boolean) => Doc; forward?: () => boolean; back?: () => boolean }) => (this._componentView = view)); - isContentActive = (outsideReaction?: boolean): boolean | undefined => { + @computed get _isContentActive() { // true - if the document has been activated directly or indirectly (by having its children selected) // false - if its pointer events are explicitly turned off or if it's container tells it that it's inactive // undefined - it is not active, but it should be responsive to actions that might active it or its contents (eg clicking) - return this.props.isContentActive() === false || this.props.pointerEvents?.() === 'none' || (this.rootDoc.pointerEvents === 'none' && !StrCast(this.props.LayoutTemplateString).includes(KeyValueBox.name)) + return this.props.isContentActive() === false || this.props.pointerEvents?.() === 'none' ? false : Doc.ActiveTool !== InkTool.None || SnappingManager.GetIsDragging() || this.rootSelected() || this.rootDoc.forceActive || this._componentView?.isAnyChildContentActive?.() || this.props.isContentActive() ? true : undefined; - }; + } + isContentActive = (): boolean | undefined => this._isContentActive; @observable _retryThumb = 1; - thumbShown = () => { - const childHighlighted = () => - Array.from(Doc.highlightedDocs.keys()) - .concat(Array.from(Doc.brushManager.BrushedDoc.keys())) - .some(doc => Doc.AreProtosEqual(DocCast(doc.annotationOn), this.rootDoc)); + @computed get _thumbShown() { + const childHighlighted = () => false; + // Array.from(Doc.highlightedDocs.keys()) + // .concat(Array.from(Doc.brushManager.BrushedDoc.keys())) + // .some(doc => Doc.AreProtosEqual(DocCast(doc.annotationOn), this.rootDoc)); const childOverlayed = () => Array.from(DocumentManager._overlayViews).some(view => Doc.AreProtosEqual(view.rootDoc, this.rootDoc)); return !this.props.LayoutTemplateString && !this.isContentActive() && @@ -893,12 +897,15 @@ export class DocumentViewInternal extends DocComponent this._thumbShown; childFilters = () => [...this.props.childFilters(), ...StrListCast(this.layoutDoc.childFilters)]; /// disable pointer events on content when there's an enabled onClick script (but not the browse script) and the contents aren't forced active, or if contents are marked inactive - contentPointerEvents = () => ((!this.disableClickScriptFunc && this.onClickHandler && !this.props.onBrowseClick?.() && this.isContentActive() !== true) || this.isContentActive() === false ? 'none' : this.pointerEvents); - + @computed get _contentPointerEvents() { + return (!this.disableClickScriptFunc && this.onClickHandler && !this.props.onBrowseClick?.() && this.isContentActive() !== true) || this.isContentActive() === false ? 'none' : this.pointerEvents; + } + contentPointerEvents = () => this._contentPointerEvents; @computed get contents() { TraceMobx(); const isInk = StrCast(this.layoutDoc.layout).includes(InkingStroke.name) && !this.props.LayoutTemplateString; @@ -1081,7 +1088,7 @@ export class DocumentViewInternal extends DocComponent @@ -1216,16 +1223,22 @@ export class DocumentViewInternal extends DocComponent{renderDoc}; } } + @computed get highlighting() { + return this.props.styleProvider?.(this.props.Document, this.props, StyleProp.Highlighting); + } + @computed get borderPath() { + return this.props.styleProvider?.(this.props.Document, this.props, StyleProp.BorderPath); + } render() { TraceMobx(); - const highlighting = this.props.styleProvider?.(this.props.Document, this.props, StyleProp.Highlighting); - const borderPath = this.props.styleProvider?.(this.props.Document, this.props, StyleProp.BorderPath); + const highlighting = this.highlighting; + const borderPath = this.borderPath; const boxShadow = this.props.treeViewDoc || !highlighting ? this.boxShadow : highlighting && this.borderRounding && highlighting.highlightStyle !== 'dashed' ? `0 0 0 ${highlighting.highlightIndex}px ${highlighting.highlightColor}` - : this.boxShadow || (this.props.Document.isTemplateForField ? 'black 0.2vw 0.2vw 0.8vw' : undefined); + : this.boxShadow || (this.rootDoc.isTemplateForField ? 'black 0.2vw 0.2vw 0.8vw' : undefined); const renderDoc = this.renderDoc({ borderRadius: this.borderRounding, outline: highlighting && !this.borderRounding && !highlighting.highlightStroke ? `${highlighting.highlightColor} ${highlighting.highlightStyle} ${highlighting.highlightIndex}px` : 'solid 0px', @@ -1241,9 +1254,9 @@ export class DocumentViewInternal extends DocComponent (!SnappingManager.GetIsDragging() || DragManager.CanEmbed) && Doc.BrushDoc(this.props.Document)} - onPointerOver={e => (!SnappingManager.GetIsDragging() || DragManager.CanEmbed) && Doc.BrushDoc(this.props.Document)} - onPointerLeave={e => !isParentOf(this.ContentDiv, document.elementFromPoint(e.nativeEvent.x, e.nativeEvent.y)) && Doc.UnBrushDoc(this.props.Document)} + onPointerEnter={e => (!SnappingManager.GetIsDragging() || DragManager.CanEmbed) && Doc.BrushDoc(this.rootDoc)} + onPointerOver={e => (!SnappingManager.GetIsDragging() || DragManager.CanEmbed) && Doc.BrushDoc(this.rootDoc)} + onPointerLeave={e => !isParentOf(this.ContentDiv, document.elementFromPoint(e.nativeEvent.x, e.nativeEvent.y)) && Doc.UnBrushDoc(this.rootDoc)} style={{ borderRadius: this.borderRounding, pointerEvents: this.pointerEvents === 'visiblePainted' ? 'none' : this.pointerEvents, diff --git a/src/client/views/nodes/FontIconBox/FontIconBox.tsx b/src/client/views/nodes/FontIconBox/FontIconBox.tsx index da1b89200..ad3532502 100644 --- a/src/client/views/nodes/FontIconBox/FontIconBox.tsx +++ b/src/client/views/nodes/FontIconBox/FontIconBox.tsx @@ -1,6 +1,6 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Button, ColorPicker, Dropdown, DropdownType, EditableText, IconButton, IListItemProps, NumberDropdown, NumberDropdownType, Popup, Size, Toggle, ToggleType, Type } from 'browndash-components'; +import { Button, MultiToggle, ColorPicker, Dropdown, DropdownType, EditableText, IconButton, IListItemProps, NumberDropdown, NumberDropdownType, Popup, Size, Toggle, ToggleType, Type } from 'browndash-components'; import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; @@ -21,6 +21,7 @@ import { RichTextMenu } from '../formattedText/RichTextMenu'; import './FontIconBox.scss'; import { SelectedDocView } from '../../selectedDoc'; import { Utils } from '../../../../Utils'; +import { FaAlignCenter, FaAlignJustify, FaAlignLeft, FaAlignRight } from 'react-icons/fa'; export enum ButtonType { TextButton = 'textBtn', @@ -209,13 +210,10 @@ export class FontIconBox extends DocComponent() { if (isViewDropdown) { const selectedDocs: Doc[] = SelectionManager.Docs(); const selected = SelectionManager.Docs().lastElement(); - console.log('selected'); if (selected) { if (StrCast(selected.type) === DocumentType.COL) { text = StrCast(selected._type_collection); - console.log('collection selected', text); } else { - console.log('doc selected', selected.title); dropdown = false; if (selectedDocs.length > 1) { text = selectedDocs.length + ' selected'; @@ -240,8 +238,6 @@ export class FontIconBox extends DocComponent() { console.log(e); } - console.log('current item: ', text); - // Get items to place into the list const list: IListItemProps[] = this.buttonList .filter(value => !Doc.noviceMode || !noviceList.length || noviceList.includes(value)) @@ -295,6 +291,34 @@ export class FontIconBox extends DocComponent() { /> ); } + @computed get multiToggleButton() { + // Determine the type of toggle button + const tooltip: string = StrCast(this.rootDoc.toolTip); + + const script = ScriptCast(this.rootDoc.onClick); + const toggleStatus = script ? script.script.run({ this: this.layoutDoc, self: this.rootDoc, value: undefined, _readOnly_: true }).result : false; + // Colors + const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color); + const items = DocListCast(this.rootDoc.data); + return ( + ({ + icon: , + tooltip: StrCast(item.toolTip), + val: StrCast(item.toolType), + }))} + selectedVal={StrCast(items.find(itemDoc => ScriptCast(itemDoc.onClick).script.run({ this: itemDoc, self: itemDoc, value: undefined, _readOnly_: true }).result)?.toolType)} + setSelectedVal={(val: string | number) => { + const itemDoc = items.find(item => item.toolType === val); + itemDoc && ScriptCast(itemDoc.onClick).script.run({ this: itemDoc, self: itemDoc, value: val, _readOnly_: false }); + }} + /> + ); + } @computed get toggleButton() { // Determine the type of toggle button @@ -356,48 +380,34 @@ export class FontIconBox extends DocComponent() { render() { // determine dash button metadata const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color); - const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor); const tooltip: string = StrCast(this.rootDoc.toolTip); const onClickScript = ScriptCast(this.rootDoc.onClick); - const script = ScriptCast(this.rootDoc.script); // TODO:glr Add label of button type let button: JSX.Element = this.defaultButton; // prettier-ignore switch (this.type) { case ButtonType.EditableText: - button = this.editableText; - break; + button = this.editableText; break; case ButtonType.DropdownList: - button = this.dropdownListButton; - break; + button = this.dropdownListButton; break; case ButtonType.ColorButton: - button = this.colorButton; - break; + button = this.colorButton; break; case ButtonType.NumberDropdownButton: case ButtonType.NumberInlineButton: case ButtonType.NumberSliderButton: - button = this.numberDropdown; - break; + button = this.numberDropdown; break; case ButtonType.DropdownButton: - button = this.dropdownButton; - break; + button = this.dropdownButton; break; + case ButtonType.MultiToggleButton: + button = this.multiToggleButton; break; case ButtonType.ToggleButton: button = this.toggleButton; break; case ButtonType.ClickButton: case ButtonType.ToolButton: - button = ( - - ); - break; + button = ; break; case ButtonType.TextButton: - button = ( -