diff options
Diffstat (limited to 'src/client/views/nodes/button/FontIconBox.tsx')
| -rw-r--r-- | src/client/views/nodes/button/FontIconBox.tsx | 295 |
1 files changed, 154 insertions, 141 deletions
diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx index 26515da30..5bba51ec8 100644 --- a/src/client/views/nodes/button/FontIconBox.tsx +++ b/src/client/views/nodes/button/FontIconBox.tsx @@ -5,7 +5,8 @@ import { action, computed, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { ColorState, SketchPicker } from 'react-color'; -import { Doc, HeightSym, StrListCast, WidthSym } from '../../../../fields/Doc'; +import { Doc, StrListCast } from '../../../../fields/Doc'; +import { Height, Width } from '../../../../fields/DocSymbols'; import { InkTool } from '../../../../fields/InkField'; import { ScriptField } from '../../../../fields/ScriptField'; import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; @@ -16,7 +17,7 @@ import { CollectionViewType, DocumentType } from '../../../documents/DocumentTyp import { LinkManager } from '../../../util/LinkManager'; import { ScriptingGlobals } from '../../../util/ScriptingGlobals'; import { SelectionManager } from '../../../util/SelectionManager'; -import { undoBatch, UndoManager } from '../../../util/UndoManager'; +import { undoable, undoBatch, UndoManager } from '../../../util/UndoManager'; import { CollectionFreeFormView } from '../../collections/collectionFreeForm'; import { ContextMenu } from '../../ContextMenu'; import { DocComponent } from '../../DocComponent'; @@ -44,16 +45,12 @@ export enum ButtonType { ToggleButton = 'tglBtn', ColorButton = 'colorBtn', ToolButton = 'toolBtn', - NumberButton = 'numBtn', + NumberSliderButton = 'numSliderBtn', + NumberDropdownButton = 'numDropdownBtn', + NumberInlineButton = 'numInlineBtn', EditableText = 'editableText', } -export enum NumButtonType { - Slider = 'slider', - DropdownOptions = 'list', - Inline = 'inline', -} - export interface ButtonProps extends FieldViewProps { type?: ButtonType; } @@ -98,7 +95,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() { // Determining UI Specs @computed get label() { - return StrCast(this.rootDoc.label, StrCast(this.rootDoc.title)); + return StrCast(this.rootDoc.icon_label, StrCast(this.rootDoc.title)); } Icon = (color: string) => { const icon = StrCast(this.dataDoc[this.fieldKey ?? 'icon'] ?? this.dataDoc.icon, 'user') as any; @@ -132,112 +129,116 @@ export class FontIconBox extends DocComponent<ButtonProps>() { /** * Number button */ - @computed get numberButton() { - const numBtnType: string = StrCast(this.rootDoc.numBtnType); - const numScript = ScriptCast(this.rootDoc.script); - const setValue = (value: number) => UndoManager.RunInBatch(() => numScript?.script.run({ self: this.rootDoc, value, _readOnly_: false }), 'set num value'); - + @computed get numberSliderButton() { + const numScript = (value?: number) => ScriptCast(this.rootDoc.script).script.run({ self: this.rootDoc, value, _readOnly_: value === undefined }); // Script for checking the outcome of the toggle - const checkResult = Number(numScript?.script.run({ self: this.rootDoc, value: 0, _readOnly_: true }).result ?? 0).toPrecision(NumCast(this.dataDoc.numPrecision, 3)); - + const checkResult = Number(numScript().result ?? 0).toPrecision(NumCast(this.dataDoc.numPrecision, 3)); const label = !FontIconBox.GetShowLabels() ? null : <div className="fontIconBox-label">{this.label}</div>; - if (numBtnType === NumButtonType.Slider) { - const dropdown = ( - <div className="menuButton-dropdownBox" onPointerDown={e => e.stopPropagation()}> - <input - type="range" - step="1" - min={NumCast(this.rootDoc.numBtnMin, 0)} - max={NumCast(this.rootDoc.numBtnMax, 100)} - value={checkResult} - className="menu-slider" - onPointerDown={() => (this._batch = UndoManager.StartBatch('presDuration'))} - onPointerUp={() => this._batch?.end()} - onChange={e => { - e.stopPropagation(); - setValue(Number(e.target.value)); - }} - /> + const dropdown = ( + <div className="menuButton-dropdownBox" onPointerDown={e => e.stopPropagation()}> + <input + className="menu-slider" + type="range" + step="1" + min={NumCast(this.rootDoc.numBtnMin, 0)} + max={NumCast(this.rootDoc.numBtnMax, 100)} + //readOnly={true} + value={checkResult} + onPointerDown={() => (this._batch = UndoManager.StartBatch('num slider changing'))} + onPointerUp={() => this._batch?.end()} + onChange={undoable(e => { + e.stopPropagation(); + numScript(Number(e.target.value)); + }, 'set num value')} + /> + </div> + ); + return ( + <div + className="menuButton numBtn slider" + onPointerDown={e => e.stopPropagation()} + onClick={action(() => { + this.rootDoc.dropDownOpen = !this.rootDoc.dropDownOpen; + this.noTooltip = this.rootDoc.dropDownOpen; + Doc.UnBrushAllDocs(); + })}> + {checkResult} + {label} + {this.rootDoc.dropDownOpen ? dropdown : null} + </div> + ); + } + /** + * Number button + */ + @computed get numberDropdownButton() { + const numScript = (value?: number) => ScriptCast(this.rootDoc.script)?.script.run({ self: this.rootDoc, value, _readOnly_: value === undefined }); + + const checkResult = Number(numScript().result ?? 0).toPrecision(NumCast(this.dataDoc.numPrecision, 3)); + + const items: number[] = []; + for (let i = 0; i < 100; i += 2) items.push(i); + + const list = items.map(value => { + return ( + <div + className="list-item" + key={`${value}`} + style={{ + backgroundColor: value.toString() === checkResult ? Colors.LIGHT_BLUE : undefined, + }} + onClick={undoable(value => numScript(value), `${this.rootDoc.title} button set from list`)}> + {value} </div> ); - return ( + }); + return ( + <div className="menuButton numBtn list"> + <div className="button" onClick={undoable(e => numScript(Number(checkResult) - 1), `${this.rootDoc.title} decrement value`)}> + <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon="minus" /> + </div> <div - className={`menuButton ${this.type} ${numBtnType}`} - onPointerDown={e => e.stopPropagation()} + className={`button ${'number'}`} + onPointerDown={e => { + e.stopPropagation(); + e.preventDefault(); + }} onClick={action(() => { this.rootDoc.dropDownOpen = !this.rootDoc.dropDownOpen; this.noTooltip = this.rootDoc.dropDownOpen; Doc.UnBrushAllDocs(); })}> - {checkResult} - {label} - {this.rootDoc.dropDownOpen ? dropdown : null} + <input style={{ width: 30 }} className="button-input" type="number" value={checkResult} readOnly={true} onChange={undoable(e => numScript(Number(e.target.value)), `${this.rootDoc.title} button set value`)} /> + </div> + <div className={`button`} onClick={undoable(e => numScript(Number(checkResult) + 1), `${this.rootDoc.title} increment value`)}> + <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={'plus'} /> </div> - ); - } else if (numBtnType === NumButtonType.DropdownOptions) { - const items: number[] = []; - for (let i = 0; i < 100; i++) { - if (i % 2 === 0) { - items.push(i); - } - } - const list = items.map(value => { - return ( - <div - className="list-item" - key={`${value}`} - style={{ - backgroundColor: value.toString() === checkResult ? Colors.LIGHT_BLUE : undefined, - }} - onClick={() => setValue(value)}> - {value} - </div> - ); - }); - return ( - <div className={`menuButton ${this.type} ${numBtnType}`}> - <div className={`button`} onClick={action(e => setValue(Number(checkResult) - 1))}> - <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={'minus'} /> - </div> - <div - className={`button ${'number'}`} - onPointerDown={e => { - e.stopPropagation(); - e.preventDefault(); - }} - onClick={action(() => { - this.rootDoc.dropDownOpen = !this.rootDoc.dropDownOpen; - this.noTooltip = this.rootDoc.dropDownOpen; - Doc.UnBrushAllDocs(); - })}> - <input style={{ width: 30 }} className="button-input" type="number" value={checkResult} onChange={undoBatch(action(e => setValue(Number(e.target.value))))} /> - </div> - <div className={`button`} onClick={action(e => setValue(Number(checkResult) + 1))}> - <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={'plus'} /> - </div> - {this.rootDoc.dropDownOpen ? ( - <div> - <div className="menuButton-dropdownList" style={{ left: '25%' }}> - {list} - </div> - <div - className="dropbox-background" - onClick={action(e => { - e.stopPropagation(); - this.rootDoc.dropDownOpen = false; - this.noTooltip = false; - Doc.UnBrushAllDocs(); - })} - /> + {this.rootDoc.dropDownOpen ? ( + <div> + <div className="menuButton-dropdownList" style={{ left: '25%' }}> + {list} </div> - ) : null} - </div> - ); - } else { - return <div />; - } + <div + className="dropbox-background" + onClick={action(e => { + e.stopPropagation(); + this.rootDoc.dropDownOpen = false; + this.noTooltip = false; + Doc.UnBrushAllDocs(); + })} + /> + </div> + ) : null} + </div> + ); + } + /** + * Number button + */ + @computed get numberInlineButton() { + return <div />; } /** @@ -290,7 +291,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() { const selected = SelectionManager.Docs().lastElement(); if (selected) { if (StrCast(selected.type) === DocumentType.COL) { - text = StrCast(selected._viewType); + text = StrCast(selected._type_collection); } else { dropdown = false; text = selected.type === DocumentType.RTF ? 'Text' : StrCast(selected.type); @@ -313,12 +314,12 @@ export class FontIconBox extends DocComponent<ButtonProps>() { .map(value => ( <div className="list-item" - key={`${value}`} + key={value} style={{ fontFamily: script.script.originalScript.startsWith('{ return setFont') ? value : undefined, backgroundColor: value === text ? Colors.LIGHT_BLUE : undefined, }} - onClick={undoBatch(() => script.script.run({ self: this.rootDoc, value }))}> + onClick={undoable(() => script.script.run({ self: this.rootDoc, value }), value)}> {value[0].toUpperCase() + value.slice(1)} </div> )); @@ -505,7 +506,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() { <div className="menuButton editableText"> <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={'lock'} /> <div style={{ width: 'calc(100% - .875em)', paddingLeft: '4px' }}> - <EditableView GetValue={() => script?.script.run({ value: '', _readOnly_: true }).result} SetValue={setValue} contents={checkResult} /> + <EditableView GetValue={() => script?.script.run({ value: '', _readOnly_: true }).result} SetValue={setValue} oneLine={true} contents={checkResult} /> </div> </div> ); @@ -528,7 +529,9 @@ export class FontIconBox extends DocComponent<ButtonProps>() { case ButtonType.EditableText: return this.editableText; case ButtonType.DropdownList: button = this.dropdownListButton; break; case ButtonType.ColorButton: button = this.colorButton; break; - case ButtonType.NumberButton: button = this.numberButton; break; + case ButtonType.NumberDropdownButton: button = this.numberDropdownButton; break; + case ButtonType.NumberInlineButton: button = this.numberInlineButton; break; + case ButtonType.NumberSliderButton: button = this.numberSliderButton; break; case ButtonType.DropdownButton: button = this.dropdownButton; break; case ButtonType.ToggleButton: button = this.toggleButton; break; case ButtonType.TextButton: @@ -568,7 +571,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() { // toggle: Set overlay status of selected document ScriptingGlobals.add(function setView(view: string) { const selected = SelectionManager.Docs().lastElement(); - selected ? (selected._viewType = view) : console.log('[FontIconBox.tsx] changeView failed'); + selected ? (selected._type_collection = view) : console.log('[FontIconBox.tsx] changeView failed'); }); // toggle: Set overlay status of selected document @@ -613,7 +616,7 @@ ScriptingGlobals.add(function setHeaderColor(color?: string, checkResult?: boole } Doc.SharingDoc().userColor = undefined; Doc.GetProto(Doc.SharingDoc()).userColor = color; - Doc.UserDoc().showTitle = color === 'transparent' ? undefined : StrCast(Doc.UserDoc().showTitle, 'creationDate'); + Doc.UserDoc().layout_showTitle = color === 'transparent' ? undefined : StrCast(Doc.UserDoc().layout_showTitle, 'author_date'); }); // toggle: Set overlay status of selected document @@ -626,41 +629,42 @@ ScriptingGlobals.add(function toggleOverlay(checkResult?: boolean) { selected ? selected.props.CollectionFreeFormDocumentView?.().float() : console.log('[FontIconBox.tsx] toggleOverlay failed'); }); -ScriptingGlobals.add(function showFreeform(attr: 'grid' | 'snapline' | 'clusters' | 'arrange' | 'viewAll', checkResult?: boolean) { +ScriptingGlobals.add(function showFreeform(attr: 'flashcards' | 'grid' | 'snaplines' | 'clusters' | 'arrange' | 'viewAll', checkResult?: boolean) { const selected = SelectionManager.Docs().lastElement(); // prettier-ignore - const map: Map<'grid' | 'snapline' | 'clusters' | 'arrange'| 'viewAll', { undo: boolean, checkResult: (doc:Doc) => any; setDoc: (doc:Doc) => void;}> = new Map([ + const map: Map<'flashcards' | 'grid' | 'snaplines' | 'clusters' | 'arrange'| 'viewAll', { waitForRender?: boolean, checkResult: (doc:Doc) => any; setDoc: (doc:Doc) => void;}> = new Map([ ['grid', { - undo: false, - checkResult: (doc:Doc) => doc._backgroundGridShow, - setDoc: (doc:Doc) => doc._backgroundGridShow = !doc._backgroundGridShow, + checkResult: (doc:Doc) => doc._freeform_backgroundGrid, + setDoc: (doc:Doc) => doc._freeform_backgroundGrid = !doc._freeform_backgroundGrid, }], - ['snapline', { - undo: false, - checkResult: (doc:Doc) => doc.showSnapLines, - setDoc: (doc:Doc) => doc._showSnapLines = !doc._showSnapLines, + ['snaplines', { + checkResult: (doc:Doc) => doc._freeform_snapLines, + setDoc: (doc:Doc) => doc._freeform_snapLines = !doc._freeform_snapLines, }], ['viewAll', { - undo: false, - checkResult: (doc:Doc) => doc._fitContentsToBox, - setDoc: (doc:Doc) => doc._fitContentsToBox = !doc._fitContentsToBox, + checkResult: (doc:Doc) => doc._freeform_fitContentsToBox, + setDoc: (doc:Doc) => doc._freeform_fitContentsToBox = !doc._freeform_fitContentsToBox, }], ['clusters', { - undo: false, - checkResult: (doc:Doc) => doc._useClusters, - setDoc: (doc:Doc) => doc._useClusters = !doc._useClusters, + waitForRender: true, // flags that undo batch should terminate after a re-render giving the script the chance to fire + checkResult: (doc:Doc) => doc._freeform_useClusters, + setDoc: (doc:Doc) => doc._freeform_useClusters = !doc._freeform_useClusters, }], ['arrange', { - undo: true, + waitForRender: true, // flags that undo batch should terminate after a re-render giving the script the chance to fire checkResult: (doc:Doc) => doc._autoArrange, setDoc: (doc:Doc) => doc._autoArrange = !doc._autoArrange, }], - ]); + ['flashcards', { + checkResult: (doc:Doc) => Doc.UserDoc().defaultToFlashcards, + setDoc: (doc:Doc) => Doc.UserDoc().defaultToFlashcards = !Doc.UserDoc().defaultToFlashcards, + }], + ]); if (checkResult) { return map.get(attr)?.checkResult(selected) ? Colors.MEDIUM_BLUE : 'transparent'; } - const batch = map.get(attr)?.undo ? UndoManager.StartBatch('set feature') : { end: () => {} }; + const batch = map.get(attr)?.waitForRender ? UndoManager.StartBatch('set freeform attribute') : { end: () => {} }; SelectionManager.Docs().map(dv => map.get(attr)?.setDoc(dv)); setTimeout(() => batch.end(), 100); }); @@ -754,8 +758,8 @@ export function createInkGroup(inksToGroup?: Doc[], isSubGroup?: boolean) { action(d => { const x = NumCast(d.x); const y = NumCast(d.y); - const width = d[WidthSym](); - const height = d[HeightSym](); + const width = d[Width](); + const height = d[Height](); bounds.push({ x, y, width, height }); }) ); @@ -792,8 +796,8 @@ export function createInkGroup(inksToGroup?: Doc[], isSubGroup?: boolean) { // TODO: nda - this is the code to actually get a new grouped collection const newCollection = marqViewRef?.getCollection(selected, undefined, true); if (newCollection) { - newCollection.height = newCollection[HeightSym](); - newCollection.width = newCollection[WidthSym](); + newCollection.height = newCollection[Height](); + newCollection.width = newCollection[Width](); } // nda - bug: when deleting a stroke before leaving writing mode, delete the stroke from unprocessed ink docs @@ -850,8 +854,8 @@ ScriptingGlobals.add(function setInkProperty(option: 'inkMask' | 'fillColor' | ' // prettier-ignore const map: Map<'inkMask' | 'fillColor' | 'strokeWidth' | 'strokeColor', { checkResult: () => any; setInk: (doc: Doc) => void; setMode: () => void }> = new Map([ ['inkMask', { - checkResult: () => ((selected?.type === DocumentType.INK ? BoolCast(selected.isInkMask) : ActiveIsInkMask()) ? Colors.MEDIUM_BLUE : 'transparent'), - setInk: (doc: Doc) => (doc.isInkMask = !doc.isInkMask), + checkResult: () => ((selected?.type === DocumentType.INK ? BoolCast(selected.stroke_isInkMask) : ActiveIsInkMask()) ? Colors.MEDIUM_BLUE : 'transparent'), + setInk: (doc: Doc) => (doc.stroke_isInkMask = !doc.stroke_isInkMask), setMode: () => selected?.type !== DocumentType.INK && SetActiveIsInkMask(!ActiveIsInkMask()), }], ['fillColor', { @@ -860,8 +864,8 @@ ScriptingGlobals.add(function setInkProperty(option: 'inkMask' | 'fillColor' | ' setMode: () => SetActiveFillColor(StrCast(value)), }], [ 'strokeWidth', { - checkResult: () => (selected?.type === DocumentType.INK ? NumCast(selected.strokeWidth) : ActiveInkWidth()), - setInk: (doc: Doc) => (doc.strokeWidth = NumCast(value)), + checkResult: () => (selected?.type === DocumentType.INK ? NumCast(selected.stroke_width) : ActiveInkWidth()), + setInk: (doc: Doc) => (doc.stroke_width = NumCast(value)), setMode: () => SetActiveInkWidth(value.toString()), }], ['strokeColor', { @@ -889,7 +893,7 @@ ScriptingGlobals.add(function webSetURL(url: string, checkResult?: boolean) { if (checkResult) { return StrCast(selected.rootDoc.data, Cast(selected.rootDoc.data, WebField, null)?.url?.href); } - (selected.ComponentView as WebBox).submitURL(url); + selected.ComponentView?.setData?.(url); //selected.rootDoc.data = new WebField(url); } }); @@ -914,23 +918,32 @@ ScriptingGlobals.add(function webBack(checkResult?: boolean) { ScriptingGlobals.add(function toggleSchemaPreview(checkResult?: boolean) { const selected = SelectionManager.Docs().lastElement(); if (checkResult && selected) { - const result: boolean = NumCast(selected.schemaPreviewWidth) > 0; + const result: boolean = NumCast(selected.schema_previewWidth) > 0; if (result) return Colors.MEDIUM_BLUE; else return 'transparent'; } else if (selected) { - if (NumCast(selected.schemaPreviewWidth) > 0) { - selected.schemaPreviewWidth = 0; + if (NumCast(selected.schema_previewWidth) > 0) { + selected.schema_previewWidth = 0; } else { - selected.schemaPreviewWidth = 200; + selected.schema_previewWidth = 200; } } }); +ScriptingGlobals.add(function toggleSingleLineSchema(checkResult?: boolean) { + const selected = SelectionManager.Docs().lastElement(); + if (checkResult && selected) { + return NumCast(selected._schema_singleLine) > 0 ? Colors.MEDIUM_BLUE : 'transparent'; + } + if (selected) { + selected._schema_singleLine = !selected._schema_singleLine; + } +}); /** STACK * groupBy */ ScriptingGlobals.add(function setGroupBy(key: string, checkResult?: boolean) { - SelectionManager.Docs().map(doc => (doc._fontFamily = key)); + SelectionManager.Docs().map(doc => (doc._text_fontFamily = key)); const editorView = RichTextMenu.Instance.TextView?.EditorView; if (checkResult) { return StrCast((editorView ? RichTextMenu.Instance : Doc.UserDoc()).fontFamily); |
