From 932ecd6092bd1b0ac3391309a550bac76cfb0e04 Mon Sep 17 00:00:00 2001 From: Sophie Zhang Date: Thu, 29 Jun 2023 13:56:41 -0400 Subject: undo and redo --- src/client/views/nodes/formattedText/FormattedTextBox.tsx | 1 + 1 file changed, 1 insertion(+) (limited to 'src/client/views/nodes/formattedText') diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 0dc186eaf..3fa5c099b 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -882,6 +882,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { + console.log(this.gptRes); if (resIndex < this.gptRes.length) { this.dataDoc.text = (this.dataDoc.text as RichTextField)?.Text + this.gptRes[resIndex]; setTimeout(() => { -- cgit v1.2.3-70-g09d2 From 162ca319eae256be523f2ee75e7aae7a9a408e37 Mon Sep 17 00:00:00 2001 From: Sophie Zhang Date: Tue, 18 Jul 2023 12:06:21 -0400 Subject: . --- src/client/views/nodes/formattedText/FormattedTextBox.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/client/views/nodes/formattedText') diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 3fa5c099b..307e52cff 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -882,7 +882,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - console.log(this.gptRes); + console.log(this.dataDoc.text); if (resIndex < this.gptRes.length) { this.dataDoc.text = (this.dataDoc.text as RichTextField)?.Text + this.gptRes[resIndex]; setTimeout(() => { @@ -891,6 +891,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { try { let res = await gptAPICall((this.dataDoc.text as RichTextField)?.Text, GPTCallType.COMPLETION); -- cgit v1.2.3-70-g09d2 From 078d595cb498592667a653a937b8ba25bcbf41bb Mon Sep 17 00:00:00 2001 From: Sophie Zhang Date: Thu, 20 Jul 2023 00:54:07 -0400 Subject: refactoring gpt functionalities --- src/client/views/MainView.tsx | 2 + .../views/nodes/formattedText/FormattedTextBox.tsx | 2 +- src/client/views/pdf/AnchorMenu.tsx | 157 ++++++--------------- src/client/views/pdf/GPTPopup/GPTPopup.scss | 12 +- src/client/views/pdf/GPTPopup/GPTPopup.tsx | 102 +++++++++---- src/client/views/pdf/PDFViewer.tsx | 5 + 6 files changed, 130 insertions(+), 150 deletions(-) (limited to 'src/client/views/nodes/formattedText') diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index a129c35cf..f6829a4cb 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -67,6 +67,7 @@ import { PropertiesView } from './PropertiesView'; import { DashboardStyleProvider, DefaultStyleProvider } from './StyleProvider'; import { TopBar } from './topbar/TopBar'; import GenerativeFill from './nodes/generativeFill/GenerativeFill'; +import { GPTPopup } from './pdf/GPTPopup/GPTPopup'; const _global = (window /* browser */ || global) /* node */ as any; @observer @@ -1032,6 +1033,7 @@ export class MainView extends React.Component { {this.snapLines} + {/* */} diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 20a176c58..212d24165 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -909,7 +909,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { try { diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx index 07b2afd91..e6b9cb382 100644 --- a/src/client/views/pdf/AnchorMenu.tsx +++ b/src/client/views/pdf/AnchorMenu.tsx @@ -48,9 +48,6 @@ export class AnchorMenu extends AntimodeMenu { @observable public Status: 'marquee' | 'annotation' | '' = ''; // GPT additions - @observable private GPTpopupText: string = ''; - @observable private loadingGPT: boolean = false; - @observable private showGPTPopup: boolean = false; @observable private GPTMode: GPTPopupMode = GPTPopupMode.SUMMARY; @observable private selectedText: string = ''; @observable private editorView?: EditorView; @@ -58,25 +55,11 @@ export class AnchorMenu extends AntimodeMenu { @observable private highlightRange: number[] | undefined; private selectionRange: number[] | undefined; - @action - setGPTPopupVis = (vis: boolean) => { - this.showGPTPopup = vis; - }; @action setGPTMode = (mode: GPTPopupMode) => { this.GPTMode = mode; }; - @action - setGPTPopupText = (txt: string) => { - this.GPTpopupText = txt; - }; - - @action - setLoading = (loading: boolean) => { - this.loadingGPT = loading; - }; - @action setHighlightRange(r: number[] | undefined) { this.highlightRange = r; @@ -130,19 +113,12 @@ export class AnchorMenu extends AntimodeMenu { componentDidMount() { this._disposer2 = reaction( () => this._opacity, - opacity => { - if (!opacity) { - this.setGPTPopupVis(false); - this.setGPTPopupText(''); - } - }, + opacity => {}, { fireImmediately: true } ); this._disposer = reaction( () => SelectionManager.Views().slice(), selected => { - this.setGPTPopupVis(false); - this.setGPTPopupText(''); AnchorMenu.Instance.fadeOut(true); } ); @@ -153,23 +129,22 @@ export class AnchorMenu extends AntimodeMenu { * @param e pointer down event */ gptSummarize = async (e: React.PointerEvent) => { + GPTPopup.Instance.setVisible(true); this.setHighlightRange(undefined); - this.setGPTPopupVis(true); this.setGPTMode(GPTPopupMode.SUMMARY); - this.setLoading(true); + GPTPopup.Instance.setLoading(true); try { const res = await gptAPICall(this.selectedText, GPTCallType.SUMMARY); if (res) { - this.setGPTPopupText(res); + GPTPopup.Instance.setText(res); } else { - this.setGPTPopupText('Something went wrong.'); + GPTPopup.Instance.setText('Something went wrong.'); } } catch (err) { console.error(err); } - - this.setLoading(false); + GPTPopup.Instance.setLoading(false); }; /** @@ -184,9 +159,9 @@ export class AnchorMenu extends AntimodeMenu { const fullText = state.doc.textBetween(0, this.editorView.state.doc.content.size, ' \n'); const selectedText = state.doc.textBetween(sel.from, sel.to); - this.setGPTPopupVis(true); + GPTPopup.Instance.setVisible(true); this.setGPTMode(GPTPopupMode.EDIT); - this.setLoading(true); + GPTPopup.Instance.setLoading(true); try { let res = await gptAPICall(selectedText, GPTCallType.EDIT); @@ -196,16 +171,16 @@ export class AnchorMenu extends AntimodeMenu { const resultText = fullText.slice(0, sel.from - 1) + res + fullText.slice(sel.to - 1); if (res) { - this.setGPTPopupText(resultText); + GPTPopup.Instance.setText(resultText); this.setHighlightRange([sel.from - 1, sel.from - 1 + res.length]); } else { - this.setGPTPopupText('Something went wrong.'); + GPTPopup.Instance.setText('Something went wrong.'); } } catch (err) { console.error(err); } - this.setLoading(false); + GPTPopup.Instance.setLoading(false); }; /** @@ -253,21 +228,18 @@ export class AnchorMenu extends AntimodeMenu { }; @computed get highlighter() { - return - } - tooltip={'Click to Highlight'} - onClick={this.highlightClicked} - colorPicker={this.highlightColor} - color={StrCast(Doc.UserDoc().userColor)} - /> - this.changeHighlightColor(color)} - size={Size.XSMALL} - /> - + return ( + + } + tooltip={'Click to Highlight'} + onClick={this.highlightClicked} + colorPicker={this.highlightColor} + color={StrCast(Doc.UserDoc().userColor)} + /> + this.changeHighlightColor(color)} size={Size.XSMALL} /> + + ); } @action changeHighlightColor = (color: string) => { @@ -312,12 +284,7 @@ export class AnchorMenu extends AntimodeMenu { this.Status === 'marquee' ? ( <> {this.highlighter} - } - color={StrCast(Doc.UserDoc().userColor)} - /> + } color={StrCast(Doc.UserDoc().userColor)} /> {/* GPT Summarize icon only shows up when text is highlighted, not on marquee selection*/} {AnchorMenu.Instance.StartCropDrag === unimplementedFunction && this.canSummarize() && ( Summarize with AI}> @@ -326,7 +293,7 @@ export class AnchorMenu extends AntimodeMenu { )} - { callEditApi={this.gptEdit} replaceText={this.replaceText} mode={this.GPTMode} - /> + /> */} {AnchorMenu.Instance.OnAudio === unimplementedFunction ? null : ( - } - color={StrCast(Doc.UserDoc().userColor)} - /> - )} - {this.canEdit() && ( - } - color={StrCast(Doc.UserDoc().userColor)} - /> + } color={StrCast(Doc.UserDoc().userColor)} /> )} - } - popup={} - color={StrCast(Doc.UserDoc().userColor)} - /> + {this.canEdit() && } color={StrCast(Doc.UserDoc().userColor)} />} + } popup={} color={StrCast(Doc.UserDoc().userColor)} /> {AnchorMenu.Instance.StartCropDrag === unimplementedFunction ? null : ( - } - color={StrCast(Doc.UserDoc().userColor)} - /> + } color={StrCast(Doc.UserDoc().userColor)} /> )} ) : ( <> - {this.Delete !== returnFalse && } - color={StrCast(Doc.UserDoc().userColor)} - />} - {this.PinToPres !== returnFalse && } - color={StrCast(Doc.UserDoc().userColor)} - />} - {this.ShowTargetTrail !== returnFalse && } - color={StrCast(Doc.UserDoc().userColor)} - />} - {this.IsTargetToggler !== returnFalse && } - color={StrCast(Doc.UserDoc().userColor)} - />} + {this.Delete !== returnFalse && } color={StrCast(Doc.UserDoc().userColor)} />} + {this.PinToPres !== returnFalse && } color={StrCast(Doc.UserDoc().userColor)} />} + {this.ShowTargetTrail !== returnFalse && } color={StrCast(Doc.UserDoc().userColor)} />} + {this.IsTargetToggler !== returnFalse && ( + } + color={StrCast(Doc.UserDoc().userColor)} + /> + )} ); diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.scss b/src/client/views/pdf/GPTPopup/GPTPopup.scss index 44413ede7..2f0ff83e2 100644 --- a/src/client/views/pdf/GPTPopup/GPTPopup.scss +++ b/src/client/views/pdf/GPTPopup/GPTPopup.scss @@ -6,12 +6,6 @@ $button: #5b97ff; $highlightedText: #82e0ff; .summary-box { - display: flex; - flex-direction: column; - justify-content: space-between; - background-color: #ffffff; - box-shadow: 0 2px 5px #7474748d; - color: $textgrey; position: fixed; bottom: 10px; right: 10px; @@ -21,6 +15,12 @@ $highlightedText: #82e0ff; padding: 15px; padding-bottom: 0; z-index: 999; + display: flex; + flex-direction: column; + justify-content: space-between; + background-color: #ffffff; + box-shadow: 0 2px 5px #7474748d; + color: $textgrey; .summary-heading { display: flex; diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.tsx b/src/client/views/pdf/GPTPopup/GPTPopup.tsx index 8bd060d4f..9f28cb5d1 100644 --- a/src/client/views/pdf/GPTPopup/GPTPopup.tsx +++ b/src/client/views/pdf/GPTPopup/GPTPopup.tsx @@ -5,56 +5,96 @@ import { observer } from 'mobx-react'; import ReactLoading from 'react-loading'; import Typist from 'react-typist'; import { Doc } from '../../../../fields/Doc'; -import { Docs } from '../../../documents/Documents'; +import { DocUtils, Docs } from '../../../documents/Documents'; import './GPTPopup.scss'; +import { Button, IconButton } from 'browndash-components'; +import { StrCast } from '../../../../fields/Types'; export enum GPTPopupMode { SUMMARY, EDIT, } -interface GPTPopupProps { - visible: boolean; - text: string; - loading: boolean; - mode: GPTPopupMode; - callSummaryApi: (e: React.PointerEvent) => Promise; - callEditApi: (e: React.PointerEvent) => Promise; - replaceText: (replacement: string) => void; - highlightRange?: number[]; -} +interface GPTPopupProps {} @observer export class GPTPopup extends React.Component { static Instance: GPTPopup; @observable - private done: boolean = false; + public visible: boolean = false; + @action + public setVisible = (vis: boolean) => { + this.visible = vis; + }; @observable - private sidebarId: string = ''; + public loading: boolean = false; + @action + public setLoading = (loading: boolean) => { + this.loading = loading; + }; + @observable + public text: string = ''; + @action + public setText = (text: string) => { + this.text = text; + }; + @observable + public mode: GPTPopupMode = GPTPopupMode.SUMMARY; + @action + public setMode = (mode: GPTPopupMode) => { + this.mode = mode; + }; + @observable + public highlightRange: number[] = []; + @action callSummaryApi = () => {}; + @action callEditApi = () => {}; + @action replaceText = (replacement: string) => {}; + + @observable + private done: boolean = false; @action public setDone = (done: boolean) => { this.done = done; }; + @observable + private sidebarId: string = ''; @action public setSidebarId = (id: string) => { this.sidebarId = id; }; + // reference + // if (focusNode) { + // const anchor = srcWeb?.ComponentView?.getAnchor?.(true); + // anchor && DocUtils.MakeLink(htmlDoc, anchor, {}); + // } + @observable + private pdfAnchor: Doc | undefined; + @action + public setPdfAnchor = (anchor: Doc) => { + this.pdfAnchor = anchor; + }; + public addDoc: (doc: Doc | Doc[], sidebarKey?: string | undefined) => boolean = () => false; /** * Transfers the summarization text to a sidebar annotation text document. */ private transferToText = () => { - const newDoc = Docs.Create.TextDocument(this.props.text.trim(), { + const newDoc = Docs.Create.TextDocument(this.text.trim(), { _width: 200, _height: 50, _layout_fitWidth: true, _layout_autoHeight: true, }); this.addDoc(newDoc, this.sidebarId); + if (this.pdfAnchor) { + DocUtils.MakeLink(newDoc, this.pdfAnchor, { + link_relationship: 'GPT Summary', + }); + } }; constructor(props: GPTPopupProps) { @@ -63,7 +103,7 @@ export class GPTPopup extends React.Component { } componentDidUpdate = () => { - if (this.props.loading) { + if (this.loading) { this.setDone(false); } }; @@ -73,10 +113,10 @@ export class GPTPopup extends React.Component {
{this.heading('SUMMARY')}
- {!this.props.loading && + {!this.loading && (!this.done ? ( { @@ -84,18 +124,18 @@ export class GPTPopup extends React.Component { this.setDone(true); }, 500); }}> - {this.props.text} + {this.text} ) : ( - this.props.text + this.text ))}
- {!this.props.loading && ( + {!this.loading && (
{this.done ? ( <> - + */} + } color={StrCast(Doc.UserDoc().userVariantColor)} /> + @@ -174,14 +216,14 @@ export class GPTPopup extends React.Component { heading = (headingText: string) => (
- {this.props.loading && } + {this.loading && }
); render() { return ( -
- {this.props.mode === GPTPopupMode.SUMMARY ? this.summaryBox() : this.editBox()} +
+ {this.mode === GPTPopupMode.SUMMARY ? this.summaryBox() : this.editBox()}
); } diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 0fd93868a..4fc31ffe3 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -423,6 +423,11 @@ export class PDFViewer extends React.Component { // Changing which document to add the annotation to (the currently selected PDF) GPTPopup.Instance.setSidebarId('data_sidebar'); + const anchor = this._getAnchor(undefined, false); + if (anchor) { + console.log(anchor); + GPTPopup.Instance.setPdfAnchor(anchor); + } GPTPopup.Instance.addDoc = this.props.sidebarAddDoc; }; -- cgit v1.2.3-70-g09d2 From fec79d2b5b8feb361e489c9ee41ee720507d0806 Mon Sep 17 00:00:00 2001 From: Sophie Zhang Date: Thu, 27 Jul 2023 13:23:42 -0400 Subject: changes --- report.20230720.011057.28881.0.001.json | 1269 ++++++++++++++++++++ src/client/apis/gpt/GPT.ts | 28 +- src/client/util/DragManager.ts | 4 +- src/client/views/collections/TabDocView.tsx | 6 +- .../CollectionFreeFormLinkView.tsx | 8 +- src/client/views/global/globalScripts.ts | 50 +- src/client/views/nodes/WebBox.tsx | 5 + .../views/nodes/formattedText/FormattedTextBox.tsx | 89 +- src/client/views/pdf/AnchorMenu.tsx | 21 +- src/client/views/pdf/GPTPopup/GPTPopup.scss | 52 + src/client/views/pdf/GPTPopup/GPTPopup.tsx | 129 +- src/client/views/pdf/PDFViewer.tsx | 3 +- 12 files changed, 1530 insertions(+), 134 deletions(-) create mode 100644 report.20230720.011057.28881.0.001.json (limited to 'src/client/views/nodes/formattedText') diff --git a/report.20230720.011057.28881.0.001.json b/report.20230720.011057.28881.0.001.json new file mode 100644 index 000000000..5c72c0c91 --- /dev/null +++ b/report.20230720.011057.28881.0.001.json @@ -0,0 +1,1269 @@ + +{ + "header": { + "reportVersion": 1, + "event": "Allocation failed - JavaScript heap out of memory", + "trigger": "FatalError", + "filename": "report.20230720.011057.28881.0.001.json", + "dumpEventTime": "2023-07-20T01:10:57Z", + "dumpEventTimeStamp": "1689829857721", + "processId": 28881, + "cwd": "/Users/smallwhale/Desktop/Projects/Dash-Web", + "commandLine": [ + "/Users/smallwhale/.nvm/versions/node/v12.16.0/bin/node", + "--max-old-space-size=2048", + "/Users/smallwhale/Desktop/Projects/Dash-Web/node_modules/ts-node-dev/lib/wrap.js", + "/Users/smallwhale/Desktop/Projects/Dash-Web/node_modules/fork-ts-checker-webpack-plugin/lib/service.js" + ], + "nodejsVersion": "v12.16.0", + "wordSize": 64, + "arch": "x64", + "platform": "darwin", + "componentVersions": { + "node": "12.16.0", + "v8": "7.8.279.23-node.31", + "uv": "1.34.0", + "zlib": "1.2.11", + "brotli": "1.0.7", + "ares": "1.15.0", + "modules": "72", + "nghttp2": "1.40.0", + "napi": "5", + "llhttp": "2.0.4", + "http_parser": "2.9.3", + "openssl": "1.1.1d", + "cldr": "35.1", + "icu": "64.2", + "tz": "2019c", + "unicode": "12.1" + }, + "release": { + "name": "node", + "lts": "Erbium", + "headersUrl": "https://nodejs.org/download/release/v12.16.0/node-v12.16.0-headers.tar.gz", + "sourceUrl": "https://nodejs.org/download/release/v12.16.0/node-v12.16.0.tar.gz" + }, + "osName": "Darwin", + "osRelease": "22.4.0", + "osVersion": "Darwin Kernel Version 22.4.0: Mon Mar 6 21:01:02 PST 2023; root:xnu-8796.101.5~3/RELEASE_ARM64_T8112", + "osMachine": "x86_64", + "cpus": [ + { + "model": "Apple M2", + "speed": 2400, + "user": 40342390, + "nice": 0, + "sys": 32818540, + "idle": 263532590, + "irq": 0 + }, + { + "model": "Apple M2", + "speed": 2400, + "user": 37882510, + "nice": 0, + "sys": 28750670, + "idle": 270292020, + "irq": 0 + }, + { + "model": "Apple M2", + "speed": 2400, + "user": 32806560, + "nice": 0, + "sys": 24772270, + "idle": 279705870, + "irq": 0 + }, + { + "model": "Apple M2", + "speed": 2400, + "user": 28917140, + "nice": 0, + "sys": 21505900, + "idle": 287180070, + "irq": 0 + }, + { + "model": "Apple M2", + "speed": 2400, + "user": 52175300, + "nice": 0, + "sys": 11670040, + "idle": 274363170, + "irq": 0 + }, + { + "model": "Apple M2", + "speed": 2400, + "user": 30406640, + "nice": 0, + "sys": 8969580, + "idle": 298959950, + "irq": 0 + }, + { + "model": "Apple M2", + "speed": 2400, + "user": 21936370, + "nice": 0, + "sys": 6476860, + "idle": 310114030, + "irq": 0 + }, + { + "model": "Apple M2", + "speed": 2400, + "user": 16048180, + "nice": 0, + "sys": 4956530, + "idle": 317649610, + "irq": 0 + } + ], + "networkInterfaces": [ + { + "name": "lo0", + "internal": true, + "mac": "00:00:00:00:00:00", + "address": "127.0.0.1", + "netmask": "255.0.0.0", + "family": "IPv4" + }, + { + "name": "lo0", + "internal": true, + "mac": "00:00:00:00:00:00", + "address": "::1", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + "family": "IPv6", + "scopeid": 0 + }, + { + "name": "lo0", + "internal": true, + "mac": "00:00:00:00:00:00", + "address": "fe80::1", + "netmask": "ffff:ffff:ffff:ffff::", + "family": "IPv6", + "scopeid": 1 + }, + { + "name": "anpi0", + "internal": false, + "mac": "42:10:d5:5b:93:9e", + "address": "fe80::4010:d5ff:fe5b:939e", + "netmask": "ffff:ffff:ffff:ffff::", + "family": "IPv6", + "scopeid": 4 + }, + { + "name": "anpi1", + "internal": false, + "mac": "42:10:d5:5b:93:9f", + "address": "fe80::4010:d5ff:fe5b:939f", + "netmask": "ffff:ffff:ffff:ffff::", + "family": "IPv6", + "scopeid": 5 + }, + { + "name": "en0", + "internal": false, + "mac": "9c:3e:53:8e:59:0e", + "address": "fe80::2b:dde:e859:46b8", + "netmask": "ffff:ffff:ffff:ffff::", + "family": "IPv6", + "scopeid": 12 + }, + { + "name": "en0", + "internal": false, + "mac": "9c:3e:53:8e:59:0e", + "address": "192.168.1.154", + "netmask": "255.255.255.0", + "family": "IPv4" + }, + { + "name": "en0", + "internal": false, + "mac": "9c:3e:53:8e:59:0e", + "address": "2600:4040:572e:2f00:18fe:e894:e23c:f4c2", + "netmask": "ffff:ffff:ffff:ffff::", + "family": "IPv6", + "scopeid": 0 + }, + { + "name": "en0", + "internal": false, + "mac": "9c:3e:53:8e:59:0e", + "address": "2600:4040:572e:2f00:c182:d0ad:6e64:1fae", + "netmask": "ffff:ffff:ffff:ffff::", + "family": "IPv6", + "scopeid": 0 + }, + { + "name": "awdl0", + "internal": false, + "mac": "b6:6c:9a:3c:a7:93", + "address": "fe80::b46c:9aff:fe3c:a793", + "netmask": "ffff:ffff:ffff:ffff::", + "family": "IPv6", + "scopeid": 13 + }, + { + "name": "llw0", + "internal": false, + "mac": "b6:6c:9a:3c:a7:93", + "address": "fe80::b46c:9aff:fe3c:a793", + "netmask": "ffff:ffff:ffff:ffff::", + "family": "IPv6", + "scopeid": 14 + }, + { + "name": "utun0", + "internal": false, + "mac": "00:00:00:00:00:00", + "address": "fe80::be27:76ec:8f11:5429", + "netmask": "ffff:ffff:ffff:ffff::", + "family": "IPv6", + "scopeid": 15 + }, + { + "name": "utun1", + "internal": false, + "mac": "00:00:00:00:00:00", + "address": "fe80::ce81:b1c:bd2c:69e", + "netmask": "ffff:ffff:ffff:ffff::", + "family": "IPv6", + "scopeid": 16 + }, + { + "name": "utun2", + "internal": false, + "mac": "00:00:00:00:00:00", + "address": "fe80::7707:8801:aef4:1907", + "netmask": "ffff:ffff:ffff:ffff::", + "family": "IPv6", + "scopeid": 17 + }, + { + "name": "utun3", + "internal": false, + "mac": "00:00:00:00:00:00", + "address": "fe80::a4f8:a3ce:851e:23dd", + "netmask": "ffff:ffff:ffff:ffff::", + "family": "IPv6", + "scopeid": 18 + }, + { + "name": "utun4", + "internal": false, + "mac": "00:00:00:00:00:00", + "address": "fe80::8d47:6641:b300:bde8", + "netmask": "ffff:ffff:ffff:ffff::", + "family": "IPv6", + "scopeid": 19 + }, + { + "name": "utun5", + "internal": false, + "mac": "00:00:00:00:00:00", + "address": "fe80::7c36:c665:d5f7:49d7", + "netmask": "ffff:ffff:ffff:ffff::", + "family": "IPv6", + "scopeid": 20 + }, + { + "name": "utun6", + "internal": false, + "mac": "00:00:00:00:00:00", + "address": "fe80::10d8:db7a:d714:7746", + "netmask": "ffff:ffff:ffff:ffff::", + "family": "IPv6", + "scopeid": 21 + } + ], + "host": "Sophies-MBP" + }, + "javascriptStack": { + "message": "No stack.", + "stack": [ + "Unavailable." + ] + }, + "nativeStack": [ + { + "pc": "0x000000010015c8ca", + "symbol": "report::TriggerNodeReport(v8::Isolate*, node::Environment*, char const*, char const*, std::__1::basic_string, std::__1::allocator> const&, v8::Local) [/Users/smallwhale/.nvm/versions/node/v12.16.0/bin/node]" + }, + { + "pc": "0x0000000100080f3e", + "symbol": "node::OnFatalError(char const*, char const*) [/Users/smallwhale/.nvm/versions/node/v12.16.0/bin/node]" + }, + { + "pc": "0x0000000100185467", + "symbol": "v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [/Users/smallwhale/.nvm/versions/node/v12.16.0/bin/node]" + }, + { + "pc": "0x0000000100185403", + "symbol": "v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [/Users/smallwhale/.nvm/versions/node/v12.16.0/bin/node]" + }, + { + "pc": "0x000000010030b5f5", + "symbol": "v8::internal::Heap::FatalProcessOutOfMemory(char const*) [/Users/smallwhale/.nvm/versions/node/v12.16.0/bin/node]" + }, + { + "pc": "0x000000010030ccc4", + "symbol": "v8::internal::Heap::RecomputeLimits(v8::internal::GarbageCollector) [/Users/smallwhale/.nvm/versions/node/v12.16.0/bin/node]" + }, + { + "pc": "0x0000000100309b37", + "symbol": "v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector, v8::GCCallbackFlags) [/Users/smallwhale/.nvm/versions/node/v12.16.0/bin/node]" + }, + { + "pc": "0x0000000100307afd", + "symbol": "v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [/Users/smallwhale/.nvm/versions/node/v12.16.0/bin/node]" + }, + { + "pc": "0x00000001003132ba", + "symbol": "v8::internal::Heap::AllocateRawWithLightRetry(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [/Users/smallwhale/.nvm/versions/node/v12.16.0/bin/node]" + }, + { + "pc": "0x0000000100313341", + "symbol": "v8::internal::Heap::AllocateRawWithRetryOrFail(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [/Users/smallwhale/.nvm/versions/node/v12.16.0/bin/node]" + }, + { + "pc": "0x00000001002e065b", + "symbol": "v8::internal::Factory::NewFillerObject(int, bool, v8::internal::AllocationType, v8::internal::AllocationOrigin) [/Users/smallwhale/.nvm/versions/node/v12.16.0/bin/node]" + }, + { + "pc": "0x0000000100618a18", + "symbol": "v8::internal::Runtime_AllocateInYoungGeneration(int, unsigned long*, v8::internal::Isolate*) [/Users/smallwhale/.nvm/versions/node/v12.16.0/bin/node]" + }, + { + "pc": "0x0000000100950c19", + "symbol": "Builtins_CEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit [/Users/smallwhale/.nvm/versions/node/v12.16.0/bin/node]" + }, + { + "pc": "0x00000001008d2291", + "symbol": "Builtins_FastNewObject [/Users/smallwhale/.nvm/versions/node/v12.16.0/bin/node]" + } + ], + "javascriptHeap": { + "totalMemory": 2152435712, + "totalCommittedMemory": 2150538320, + "usedMemory": 2139294040, + "availableMemory": 47735856, + "memoryLimit": 2197815296, + "heapSpaces": { + "read_only_space": { + "memorySize": 262144, + "committedMemory": 33088, + "capacity": 32808, + "used": 32808, + "available": 0 + }, + "new_space": { + "memorySize": 2097152, + "committedMemory": 1236968, + "capacity": 1047456, + "used": 203328, + "available": 844128 + }, + "old_space": { + "memorySize": 1956003840, + "committedMemory": 1955767472, + "capacity": 1948209048, + "used": 1947744360, + "available": 464688 + }, + "code_space": { + "memorySize": 14061568, + "committedMemory": 13610624, + "capacity": 12121760, + "used": 12121760, + "available": 0 + }, + "map_space": { + "memorySize": 1576960, + "committedMemory": 1456120, + "capacity": 1257120, + "used": 1257120, + "available": 0 + }, + "large_object_space": { + "memorySize": 178384896, + "committedMemory": 178384896, + "capacity": 177931880, + "used": 177931880, + "available": 0 + }, + "code_large_object_space": { + "memorySize": 49152, + "committedMemory": 49152, + "capacity": 2784, + "used": 2784, + "available": 0 + }, + "new_large_object_space": { + "memorySize": 0, + "committedMemory": 0, + "capacity": 1047456, + "used": 0, + "available": 1047456 + } + } + }, + "resourceUsage": { + "userCpuSeconds": 312.946, + "kernelCpuSeconds": 137.981, + "cpuConsumptionPercent": 62.0257, + "maxRss": 2062897119232, + "pageFaults": { + "IORequired": 658, + "IONotRequired": 43579208 + }, + "fsActivity": { + "reads": 0, + "writes": 0 + } + }, + "libuv": [ + ], + "environmentVariables": { + "npm_config_save_dev": "", + "npm_config_legacy_bundling": "", + "npm_config_dry_run": "", + "npm_package_dependencies_translate_google_api": "^1.0.4", + "npm_package_dependencies_request": "^2.88.2", + "npm_package_dependencies_express_flash": "0.0.2", + "npm_package_dependencies__fortawesome_fontawesome_svg_core": "^6.3.0", + "NVM_INC": "/Users/smallwhale/.nvm/versions/node/v12.16.0/include/node", + "npm_config_viewer": "man", + "npm_config_only": "", + "npm_config_commit_hooks": "true", + "npm_config_browser": "", + "npm_package_gitHead": "e11aa60b774d457cb016bb0f375ce092f0a733af", + "npm_package_dependencies_webpack_dev_middleware": "^5.3.1", + "npm_package_dependencies_webpack_cli": "^4.10.0", + "npm_package_devDependencies_prettier": "^2.7.1", + "npm_package_devDependencies_awesome_typescript_loader": "^5.2.1", + "npm_package_devDependencies__types_archiver": "^3.1.1", + "MANPATH": "/Users/smallwhale/.nvm/versions/node/v12.16.0/share/man:/Users/smallwhale/.nvm/versions/node/v18.16.0/share/man:/opt/homebrew/share/man:/usr/share/man:/usr/local/share/man:/Users/smallwhale/.nvm/versions/node/v18.16.0/share/man:/opt/homebrew/share/man::", + "npm_config_also": "", + "npm_package_dependencies_react_jsx_parser": "^1.29.0", + "npm_package_dependencies_mongoose": "^5.13.14", + "npm_package_dependencies_connect_flash": "^0.1.1", + "npm_package_browser_child_process": "false", + "npm_config_sign_git_commit": "", + "npm_config_rollback": "true", + "npm_package_dependencies_material_ui": "^0.20.2", + "npm_package_devDependencies__types_sharp": "^0.23.1", + "npm_package_devDependencies__types_passport_local": "^1.0.34", + "npm_package_devDependencies__types_dotenv": "^6.1.1", + "npm_package_devDependencies__types_cookie_parser": "^1.4.2", + "TERM_PROGRAM": "vscode", + "NODE": "/Users/smallwhale/.nvm/versions/node/v12.16.0/bin/node", + "npm_config_usage": "", + "npm_config_audit": "true", + "npm_package_dependencies_reveal_js": "^4.3.0", + "npm_package_dependencies_process": "^0.11.10", + "npm_package_dependencies_pdfjs": "^2.4.7", + "npm_package_dependencies_html_to_image": "^0.1.3", + "npm_package_devDependencies_file_loader": "^3.0.1", + "npm_package_devDependencies__types_express_flash": "0.0.0", + "npm_package_scripts_monitor": "cross-env MONITORED=true NODE_OPTIONS=--max_old_space_size=4096 ts-node src/server/index.ts", + "INIT_CWD": "/Users/smallwhale/Desktop/Projects/Dash-Web", + "npm_package_dependencies_rehype_raw": "^6.1.1", + "npm_package_dependencies_react_audio_waveform": "0.0.5", + "npm_package_dependencies_path_browserify": "^1.0.1", + "npm_package_dependencies_nodemailer": "^5.1.1", + "npm_package_dependencies_axios": "^0.19.2", + "npm_package_devDependencies_typescript": "^4.7.4", + "NVM_CD_FLAGS": "-q", + "npm_config_globalignorefile": "/Users/smallwhale/.nvm/versions/node/v12.16.0/etc/npmignore", + "npm_package_dependencies_react_grid_layout": "^1.3.4", + "npm_package_dependencies_prosemirror_find_replace": "^0.9.0", + "npm_package_dependencies_normalize_css": "^8.0.1", + "npm_package_devDependencies_mocha": "^5.2.0", + "npm_package_devDependencies__types_express_session": "^1.17.5", + "TERM": "xterm-256color", + "SHELL": "/bin/zsh", + "npm_config_shell": "/bin/zsh", + "npm_config_maxsockets": "50", + "npm_config_init_author_url": "", + "npm_package_dependencies_prosemirror_dev_tools": "^3.1.0", + "npm_package_dependencies_p_limit": "^2.2.0", + "npm_package_dependencies_bson": "^4.6.1", + "npm_package_dependencies__types_dom_speech_recognition": "0.0.1", + "npm_package_dependencies__emotion_styled": "^11.11.0", + "npm_package_devDependencies_style_loader": "^0.23.1", + "npm_package_devDependencies__types_react_datepicker": "^3.1.8", + "npm_config_shrinkwrap": "true", + "npm_config_parseable": "", + "npm_config_metrics_registry": "https://registry.npmjs.org/", + "npm_package_dependencies_xregexp": "^4.4.1", + "npm_package_dependencies_shelljs": "^0.8.5", + "npm_package_dependencies_bezier_curve": "^1.0.0", + "npm_package_dependencies__mui_icons_material": "^5.11.16", + "npm_package_devDependencies_tslint": "^5.20.1", + "npm_package_devDependencies__types_react_transition_group": "^4.4.5", + "npm_package_scripts_tsc": "tsc", + "HOMEBREW_REPOSITORY": "/opt/homebrew", + "TMPDIR": "/var/folders/bv/1xck6d7j7bz14bvhgdsllbj40000gn/T/", + "npm_config_timing": "", + "npm_config_init_license": "ISC", + "npm_package_dependencies_socket_io": "^2.5.0", + "npm_package_dependencies_probe_image_size": "^4.0.0", + "npm_package_dependencies_canvas": "^2.9.3", + "npm_package_dependencies__hig_theme_data": "^2.23.1", + "npm_package_devDependencies__types_react_select": "^3.1.2", + "npm_package_devDependencies__types_prosemirror_model": "^1.16.1", + "npm_config_if_present": "", + "npm_package_dependencies_typescript_collections": "^1.3.3", + "npm_package_dependencies_rimraf": "^3.0.0", + "npm_package_dependencies_react_autosuggest": "^9.4.3", + "npm_package_dependencies_flexlayout_react": "^0.3.11", + "npm_package_dependencies_find_in_files": "^0.5.0", + "npm_package_devDependencies__types_chai": "^4.3.0", + "TERM_PROGRAM_VERSION": "1.79.2", + "npm_package_dependencies_prosemirror_inputrules": "^1.1.3", + "npm_package_dependencies_bcrypt_nodejs": "0.0.3", + "npm_package_dependencies_async": "^2.6.2", + "npm_config_sign_git_tag": "", + "npm_config_init_author_email": "", + "npm_config_cache_max": "Infinity", + "npm_package_dependencies_uuid": "^3.4.0", + "npm_package_dependencies_supercluster": "^7.1.4", + "npm_package_dependencies_remark_gfm": "^3.0.1", + "npm_package_dependencies_connect_mongo": "^2.0.3", + "npm_package_dependencies_browser_assert": "^1.2.1", + "npm_package_devDependencies_sass_loader": "^7.3.1", + "ZDOTDIR": "/Users/smallwhale", + "ORIGINAL_XDG_CURRENT_DESKTOP": "undefined", + "MallocNanoZone": "0", + "npm_config_preid": "", + "npm_config_long": "", + "npm_config_local_address": "", + "npm_config_git_tag_version": "true", + "npm_config_cert": "", + "npm_package_dependencies_js_datepicker": "^4.6.6", + "npm_package_devDependencies__types_webpack_hot_middleware": "^2.25.6", + "npm_package_devDependencies__types_mongodb": "^3.6.20", + "npm_package_devDependencies__types_mocha": "^5.2.6", + "TERM_SESSION_ID": "F2049B14-CDC7-4078-A2C4-82A8C869F43E", + "npm_config_registry": "https://registry.npmjs.org/", + "npm_config_noproxy": "", + "npm_config_fetch_retries": "2", + "npm_package_dependencies_react_compound_slider": "^2.5.0", + "npm_package_dependencies_prosemirror_history": "^1.2.0", + "npm_package_devDependencies__types_react_color": "^2.17.6", + "npm_package_devDependencies__types_google_maps_react": "^2.0.5", + "npm_package_devDependencies__types_color": "^3.0.3", + "npm_package_dependencies_react_dom": "^18.2.0", + "npm_package_dependencies_passport_local": "^1.0.0", + "npm_package_dependencies__octokit_core": "^4.0.4", + "npm_package_devDependencies__types_async": "^2.4.1", + "npm_package_scripts_debug": "cross-env NODE_OPTIONS=--max_old_space_size=8192 ts-node-dev --transpile-only --inspect -- src/server/index.ts", + "npm_package_scripts_oldstart": "cross-env NODE_OPTIONS=--max_old_space_size=4096 ts-node-dev --debug -- src/server/index.ts", + "npm_config_versions": "", + "npm_config_message": "%s", + "npm_config_key": "", + "npm_package_readmeFilename": "README.md", + "npm_package_dependencies_react_refresh_typescript": "^2.0.7", + "npm_package_dependencies_image_size": "^0.7.5", + "npm_package_dependencies_html_to_text": "^5.1.1", + "npm_package_dependencies_express_validator": "^5.3.1", + "npm_package_devDependencies_eslint_plugin_jsx_a11y": "^6.6.0", + "npm_package_node_child_process": "empty", + "npm_package_dependencies_react_resizable_rotatable_draggable": "^0.2.0", + "npm_package_dependencies_got": "^12.0.1", + "npm_package_dependencies__types_d3_color": "^2.0.3", + "npm_package_devDependencies_webpack": "^5.69.1", + "npm_package_devDependencies__types_nodemailer": "^4.6.6", + "npm_package_description": "Install Node.js, then, from the project directory, run", + "NVM_DIR": "/Users/smallwhale/.nvm", + "USER": "smallwhale", + "npm_package_dependencies__types_d3_scale": "^3.3.2", + "npm_package_devDependencies_dotenv": "^8.6.0", + "npm_package_devDependencies__types_react": "^18.0.15", + "npm_package_devDependencies__types_prosemirror_transform": "^1.1.5", + "npm_package_devDependencies__types_prosemirror_history": "^1.0.3", + "npm_package_dependencies_readline": "^1.3.0", + "npm_package_dependencies__types_supercluster": "^7.1.0", + "COMMAND_MODE": "unix2003", + "npm_config_globalconfig": "/Users/smallwhale/.nvm/versions/node/v12.16.0/etc/npmrc", + "npm_package_dependencies_depcheck": "^0.9.2", + "npm_package_dependencies__types_web": "0.0.53", + "npm_config_prefer_online": "", + "npm_config_logs_max": "10", + "npm_config_always_auth": "", + "npm_package_dependencies_react_icons": "^4.3.1", + "npm_package_dependencies_passport_google_oauth20": "^2.0.0", + "npm_package_devDependencies_webpack_dev_server": "^3.11.3", + "npm_package_devDependencies__types_brotli": "^1.3.1", + "npm_package_dependencies_url_loader": "^1.1.2", + "npm_package_dependencies_stream_browserify": "^3.0.0", + "npm_package_dependencies_prosemirror_transform": "^1.3.4", + "npm_package_dependencies_lodash": "^4.17.21", + "npm_package_dependencies_i": "^0.3.7", + "npm_package_devDependencies_tslint_loader": "^3.6.0", + "SSH_AUTH_SOCK": "/private/tmp/com.apple.launchd.iMTrb4REX6/Listeners", + "npm_package_dependencies_words_to_numbers": "^1.5.1", + "npm_package_dependencies_valid_url": "^1.0.9", + "npm_package_dependencies_styled_components": "^4.4.1", + "npm_package_dependencies_csv_parser": "^3.0.0", + "npm_package_dependencies_class_transformer": "^0.2.0", + "npm_package_devDependencies_eslint": "^8.36.0", + "npm_package_devDependencies__types_prosemirror_inputrules": "^1.0.4", + "npm_package_devDependencies__types_express": "^4.17.13", + "__CF_USER_TEXT_ENCODING": "0x1F5:0x0:0x0", + "npm_execpath": "/Users/smallwhale/.nvm/versions/node/v12.16.0/lib/node_modules/npm/bin/npm-cli.js", + "npm_config_global_style": "", + "npm_config_cache_lock_retries": "10", + "npm_package_dependencies_wikijs": "^6.3.3", + "npm_package_dependencies_bluebird": "^3.7.2", + "npm_package_devDependencies__types_react_typist": "^2.0.3", + "npm_config_update_notifier": "true", + "npm_config_cafile": "", + "npm_package_dependencies_util": "^0.12.4", + "npm_package_dependencies_raw_loader": "^1.0.0", + "npm_package_dependencies_https_browserify": "^1.0.0", + "npm_package_dependencies_brotli": "^1.3.3", + "npm_package_dependencies__mui_material": "^5.13.1", + "npm_package_dependencies__fortawesome_react_fontawesome": "^0.2.0", + "npm_package_devDependencies__types_passport_google_oauth20": "^2.0.11", + "npm_package_dependencies_cors": "^2.8.5", + "npm_package_dependencies_bezier_js": "^4.1.1", + "npm_package_dependencies__fortawesome_free_brands_svg_icons": "^6.3.0", + "npm_config_heading": "npm", + "npm_config_audit_level": "low", + "npm_package_dependencies_chrome": "^0.1.0", + "npm_package_dependencies__react_three_fiber": "^6.2.3", + "npm_package_devDependencies_eslint_plugin_prettier": "^4.2.1", + "npm_package_devDependencies_copy_webpack_plugin": "^4.6.0", + "npm_package_devDependencies__types_react_measure": "^2.0.8", + "npm_package_devDependencies__types_react_dom": "^18.0.6", + "npm_package_devDependencies__types_mobile_detect": "^1.3.4", + "npm_config_searchlimit": "20", + "npm_config_read_only": "", + "npm_config_offline": "", + "npm_config_fetch_retry_mintimeout": "10000", + "npm_package_dependencies_react_typist": "^2.0.5", + "npm_package_dependencies_mobx_react_devtools": "^6.1.1", + "npm_package_dependencies_md5_file": "^5.0.0", + "npm_package_dependencies_forever_agent": "^0.6.1", + "npm_package_devDependencies__types_xregexp": "^4.4.0", + "npm_package_devDependencies__types_typescript": "^2.0.0", + "npm_package_devDependencies__types_request": "^2.48.8", + "npm_package_devDependencies__types_prosemirror_commands": "^1.0.4", + "npm_config_json": "", + "npm_config_access": "", + "npm_config_argv": "{\"remain\":[],\"cooked\":[\"start\"],\"original\":[\"start\"]}", + "npm_package_dependencies__fortawesome_free_solid_svg_icons": "^6.3.0", + "npm_package_devDependencies__types_socket_io": "^2.1.13", + "PATH": "/Users/smallwhale/.nvm/versions/node/v12.16.0/lib/node_modules/npm/node_modules/npm-lifecycle/node-gyp-bin:/Users/smallwhale/Desktop/Projects/Dash-Web/node_modules/.bin:/Users/smallwhale/.nvm/versions/node/v12.16.0/bin:/Users/smallwhale/.nvm/versions/node/v18.16.0/bin:/Library/Frameworks/Python.framework/Versions/3.11/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin:/Users/smallwhale/.nvm/versions/node/v18.16.0/bin:/Library/Frameworks/Python.framework/Versions/3.11/bin:/opt/homebrew/bin:/opt/homebrew/sbin", + "npm_config_allow_same_version": "", + "npm_package_dependencies_webrtc_adapter": "^7.7.1", + "npm_package_dependencies_react_reveal": "^1.2.2", + "npm_package_dependencies_prosemirror_schema_list": "^1.1.6", + "npm_package_dependencies__material_ui_core": "^4.12.3", + "npm_package_devDependencies__types_rimraf": "^2.0.5", + "npm_package_devDependencies__types_connect_flash": "0.0.34", + "npm_config_https_proxy": "", + "npm_config_engine_strict": "", + "npm_config_description": "true", + "npm_package_dependencies_pug": "^2.0.4", + "npm_package_dependencies_prosemirror_keymap": "^1.1.5", + "npm_package_dependencies_pdfjs_dist": "^2.14.305", + "npm_package_dependencies_mobile_detect": "^1.4.5", + "npm_package_dependencies_image_size_stream": "^1.1.0", + "npm_package_dependencies_golden_layout": "^1.5.9", + "npm_package_dependencies_child_process": "^1.0.2", + "npm_package_dependencies__types_d3_axis": "^2.1.3", + "_": "/Users/smallwhale/Desktop/Projects/Dash-Web/node_modules/.bin/cross-env", + "LaunchInstanceID": "57D8446D-0E37-4DF2-8110-E0AA2FF019D8", + "npm_config_userconfig": "/Users/smallwhale/.npmrc", + "npm_config_init_module": "/Users/smallwhale/.npm-init.js", + "npm_package_dependencies__react_google_maps_api": "^2.7.0", + "USER_ZDOTDIR": "/Users/smallwhale", + "__CFBundleIdentifier": "com.microsoft.VSCode", + "npm_config_cidr": "", + "npm_package_dependencies_puppeteer": "^3.3.0", + "npm_package_dependencies_prosemirror_view": "^1.26.5", + "npm_package_dependencies_mongodb": "^3.7.3", + "npm_package_dependencies_google_auth_library": "^4.2.4", + "npm_package_dependencies_bootstrap": "^4.6.1", + "npm_package_devDependencies_eslint_config_airbnb": "^19.0.4", + "PWD": "/Users/smallwhale/Desktop/Projects/Dash-Web", + "npm_config_user": "501", + "npm_config_node_version": "12.16.0", + "npm_package_dependencies_node_sass": "^4.14.1", + "npm_package_dependencies_howler": "^2.2.3", + "npm_package_dependencies_expressjs": "^1.0.1", + "npm_package_dependencies_core_js": "^3.28.0", + "npm_package_dependencies_browndash_components": "0.0.82", + "npm_package_devDependencies_eslint_plugin_react_hooks": "^4.6.0", + "npm_package_devDependencies__types_lodash": "^4.14.179", + "npm_lifecycle_event": "start", + "npm_package_dependencies_react_table": "^6.11.5", + "npm_package_dependencies_react_loading": "^2.0.3", + "npm_package_dependencies_mobx": "^5.15.7", + "npm_package_dependencies_babel": "^6.23.0", + "npm_package_devDependencies_jsdom": "^15.2.1", + "npm_package_devDependencies_chai": "^4.3.6", + "npm_config_save": "true", + "npm_config_ignore_prepublish": "", + "npm_config_editor": "vi", + "npm_config_auth_type": "legacy", + "npm_package_dependencies_npm": "^6.14.18", + "npm_package_dependencies_node_stream_zip": "^1.15.0", + "npm_package_dependencies_image_data_uri": "^2.0.1", + "npm_package_scripts_start_release": "cross-env RELEASE=true NODE_OPTIONS=--max_old_space_size=4096 ts-node-dev -- src/server/index.ts", + "npm_package_name": "dash", + "LANG": "en_US.UTF-8", + "npm_config_tag": "latest", + "npm_config_script_shell": "", + "npm_package_dependencies_query_string": "^6.14.1", + "npm_package_dependencies_mobx_utils": "^5.6.2", + "npm_package_dependencies_file_saver": "^2.0.5", + "npm_package_dependencies_body_parser": "^1.19.2", + "npm_package_dependencies__types_reveal": "^3.3.33", + "npm_package_devDependencies_eslint_plugin_import": "^2.26.0", + "npm_package_devDependencies__types_prosemirror_view": "^1.23.1", + "npm_config_progress": "true", + "npm_config_global": "", + "npm_config_before": "", + "npm_package_dependencies_xoauth2": "^1.2.0", + "npm_package_dependencies_standard_http_error": "^2.0.1", + "npm_package_dependencies_react_loader_spinner": "^5.3.4", + "npm_package_dependencies_http_browserify": "^1.7.0", + "npm_package_dependencies__types_d3_selection": "^2.0.1", + "npm_package_dependencies__hig_flyout": "^1.3.1", + "npm_package_devDependencies_fork_ts_checker_webpack_plugin": "^1.6.0", + "npm_package_scripts_build": "cross-env NODE_OPTIONS=--max_old_space_size=8192 webpack --env production", + "npm_package_scripts_start": "cross-env NODE_OPTIONS=--max_old_space_size=4096 ts-node-dev --debug --transpile-only -- src/server/index.ts", + "npm_config_searchstaleness": "900", + "npm_config_optional": "true", + "npm_config_ham_it_up": "", + "npm_package_dependencies_sharp": "^0.23.4", + "npm_package_dependencies_rc_switch": "^1.9.2", + "npm_package_dependencies_googlephotos": "^0.2.5", + "npm_package_dependencies_exifr": "^7.1.3", + "npm_package_dependencies__types_google_maps": "^3.2.3", + "npm_package_dependencies__types_bezier_js": "^4.1.0", + "npm_package_dependencies__ffmpeg_core": "0.10.0", + "npm_package_devDependencies_ts_loader": "^5.3.3", + "npm_package_devDependencies__types_bcrypt_nodejs": "0.0.30", + "VSCODE_GIT_ASKPASS_EXTRA_ARGS": "--ms-enable-electron-run-as-node", + "XPC_FLAGS": "0x0", + "npm_config_save_prod": "", + "npm_config_force": "", + "npm_config_bin_links": "true", + "npm_package_devDependencies__types_youtube": "0.0.39", + "npm_config_searchopts": "", + "npm_package_dependencies_react_beautiful_dnd": "^13.1.0", + "npm_package_dependencies_jszip": "^3.7.1", + "npm_package_dependencies_csv_stringify": "^6.3.0", + "npm_package_devDependencies__types_react_icons": "^3.0.0", + "npm_config_node_gyp": "/Users/smallwhale/.nvm/versions/node/v12.16.0/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js", + "npm_config_depth": "Infinity", + "npm_package_dependencies_google_maps_react": "^2.0.6", + "npm_package_dependencies_express_session": "^1.17.2", + "npm_package_devDependencies_eslint_plugin_node": "^11.1.0", + "npm_package_devDependencies_eslint_config_prettier": "^8.5.0", + "npm_package_main": "index.js", + "npm_config_sso_poll_frequency": "500", + "npm_config_rebuild_bundle": "true", + "npm_package_dependencies_chart_js": "^3.8.0", + "npm_package_dependencies__emotion_react": "^11.11.0", + "npm_package_devDependencies__types_prosemirror_menu": "^1.0.6", + "npm_package_devDependencies__types_prosemirror_keymap": "^1.0.4", + "npm_package_devDependencies__types_pdfjs_dist": "^2.10.378", + "npm_package_devDependencies__types_exif": "^0.6.3", + "npm_package_version": "1.0.0", + "XPC_SERVICE_NAME": "0", + "npm_config_unicode": "true", + "VSCODE_INJECTION": "1", + "npm_package_dependencies_typescript_language_server": "^0.4.0", + "npm_package_dependencies_prosemirror_model": "^1.18.1", + "npm_package_dependencies__ffmpeg_ffmpeg": "0.10.0", + "SHLVL": "4", + "HOME": "/Users/smallwhale", + "npm_config_fetch_retry_maxtimeout": "60000", + "npm_package_dependencies_request_promise": "^4.2.6", + "npm_package_dependencies_react_markdown": "^8.0.3", + "npm_package_dependencies__hig_theme_context": "^2.1.3", + "npm_package_devDependencies__types_react_autosuggest": "^9.3.14", + "npm_package_devDependencies__types_mongoose": "^5.11.97", + "npm_package_devDependencies__types_d3": "^7.4.0", + "npm_package_devDependencies__types_animejs": "^2.0.2", + "npm_package_scripts_test": "mocha -r ts-node/register test/**/*.ts", + "VSCODE_GIT_ASKPASS_MAIN": "/Applications/Visual Studio Code.app/Contents/Resources/app/extensions/git/dist/askpass-main.js", + "npm_config_tag_version_prefix": "v", + "npm_config_strict_ssl": "true", + "npm_config_sso_type": "oauth", + "npm_config_scripts_prepend_node_path": "warn-only", + "npm_config_save_prefix": "^", + "npm_config_loglevel": "notice", + "npm_config_ca": "", + "npm_package_dependencies_three": "^0.127.0", + "npm_package_dependencies_openai": "^3.2.1", + "npm_package_dependencies_mobx_react": "^5.4.4", + "npm_package_dependencies_cookie_parser": "^1.4.6", + "npm_package_dependencies_adm_zip": "^0.4.16", + "npm_package_devDependencies_eslint_config_node": "^4.1.0", + "npm_config_save_exact": "", + "npm_config_group": "20", + "npm_config_fetch_retry_factor": "10", + "npm_config_dev": "", + "npm_package_devDependencies_webpack_hot_middleware": "^2.25.1", + "npm_package_devDependencies_cross_env": "^5.2.1", + "HOMEBREW_PREFIX": "/opt/homebrew", + "npm_config_version": "", + "npm_config_prefer_offline": "", + "npm_config_cache_lock_stale": "60000", + "npm_package_devDependencies__types_prosemirror_state": "^1.2.8", + "npm_package_devDependencies__types_body_parser": "^1.19.2", + "npm_config_otp": "", + "npm_config_cache_min": "10", + "npm_package_dependencies_react_color": "^2.19.3", + "npm_package_dependencies_d3": "^7.6.1", + "npm_package_devDependencies_ts_node": "^10.9.1", + "npm_package_devDependencies__types_react_grid_layout": "^1.3.2", + "npm_config_searchexclude": "", + "npm_config_cache": "/Users/smallwhale/.npm", + "npm_package_dependencies_tough_cookie": "^4.0.0", + "npm_package_dependencies_googleapis": "^40.0.0", + "npm_package_devDependencies__types_valid_url": "^1.0.3", + "npm_package_devDependencies__types_passport": "^1.0.9", + "npm_package_devDependencies__types_adm_zip": "^0.4.34", + "LOGNAME": "smallwhale", + "npm_lifecycle_script": "cross-env NODE_OPTIONS=--max_old_space_size=4096 ts-node-dev --debug --transpile-only -- src/server/index.ts", + "npm_config_color": "true", + "npm_package_dependencies_solr_node": "^1.2.1", + "npm_package_dependencies_react_transition_group": "^4.4.2", + "npm_package_dependencies_iink_js": "^1.5.4", + "npm_package_dependencies_html_webpack_plugin": "^5.5.0", + "npm_config_proxy": "", + "npm_config_package_lock": "true", + "npm_package_dependencies_prosemirror_state": "^1.4.1", + "npm_package_dependencies_nodemon": "^1.19.4", + "npm_package_dependencies_function_plot": "^1.22.8", + "npm_package_dependencies_equation_editor_react": "github:bobzel/equation-editor-react#useLocally", + "npm_package_devDependencies__types_socket_io_parser": "^3.0.0", + "VSCODE_GIT_IPC_HANDLE": "/var/folders/bv/1xck6d7j7bz14bvhgdsllbj40000gn/T/vscode-git-b8c8318074.sock", + "npm_config_package_lock_only": "", + "npm_config_fund": "true", + "npm_package_dependencies_react": "^18.2.0", + "npm_package_dependencies_bingmaps_react": "^1.2.10", + "npm_package_devDependencies_scss_loader": "0.0.1", + "npm_package_devDependencies__types_cookie_session": "^2.0.44", + "npm_config_save_optional": "", + "npm_package_dependencies_textarea_caret": "^3.1.0", + "npm_package_dependencies_react_measure": "^2.5.2", + "npm_package_dependencies_exif": "^0.6.0", + "NVM_BIN": "/Users/smallwhale/.nvm/versions/node/v12.16.0/bin", + "npm_config_ignore_scripts": "", + "npm_config_user_agent": "npm/6.13.4 node/v12.16.0 darwin x64", + "npm_package_dependencies_react_resizable": "^1.11.1", + "npm_package_dependencies_prosemirror_commands": "^1.2.1", + "npm_package_dependencies_memorystream": "^0.3.1", + "npm_package_dependencies_formidable": "1.2.1", + "npm_package_devDependencies__types_uuid": "^3.4.10", + "npm_config_cache_lock_wait": "10000", + "npm_package_dependencies_socket_io_client": "^2.5.0", + "npm_package_dependencies_recharts": "^2.1.12", + "npm_package_dependencies_react_chartjs_2": "^4.3.0", + "npm_package_dependencies_fluent_ffmpeg": "^2.1.2", + "npm_package_dependencies__types_cors": "^2.8.12", + "npm_package_devDependencies__types_node": "^10.17.60", + "npm_package_devDependencies__types_file_saver": "^2.0.5", + "VSCODE_GIT_ASKPASS_NODE": "/Applications/Visual Studio Code.app/Contents/Frameworks/Code Helper (Plugin).app/Contents/MacOS/Code Helper (Plugin)", + "GIT_ASKPASS": "/Applications/Visual Studio Code.app/Contents/Resources/app/extensions/git/dist/askpass.sh", + "HOMEBREW_CELLAR": "/opt/homebrew/Cellar", + "INFOPATH": "/opt/homebrew/share/info:/opt/homebrew/share/info:", + "npm_config_production": "", + "npm_package_dependencies_jsonschema": "^1.4.0", + "npm_package_dependencies_ffmpeg": "0.0.4", + "npm_package_dependencies_cookie_session": "^2.0.0", + "npm_package_dependencies_color": "^3.2.1", + "npm_package_devDependencies__types_webpack": "^4.41.32", + "npm_package_devDependencies__types_request_promise": "^4.1.48", + "npm_package_devDependencies__types_prosemirror_schema_list": "^1.0.3", + "npm_config_send_metrics": "", + "npm_config_save_bundle": "", + "npm_package_dependencies_web_request": "^1.0.7", + "npm_package_dependencies_react_datepicker": "^3.8.0", + "npm_package_dependencies_express": "^4.17.3", + "npm_package_dependencies_D": "^1.0.0", + "npm_package_dependencies__types_formidable": "1.0.31", + "npm_package_devDependencies__types_rc_switch": "^1.9.2", + "npm_package_devDependencies__types_prosemirror_dev_tools": "^2.1.0", + "npm_package_devDependencies__types_jquery": "^3.5.14", + "npm_config_umask": "0022", + "npm_config_node_options": "", + "npm_config_init_version": "1.0.0", + "npm_package_dependencies_https": "^1.0.0", + "npm_package_dependencies_array_batcher": "^1.2.3", + "npm_package_dependencies__fortawesome_free_regular_svg_icons": "^6.3.0", + "npm_package_devDependencies__types_shelljs": "^0.8.11", + "npm_package_devDependencies__types_libxmljs": "^0.18.7", + "npm_package_devDependencies__types_express_validator": "^3.0.0", + "npm_package_devDependencies__types_bluebird": "^3.5.36", + "npm_config_init_author_name": "", + "npm_config_git": "git", + "npm_config_scope": "", + "npm_package_dependencies_react_select": "^3.2.0", + "npm_package_dependencies_pdf_parse": "^1.1.1", + "npm_package_dependencies_colors": "^1.4.0", + "npm_package_dependencies_archiver": "^3.1.1", + "npm_package_devDependencies_css_loader": "^2.1.1", + "npm_package_devDependencies__types_socket_io_client": "^1.4.36", + "SECURITYSESSIONID": "186a4", + "npm_config_unsafe_perm": "true", + "npm_config_tmp": "/var/folders/bv/1xck6d7j7bz14bvhgdsllbj40000gn/T", + "npm_config_onload_script": "", + "npm_package_dependencies_serializr": "^1.5.4", + "npm_package_dependencies_fit_curve": "^0.1.7", + "npm_package_dependencies__webscopeio_react_textarea_autocomplete": "^4.9.1", + "npm_package_dependencies__types_three": "^0.126.2", + "npm_package_devDependencies_ts_node_dev": "^2.0.0", + "npm_node_execpath": "/Users/smallwhale/.nvm/versions/node/v12.16.0/bin/node", + "npm_config_prefix": "/Users/smallwhale/.nvm/versions/node/v12.16.0", + "npm_config_link": "", + "npm_config_format_package_lock": "true", + "npm_package_dependencies_passport": "^0.4.0", + "npm_package_devDependencies_eslint_plugin_react": "^7.30.1", + "npm_package_devDependencies__types_react_table": "^6.8.9", + "npm_package_devDependencies__types_react_reconciler": "^0.26.4", + "COLORTERM": "truecolor", + "NODE_OPTIONS": "--max_old_space_size=4096", + "TS_NODE_DEV": "true", + "_CLIENT_OPENAI_KEY": "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", + "_CLIENT_GITHUB_ACCESS_TOKEN": "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", + "VIPSHOME": "/usr/local/Cellar/vips/8.8.1", + "TYPESCRIPT_PATH": "/Users/smallwhale/Desktop/Projects/Dash-Web/node_modules/typescript/lib/typescript.js", + "TSCONFIG": "/Users/smallwhale/Desktop/Projects/Dash-Web/tsconfig.json", + "COMPILER_OPTIONS": "{}", + "TSLINT": "true", + "CONTEXT": "/Users/smallwhale/Desktop/Projects/Dash-Web", + "TSLINTAUTOFIX": "false", + "ESLINT": "false", + "ESLINT_OPTIONS": "{}", + "WATCH": "", + "WORK_DIVISION": "1", + "MEMORY_LIMIT": "2048", + "CHECK_SYNTACTIC_ERRORS": "false", + "USE_INCREMENTAL_API": "true", + "VUE": "false" + }, + "userLimits": { + "core_file_size_blocks": { + "soft": 0, + "hard": "unlimited" + }, + "data_seg_size_kbytes": { + "soft": "unlimited", + "hard": "unlimited" + }, + "file_size_blocks": { + "soft": "unlimited", + "hard": "unlimited" + }, + "max_locked_memory_bytes": { + "soft": "unlimited", + "hard": "unlimited" + }, + "max_memory_size_kbytes": { + "soft": "unlimited", + "hard": "unlimited" + }, + "open_files": { + "soft": 1048575, + "hard": "unlimited" + }, + "stack_size_bytes": { + "soft": 8372224, + "hard": 67092480 + }, + "cpu_time_seconds": { + "soft": "unlimited", + "hard": "unlimited" + }, + "max_user_processes": { + "soft": 1333, + "hard": 2000 + }, + "virtual_memory_kbytes": { + "soft": "unlimited", + "hard": "unlimited" + } + }, + "sharedObjects": [ + "/Users/smallwhale/.nvm/versions/node/v12.16.0/bin/node", + "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation", + "/usr/lib/libobjc.A.dylib", + "/System/Library/PrivateFrameworks/CoreServicesInternal.framework/Versions/A/CoreServicesInternal", + "/usr/lib/liboah.dylib", + "/usr/lib/libfakelink.dylib", + "/usr/lib/libicucore.A.dylib", + "/usr/lib/libSystem.B.dylib", + "/System/Library/PrivateFrameworks/SoftLinking.framework/Versions/A/SoftLinking", + "/usr/lib/libc++abi.dylib", + "/usr/lib/libc++.1.dylib", + "/usr/lib/system/libcache.dylib", + "/usr/lib/system/libcommonCrypto.dylib", + "/usr/lib/system/libcompiler_rt.dylib", + "/usr/lib/system/libcopyfile.dylib", + "/usr/lib/system/libcorecrypto.dylib", + "/usr/lib/system/libdispatch.dylib", + "/usr/lib/system/libdyld.dylib", + "/usr/lib/system/libkeymgr.dylib", + "/usr/lib/system/libmacho.dylib", + "/usr/lib/system/libquarantine.dylib", + "/usr/lib/system/libremovefile.dylib", + "/usr/lib/system/libsystem_asl.dylib", + "/usr/lib/system/libsystem_blocks.dylib", + "/usr/lib/system/libsystem_c.dylib", + "/usr/lib/system/libsystem_collections.dylib", + "/usr/lib/system/libsystem_configuration.dylib", + "/usr/lib/system/libsystem_containermanager.dylib", + "/usr/lib/system/libsystem_coreservices.dylib", + "/usr/lib/system/libsystem_darwin.dylib", + "/usr/lib/system/libsystem_dnssd.dylib", + "/usr/lib/system/libsystem_featureflags.dylib", + "/usr/lib/system/libsystem_info.dylib", + "/usr/lib/system/libsystem_m.dylib", + "/usr/lib/system/libsystem_malloc.dylib", + "/usr/lib/system/libsystem_networkextension.dylib", + "/usr/lib/system/libsystem_notify.dylib", + "/usr/lib/system/libsystem_sandbox.dylib", + "/usr/lib/system/libsystem_secinit.dylib", + "/usr/lib/system/libsystem_kernel.dylib", + "/usr/lib/system/libsystem_platform.dylib", + "/usr/lib/system/libsystem_pthread.dylib", + "/usr/lib/system/libsystem_symptoms.dylib", + "/usr/lib/system/libsystem_trace.dylib", + "/usr/lib/system/libunwind.dylib", + "/usr/lib/system/libxpc.dylib", + "/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit", + "/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices", + "/usr/lib/libDiagnosticMessagesClient.dylib", + "/usr/lib/libenergytrace.dylib", + "/usr/lib/libbsm.0.dylib", + "/usr/lib/libz.1.dylib", + "/usr/lib/system/libkxld.dylib", + "/System/Library/Frameworks/CFNetwork.framework/Versions/A/CFNetwork", + "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/FSEvents.framework/Versions/A/FSEvents", + "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/CarbonCore", + "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/Metadata.framework/Versions/A/Metadata", + "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/OSServices.framework/Versions/A/OSServices", + "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/SearchKit.framework/Versions/A/SearchKit", + "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/AE.framework/Versions/A/AE", + "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/LaunchServices", + "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/DictionaryServices.framework/Versions/A/DictionaryServices", + "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/SharedFileList.framework/Versions/A/SharedFileList", + "/System/Library/Frameworks/Security.framework/Versions/A/Security", + "/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration", + "/usr/lib/libapple_nghttp2.dylib", + "/usr/lib/libcompression.dylib", + "/usr/lib/libnetwork.dylib", + "/usr/lib/libsqlite3.dylib", + "/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation", + "/System/Library/Frameworks/Network.framework/Versions/A/Network", + "/usr/lib/libCoreEntitlements.dylib", + "/System/Library/PrivateFrameworks/MessageSecurity.framework/Versions/A/MessageSecurity", + "/System/Library/PrivateFrameworks/ProtocolBuffer.framework/Versions/A/ProtocolBuffer", + "/usr/lib/libMobileGestalt.dylib", + "/System/Library/PrivateFrameworks/AppleFSCompression.framework/Versions/A/AppleFSCompression", + "/usr/lib/libcoretls.dylib", + "/usr/lib/libcoretls_cfhelpers.dylib", + "/usr/lib/libpam.2.dylib", + "/usr/lib/libxar.1.dylib", + "/System/Library/PrivateFrameworks/CoreAutoLayout.framework/Versions/A/CoreAutoLayout", + "/System/Library/Frameworks/DiskArbitration.framework/Versions/A/DiskArbitration", + "/usr/lib/libarchive.2.dylib", + "/usr/lib/libxml2.2.dylib", + "/usr/lib/liblangid.dylib", + "/System/Library/Frameworks/Combine.framework/Versions/A/Combine", + "/usr/lib/swift/libswiftCore.dylib", + "/usr/lib/swift/libswiftCoreFoundation.dylib", + "/usr/lib/swift/libswiftDarwin.dylib", + "/usr/lib/swift/libswiftDispatch.dylib", + "/usr/lib/swift/libswiftIOKit.dylib", + "/usr/lib/swift/libswiftObjectiveC.dylib", + "/usr/lib/swift/libswiftXPC.dylib", + "/usr/lib/swift/libswift_Concurrency.dylib", + "/usr/lib/swift/libswift_StringProcessing.dylib", + "/usr/lib/swift/libswiftos.dylib", + "/System/Library/PrivateFrameworks/AppleSystemInfo.framework/Versions/A/AppleSystemInfo", + "/System/Library/PrivateFrameworks/IOMobileFramebuffer.framework/Versions/A/IOMobileFramebuffer", + "/System/Library/Frameworks/IOSurface.framework/Versions/A/IOSurface", + "/usr/lib/libpcap.A.dylib", + "/usr/lib/libdns_services.dylib", + "/usr/lib/liblzma.5.dylib", + "/usr/lib/libbz2.1.0.dylib", + "/usr/lib/libiconv.2.dylib", + "/usr/lib/libcharset.1.dylib", + "/usr/lib/swift/libswift_RegexParser.dylib", + "/usr/lib/libheimdal-asn1.dylib", + "/usr/lib/libCheckFix.dylib", + "/System/Library/PrivateFrameworks/TCC.framework/Versions/A/TCC", + "/System/Library/PrivateFrameworks/CoreNLP.framework/Versions/A/CoreNLP", + "/System/Library/PrivateFrameworks/MetadataUtilities.framework/Versions/A/MetadataUtilities", + "/System/Library/Frameworks/Accelerate.framework/Versions/A/Accelerate", + "/usr/lib/libmecab.dylib", + "/usr/lib/libCRFSuite.dylib", + "/usr/lib/libgermantok.dylib", + "/usr/lib/libThaiTokenizer.dylib", + "/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vImage.framework/Versions/A/vImage", + "/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/vecLib", + "/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libvMisc.dylib", + "/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libvDSP.dylib", + "/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib", + "/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libLAPACK.dylib", + "/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libLinearAlgebra.dylib", + "/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libSparseBLAS.dylib", + "/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libQuadrature.dylib", + "/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBNNS.dylib", + "/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libSparse.dylib", + "/System/Library/PrivateFrameworks/MIL.framework/Versions/A/MIL", + "/System/Library/Frameworks/OpenDirectory.framework/Versions/A/Frameworks/CFOpenDirectory.framework/Versions/A/CFOpenDirectory", + "/System/Library/Frameworks/OpenDirectory.framework/Versions/A/OpenDirectory", + "/System/Library/PrivateFrameworks/APFS.framework/Versions/A/APFS", + "/System/Library/Frameworks/SecurityFoundation.framework/Versions/A/SecurityFoundation", + "/usr/lib/libutil.dylib", + "/System/Library/PrivateFrameworks/InstalledContentLibrary.framework/Versions/A/InstalledContentLibrary", + "/System/Library/PrivateFrameworks/CoreServicesStore.framework/Versions/A/CoreServicesStore", + "/usr/lib/libapp_launch_measurement.dylib", + "/System/Library/PrivateFrameworks/AppleMobileFileIntegrity.framework/Versions/A/AppleMobileFileIntegrity", + "/usr/lib/libmis.dylib", + "/System/Library/PrivateFrameworks/MobileSystemServices.framework/Versions/A/MobileSystemServices", + "/System/Library/PrivateFrameworks/ConfigProfileHelper.framework/Versions/A/ConfigProfileHelper", + "/System/Library/PrivateFrameworks/CoreAnalytics.framework/Versions/A/CoreAnalytics", + "/System/Library/PrivateFrameworks/AppleSauce.framework/Versions/A/AppleSauce", + "/System/Library/PrivateFrameworks/LanguageModeling.framework/Versions/A/LanguageModeling", + "/usr/lib/libxslt.1.dylib", + "/usr/lib/libcmph.dylib", + "/System/Library/PrivateFrameworks/CoreEmoji.framework/Versions/A/CoreEmoji", + "/System/Library/PrivateFrameworks/LinguisticData.framework/Versions/A/LinguisticData", + "/System/Library/PrivateFrameworks/Lexicon.framework/Versions/A/Lexicon", + "/System/Library/PrivateFrameworks/BackgroundTaskManagement.framework/Versions/A/BackgroundTaskManagement", + "/usr/lib/libTLE.dylib", + "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices", + "/System/Library/Frameworks/CoreGraphics.framework/Versions/A/CoreGraphics", + "/System/Library/Frameworks/CoreText.framework/Versions/A/CoreText", + "/System/Library/Frameworks/ImageIO.framework/Versions/A/ImageIO", + "/System/Library/Frameworks/ColorSync.framework/Versions/A/ColorSync", + "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/ATS", + "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/HIServices.framework/Versions/A/HIServices", + "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/PrintCore.framework/Versions/A/PrintCore", + "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/QD.framework/Versions/A/QD", + "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ColorSyncLegacy.framework/Versions/A/ColorSyncLegacy", + "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/SpeechSynthesis.framework/Versions/A/SpeechSynthesis", + "/System/Library/PrivateFrameworks/SkyLight.framework/Versions/A/SkyLight", + "/System/Library/PrivateFrameworks/FontServices.framework/libFontParser.dylib", + "/System/Library/PrivateFrameworks/RunningBoardServices.framework/Versions/A/RunningBoardServices", + "/System/Library/PrivateFrameworks/IOSurfaceAccelerator.framework/Versions/A/IOSurfaceAccelerator", + "/System/Library/PrivateFrameworks/WatchdogClient.framework/Versions/A/WatchdogClient", + "/System/Library/Frameworks/CoreDisplay.framework/Versions/A/CoreDisplay", + "/System/Library/Frameworks/CoreMedia.framework/Versions/A/CoreMedia", + "/System/Library/PrivateFrameworks/IOAccelerator.framework/Versions/A/IOAccelerator", + "/System/Library/Frameworks/Metal.framework/Versions/A/Metal", + "/System/Library/Frameworks/CoreVideo.framework/Versions/A/CoreVideo", + "/System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/MetalPerformanceShaders", + "/System/Library/PrivateFrameworks/MultitouchSupport.framework/Versions/A/MultitouchSupport", + "/System/Library/Frameworks/QuartzCore.framework/Versions/A/QuartzCore", + "/System/Library/Frameworks/VideoToolbox.framework/Versions/A/VideoToolbox", + "/System/Library/PrivateFrameworks/BaseBoard.framework/Versions/A/BaseBoard", + "/System/Library/PrivateFrameworks/AppleJPEG.framework/Versions/A/AppleJPEG", + "/usr/lib/libexpat.1.dylib", + "/System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libPng.dylib", + "/System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libTIFF.dylib", + "/System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libGIF.dylib", + "/System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libJP2.dylib", + "/usr/lib/libate.dylib", + "/System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libJPEG.dylib", + "/System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libRadiance.dylib", + "/System/Library/PrivateFrameworks/GPUWrangler.framework/Versions/A/GPUWrangler", + "/System/Library/PrivateFrameworks/IOPresentment.framework/Versions/A/IOPresentment", + "/System/Library/PrivateFrameworks/DSExternalDisplay.framework/Versions/A/DSExternalDisplay", + "/System/Library/PrivateFrameworks/GPUCompiler.framework/Versions/31001/Libraries/libllvm-flatbuffers.dylib", + "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libCoreFSCache.dylib", + "/System/Library/PrivateFrameworks/GPUCompiler.framework/Versions/31001/Libraries/libGPUCompilerUtils.dylib", + "/System/Library/PrivateFrameworks/CMCaptureCore.framework/Versions/A/CMCaptureCore", + "/usr/lib/libspindump.dylib", + "/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio", + "/System/Library/Frameworks/ExtensionFoundation.framework/Versions/A/ExtensionFoundation", + "/System/Library/PrivateFrameworks/CoreTime.framework/Versions/A/CoreTime", + "/System/Library/PrivateFrameworks/AppServerSupport.framework/Versions/A/AppServerSupport", + "/System/Library/PrivateFrameworks/perfdata.framework/Versions/A/perfdata", + "/System/Library/PrivateFrameworks/AudioToolboxCore.framework/Versions/A/AudioToolboxCore", + "/System/Library/PrivateFrameworks/caulk.framework/Versions/A/caulk", + "/usr/lib/libAudioStatistics.dylib", + "/System/Library/PrivateFrameworks/SystemPolicy.framework/Versions/A/SystemPolicy", + "/usr/lib/libSMC.dylib", + "/System/Library/Frameworks/CoreMIDI.framework/Versions/A/CoreMIDI", + "/usr/lib/libAudioToolboxUtility.dylib", + "/System/Library/PrivateFrameworks/OSAServicesClient.framework/Versions/A/OSAServicesClient", + "/usr/lib/libperfcheck.dylib", + "/System/Library/PrivateFrameworks/PlugInKit.framework/Versions/A/PlugInKit", + "/System/Library/PrivateFrameworks/AssertionServices.framework/Versions/A/AssertionServices", + "/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL", + "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGLU.dylib", + "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGFXShared.dylib", + "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib", + "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGLImage.dylib", + "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libCVMSPluginSupport.dylib", + "/usr/lib/libRosetta.dylib", + "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libCoreVMClient.dylib", + "/System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSCore.framework/Versions/A/MPSCore", + "/System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSImage.framework/Versions/A/MPSImage", + "/System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSNeuralNetwork.framework/Versions/A/MPSNeuralNetwork", + "/System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSMatrix.framework/Versions/A/MPSMatrix", + "/System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSRayIntersector.framework/Versions/A/MPSRayIntersector", + "/System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSNDArray.framework/Versions/A/MPSNDArray", + "/System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSFunctions.framework/Versions/A/MPSFunctions", + "/System/Library/PrivateFrameworks/MetalTools.framework/Versions/A/MetalTools", + "/System/Library/PrivateFrameworks/AggregateDictionary.framework/Versions/A/AggregateDictionary", + "/usr/lib/libIOReport.dylib", + "/System/Library/Frameworks/CoreImage.framework/Versions/A/CoreImage", + "/System/Library/PrivateFrameworks/PhotosensitivityProcessing.framework/Versions/A/PhotosensitivityProcessing", + "/System/Library/Frameworks/OpenCL.framework/Versions/A/OpenCL", + "/System/Library/PrivateFrameworks/GraphVisualizer.framework/Versions/A/GraphVisualizer", + "/System/Library/PrivateFrameworks/FontServices.framework/Versions/A/FontServices", + "/System/Library/Frameworks/UniformTypeIdentifiers.framework/Versions/A/UniformTypeIdentifiers", + "/System/Library/PrivateFrameworks/OTSVG.framework/Versions/A/OTSVG", + "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/libFontRegistry.dylib", + "/System/Library/PrivateFrameworks/FontServices.framework/libhvf.dylib", + "/System/Library/PrivateFrameworks/FontServices.framework/libXTFontStaticRegistryData.dylib", + "/System/Library/PrivateFrameworks/VideoToolboxParavirtualizationSupport.framework/Versions/A/VideoToolboxParavirtualizationSupport", + "/System/Library/PrivateFrameworks/AppleVA.framework/Versions/A/AppleVA", + "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATSUI.framework/Versions/A/ATSUI", + "/usr/lib/libcups.2.dylib", + "/System/Library/Frameworks/Kerberos.framework/Versions/A/Kerberos", + "/System/Library/Frameworks/GSS.framework/Versions/A/GSS", + "/usr/lib/libresolv.9.dylib", + "/System/Library/PrivateFrameworks/Heimdal.framework/Versions/A/Heimdal", + "/System/Library/Frameworks/Kerberos.framework/Versions/A/Libraries/libHeimdalProxy.dylib", + "/System/Library/PrivateFrameworks/CommonAuth.framework/Versions/A/CommonAuth", + "/System/Library/Frameworks/AVFAudio.framework/Versions/A/AVFAudio", + "/System/Library/PrivateFrameworks/AXCoreUtilities.framework/Versions/A/AXCoreUtilities", + "/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox", + "/System/Library/PrivateFrameworks/AudioSession.framework/Versions/A/AudioSession", + "/System/Library/Frameworks/IOBluetooth.framework/Versions/A/IOBluetooth", + "/System/Library/PrivateFrameworks/MediaExperience.framework/Versions/A/MediaExperience", + "/System/Library/PrivateFrameworks/AudioSession.framework/libSessionUtility.dylib", + "/System/Library/PrivateFrameworks/AudioResourceArbitration.framework/Versions/A/AudioResourceArbitration", + "/System/Library/PrivateFrameworks/PowerLog.framework/Versions/A/PowerLog", + "/System/Library/Frameworks/CoreData.framework/Versions/A/CoreData", + "/System/Library/Frameworks/CoreBluetooth.framework/Versions/A/CoreBluetooth", + "/System/Library/Frameworks/AudioUnit.framework/Versions/A/AudioUnit", + "/System/Library/PrivateFrameworks/CoreUtils.framework/Versions/A/CoreUtils", + "/System/Library/PrivateFrameworks/CoreUtilsExtras.framework/Versions/A/CoreUtilsExtras", + "/System/Library/PrivateFrameworks/IO80211.framework/Versions/A/IO80211", + "/System/Library/PrivateFrameworks/MobileKeyBag.framework/Versions/A/MobileKeyBag", + "/System/Library/PrivateFrameworks/MallocStackLogging.framework/Versions/A/MallocStackLogging" + ] +} \ No newline at end of file diff --git a/src/client/apis/gpt/GPT.ts b/src/client/apis/gpt/GPT.ts index 18222b32a..6b4106f56 100644 --- a/src/client/apis/gpt/GPT.ts +++ b/src/client/apis/gpt/GPT.ts @@ -14,7 +14,7 @@ type GPTCallOpts = { }; const callTypeMap: { [type: string]: GPTCallOpts } = { - summary: { model: 'text-davinci-003', maxTokens: 256, temp: 0.5, prompt: 'Summarize this text briefly: ' }, + summary: { model: 'text-davinci-003', maxTokens: 256, temp: 0.5, prompt: 'Summarize this text in simpler terms: ' }, edit: { model: 'text-davinci-003', maxTokens: 256, temp: 0.5, prompt: 'Reword this: ' }, completion: { model: 'text-davinci-003', maxTokens: 256, temp: 0.5, prompt: '' }, }; @@ -47,7 +47,7 @@ const gptAPICall = async (inputText: string, callType: GPTCallType) => { } }; -const gptImageCall = async (prompt: string) => { +const gptImageCall = async (prompt: string, n?: number) => { try { const configuration = new Configuration({ apiKey: process.env.OPENAI_KEY, @@ -55,33 +55,15 @@ const gptImageCall = async (prompt: string) => { const openai = new OpenAIApi(configuration); const response = await openai.createImage({ prompt: prompt, - n: 1, + n: n ?? 1, size: '1024x1024', }); - return response.data.data[0].url; + return response.data.data.map(data => data.url); + // return response.data.data[0].url; } catch (err) { console.error(err); return; } }; -// const gptEditCall = async (selectedText: string, fullText: string) => { -// try { -// const configuration = new Configuration({ -// apiKey: process.env.OPENAI_KEY, -// }); -// const openai = new OpenAIApi(configuration); -// const response = await openai.createCompletion({ -// model: 'text-davinci-003', -// max_tokens: 256, -// temperature: 0.1, -// prompt: `Replace the phrase ${selectedText} inside of ${fullText}.`, -// }); -// return response.data.choices[0].text.trim(); -// } catch (err) { -// console.log(err); -// return 'Error connecting with API.'; -// } -// }; - export { gptAPICall, gptImageCall, GPTCallType }; diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 85101fcab..ac948c7c7 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -195,7 +195,7 @@ export namespace DragManager { } // drag a document and drop it (or make an embed/copy on drop) - export function StartDocumentDrag(eles: HTMLElement[], dragData: DocumentDragData, downX: number, downY: number, options?: DragOptions, dropEvent?: () => any) { + export function StartDocumentDrag(eles: HTMLElement[], dragData: DocumentDragData, downX: number, downY: number, options?: DragOptions, onDropCompleted?: (e?: DragCompleteEvent) => any) { const addAudioTag = (dropDoc: any) => { dropDoc && !dropDoc.author_date && (dropDoc.author_date = new DateField()); dropDoc instanceof Doc && DocUtils.MakeLinkToActiveAudio(() => dropDoc); @@ -203,7 +203,7 @@ export namespace DragManager { }; const finishDrag = async (e: DragCompleteEvent) => { const docDragData = e.docDragData; - dropEvent?.(); // glr: optional additional function to be called - in this case with presentation trails + onDropCompleted?.(e); // glr: optional additional function to be called - in this case with presentation trails if (docDragData && !docDragData.droppedDocuments.length) { docDragData.dropAction = dragData.userDropAction || dragData.dropAction; docDragData.droppedDocuments = ( diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 67b7b39dd..1ff5688f9 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -137,7 +137,11 @@ export class TabDocView extends React.Component { setupMoveUpEvents( this, e, - e => !e.defaultPrevented && DragManager.StartDocumentDrag([iconWrap], new DragManager.DocumentDragData([doc], doc.dropAction as dropActionType), e.clientX, e.clientY), + e => + !e.defaultPrevented && + DragManager.StartDocumentDrag([iconWrap], new DragManager.DocumentDragData([doc], doc.dropAction as dropActionType), e.clientX, e.clientY, undefined, () => { + CollectionDockingView.CloseSplit(doc); + }), returnFalse, action(e => { if (this.view) { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index db000d5de..747ab9249 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -238,11 +238,11 @@ export class CollectionFreeFormLinkView extends React.Component {} }; diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 34a1229ba..5cdd6b5f2 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -354,6 +354,11 @@ export class WebBox extends ViewBoxAnnotatableComponent, dataDoc: Doc) => void; @@ -896,12 +897,13 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - console.log(this.dataDoc.text); - if (resIndex < this.gptRes.length) { - this.dataDoc.text = (this.dataDoc.text as RichTextField)?.Text + this.gptRes[resIndex]; + animateRes = (resIndex: number, newText: string) => { + if (resIndex < newText.length) { + const marks = this._editorView?.state.storedMarks ?? []; + // if (!marks) return; + this._editorView?.dispatch(this._editorView.state.tr.setStoredMarks(marks).insertText(newText[resIndex]).setStoredMarks(marks)); setTimeout(() => { - this.animateRes(resIndex + 1); + this.animateRes(resIndex + 1, newText); }, 20); } }; @@ -912,47 +914,68 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { + // const state = this._editorView?.state; + // if (!state) return; + // const to = state.selection.to; + // const updated = TextSelection.create(state.doc, to, to); + // this._editorView?.dispatch(state.tr.setSelection(updated).insertText('\n', to)); + // this._editorView?.dispatch(this._editorView.state.tr.setStoredMarks(marks).insertText('\nTesting').setStoredMarks(marks)); + // console.log('After ', this._editorView?.state.storedMarks); try { let res = await gptAPICall((this.dataDoc.text as RichTextField)?.Text, GPTCallType.COMPLETION); - if (res) { - this.gptRes = res; - this.animateRes(0); + if (!res) { + console.error('GPT call failed'); + this.animateRes(0, 'Something went wrong.'); + } else { + this.animateRes(0, res); } } catch (err) { - console.log(err); - this.dataDoc.text = (this.dataDoc.text as RichTextField)?.Text + 'Something went wrong'; + console.error('GPT call failed'); + this.animateRes(0, 'Something went wrong.'); } }); generateImage = async () => { console.log('Generate image from text: ', (this.dataDoc.text as RichTextField)?.Text); + GPTPopup.Instance?.setImgTargetDoc(this.rootDoc); + GPTPopup.Instance.setImgUrls([]); + GPTPopup.Instance.setMode(GPTPopupMode.IMAGE); + GPTPopup.Instance.setVisible(true); + GPTPopup.Instance.addToCollection = this.props.addDocument; + GPTPopup.Instance.setLoading(true); + try { - let image_url = await gptImageCall((this.dataDoc.text as RichTextField)?.Text); - if (image_url) { - const [result] = await Networking.PostToServer('/uploadRemoteImage', { sources: [image_url] }); + // make this support multiple images + let image_urls = await gptImageCall((this.dataDoc.text as RichTextField)?.Text); + console.log(image_urls); + if (image_urls) { + const [result] = await Networking.PostToServer('/uploadRemoteImage', { sources: [image_urls[0]] }); const source = Utils.prepend(result.accessPaths.agnostic.client); - const newDoc = Docs.Create.ImageDocument(source, { - x: NumCast(this.rootDoc.x) + NumCast(this.layoutDoc._width) + 10, - y: NumCast(this.rootDoc.y), - _height: 200, - _width: 200, - data_nativeWidth: result.nativeWidth, - data_nativeHeight: result.nativeHeight, - }); - if (Doc.IsInMyOverlay(this.rootDoc)) { - newDoc.overlayX = this.rootDoc.x; - newDoc.overlayY = NumCast(this.rootDoc.y) + NumCast(this.rootDoc._height); - Doc.AddToMyOverlay(newDoc); - } else { - this.props.addDocument?.(newDoc); - } - // Create link between prompt and image - DocUtils.MakeLink(this.rootDoc, newDoc, { link_relationship: 'Image Prompt' }); + GPTPopup.Instance.setImgUrls([source]); + + // const newDoc = Docs.Create.ImageDocument(source, { + // x: NumCast(this.rootDoc.x) + NumCast(this.layoutDoc._width) + 10, + // y: NumCast(this.rootDoc.y), + // _height: 200, + // _width: 200, + // data_nativeWidth: result.nativeWidth, + // data_nativeHeight: result.nativeHeight, + // }); + // if (Doc.IsInMyOverlay(this.rootDoc)) { + // newDoc.overlayX = this.rootDoc.x; + // newDoc.overlayY = NumCast(this.rootDoc.y) + NumCast(this.rootDoc._height); + // Doc.AddToMyOverlay(newDoc); + // } else { + // this.props.addDocument?.(newDoc); + // } + // // Create link between prompt and image + // DocUtils.MakeLink(this.rootDoc, newDoc, { link_relationship: 'Image Prompt' }); } } catch (err) { console.log(err); return ''; } + GPTPopup.Instance.setLoading(false); }; breakupDictation = () => { @@ -1249,8 +1272,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { gptSummarize = async (e: React.PointerEvent) => { GPTPopup.Instance.setVisible(true); this.setHighlightRange(undefined); - this.setGPTMode(GPTPopupMode.SUMMARY); + GPTPopup.Instance.setMode(GPTPopupMode.SUMMARY); GPTPopup.Instance.setLoading(true); try { @@ -183,6 +183,10 @@ export class AnchorMenu extends AntimodeMenu { GPTPopup.Instance.setLoading(false); }; + gptImage = async () => { + console.log(this.GetAnchor(undefined, false)); + }; + /** * Replaces text suggestions from GPT. */ @@ -293,21 +297,12 @@ export class AnchorMenu extends AntimodeMenu { )} - {/* */} {AnchorMenu.Instance.OnAudio === unimplementedFunction ? null : ( } color={StrCast(Doc.UserDoc().userColor)} /> )} - {this.canEdit() && } color={StrCast(Doc.UserDoc().userColor)} />} + {/* Removed text editing for now, not quite ready */} + {/* {this.canEdit() && } color={StrCast(Doc.UserDoc().userColor)} />} */} + {} color={StrCast(Doc.UserDoc().userColor)} />} } popup={} color={StrCast(Doc.UserDoc().userColor)} /> {AnchorMenu.Instance.StartCropDrag === unimplementedFunction ? null : ( } color={StrCast(Doc.UserDoc().userColor)} /> diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.scss b/src/client/views/pdf/GPTPopup/GPTPopup.scss index 2f0ff83e2..478b7d4ba 100644 --- a/src/client/views/pdf/GPTPopup/GPTPopup.scss +++ b/src/client/views/pdf/GPTPopup/GPTPopup.scss @@ -24,6 +24,7 @@ $highlightedText: #82e0ff; .summary-heading { display: flex; + justify-content: space-between; align-items: center; border-bottom: 1px solid $greyborder; padding-bottom: 5px; @@ -110,6 +111,57 @@ $highlightedText: #82e0ff; } } +.image-content-wrapper { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 8px; + padding-bottom: 16px; + + .img-wrapper { + position: relative; + cursor: pointer; + + .img-container { + position: relative; + + img { + position: relative; + } + } + + .img-container::after { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.5); + opacity: 0; + transition: opacity 0.3s ease; + } + + .btn-container { + position: absolute; + right: 8px; + bottom: 8px; + opacity: 0; + transition: opacity 0.3s ease; + } + + &:hover { + .img-container::after { + opacity: 1; + } + + .btn-container { + opacity: 1; + } + } + } +} + // Typist CSS .Typist .Cursor { display: inline-block; diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.tsx b/src/client/views/pdf/GPTPopup/GPTPopup.tsx index 9f28cb5d1..aeee90d16 100644 --- a/src/client/views/pdf/GPTPopup/GPTPopup.tsx +++ b/src/client/views/pdf/GPTPopup/GPTPopup.tsx @@ -1,4 +1,5 @@ import React = require('react'); +import './GPTPopup.scss'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; @@ -6,13 +7,14 @@ import ReactLoading from 'react-loading'; import Typist from 'react-typist'; import { Doc } from '../../../../fields/Doc'; import { DocUtils, Docs } from '../../../documents/Documents'; -import './GPTPopup.scss'; -import { Button, IconButton } from 'browndash-components'; -import { StrCast } from '../../../../fields/Types'; +import { Button, IconButton, Type } from 'browndash-components'; +import { NumCast, StrCast } from '../../../../fields/Types'; +import { CgClose } from 'react-icons/cg'; export enum GPTPopupMode { SUMMARY, EDIT, + IMAGE, } interface GPTPopupProps {} @@ -39,6 +41,14 @@ export class GPTPopup extends React.Component { public setText = (text: string) => { this.text = text; }; + + @observable + public imageUrls: string[] = []; + @action + public setImgUrls = (imgs: string[]) => { + this.imageUrls = imgs; + }; + @observable public mode: GPTPopupMode = GPTPopupMode.SUMMARY; @action @@ -58,6 +68,8 @@ export class GPTPopup extends React.Component { public setDone = (done: boolean) => { this.done = done; }; + + // change what can be a ref into a ref @observable private sidebarId: string = ''; @action @@ -65,19 +77,30 @@ export class GPTPopup extends React.Component { this.sidebarId = id; }; - // reference - // if (focusNode) { - // const anchor = srcWeb?.ComponentView?.getAnchor?.(true); - // anchor && DocUtils.MakeLink(htmlDoc, anchor, {}); - // } + // pdfs and webpages + @observable + private targetAnchor: Doc | undefined; + @action + public setTargetAnchor = (anchor: Doc) => { + this.targetAnchor = anchor; + }; + @observable - private pdfAnchor: Doc | undefined; + private imgTargetDoc: Doc | undefined; @action - public setPdfAnchor = (anchor: Doc) => { - this.pdfAnchor = anchor; + public setImgTargetDoc = (anchor: Doc) => { + this.imgTargetDoc = anchor; + }; + + @observable + private textAnchor: Doc | undefined; + @action + public setTextAnchor = (anchor: Doc) => { + this.textAnchor = anchor; }; public addDoc: (doc: Doc | Doc[], sidebarKey?: string | undefined) => boolean = () => false; + public addToCollection: ((doc: Doc | Doc[], annotationKey?: string | undefined) => boolean) | undefined; /** * Transfers the summarization text to a sidebar annotation text document. @@ -90,13 +113,42 @@ export class GPTPopup extends React.Component { _layout_autoHeight: true, }); this.addDoc(newDoc, this.sidebarId); - if (this.pdfAnchor) { - DocUtils.MakeLink(newDoc, this.pdfAnchor, { + if (this.targetAnchor) { + DocUtils.MakeLink(newDoc, this.targetAnchor, { link_relationship: 'GPT Summary', }); } }; + /** + * Transfers the image urls to actual image docs + */ + private transferToImage = (source: string) => { + console.log('Text Anchor', this.textAnchor); + console.log('Whole doc anchor', this.imgTargetDoc); + const textAnchor = this.textAnchor ?? this.imgTargetDoc; + if (!textAnchor) return; + const newDoc = Docs.Create.ImageDocument(source, { + x: NumCast(textAnchor.x) + NumCast(textAnchor._width) + 10, + y: NumCast(textAnchor.y), + _height: 200, + _width: 200, + data_nativeWidth: 1024, + data_nativeHeight: 1024, + }); + if (Doc.IsInMyOverlay(textAnchor)) { + newDoc.overlayX = textAnchor.x; + newDoc.overlayY = NumCast(textAnchor.y) + NumCast(textAnchor._height); + Doc.AddToMyOverlay(newDoc); + } else { + this.addToCollection?.(newDoc); + } + // Create link between prompt and image + DocUtils.MakeLink(textAnchor, newDoc, { link_relationship: 'Image Prompt' }); + }; + + private getPreviewUrl = (source: string) => source.split('.').join('_m.'); + constructor(props: GPTPopupProps) { super(props); GPTPopup.Instance = this; @@ -108,6 +160,26 @@ export class GPTPopup extends React.Component { } }; + imageBox = () => { + return ( +
+ {this.heading('GENERATED IMAGE')} +
+ {this.imageUrls.map(rawSrc => ( +
+
+ dalle generation +
+
+
+
+ ))} +
+
+ ); + }; + summaryBox = () => ( <>
@@ -135,30 +207,21 @@ export class GPTPopup extends React.Component {
{this.done ? ( <> - {/* - */} - } color={StrCast(Doc.UserDoc().userVariantColor)} /> - + }} + color={StrCast(Doc.UserDoc().userVariantColor)} + type={Type.TERT} + />
)}
@@ -216,14 +279,14 @@ export class GPTPopup extends React.Component { heading = (headingText: string) => (
- {this.loading && } + {this.loading ? : } onClick={() => this.setVisible(false)} />}
); render() { return (
- {this.mode === GPTPopupMode.SUMMARY ? this.summaryBox() : this.editBox()} + {this.mode === GPTPopupMode.SUMMARY ? this.summaryBox() : this.mode === GPTPopupMode.IMAGE ? this.imageBox() : this.editBox()}
); } diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 4fc31ffe3..1d1c34f4f 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -425,8 +425,7 @@ export class PDFViewer extends React.Component { GPTPopup.Instance.setSidebarId('data_sidebar'); const anchor = this._getAnchor(undefined, false); if (anchor) { - console.log(anchor); - GPTPopup.Instance.setPdfAnchor(anchor); + GPTPopup.Instance.setTargetAnchor(anchor); } GPTPopup.Instance.addDoc = this.props.sidebarAddDoc; }; -- cgit v1.2.3-70-g09d2 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. --- package-lock.json | 103 ++------------------- package.json | 2 +- 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 ++++----- 18 files changed, 228 insertions(+), 298 deletions(-) (limited to 'src/client/views/nodes/formattedText') diff --git a/package-lock.json b/package-lock.json index 54d1b568c..082531ea0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6351,9 +6351,9 @@ } }, "browndash-components": { - "version": "0.0.90", - "resolved": "https://registry.npmjs.org/browndash-components/-/browndash-components-0.0.90.tgz", - "integrity": "sha512-56dsp2yoP5axTnXSPtSpWsQUkcj3hAekYBHLk7Kw6OV7LHVuu5PZruSmGE9xDrdhAFz2UdUyxKeAGB3PdbQoew==", + "version": "0.0.91", + "resolved": "https://registry.npmjs.org/browndash-components/-/browndash-components-0.0.91.tgz", + "integrity": "sha512-VYW1C1XY6CcQD4OceQHK/2VGhSa0H0iboom7M9zy5F6WHJP03LFHrwKkRtgsqwxQBQLsj69XXlEfygbSkV3FvQ==", "requires": { "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", @@ -6902,97 +6902,12 @@ "strip-ansi": "^7.0.1" } }, - "string-width-cjs": { - "version": "npm:string-width@4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "requires": { - "ansi-regex": "^5.0.1" - } - } - } - }, "strip-ansi": { "version": "7.1.0", "bundled": true, "requires": { "ansi-regex": "^6.0.1" } - }, - "strip-ansi-cjs": { - "version": "npm:strip-ansi@6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "requires": { - "ansi-regex": "^5.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - } - } - }, - "wrap-ansi-cjs": { - "version": "npm:wrap-ansi@7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "requires": { - "ansi-regex": "^5.0.1" - } - } - } } } }, @@ -8497,7 +8412,7 @@ } }, "string-width-cjs": { - "version": "npm:string-width-cjs@4.2.3", + "version": "npm:string-width@4.2.3", "bundled": true, "requires": { "emoji-regex": "^8.0.0", @@ -8520,7 +8435,7 @@ } }, "strip-ansi-cjs": { - "version": "npm:strip-ansi-cjs@6.0.1", + "version": "npm:strip-ansi@6.0.1", "bundled": true, "requires": { "ansi-regex": "^5.0.1" @@ -8679,7 +8594,7 @@ } }, "wrap-ansi-cjs": { - "version": "npm:wrap-ansi-cjs@7.0.0", + "version": "npm:wrap-ansi@7.0.0", "bundled": true, "requires": { "ansi-styles": "^4.0.0", @@ -9865,9 +9780,9 @@ "integrity": "sha512-GiZn9D4Z/rSYvTeg1ljAIsEqFm0LaN9gVtwDCrKL80zHtS31p9BAjmTxVqTQDMpwlMolJZOFntUG2uwyj7DAqw==" }, "core-js-compat": { - "version": "3.31.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.31.1.tgz", - "integrity": "sha512-wIDWd2s5/5aJSdpOJHfSibxNODxoGoWOBHt8JSPB41NOE94M7kuTPZCYLOlTtuoXTsBPKobpJ6T+y0SSy5L9SA==", + "version": "3.32.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.32.0.tgz", + "integrity": "sha512-7a9a3D1k4UCVKnLhrgALyFcP7YCsLOQIxPd0dKjf/6GuPcgyiGP70ewWdCGrSK7evyhymi0qO4EqCmSJofDeYw==", "requires": { "browserslist": "^4.21.9" } diff --git a/package.json b/package.json index 8da591254..822460a10 100644 --- a/package.json +++ b/package.json @@ -177,7 +177,7 @@ "body-parser": "^1.19.2", "bootstrap": "^4.6.1", "brotli": "^1.3.3", - "browndash-components": "^0.0.90", + "browndash-components": "^0.0.91", "browser-assert": "^1.2.1", "bson": "^4.6.1", "canvas": "^2.9.3", 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 = ( - */} - {/*
*/} - {this.sharingTable} - } - isOpen={this.openSharing} - setIsOpen={(bool) => this.openSharing = bool} - onDoubleClick={() => this.onDoubleClick()} - /> + {/*
*/} + {this.sharingTable} + + } + isOpen={this.openSharing} + setIsOpen={bool => (this.openSharing = bool)} + onDoubleClick={() => this.onDoubleClick()} + /> + ); } /** @@ -1192,15 +1148,19 @@ export class PropertiesView extends React.Component { }; @computed get filtersSubMenu() { - return - -
} - isOpen={this.openFilters} - setIsOpen={(bool) => this.openFilters = bool} - onDoubleClick={() => this.onDoubleClick()} - /> + return ( + + +
+ } + isOpen={this.openFilters} + setIsOpen={bool => (this.openFilters = bool)} + onDoubleClick={() => this.onDoubleClick()} + /> + ); } @computed get inkSubMenu() { @@ -1208,68 +1168,42 @@ export class PropertiesView extends React.Component { return ( <> - this.openAppearance = bool} - onDoubleClick={() => this.onDoubleClick()} - /> - this.openTransform = bool} - onDoubleClick={() => this.onDoubleClick()} - /> + (this.openAppearance = bool)} onDoubleClick={() => this.onDoubleClick()} /> + (this.openTransform = bool)} onDoubleClick={() => this.onDoubleClick()} /> ); } @computed get fieldsSubMenu() { - return { - Doc.noviceMode ? this.noviceFields : this.expandedField} - } - isOpen={this.openFields} - setIsOpen={(bool) => this.openFields = bool} - onDoubleClick={() => this.onDoubleClick()} - /> + return ( + {Doc.noviceMode ? this.noviceFields : this.expandedField}} + isOpen={this.openFields} + setIsOpen={bool => (this.openFields = bool)} + onDoubleClick={() => this.onDoubleClick()} + /> + ); } @computed get contextsSubMenu() { - return 0 ? this.contexts : "There are no other contexts."} - isOpen={this.openContexts} - setIsOpen={(bool) => this.openContexts = bool} - onDoubleClick={() => this.onDoubleClick()} - /> + return ( + 0 ? this.contexts : 'There are no other contexts.'} + isOpen={this.openContexts} + setIsOpen={bool => (this.openContexts = bool)} + onDoubleClick={() => this.onDoubleClick()} + /> + ); } - - - - @computed get linksSubMenu() { - return 0 ? this.links : "There are no current links." } - isOpen={this.openLinks} - setIsOpen={(bool) => this.openLinks = bool} - onDoubleClick={() => this.onDoubleClick()} - /> + return 0 ? this.links : 'There are no current links.'} isOpen={this.openLinks} setIsOpen={bool => (this.openLinks = bool)} onDoubleClick={() => this.onDoubleClick()} />; } @computed get layoutSubMenu() { - return this.openLayout = bool} - onDoubleClick={() => this.onDoubleClick()} - /> + return (this.openLayout = bool)} onDoubleClick={() => this.onDoubleClick()} />; } @computed get description() { @@ -1470,224 +1404,226 @@ export class PropertiesView extends React.Component { if (scale > 1) scale = 1; this.sourceAnchor && (this.sourceAnchor.followLinkZoomScale = scale); }; - + @computed get linkProperties() { const zoom = Number((NumCast(this.sourceAnchor?.followLinkZoomScale, 1) * 100).toPrecision(3)); const targZoom = this.sourceAnchor?.followLinkZoom; const indent = 30; const hasSelectedAnchor = LinkManager.Links(this.sourceAnchor).includes(LinkManager.currentLink!); - return <> -
-
-

Relationship

- {this.editRelationship} -
-
-

Description

- {this.editDescription} -
-
-

Show link

- -
-
-

Auto-move anchors

- -
-
-

Display arrow

- -
-
- {!hasSelectedAnchor ? null : ( -
-
-

Follow by

- -
-
-

Animation

- -
- {this.animationDirection(PresEffectDirection.Left, 'angle-right', 1, 2, {})} - {this.animationDirection(PresEffectDirection.Right, 'angle-left', 3, 2, {})} - {this.animationDirection(PresEffectDirection.Top, 'angle-down', 2, 1, {})} - {this.animationDirection(PresEffectDirection.Bottom, 'angle-up', 2, 3, {})} - {this.animationDirection(PresEffectDirection.Center, '', 2, 2, { width: 10, height: 10, alignSelf: 'center' })} + return ( + <> +
+
+

Relationship

+ {this.editRelationship} +
+
+

Description

+ {this.editDescription} +
+
+

Show link

+ +
+
+

Auto-move anchors

+ +
+
+

Display arrow

+
- {PresBox.inputter( - '0.1', - '0.1', - '10', - NumCast(this.sourceAnchor?.followLinkTransitionTime) / 1000, - true, - (val: string) => PresBox.SetTransitionTime(val, (timeInMS: number) => this.sourceAnchor && (this.sourceAnchor.followLinkTransitionTime = timeInMS)), - indent - )}{' '} -
-
Fast
-
Slow
-
{' '} -
-

Play Target Audio

- -
-
-

Zoom Text Selections

- -
-
-

Toggle Follow to Outer Context

- -
-
-

Toggle Target (Show/Hide)

- -
-
-

Ease Transitions

- -
-
-

Capture Offset to Target

- -
-
-

Center Target (no zoom)

- -
-
-

Zoom %

-
- -
-
this.setZoom(String(zoom), 0.1))}> - + {!hasSelectedAnchor ? null : ( +
+
+

Follow by

+ +
+
+

Animation

+ +
+ {this.animationDirection(PresEffectDirection.Left, 'angle-right', 1, 2, {})} + {this.animationDirection(PresEffectDirection.Right, 'angle-left', 3, 2, {})} + {this.animationDirection(PresEffectDirection.Top, 'angle-down', 2, 1, {})} + {this.animationDirection(PresEffectDirection.Bottom, 'angle-up', 2, 3, {})} + {this.animationDirection(PresEffectDirection.Center, '', 2, 2, { width: 10, height: 10, alignSelf: 'center' })}
-
this.setZoom(String(zoom), -0.1))}> - +
+ {PresBox.inputter( + '0.1', + '0.1', + '10', + NumCast(this.sourceAnchor?.followLinkTransitionTime) / 1000, + true, + (val: string) => PresBox.SetTransitionTime(val, (timeInMS: number) => this.sourceAnchor && (this.sourceAnchor.followLinkTransitionTime = timeInMS)), + indent + )}{' '} +
+
Fast
+
Slow
+
{' '} +
+

Play Target Audio

+ +
+
+

Zoom Text Selections

+ +
+
+

Toggle Follow to Outer Context

+ +
+
+

Toggle Target (Show/Hide)

+ +
+
+

Ease Transitions

+ +
+
+

Capture Offset to Target

+ +
+
+

Center Target (no zoom)

+ +
+
+

Zoom %

+
+ +
+
this.setZoom(String(zoom), 0.1))}> + +
+
this.setZoom(String(zoom), -0.1))}> + +
+
+
+ {!targZoom ? null : PresBox.inputter('0', '1', '100', zoom, true, this.setZoom, 30)} +
+
0%
+
100%
+
{' '}
- -
- {!targZoom ? null : PresBox.inputter('0', '1', '100', zoom, true, this.setZoom, 30)} -
-
0%
-
100%
-
{' '} -
- )} - + )} + + ); } /** @@ -1723,23 +1659,20 @@ export class PropertiesView extends React.Component { width: this.props.width, minWidth: this.props.width, }}> -
+
Properties
-
window.open('https://brown-dash.github.io/Dash-Documentation/')}> -
- +
window.open('https://brown-dash.github.io/Dash-Documentation/')}> + {' '} +
-
{this.editableTitle}
-
{this.currentType}
+
{this.currentType}
{this.contextsSubMenu} {this.linksSubMenu} - {!this.selectedDoc || !LinkManager.currentLink || (!hasSelectedAnchor && this.selectedDoc !== LinkManager.currentLink) ? null : ( - this.linkProperties - )} + {!this.selectedDoc || !LinkManager.currentLink || (!hasSelectedAnchor && this.selectedDoc !== LinkManager.currentLink) ? null : this.linkProperties} {this.inkSubMenu} {this.optionsSubMenu} {this.fieldsSubMenu} @@ -1760,7 +1693,6 @@ export class PropertiesView extends React.Component { Presentation
- {this.editableTitle}
{PresBox.Instance.selectedArray.size} selected
@@ -1772,7 +1704,7 @@ export class PropertiesView extends React.Component {
(this.openPresTransitions = !this.openPresTransitions))} style={{ backgroundColor: this.openPresTransitions ? 'black' : '' }}>     Transitions
- +
{this.openPresTransitions ?
{PresBox.Instance.transitionDropdown}
: null} @@ -1786,7 +1718,7 @@ export class PropertiesView extends React.Component { style={{ backgroundColor: this.openPresTransitions ? 'black' : '' }}>     Visibilty
- +
{this.openPresVisibilityAndDuration ?
{PresBox.Instance.visibiltyDurationDropdown}
: null} @@ -1797,7 +1729,7 @@ export class PropertiesView extends React.Component {
(this.openPresProgressivize = !this.openPresProgressivize))} style={{ backgroundColor: this.openPresTransitions ? 'black' : '' }}>     Progressivize
- +
{this.openPresProgressivize ?
{PresBox.Instance.progressivizeDropdown}
: null} @@ -1808,7 +1740,7 @@ export class PropertiesView extends React.Component {
(this.openSlideOptions = !this.openSlideOptions))} style={{ backgroundColor: this.openSlideOptions ? 'black' : '' }}>     {type === DocumentType.AUDIO ? 'Audio Options' : 'Video Options'}
- +
{this.openSlideOptions ?
{PresBox.Instance.mediaOptionsDropdown}
: null} diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index bbbad3690..94748e884 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -22,7 +22,7 @@ import { DocumentViewProps } from './nodes/DocumentView'; import { FieldViewProps } from './nodes/FieldView'; import { KeyValueBox } from './nodes/KeyValueBox'; import { SliderBox } from './nodes/SliderBox'; -import { BsArrowDown, BsArrowUp, BsArrowDownUp } from 'react-icons/bs' +import { BsArrowDown, BsArrowUp, BsArrowDownUp } from 'react-icons/bs'; import './StyleProvider.scss'; import React = require('react'); @@ -161,7 +161,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt = StrCast(doc?.[fieldKey + 'color'], StrCast(doc?._color)); @@ -208,12 +208,10 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, props: Opt { @observable static HideInline: boolean; @observable static Expand: boolean; render() { - const background = UndoManager.batchCounter.get() ? 'yellow' : StrCast(Doc.UserDoc().userBackgroundColor) + const background = UndoManager.batchCounter.get() ? 'yellow' : SettingsManager.Instance.userBackgroundColor; return this.props.inline && UndoStack.HideInline ? null : (
- r?.scroll({ behavior: 'auto', top: r?.scrollHeight + 20 })} - style={{ - background: background, - color: isDark(background) ? Colors.LIGHT_GRAY : Colors.DARK_GRAY - }}> - {UndoManager.undoStackNames.map((name, i) => ( -
-
{name.replace(/[^\.]*\./, '')}
-
- ))} - {Array.from(UndoManager.redoStackNames) - .reverse() - .map((name, i) => ( +
r?.scroll({ behavior: 'auto', top: r?.scrollHeight + 20 })} + style={{ + background: background, + color: isDark(background) ? Colors.LIGHT_GRAY : Colors.DARK_GRAY, + }}> + {UndoManager.undoStackNames.map((name, i) => (
-
- {name.replace(/[^\.]*\./, '')} -
+
{name.replace(/[^\.]*\./, '')}
- ))} -
+ ))} + {Array.from(UndoManager.redoStackNames) + .reverse() + .map((name, i) => ( +
+
+ {name.replace(/[^\.]*\./, '')} +
+
+ ))} +
} />
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 16982595d..0052c4196 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -164,7 +164,7 @@ export class CollectionDockingView extends CollectionSubView() { public static AddSplit(document: Doc, pullSide: OpenWhereMod, stack?: any, panelName?: string, keyValue?: boolean) { if (document?._type_collection === CollectionViewType.Docking && !keyValue) return DashboardView.openDashboard(document); if (!CollectionDockingView.Instance) return false; - const tab = Array.from(CollectionDockingView.Instance.tabMap).find(tab => tab.DashDoc === document && !keyValue); + const tab = Array.from(CollectionDockingView.Instance.tabMap).find(tab => tab.DashDoc === document && !tab.contentItem.config.props.keyValue && !keyValue); if (tab) { tab.header.parent.setActiveContentItem(tab.contentItem); return true; @@ -466,7 +466,10 @@ export class CollectionDockingView extends CollectionSubView() { this._flush = this._flush ?? UndoManager.StartBatch('tab movement'); if (tab.DashDoc && ![DocumentType.PRES].includes(tab.DashDoc?.type) && !tab.contentItem.config.props.keyValue) { Doc.AddDocToList(Doc.MyHeaderBar, 'data', tab.DashDoc); - Doc.AddDocToList(Doc.MyRecentlyClosed, 'data', tab.DashDoc, undefined, true, true); + // if you close a tab that is not embedded somewhere else (an embedded Doc can be opened simultaneously in a tab), then add the tab to recently closed + if (tab.DashDoc.embedContainer === this.rootDoc) tab.DashDoc.embedContainer = undefined; + if (!tab.DashDoc.embedContainer) Doc.AddDocToList(Doc.MyRecentlyClosed, 'data', tab.DashDoc, undefined, true, true); + Doc.RemoveDocFromList(Doc.GetProto(tab.DashDoc), 'proto_embeddings', tab.DashDoc); } if (CollectionDockingView.Instance) { const dview = CollectionDockingView.Instance.props.Document; diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index 5135cfb57..f65e8698f 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -181,7 +181,7 @@ export class CollectionMenu extends AntimodeMenu {
{this.contMenuButtons} diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index a5c276125..056204ad3 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -669,7 +669,6 @@ export class CollectionStackingView extends CollectionSubView { return NumCast(Cast(PresBox.Instance.activeItem.presentationTargetDoc, Doc, null)._currentFrame); }; static Activate = (tabDoc: Doc) => { - const tab = Array.from(CollectionDockingView.Instance?.tabMap!).find(tab => tab.DashDoc === tabDoc); + const tab = Array.from(CollectionDockingView.Instance?.tabMap!).find(tab => tab.DashDoc === tabDoc && !tab.contentItem.config.props.keyValue); tab?.header.parent.setActiveContentItem(tab.contentItem); // glr: Panning does not work when this is set - (this line is for trying to make a tab that is not topmost become topmost) return tab !== undefined; }; diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index fb23fc7f1..6e0ccd4be 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -127,7 +127,7 @@ export class TreeView extends React.Component { : this.props.treeView.fileSysMode ? this.doc.isFolder ? this.fieldKey - : 'embeddings' // for displaying + : 'data' // file system folders display their contents (data). used to be they displayed their embeddings but now its a tree structure and not a flat list : this.props.treeView.outlineMode || this.childDocs ? this.fieldKey : Doc.noviceMode diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 090cf356c..7c53bfdbe 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -377,7 +377,6 @@ export class MarqueeView extends React.Component { Doc.GetProto(doc).data = new List(selected); Doc.GetProto(doc).title = makeGroup ? 'grouping' : 'nested freeform'; - !this.props.isAnnotationOverlay && Doc.AddFileOrphan(Doc.GetProto(doc)); doc._freeform_panX = doc._freeform_panY = 0; return doc; })(Doc.MakeCopy(Doc.UserDoc().emptyCollection as Doc, true)); diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts index 79842047b..256377758 100644 --- a/src/client/views/global/globalScripts.ts +++ b/src/client/views/global/globalScripts.ts @@ -197,7 +197,6 @@ ScriptingGlobals.add(function toggleCharStyle(charStyle: attrname, checkResult?: }); export function checkInksToGroup() { - // console.log("getting here to inks group"); if (Doc.ActiveTool === InkTool.Write) { CollectionFreeFormView.collectionsWithUnprocessedInk.forEach(ffView => { // TODO: nda - will probably want to go through ffView unprocessed docs and then see if any of the inksToGroup docs are in it and only use those diff --git a/src/client/views/newlightbox/ExploreView/ExploreView.tsx b/src/client/views/newlightbox/ExploreView/ExploreView.tsx index 44a0bcd5f..a1d6375c4 100644 --- a/src/client/views/newlightbox/ExploreView/ExploreView.tsx +++ b/src/client/views/newlightbox/ExploreView/ExploreView.tsx @@ -12,14 +12,11 @@ export const ExploreView = (props: IExploreView) => {
{recs && recs.map(rec => { - console.log(rec.embedding, bounds); const x_bound: number = Math.max(Math.abs(bounds.max_x), Math.abs(bounds.min_x)); const y_bound: number = Math.max(Math.abs(bounds.max_y), Math.abs(bounds.min_y)); - console.log(x_bound, y_bound); if (rec.embedding) { const x = (rec.embedding.x / x_bound) * 50; const y = (rec.embedding.y / y_bound) * 50; - console.log(x, y); return (
{}} style={{ top: `calc(50% + ${y}%)`, left: `calc(50% + ${x}%)` }}> {rec.title} diff --git a/src/client/views/newlightbox/components/Recommendation/Recommendation.tsx b/src/client/views/newlightbox/components/Recommendation/Recommendation.tsx index b9d05c531..2c2f04b9f 100644 --- a/src/client/views/newlightbox/components/Recommendation/Recommendation.tsx +++ b/src/client/views/newlightbox/components/Recommendation/Recommendation.tsx @@ -22,7 +22,6 @@ export const Recommendation = (props: IRecommendation) => { doc = docView.rootDoc; } } else if (data) { - console.log(data, type); switch (type) { case 'YouTube': console.log('create ', type, 'document'); diff --git a/src/client/views/nodes/DataVizBox/utils/D3Utils.ts b/src/client/views/nodes/DataVizBox/utils/D3Utils.ts index e1ff6f8eb..10bfb0c64 100644 --- a/src/client/views/nodes/DataVizBox/utils/D3Utils.ts +++ b/src/client/views/nodes/DataVizBox/utils/D3Utils.ts @@ -34,7 +34,6 @@ export const createLineGenerator = (xScale: d3.ScaleLinear, height: number, xScale: d3.ScaleLinear) => { - console.log('x axis creator being called'); g.attr('class', 'x-axis').attr('transform', `translate(0,${height})`).call(d3.axisBottom(xScale).tickSize(15)); }; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 70d2f95ea..d379b2b52 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, trace } from 'mobx'; +import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; import { Bounce, Fade, Flip, LightSpeed, Roll, Rotate, Zoom } from 'react-reveal'; @@ -47,7 +47,6 @@ import { DocumentLinksButton } from './DocumentLinksButton'; import './DocumentView.scss'; import { FieldViewProps } from './FieldView'; import { FormattedTextBox } from './formattedText/FormattedTextBox'; -import { KeyValueBox } from './KeyValueBox'; import { LinkAnchorBox } from './LinkAnchorBox'; import { PresEffect, PresEffectDirection } from './trails'; import { PinProps, PresBox } from './trails/PresBox'; diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx index 86191de63..d69009415 100644 --- a/src/client/views/nodes/LinkDocPreview.tsx +++ b/src/client/views/nodes/LinkDocPreview.tsx @@ -4,7 +4,7 @@ import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; import wiki from 'wikijs'; import { Doc, DocCastAsync, Opt } from '../../../fields/Doc'; -import { Height, Width } from '../../../fields/DocSymbols'; +import { DirectLinks, Height, Width } from '../../../fields/DocSymbols'; import { Cast, DocCast, NumCast, PromiseValue, StrCast } from '../../../fields/Types'; import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnNone, setupMoveUpEvents } from '../../../Utils'; import { DocServer } from '../../DocServer'; diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx index de0b57fd7..4919ee94c 100644 --- a/src/client/views/nodes/MapBox/MapBox.tsx +++ b/src/client/views/nodes/MapBox/MapBox.tsx @@ -61,7 +61,6 @@ const script = document.createElement('script'); script.defer = true; script.async = true; script.src = `https://maps.googleapis.com/maps/api/js?key=${apiKey}&libraries=places,drawing`; -console.log(script.src); document.head.appendChild(script); /** diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx index 312b3c619..bbf56bdf9 100644 --- a/src/client/views/nodes/ScreenshotBox.tsx +++ b/src/client/views/nodes/ScreenshotBox.tsx @@ -224,7 +224,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent aud_chunks.push(e.data); this._audioRec.onstop = async (e: any) => { - const [{ result }] = await Networking.UploadFilesToServer(aud_chunks.map((file: any) => ({file}))); + const [{ result }] = await Networking.UploadFilesToServer(aud_chunks.map((file: any) => ({ file }))); if (!(result instanceof Error)) { this.dataDoc[this.props.fieldKey + '-audio'] = new AudioField(result.accessPaths.agnostic.client); } @@ -235,9 +235,8 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent (this.dataDoc[this.props.fieldKey + '-recordingStart'] = new DateField(new Date())); this._videoRec.ondataavailable = (e: any) => vid_chunks.push(e.data); this._videoRec.onstop = async (e: any) => { - console.log('screenshotbox: upload'); const file = new File(vid_chunks, `${this.rootDoc[Id]}.mkv`, { type: vid_chunks[0].type, lastModified: Date.now() }); - const [{ result }] = await Networking.UploadFilesToServer({file}); + const [{ result }] = await Networking.UploadFilesToServer({ file }); this.dataDoc[this.fieldKey + '_duration'] = (new Date().getTime() - this.recordingStart!) / 1000; if (!(result instanceof Error)) { // convert this screenshotBox into normal videoBox diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx index 3ad3c911d..7c8a1849e 100644 --- a/src/client/views/nodes/ScriptingBox.tsx +++ b/src/client/views/nodes/ScriptingBox.tsx @@ -610,7 +610,6 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent this.handleToken(token), component: (blob: any) => { - console.log('Blob', blob); return this.renderFuncListElement(blob.entity); }, output: (item: any, trigger: any) => { @@ -621,7 +620,6 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent this.handleToken(token), component: (blob: any) => { - console.log('Blob', blob); return this.renderFuncListElement(blob.entity); }, output: (item: any, trigger: any) => { diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 895bb80f0..1dcc445e8 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -96,6 +96,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent = React.createRef(); private _editorView: Opt; public _applyingChange: string = ''; + private _finishingLink = false; private _searchIndex = 0; private _lastTimedMark: Mark | undefined = undefined; private _cachedLinks: Doc[] = []; @@ -245,7 +246,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent m.type.name === schema.marks.noAutoLinkAnchor.name) && node.marks.find((m: Mark) => m.type.name === schema.marks.splitter.name)) { alink = alink ?? - (LinkManager.Links(this.Document).find(link => Doc.AreProtosEqual(Cast(link.link_anchor_1, Doc, null), this.rootDoc) && Doc.AreProtosEqual(Cast(link.link_anchor_2, Doc, null), target)) || - DocUtils.MakeLink(this.props.Document, target, { link_relationship: LinkManager.AutoKeywords })!); + (LinkManager.Links(this.rootDoc).find( + link => + Doc.AreProtosEqual(Cast(link.link_anchor_1, Doc, null), this.rootDoc) && // + Doc.AreProtosEqual(Cast(link.link_anchor_2, Doc, null), target) + ) || + DocUtils.MakeLink(this.rootDoc, target, { link_relationship: LinkManager.AutoKeywords })!); newAutoLinks.add(alink); const allAnchors = [{ href: Doc.localServerPath(target), title: 'a link', anchorId: this.props.Document[Id] }]; allAnchors.push(...(node.marks.find((m: Mark) => m.type.name === schema.marks.autoLinkAnchor.name)?.attrs.allAnchors ?? [])); @@ -840,7 +847,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent Doc.UserDoc().defaultTextLayout = new PrefetchProxy(this.rootDoc), icon: "eye" }); !Doc.noviceMode && @@ -1996,12 +2003,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { if (this.layoutDoc._layout_enableAltContentUI) { - const usePath = this.rootDoc[`${this.props.fieldKey}_usePath`]; + const usePath = this.rootDoc[`_${this.props.fieldKey}_usePath`]; this.rootDoc[`_${this.props.fieldKey}_usePath`] = usePath === undefined ? 'alternate' : usePath === 'alternate' ? 'alternate:hover' : undefined; } }; @computed get overlayAlternateIcon() { - const usePath = this.rootDoc[`${this.props.fieldKey}_usePath`]; + const usePath = this.rootDoc[`_${this.props.fieldKey}_usePath`]; return ( : ]] - // [[:Doc]] => hyperlink + // [[:docTitle]] => hyperlink // [[fieldKey]] => show field // [[fieldKey=value]] => show field and also set its value - // [[fieldKey:Doc]] => show field of doc + // [[fieldKey:docTitle]] => show field of doc new InputRule(new RegExp(/\[\[([a-zA-Z_\? \-0-9]*)(=[a-zA-Z_@\? /\-0-9]*)?(:[a-zA-Z_@:\.\? \-0-9]+)?\]\]$/), (state, match, start, end) => { const fieldKey = match[1]; - const docId = match[3]?.replace(':', ''); + const docTitle = match[3]?.replace(':', ''); const value = match[2]?.substring(1); const linkToDoc = (target: Doc) => { const rstate = this.TextBox.EditorView?.state; @@ -266,12 +266,12 @@ export class RichTextRules { } }; if (!fieldKey) { - if (docId) { - const target = DocServer.QUERY_SERVER_CACHE(docId); - if (target) setTimeout(() => linkToDoc(target)); - else DocServer.GetRefField(docId).then(docx => linkToDoc((docx instanceof Doc && docx) || Docs.Create.FreeformDocument([], { title: docId + '(auto)', _width: 500, _height: 500 }, docId))); - - return state.tr.deleteRange(end - 1, end).deleteRange(start, start + 3); + if (docTitle) { + const target = DocServer.FindDocByTitle(docTitle); + if (target) { + setTimeout(() => linkToDoc(target)); + return state.tr.deleteRange(end - 1, end).deleteRange(start, start + 3); + } } return state.tr; } @@ -279,8 +279,12 @@ export class RichTextRules { const num = value.match(/^[0-9.]$/); this.Document[DocData][fieldKey] = value === 'true' ? true : value === 'false' ? false : num ? Number(value) : value; } - const fieldView = state.schema.nodes.dashField.create({ fieldKey, docId, hideKey: false }); - return state.tr.setSelection(new TextSelection(state.doc.resolve(start), state.doc.resolve(end))).replaceSelectionWith(fieldView, true); + const target = DocServer.FindDocByTitle(docTitle); + if (target) { + const fieldView = state.schema.nodes.dashField.create({ fieldKey, docId: target[Id], hideKey: false }); + return state.tr.setSelection(new TextSelection(state.doc.resolve(start), state.doc.resolve(end))).replaceSelectionWith(fieldView, true); + } + return state.tr; }), // create a text display of a metadata field on this or another document, or create a hyperlink portal to another document diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx index b877cc36a..e35e011e2 100644 --- a/src/client/views/pdf/AnchorMenu.tsx +++ b/src/client/views/pdf/AnchorMenu.tsx @@ -17,6 +17,7 @@ import { EditorView } from 'prosemirror-view'; import './AnchorMenu.scss'; import { ColorPicker, Group, IconButton, Popup, Size, Toggle, ToggleType, Type } from 'browndash-components'; import { StrCast } from '../../../fields/Types'; +import { DocumentType } from '../../documents/DocumentTypes'; @observer export class AnchorMenu extends AntimodeMenu { @@ -262,7 +263,7 @@ export class AnchorMenu extends AntimodeMenu { colorPicker={this.highlightColor} color={StrCast(Doc.UserDoc().userColor)} /> - this.changeHighlightColor(color)} size={Size.XSMALL} /> + ); } @@ -287,7 +288,7 @@ export class AnchorMenu extends AntimodeMenu { canSummarize = (): boolean => { const docs = SelectionManager.Docs(); if (docs.length > 0) { - return docs.some(doc => doc.type === 'pdf' || doc.type === 'web'); + return docs.some(doc => doc.type === DocumentType.PDF || doc.type === DocumentType.WEB); } return false; }; diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index e911bd283..a28561107 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -18,6 +18,7 @@ import './SearchBox.scss'; import { fetchRecommendations } from '../newlightbox/utils'; import { IRecommendation, Recommendation } from '../newlightbox/components'; import { Colors } from '../global/globalEnums'; +import { SettingsManager } from '../../util/SettingsManager'; const DAMPENING_FACTOR = 0.9; const MAX_ITERATIONS = 25; @@ -218,7 +219,7 @@ export class SearchBox extends ViewBoxBaseComponent() { } @action static staticSearchCollection(rootDoc: Opt, query: string) { - const blockedTypes = [DocumentType.PRESELEMENT, DocumentType.CONFIG, DocumentType.KVP, DocumentType.FILTER, DocumentType.SEARCH, DocumentType.SEARCHITEM, DocumentType.FONTICON, DocumentType.BUTTON, DocumentType.SCRIPTING]; + const blockedTypes = [DocumentType.PRESELEMENT, DocumentType.CONFIG, DocumentType.KVP, DocumentType.SEARCH, DocumentType.FONTICON, DocumentType.BUTTON, DocumentType.SCRIPTING]; const blockedKeys = [ 'x', 'y', @@ -398,22 +399,21 @@ export class SearchBox extends ViewBoxBaseComponent() { if (query) { this.searchCollection(query); - const response = await fetchRecommendations('', query, [], true) - const recs = response.recommendations - const recommendations:IRecommendation[] = [] + const response = await fetchRecommendations('', query, [], true); + const recs = response.recommendations; + const recommendations: IRecommendation[] = []; for (const key in recs) { const title = recs[key].title; - console.log(title); - const url = recs[key].url - const type = recs[key].type - const text = recs[key].text - const transcript = recs[key].transcript - const previewUrl = recs[key].previewUrl - const embedding = recs[key].embedding - const distance = recs[key].distance - const source = recs[key].source - const related_concepts = recs[key].related_concepts - const docId = recs[key].doc_id + const url = recs[key].url; + const type = recs[key].type; + const text = recs[key].text; + const transcript = recs[key].transcript; + const previewUrl = recs[key].previewUrl; + const embedding = recs[key].embedding; + const distance = recs[key].distance; + const source = recs[key].source; + const related_concepts = recs[key].related_concepts; + const docId = recs[key].doc_id; recommendations.push({ title: title, data: url, @@ -425,11 +425,11 @@ export class SearchBox extends ViewBoxBaseComponent() { distance: Math.round(distance * 100) / 100, source: source, related_concepts: related_concepts, - docId: docId - }) + docId: docId, + }); } - const setRecommendations = action(() => this._recommendations = recommendations) - setRecommendations() + const setRecommendations = action(() => (this._recommendations = recommendations)); + setRecommendations(); } }; @@ -461,7 +461,7 @@ export class SearchBox extends ViewBoxBaseComponent() { */ @computed public get selectOptions() { - const selectValues = ['all', 'rtf', 'image', 'pdf', 'web', 'video', 'audio', 'collection']; + const selectValues = ['all', DocumentType.RTF, DocumentType.IMG, DocumentType.PDF, DocumentType.WEB, DocumentType.VID, DocumentType.AUDIO, DocumentType.COL]; return selectValues.map(value => (
); } }); - const recommendationsJSX: JSX.Element[] = this._recommendations.map((props) => ( - - )) + const recommendationsJSX: JSX.Element[] = this._recommendations.map(props => ); return ( -
+
{isLinkSearch ? null : ( - { - if (fileRef.current) { - fileRef.current.click(); - } - }}> - - { setBrushStyle(BrushStyle.ADD); }}> - + {/* Undo and Redo */} + + { + setCursorData(prev => ({ ...prev, width: val as number })); + }} + /> +
{/* Edits thumbnails*/}
@@ -484,12 +490,14 @@ const GenerativeFill = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addD width={100} height={100} src={edit} - onClick={() => { + onClick={async () => { + // if (savedSrcs.current.has(edit)) return; const img = new Image(); img.src = edit; ImageUtility.drawImgToCanvas(img, canvasRef); currImg.current = img; - onSave(); + savedSrcs.current.add(edit); + await onSave(); }} /> ))} @@ -521,14 +529,6 @@ const GenerativeFill = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addD currImg.current = img; }} /> -
- {saveLoading && } -
)}
@@ -541,15 +541,14 @@ const GenerativeFill = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addD type="text" label="Prompt" placeholder="Prompt..." - InputLabelProps={{ style: { fontSize: '1.5rem' } }} - inputProps={{ style: { fontSize: '1.5rem' } }} + InputLabelProps={{ style: { fontSize: '16px' } }} + inputProps={{ style: { fontSize: '16px' } }} sx={{ backgroundColor: '#ffffff', position: 'absolute', - bottom: '1rem', + bottom: '16px', transform: 'translateX(calc(50vw - 50%))', - width: 'calc(100vw - 4rem)', - scale: 1.2, + width: 'calc(100vw - 64px)', }} />
diff --git a/src/client/views/nodes/generativeFill/generativeFillUtils/BrushHandler.ts b/src/client/views/nodes/generativeFill/generativeFillUtils/BrushHandler.ts index c2716e083..f84f04190 100644 --- a/src/client/views/nodes/generativeFill/generativeFillUtils/BrushHandler.ts +++ b/src/client/views/nodes/generativeFill/generativeFillUtils/BrushHandler.ts @@ -1,87 +1,45 @@ -import { GenerativeFillMathHelpers } from "./GenerativeFillMathHelpers"; -import { eraserColor } from "./generativeFillConstants"; -import { Point } from "./generativeFillInterfaces"; +import { GenerativeFillMathHelpers } from './GenerativeFillMathHelpers'; +import { eraserColor } from './generativeFillConstants'; +import { Point } from './generativeFillInterfaces'; export class BrushHandler { - static brushCircle = ( - x: number, - y: number, - brushRadius: number, - ctx: CanvasRenderingContext2D - ) => { - ctx.globalCompositeOperation = "destination-out"; - ctx.shadowColor = "#ffffffeb"; - ctx.shadowBlur = 5; - ctx.beginPath(); - ctx.arc(x, y, brushRadius, 0, 2 * Math.PI); - ctx.fill(); - ctx.closePath(); - }; + static brushCircle = (x: number, y: number, brushRadius: number, ctx: CanvasRenderingContext2D) => { + ctx.globalCompositeOperation = 'destination-out'; + ctx.shadowColor = '#ffffffeb'; + ctx.shadowBlur = 5; + ctx.beginPath(); + ctx.arc(x, y, brushRadius, 0, 2 * Math.PI); + ctx.fill(); + ctx.closePath(); + }; - static brushCircleOverlay = ( - x: number, - y: number, - brushRadius: number, - ctx: CanvasRenderingContext2D, - fillColor: string, - erase: boolean - ) => { - ctx.globalCompositeOperation = "destination-out"; - // ctx.globalCompositeOperation = erase ? "destination-out" : "source-over"; - ctx.fillStyle = fillColor; - ctx.shadowColor = eraserColor; - ctx.shadowBlur = 5; - ctx.beginPath(); - ctx.arc(x, y, brushRadius, 0, 2 * Math.PI); - ctx.fill(); - ctx.closePath(); - }; + static brushCircleOverlay = (x: number, y: number, brushRadius: number, ctx: CanvasRenderingContext2D, fillColor: string, erase: boolean) => { + ctx.globalCompositeOperation = 'destination-out'; + // ctx.globalCompositeOperation = erase ? "destination-out" : "source-over"; + ctx.fillStyle = fillColor; + ctx.shadowColor = eraserColor; + ctx.shadowBlur = 5; + ctx.beginPath(); + ctx.arc(x, y, brushRadius, 0, 2 * Math.PI); + ctx.fill(); + ctx.closePath(); + }; - static createBrushPath = ( - startPoint: Point, - endPoint: Point, - brushRadius: number, - ctx: CanvasRenderingContext2D - ) => { - const dist = GenerativeFillMathHelpers.distanceBetween( - startPoint, - endPoint - ); + static createBrushPath = (startPoint: Point, endPoint: Point, brushRadius: number, ctx: CanvasRenderingContext2D) => { + const dist = GenerativeFillMathHelpers.distanceBetween(startPoint, endPoint); - for (let i = 0; i < dist; i += 5) { - const s = i / dist; - BrushHandler.brushCircle( - startPoint.x * (1 - s) + endPoint.x * s, - startPoint.y * (1 - s) + endPoint.y * s, - brushRadius, - ctx - ); - } - }; + for (let i = 0; i < dist; i += 5) { + const s = i / dist; + BrushHandler.brushCircle(startPoint.x * (1 - s) + endPoint.x * s, startPoint.y * (1 - s) + endPoint.y * s, brushRadius, ctx); + } + }; - static createBrushPathOverlay = ( - startPoint: Point, - endPoint: Point, - brushRadius: number, - ctx: CanvasRenderingContext2D, - fillColor: string, - erase: boolean - ) => { - const dist = GenerativeFillMathHelpers.distanceBetween( - startPoint, - endPoint - ); + static createBrushPathOverlay = (startPoint: Point, endPoint: Point, brushRadius: number, ctx: CanvasRenderingContext2D, fillColor: string, erase: boolean) => { + const dist = GenerativeFillMathHelpers.distanceBetween(startPoint, endPoint); - for (let i = 0; i < dist; i += 5) { - const s = i / dist; - BrushHandler.brushCircleOverlay( - startPoint.x * (1 - s) + endPoint.x * s, - startPoint.y * (1 - s) + endPoint.y * s, - brushRadius, - ctx, - fillColor, - erase - ); - } - }; + for (let i = 0; i < dist; i += 5) { + const s = i / dist; + BrushHandler.brushCircleOverlay(startPoint.x * (1 - s) + endPoint.x * s, startPoint.y * (1 - s) + endPoint.y * s, brushRadius, ctx, fillColor, erase); + } + }; } diff --git a/src/client/views/nodes/generativeFill/generativeFillUtils/ImageHandler.ts b/src/client/views/nodes/generativeFill/generativeFillUtils/ImageHandler.ts index 48055903c..45cf7196b 100644 --- a/src/client/views/nodes/generativeFill/generativeFillUtils/ImageHandler.ts +++ b/src/client/views/nodes/generativeFill/generativeFillUtils/ImageHandler.ts @@ -28,7 +28,7 @@ export class ImageUtility { fd.append('image', imgBlob, 'image.png'); fd.append('mask', maskBlob, 'mask.png'); fd.append('prompt', prompt); - fd.append('size', '1024x1024'); + fd.append('size', '512x512'); fd.append('n', n ? JSON.stringify(n) : '1'); fd.append('response_format', 'b64_json'); diff --git a/src/client/views/nodes/generativeFill/generativeFillUtils/generativeFillConstants.ts b/src/client/views/nodes/generativeFill/generativeFillUtils/generativeFillConstants.ts index 5a8d33742..412a4d238 100644 --- a/src/client/views/nodes/generativeFill/generativeFillUtils/generativeFillConstants.ts +++ b/src/client/views/nodes/generativeFill/generativeFillUtils/generativeFillConstants.ts @@ -1,9 +1,9 @@ // constants -export const canvasSize = 1024; +export const canvasSize = 512; export const freeformRenderSize = 300; export const offsetDistanceY = freeformRenderSize + 200; export const offsetX = 200; -export const newCollectionSize = 1000; +export const newCollectionSize = 500; export const activeColor = '#1976d2'; export const eraserColor = '#e1e9ec'; diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.tsx b/src/client/views/pdf/GPTPopup/GPTPopup.tsx index aeee90d16..fc6fc1af8 100644 --- a/src/client/views/pdf/GPTPopup/GPTPopup.tsx +++ b/src/client/views/pdf/GPTPopup/GPTPopup.tsx @@ -124,9 +124,7 @@ export class GPTPopup extends React.Component { * Transfers the image urls to actual image docs */ private transferToImage = (source: string) => { - console.log('Text Anchor', this.textAnchor); - console.log('Whole doc anchor', this.imgTargetDoc); - const textAnchor = this.textAnchor ?? this.imgTargetDoc; + const textAnchor = this.imgTargetDoc; if (!textAnchor) return; const newDoc = Docs.Create.ImageDocument(source, { x: NumCast(textAnchor.x) + NumCast(textAnchor._width) + 10, -- cgit v1.2.3-70-g09d2 From 0eb9d37a9dd1a6539f331f953d5f20c761d5f940 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 17 Aug 2023 10:00:10 -0400 Subject: fixed brushing of pinned viewports for chrome to not flash. converted pres to config_ and treeView to treeView_Property. fixed text toolbar to show/set text properties based on insertion point. --- src/client/documents/Documents.ts | 101 ++-- src/client/util/CurrentUserUtils.ts | 38 +- src/client/util/DocumentManager.ts | 6 +- src/client/views/DashboardView.tsx | 15 +- src/client/views/DocumentButtonBar.tsx | 6 +- src/client/views/InkStroke.scss | 1 + src/client/views/InkingStroke.tsx | 6 +- src/client/views/MainView.tsx | 4 +- src/client/views/MarqueeAnnotator.tsx | 2 +- src/client/views/PropertiesView.scss | 88 ++-- src/client/views/PropertiesView.tsx | 32 +- src/client/views/StyleProvider.tsx | 8 +- src/client/views/TemplateMenu.tsx | 2 +- .../views/collections/CollectionTimeView.tsx | 6 +- .../views/collections/CollectionTreeView.tsx | 22 +- src/client/views/collections/CollectionView.tsx | 2 +- src/client/views/collections/TabDocView.tsx | 45 +- src/client/views/collections/TreeView.tsx | 90 ++-- .../collectionFreeForm/CollectionFreeFormView.scss | 7 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 46 +- src/client/views/linking/LinkMenuItem.tsx | 2 +- src/client/views/nodes/DataVizBox/DataVizBox.tsx | 111 ++-- .../nodes/DataVizBox/components/Histogram.tsx | 534 ++++++++++--------- .../nodes/DataVizBox/components/LineChart.tsx | 105 ++-- .../views/nodes/DataVizBox/components/PieChart.tsx | 401 ++++++++------- .../views/nodes/DataVizBox/components/TableBox.tsx | 87 ++-- src/client/views/nodes/DocumentView.tsx | 17 +- src/client/views/nodes/FontIconBox/FontIconBox.tsx | 4 +- src/client/views/nodes/FunctionPlotBox.tsx | 4 +- src/client/views/nodes/ImageBox.tsx | 14 +- src/client/views/nodes/KeyValueBox.tsx | 17 +- src/client/views/nodes/LinkBox.tsx | 2 +- src/client/views/nodes/MapBox/MapBox.tsx | 2 +- src/client/views/nodes/MapBox/MapBox2.tsx | 2 +- src/client/views/nodes/PDFBox.tsx | 6 +- src/client/views/nodes/WebBox.tsx | 16 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 29 +- .../formattedText/ProsemirrorExampleTransfer.ts | 2 +- .../views/nodes/formattedText/RichTextMenu.tsx | 2 +- src/client/views/nodes/trails/PresBox.tsx | 567 +++++++++++---------- src/client/views/nodes/trails/PresElementBox.tsx | 50 +- src/client/views/pdf/Annotation.tsx | 4 +- src/client/views/pdf/PDFViewer.tsx | 8 +- src/fields/Doc.ts | 8 +- src/fields/documentSchemas.ts | 10 +- 45 files changed, 1334 insertions(+), 1197 deletions(-) (limited to 'src/client/views/nodes/formattedText') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 5c33e319d..96a983153 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -288,12 +288,12 @@ export class DocumentOptions { _isTimelineLabel?: BOOLt = new BoolInfo('is document a timeline label'); _isLightbox?: BOOLt = new BoolInfo('whether a collection acts as a lightbox by opening lightbox links by hiding all other documents in collection besides link target'); - presPanX?: NUMt = new NumInfo('panX saved as a view spec'); - presPanY?: NUMt = new NumInfo('panY saved as a view spec'); - presViewScale?: NUMt = new NumInfo('viewScale saved as a view Spec'); - presTransition?: NUMt = new NumInfo('the time taken for the transition TO a document'); - presDuration?: NUMt = new NumInfo('the duration of the slide in presentation view'); - presZoomText?: BOOLt = new BoolInfo('whether text anchors should shown in a larger box when following links to make them stand out'); + config_panX?: NUMt = new NumInfo('panX saved as a view spec'); + config_panY?: NUMt = new NumInfo('panY saved as a view spec'); + config_viewScale?: NUMt = new NumInfo('viewScale saved as a view Spec'); + presentation_transition?: NUMt = new NumInfo('the time taken for the transition TO a document'); + presentation_duration?: NUMt = new NumInfo('the duration of the slide in presentation view'); + presentation_zoomText?: BOOLt = new BoolInfo('whether text anchors should shown in a larger box when following links to make them stand out'); data?: any; data_useCors?: BOOLt = new BoolInfo('whether CORS protocol should be used for web page'); @@ -378,21 +378,21 @@ export class DocumentOptions { onDragStart?: ScriptField; //script to execute at start of drag operation -- e.g., when a "creator" button is dragged this script generates a different document to drop target?: Doc; // available for use in scripts. used to provide a document parameter to the script (Note, this is a convenience entry since any field could be used for parameterizing a script) - treeViewHideTitle?: BOOLt = new BoolInfo('whether to hide the top document title of a tree view'); - treeViewHideUnrendered?: BOOLt = new BoolInfo("tells tree view not to display documents that have an 'layout_unrendered' tag unless they also have a treeViewFieldKey tag (presBox)"); - treeViewHideHeaderIfTemplate?: BOOLt = new BoolInfo('whether to hide the header for a document in a tree view only if a childLayoutTemplate is provided (presBox)'); - treeViewHideHeader?: BOOLt = new BoolInfo('whether to hide the header for a document in a tree view'); - treeViewHideHeaderFields?: BOOLt = new BoolInfo('whether to hide the drop down options for tree view items.'); - treeViewChildDoubleClick?: ScriptField; // - treeViewOpenIsTransient?: BOOLt = new BoolInfo("ignores the treeViewOpen Doc flag, allowing a treeViewItem's expand/collapse state to be independent of other views of the same document in the same or any other tree view"); - treeViewOpen?: BOOLt = new BoolInfo('whether this document is expanded in a tree view'); - treeViewExpandedView?: string; // which field/thing is displayed when this item is opened in tree view - treeViewExpandedViewLock?: BOOLt = new BoolInfo('whether the expanded view can be changed'); - treeViewChecked?: ScriptField; // script to call when a tree view checkbox is checked - treeViewTruncateTitleWidth?: NUMt = new NumInfo('maximum width of a treew view title before truncation'); - treeViewHasOverlay?: BOOLt = new BoolInfo('whether the treeview has an overlay for freeform annotations'); - treeViewType?: string; // whether treeview is a Slide, file system, or (default) collection hierarchy - treeViewFreezeChildren?: STRt = new StrInfo('set (add, remove, add|remove) to disable adding, removing or both from collection'); + treeView_HideTitle?: BOOLt = new BoolInfo('whether to hide the top document title of a tree view'); + treeView_HideUnrendered?: BOOLt = new BoolInfo("tells tree view not to display documents that have an 'layout_unrendered' tag unless they also have a treeView_FieldKey tag (presBox)"); + treeView_HideHeaderIfTemplate?: BOOLt = new BoolInfo('whether to hide the header for a document in a tree view only if a childLayoutTemplate is provided (presBox)'); + treeView_HideHeader?: BOOLt = new BoolInfo('whether to hide the header for a document in a tree view'); + treeView_HideHeaderFields?: BOOLt = new BoolInfo('whether to hide the drop down options for tree view items.'); + treeView_ChildDoubleClick?: ScriptField; // + treeView_OpenIsTransient?: BOOLt = new BoolInfo("ignores the treeView_Open Doc flag, allowing a treeView_Item's expand/collapse state to be independent of other views of the same document in the same or any other tree view"); + treeView_Open?: BOOLt = new BoolInfo('whether this document is expanded in a tree view'); + treeView_ExpandedView?: string; // which field/thing is displayed when this item is opened in tree view + treeView_ExpandedViewLock?: BOOLt = new BoolInfo('whether the expanded view can be changed'); + treeView_Checked?: ScriptField; // script to call when a tree view checkbox is checked + treeView_TruncateTitleWidth?: NUMt = new NumInfo('maximum width of a treew view title before truncation'); + treeView_HasOverlay?: BOOLt = new BoolInfo('whether the treeview has an overlay for freeform annotations'); + treeView_Type?: string; // whether treeview is a Slide, file system, or (default) collection hierarchy + treeView_FreezeChildren?: STRt = new StrInfo('set (add, remove, add|remove) to disable adding, removing or both from collection'); sidebar_color?: string; // background color of text sidebar sidebar_collectionType?: string; // collection type of text sidebar @@ -635,7 +635,7 @@ export namespace Docs { DocumentType.CONFIG, { layout: { view: CollectionView, dataField: defaultDataKey }, - options: { layout_hideLinkButton: true, layout_unrendered: true }, + options: { config: '', layout_hideLinkButton: true, layout_unrendered: true }, }, ], [ @@ -679,7 +679,7 @@ export namespace Docs { DocumentType.DATAVIZ, { layout: { view: DataVizBox, dataField: defaultDataKey }, - options: { _layout_fitWidth: true, nativeDimModifiable: true }, + options: { dataViz_title: '', _layout_fitWidth: true, nativeDimModifiable: true }, }, ], [ @@ -845,7 +845,7 @@ export namespace Docs { * only when creating a DockDocument from the current user's already existing * main document. */ - function InstanceFromProto(proto: Doc, data: Field | undefined, options: DocumentOptions, delegId?: string, fieldKey: string = 'data', protoId?: string, placeholderDoc?: Doc) { + function InstanceFromProto(proto: Doc, data: Field | undefined, options: DocumentOptions, delegId?: string, fieldKey: string = 'data', protoId?: string, placeholderDoc?: Doc, noView?: boolean) { const viewKeys = ['x', 'y', 'isSystem']; // keys that should be addded to the view document even though they don't begin with an "_" const { omit: dataProps, extract: viewProps } = OmitKeys(options, viewKeys, '^_'); @@ -872,29 +872,34 @@ export namespace Docs { dataDoc.proto = proto; } - const viewFirstProps: { [id: string]: any } = { author: Doc.CurrentUserEmail }; - viewFirstProps['acl-Guest'] = options['_acl-Guest'] ?? (Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.View); - let viewDoc: Doc; - // determines whether viewDoc should be created using placeholder Doc or default - if (placeholderDoc) { - placeholderDoc._height = options._height !== undefined ? Number(options._height) : undefined; - placeholderDoc._width = options._width !== undefined ? Number(options._width) : undefined; - viewDoc = Doc.assign(placeholderDoc, viewFirstProps, true, true); - Array.from(Object.keys(placeholderDoc)) - .filter(key => key.startsWith('acl')) - .forEach(key => (dataDoc[key] = viewDoc[key] = placeholderDoc[key])); - } else { - viewDoc = Doc.assign(Doc.MakeDelegate(dataDoc, delegId), viewFirstProps, true, true); - } - Doc.assign(viewDoc, viewProps, true, true); - if (![DocumentType.LINK, DocumentType.CONFIG, DocumentType.LABEL].includes(viewDoc.type as any)) { - DocUtils.MakeLinkToActiveAudio(() => viewDoc); + if (!noView) { + const viewFirstProps: { [id: string]: any } = { author: Doc.CurrentUserEmail }; + viewFirstProps['acl-Guest'] = options['_acl-Guest'] ?? (Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.View); + let viewDoc: Doc; + // determines whether viewDoc should be created using placeholder Doc or default + if (placeholderDoc) { + placeholderDoc._height = options._height !== undefined ? Number(options._height) : undefined; + placeholderDoc._width = options._width !== undefined ? Number(options._width) : undefined; + viewDoc = Doc.assign(placeholderDoc, viewFirstProps, true, true); + Array.from(Object.keys(placeholderDoc)) + .filter(key => key.startsWith('acl')) + .forEach(key => (dataDoc[key] = viewDoc[key] = placeholderDoc[key])); + } else { + viewDoc = Doc.assign(Doc.MakeDelegate(dataDoc, delegId), viewFirstProps, true, true); + } + Doc.assign(viewDoc, viewProps, true, true); + if (![DocumentType.LINK, DocumentType.CONFIG, DocumentType.LABEL].includes(viewDoc.type as any)) { + DocUtils.MakeLinkToActiveAudio(() => viewDoc); + } + updateCachedAcls(dataDoc); + updateCachedAcls(viewDoc); + + return viewDoc; } updateCachedAcls(dataDoc); - updateCachedAcls(viewDoc); - return viewDoc; + return dataDoc; } export function ImageDocument(url: string | ImageField, options: DocumentOptions = {}, overwriteDoc?: Doc) { @@ -1065,7 +1070,7 @@ export namespace Docs { } export function ConfigDocument(options: DocumentOptions, id?: string) { - return InstanceFromProto(Prototypes.get(DocumentType.CONFIG), options?.data, options, id); + return InstanceFromProto(Prototypes.get(DocumentType.CONFIG), options?.data, options, id, '', undefined, undefined, true); } export function HTMLMarkerDocument(documents: Array, options: DocumentOptions, id?: string) { @@ -1105,7 +1110,9 @@ export namespace Docs { } export function TreeDocument(documents: Array, options: DocumentOptions, id?: string, protoId?: string) { - return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _xMargin: 5, _yMargin: 5, ...options, _type_collection: CollectionViewType.Tree }, id, undefined, protoId); + const doc = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _xMargin: 5, _yMargin: 5, ...options, _type_collection: CollectionViewType.Tree }, id, undefined, protoId); + Doc.GetProto(doc).treeView = ''; /// not really needed, but makes keyvalue pane look better + return doc; } export function StackingDocument(documents: Array, options: DocumentOptions, id?: string, protoId?: string) { @@ -1163,11 +1170,11 @@ export namespace Docs { } export function DataVizDocument(url: string, options?: DocumentOptions, overwriteDoc?: Doc) { - return InstanceFromProto(Prototypes.get(DocumentType.DATAVIZ), new CsvField(url), { title: 'Data Viz', type: 'dataviz', ...options }, undefined, undefined, undefined, overwriteDoc); + return InstanceFromProto(Prototypes.get(DocumentType.DATAVIZ), new CsvField(url), { title: 'Data Viz', type: 'dataviz', ...options }, undefined, undefined, undefined, overwriteDoc); } export function DockDocument(documents: Array, config: string, options: DocumentOptions, id?: string) { - const ret = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { treeViewFreezeChildren: 'remove|add', ...options, type_collection: CollectionViewType.Docking, dockingConfig: config }, id); + const ret = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { treeView_FreezeChildren: 'remove|add', ...options, type_collection: CollectionViewType.Docking, dockingConfig: config }, id); documents.map(c => Doc.SetContainer(c, ret)); return ret; } diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 47cd866cb..af43ef16a 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -278,12 +278,12 @@ export class CurrentUserUtils { {key: "Button", creator: Docs.Create.ButtonDocument, opts: { _width: 150, _height: 50, _xPadding: 10, _yPadding: 10}, scripts: {onClick: FollowLinkScript()?.script.originalScript ?? ""}}, {key: "Script", creator: opts => Docs.Create.ScriptingDocument(null, opts), opts: { _width: 200, _height: 250, }}, {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, treeViewHideUnrendered: true}}, - {key: "Trail", creator: Docs.Create.PresDocument, opts: { _width: 400, _height: 30, _type_collection: CollectionViewType.Stacking, dropAction: "embed" as dropActionType, treeViewHideTitle: true, _layout_fitWidth:true, _chromeHidden: true, layout_boxShadow: "0 0" }}, + {key: "Header", creator: headerTemplate, opts: { _width: 300, _height: 70, _headerPointerEvents: "all", _headerHeight: 12, _headerFontSize: 9, _layout_autoHeight: true, treeView_HideUnrendered: true}}, + {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, _chromeHidden: 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, - treeViewHasOverlay: true, _text_fontSize: "20px", _layout_autoHeight: true, - dropAction:'move', treeViewType: TreeViewType.outline, + treeView_HasOverlay: true, _text_fontSize: "20px", _layout_autoHeight: true, + dropAction:'move', treeView_Type: TreeViewType.outline, backgroundColor: "white", _xMargin: 0, _yMargin: 0, _createDocOnCR: true }, funcs: {title: 'self.text?.Text'}}, ]; @@ -493,8 +493,8 @@ export class CurrentUserUtils { const childContextMenuLabels = ["Toggle Dark Theme", "Toggle Comic Mode", "Snapshot Dashboard", "Share Dashboard", "Remove Dashboard", "Reset Dashboard"];// entries must be kept in synch with childContextMenuScripts, childContextMenuIcons, and childContextMenuFilters const childContextMenuIcons = ["chalkboard", "tv", "camera", "users", "times", "trash"]; // entries must be kept in synch with childContextMenuScripts, childContextMenuLabels, and childContextMenuFilters const reqdOpts:DocumentOptions = { - title: "My Dashboards", childHideLinkButton: true, treeViewFreezeChildren: "remove|add", treeViewHideTitle: true, layout_boxShadow: "0 0", childDontRegisterViews: true, - dropAction: "same", treeViewType: TreeViewType.fileSystem, isFolder: true, isSystem: true, treeViewTruncateTitleWidth: 350, ignoreClick: true, + title: "My Dashboards", childHideLinkButton: true, treeView_FreezeChildren: "remove|add", treeView_HideTitle: true, layout_boxShadow: "0 0", childDontRegisterViews: true, + dropAction: "same", treeView_Type: TreeViewType.fileSystem, isFolder: true, isSystem: true, treeView_TruncateTitleWidth: 350, ignoreClick: true, layout_headerButton: newDashboardButton, childDragAction: "none", _layout_showTitle: "title", _height: 400, _gridGap: 5, _forceActive: true, _lockedPosition: true, contextMenuLabels:new List(contextMenuLabels), @@ -522,16 +522,16 @@ export class CurrentUserUtils { const newFolder = `TreeView_addNewFolder()`; const newFolderOpts: DocumentOptions = { - _forceActive: true, _dragOnlyWithinContainer: true, _layout_hideContextMenu: true, _width: 30, _height: 30, undoIgnoreFields:new List(['treeViewSortCriterion']), + _forceActive: true, _dragOnlyWithinContainer: true, _layout_hideContextMenu: true, _width: 30, _height: 30, undoIgnoreFields:new List(['treeView_SortCriterion']), title: "New folder", color: Colors.BLACK, btnType: ButtonType.ClickButton, toolTip: "Create new folder", buttonText: "New folder", icon: "folder-plus", isSystem: true }; const newFolderScript = { onClick: newFolder}; const newFolderButton = DocUtils.AssignScripts(DocUtils.AssignOpts(DocCast(myFilesystem?.layout_headerButton), newFolderOpts) ?? Docs.Create.FontIconDocument(newFolderOpts), newFolderScript); const reqdOpts:DocumentOptions = { _layout_showTitle: "title", _height: 100, _gridGap: 5, _forceActive: true, _lockedPosition: true, - title: "My Documents", layout_headerButton: newFolderButton, treeViewHideTitle: true, dropAction: 'add', isSystem: true, - isFolder: true, treeViewType: TreeViewType.fileSystem, childHideLinkButton: true, layout_boxShadow: "0 0", childDontRegisterViews: true, - treeViewTruncateTitleWidth: 350, ignoreClick: true, childDragAction: "embed", + title: "My Documents", layout_headerButton: newFolderButton, treeView_HideTitle: true, dropAction: 'add', isSystem: true, + isFolder: true, treeView_Type: TreeViewType.fileSystem, childHideLinkButton: true, layout_boxShadow: "0 0", childDontRegisterViews: true, + treeView_TruncateTitleWidth: 350, ignoreClick: true, childDragAction: "embed", childContextMenuLabels: new List(["Create new folder"]), childContextMenuIcons: new List(["plus"]), layout_explainer: "This is your file manager where you can create folders to keep track of documents independently of your dashboard." @@ -548,8 +548,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, treeViewHideTitle: true, childDragAction: "move", isSystem: true, - treeViewTruncateTitleWidth: 350, ignoreClick: true, layout_boxShadow: "0 0", childDontRegisterViews: true, dropAction: "same", + 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", 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." @@ -573,9 +573,9 @@ export class CurrentUserUtils { 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, - treeViewHideTitle: true, treeViewTruncateTitleWidth: 350 + treeView_HideTitle: true, treeView_TruncateTitleWidth: 350 }; - if (!doc[field]) DocUtils.AssignOpts(doc, {treeViewOpen: true, treeViewExpandedView: "fields" }); + if (!doc[field]) DocUtils.AssignOpts(doc, {treeView_Open: true, treeView_ExpandedView: "fields" }); return DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.TreeDocument(items??[], opts), reqdOpts, [doc]); } @@ -789,19 +789,19 @@ export class CurrentUserUtils { static setupSharedDocs(doc: Doc, sharingDocumentId: string) { const dblClkScript = "{scriptContext.openLevel(documentView); addDocToList(scriptContext.props.treeView.props.Document, 'viewed', documentView.rootDoc);}"; - const sharedScripts = { treeViewChildDoubleClick: dblClkScript, } + const sharedScripts = { treeView_ChildDoubleClick: dblClkScript, } const sharedDocOpts:DocumentOptions = { title: "My Shared Docs", userColor: "rgb(202, 202, 202)", - isFolder:true, undoIgnoreFields:new List(['treeViewSortCriterion']), + isFolder:true, undoIgnoreFields:new List(['treeView_SortCriterion']), // childContextMenuFilters: new List([dashboardFilter!,]), // childContextMenuScripts: new List([addToDashboards!,]), // childContextMenuLabels: new List(["Add to Dashboards",]), // childContextMenuIcons: new List(["user-plus",]), "acl-Guest": SharingPermissions.Augment, "_acl-Guest": SharingPermissions.Augment, childDragAction: "embed", isSystem: true, contentPointerEvents: "all", childLimitHeight: 0, _yMargin: 0, _gridGap: 15, childDontRegisterViews:true, - // NOTE: treeViewHideTitle & _layout_showTitle is for a TreeView's editable title, _layout_showTitle is for DocumentViews title bar - _layout_showTitle: "title", treeViewHideTitle: true, ignoreClick: true, _lockedPosition: true, layout_boxShadow: "0 0", _chromeHidden: true, dontRegisterView: 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'" }; @@ -864,7 +864,7 @@ export class CurrentUserUtils { doc.userColor ?? (doc.userColor = Colors.LIGHT_GRAY); doc.userTheme ?? (doc.userTheme = ColorScheme.Dark); doc.filterDocCount = 0; - doc.treeViewFreezeChildren = "remove|add"; + doc.treeView_FreezeChildren = "remove|add"; doc.activePage = doc.activeDashboard === undefined ? 'home': doc.activePage; this.setupLinkDocs(doc, linkDatabaseId); this.setupSharedDocs(doc, sharingDocumentId); // sets up the right sidebar collection for mobile upload documents and sharing diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 42132c2d7..9779639f4 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -315,10 +315,10 @@ export class DocumentManager { if (options.toggleTarget && (!options.didMove || docView.rootDoc.hidden)) docView.rootDoc.hidden = !docView.rootDoc.hidden; if (options.effect) docView.rootDoc[Animation] = options.effect; - if (options.zoomTextSelections && Doc.UnhighlightTimer && contextView && viewSpec.textHtml) { + if (options.zoomTextSelections && Doc.UnhighlightTimer && contextView && viewSpec.text_html) { // if the docView is a text anchor, the contextView is the PDF/Web/Text doc - contextView.htmlOverlayEffect = StrCast(options?.effect?.presEffect, StrCast(options?.effect?.followLinkAnimEffect)); - contextView.textHtmlOverlay = StrCast(targetDoc.textHtml); + contextView.htmlOverlayEffect = StrCast(options?.effect?.presentation_effect, StrCast(options?.effect?.followLinkAnimEffect)); + contextView.textHtmlOverlay = StrCast(targetDoc.text_html); DocumentManager._overlayViews.add(contextView); } Doc.AddUnHighlightWatcher(() => { diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx index 21808d6e0..3e4827c83 100644 --- a/src/client/views/DashboardView.tsx +++ b/src/client/views/DashboardView.tsx @@ -108,7 +108,14 @@ export class DashboardView extends React.Component { }}>
Create New Dashboard
this.setNewDashboardName(val as string)} fillWidth /> - +
{!selectedItem ? null : ( -
-
(this.openPresTransitions = !this.openPresTransitions))} style={{ backgroundColor: this.openPresTransitions ? 'black' : '' }}> +
+
(this.openPresTransitions = !this.openPresTransitions))} style={{ backgroundColor: this.openPresTransitions ? 'black' : '' }}>     Transitions -
+
- {this.openPresTransitions ?
{PresBox.Instance.transitionDropdown}
: null} + {this.openPresTransitions ?
{PresBox.Instance.transitionDropdown}
: null}
)} {!selectedItem ? null : ( -
+
(this.openPresVisibilityAndDuration = !this.openPresVisibilityAndDuration))} style={{ backgroundColor: this.openPresTransitions ? 'black' : '' }}>     Visibilty -
+
- {this.openPresVisibilityAndDuration ?
{PresBox.Instance.visibiltyDurationDropdown}
: null} + {this.openPresVisibilityAndDuration ?
{PresBox.Instance.visibiltyDurationDropdown}
: null}
)} {!selectedItem ? null : ( -
-
(this.openPresProgressivize = !this.openPresProgressivize))} style={{ backgroundColor: this.openPresTransitions ? 'black' : '' }}> +
+
(this.openPresProgressivize = !this.openPresProgressivize))} style={{ backgroundColor: this.openPresTransitions ? 'black' : '' }}>     Progressivize -
+
- {this.openPresProgressivize ?
{PresBox.Instance.progressivizeDropdown}
: null} + {this.openPresProgressivize ?
{PresBox.Instance.progressivizeDropdown}
: null}
)} {!selectedItem || (type !== DocumentType.VID && type !== DocumentType.AUDIO) ? null : ( -
-
(this.openSlideOptions = !this.openSlideOptions))} style={{ backgroundColor: this.openSlideOptions ? 'black' : '' }}> +
+
(this.openSlideOptions = !this.openSlideOptions))} style={{ backgroundColor: this.openSlideOptions ? 'black' : '' }}>     {type === DocumentType.AUDIO ? 'Audio Options' : 'Video Options'} -
+
- {this.openSlideOptions ?
{PresBox.Instance.mediaOptionsDropdown}
: null} + {this.openSlideOptions ?
{PresBox.Instance.mediaOptionsDropdown}
: null}
)}
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 63ff348e3..a757a0715 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -27,8 +27,8 @@ import './StyleProvider.scss'; import React = require('react'); export enum StyleProp { - TreeViewIcon = 'treeViewIcon', - TreeViewSortings = 'treeViewSortings', // options for how to sort tree view items + TreeViewIcon = 'treeView_Icon', + TreeViewSortings = 'treeView_Sortings', // options for how to sort tree view items DocContents = 'docContents', // when specified, the JSX returned will replace the normal rendering of the document view Opacity = 'opacity', // opacity of the document view BoxShadow = 'boxShadow', // box shadow - used for making collections standout and for showing clusters in free form views @@ -133,7 +133,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, props: Opt { const templateMenu: Array = []; this.props.templates?.forEach((checked, template) => templateMenu.push()); templateMenu.push(); - addedTypes.concat(noteTypes).map(template => (template.treeViewChecked = this.templateIsUsed(firstDoc, template))); + addedTypes.concat(noteTypes).map(template => (template.treeView_Checked = this.templateIsUsed(firstDoc, template))); this._addedKeys && Array.from(this._addedKeys) .filter(key => !noteTypes.some(nt => nt.title === key)) diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 192d48c64..a8f5345b7 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -65,9 +65,9 @@ export class CollectionTimeView extends CollectionSubView() { @action scrollPreview = (docView: DocumentView, anchor: Doc, focusSpeed: number, options: DocFocusOptions) => { // if in preview, then override document's fields with view spec - this._focusFilters = StrListCast(anchor.presDocFilters); - this._focusRangeFilters = StrListCast(anchor.presPinDocRangeFilters); - this._focusPivotField = StrCast(anchor.presPivotField); + this._focusFilters = StrListCast(anchor.config_docFilters); + this._focusRangeFilters = StrListCast(anchor.config_docRangeFilters); + this._focusPivotField = StrCast(anchor.config_pivotField); return undefined; }; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index ea3b5065f..b5c7d3f5d 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -66,17 +66,17 @@ export class CollectionTreeView extends CollectionSubView (this.doc.treeViewOpenIsTransient = !this.doc.treeViewOpenIsTransient), icon: 'paint-brush' }); - layoutItems.push({ description: (this.doc.treeViewHideHeaderFields ? 'Show' : 'Hide') + ' Header Fields', event: () => (this.doc.treeViewHideHeaderFields = !this.doc.treeViewHideHeaderFields), icon: 'paint-brush' }); - layoutItems.push({ description: (this.doc.treeViewHideTitle ? 'Show' : 'Hide') + ' Title', event: () => (this.doc.treeViewHideTitle = !this.doc.treeViewHideTitle), icon: 'paint-brush' }); + layoutItems.push({ description: 'Make tree state ' + (this.doc.treeView_OpenIsTransient ? 'persistent' : 'transient'), event: () => (this.doc.treeView_OpenIsTransient = !this.doc.treeView_OpenIsTransient), icon: 'paint-brush' }); + layoutItems.push({ description: (this.doc.treeView_HideHeaderFields ? 'Show' : 'Hide') + ' Header Fields', event: () => (this.doc.treeView_HideHeaderFields = !this.doc.treeView_HideHeaderFields), icon: 'paint-brush' }); + layoutItems.push({ description: (this.doc.treeView_HideTitle ? 'Show' : 'Hide') + ' Title', event: () => (this.doc.treeView_HideTitle = !this.doc.treeView_HideTitle), icon: 'paint-brush' }); ContextMenu.Instance.addItem({ description: 'Options...', subitems: layoutItems, icon: 'eye' }); const existingOnClick = ContextMenu.Instance.findByDescription('OnClick...'); const onClicks: ContextMenuProps[] = existingOnClick && 'subitems' in existingOnClick ? existingOnClick.subitems : []; @@ -215,7 +215,7 @@ export class CollectionTreeView extends CollectionSubView StrCast(this.dataDoc.title)} SetValue={undoBatch((value: string, shift: boolean, enter: boolean) => { - if (enter && this.props.Document.treeViewType === TreeViewType.outline) this.makeTextCollection(this.treeChildren); + if (enter && this.props.Document.treeView_Type === TreeViewType.outline) this.makeTextCollection(this.treeChildren); this.dataDoc.title = value; return true; })} @@ -261,7 +261,7 @@ export class CollectionTreeView extends CollectionSubView ({ script: customScripts[i], filter: customFilters[i], icon: icons[i], label })); }; - headerFields = () => this.props.treeViewHideHeaderFields || BoolCast(this.doc.treeViewHideHeaderFields); + headerFields = () => this.props.treeViewHideHeaderFields || BoolCast(this.doc.treeView_HideHeaderFields); @observable _renderCount = 1; @computed get treeViewElements() { TraceMobx(); @@ -389,7 +389,7 @@ export class CollectionTreeView extends CollectionSubView this.props.styleProvider?.(this.doc, this.props, StyleProp.BackgroundColor); const color = () => this.props.styleProvider?.(this.doc, this.props, StyleProp.Color); const pointerEvents = () => (this.props.isContentActive() === false ? 'none' : undefined); - const titleBar = this.props.treeViewHideTitle || this.doc.treeViewHideTitle ? null : this.titleBar; + const titleBar = this.props.treeViewHideTitle || this.doc.treeView_HideTitle ? null : this.titleBar; return (
{!this.buttonMenu && !this.noviceExplainer ? null : ( @@ -401,7 +401,7 @@ export class CollectionTreeView extends CollectionSubView !this.doc.treeViewHasOverlay && r && this.createTreeDropTarget(r)} + ref={r => !this.doc.treeView_HasOverlay && r && this.createTreeDropTarget(r)} style={{ ...(!titleBar ? { marginLeft: this.marginX(), paddingTop: this.marginTop() } : {}), color: color(), @@ -440,7 +440,7 @@ export class CollectionTreeView extends CollectionSubView - {!(this.doc instanceof Doc) || !this.treeChildren ? null : this.doc.treeViewHasOverlay ? ( + {!(this.doc instanceof Doc) || !this.treeChildren ? null : this.doc.treeView_HasOverlay ? ( string; setPreviewCursor?: (func: (x: number, y: number, drag: boolean, hide: boolean) => void) => void; - setBrushViewer?: (func?: (view: { width: number; height: number; panX: number; panY: number }) => void) => void; + setBrushViewer?: (func?: (view: { width: number; height: number; panX: number; panY: number }, transTime: number) => void) => void; ignoreUnrendered?: boolean; // property overrides for child documents diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index d787f5262..ea473d5cf 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -256,46 +256,47 @@ export class TabDocView extends React.Component { return; } const anchorDoc = DocumentManager.Instance.getDocumentView(doc)?.ComponentView?.getAnchor?.(false, pinProps); - const pinDoc = Doc.MakeDelegate(anchorDoc && anchorDoc !== doc ? anchorDoc : doc); - pinDoc.presentationTargetDoc = anchorDoc ?? doc; + const pinDoc = anchorDoc?.type === DocumentType.CONFIG ? anchorDoc : Doc.MakeDelegate(anchorDoc && anchorDoc !== doc ? anchorDoc : doc); + pinDoc.presentation_targetDoc = anchorDoc ?? doc; pinDoc.title = doc.title + ' - Slide'; pinDoc.data = new List(); // the children of the embedding's layout are the presentation slide children. the embedding's data field might be children of a collection, PDF data, etc -- in any case we don't want the tree view to "see" this data - pinDoc.presMovement = doc.type === DocumentType.SCRIPTING || pinProps?.pinDocLayout ? PresMovement.None : PresMovement.Zoom; - pinDoc.presDuration = pinDoc.presDuration ?? 1000; - pinDoc.groupWithUp = false; + pinDoc.presentation_movement = doc.type === DocumentType.SCRIPTING || pinProps?.pinDocLayout ? PresMovement.None : PresMovement.Zoom; + pinDoc.presentation_duration = pinDoc.presentation_duration ?? 1000; + pinDoc.presentation_groupWithUp = false; Doc.SetContainer(pinDoc, curPres); // these should potentially all be props passed down by the CollectionTreeView to the TreeView elements. That way the PresBox could configure all of its children at render time - pinDoc.treeViewRenderAsBulletHeader = true; // forces a tree view to render the document next to the bullet in the header area - pinDoc.treeViewHeaderWidth = '100%'; // forces the header to grow to be the same size as its largest sibling. - pinDoc.treeViewChildrenOnRoot = true; // tree view will look for hierarchical children on the root doc, not the data doc. - pinDoc.treeViewFieldKey = 'data'; // tree view will treat the 'data' field as the field where the hierarchical children are located instead of using the document's layout string field - pinDoc.treeViewExpandedView = 'data'; // in case the data doc has an expandedView set, this will mask that field and use the 'data' field when expanding the tree view - pinDoc.treeViewHideHeaderIfTemplate = true; // this will force the document to render itself as the tree view header + pinDoc.treeView = ''; // not really needed, but makes key value pane look better + pinDoc.treeView_RenderAsBulletHeader = true; // forces a tree view to render the document next to the bullet in the header area + pinDoc.treeView_HeaderWidth = '100%'; // forces the header to grow to be the same size as its largest sibling. + pinDoc.treeView_ChildrenOnRoot = true; // tree view will look for hierarchical children on the root doc, not the data doc. + pinDoc.treeView_FieldKey = 'data'; // tree view will treat the 'data' field as the field where the hierarchical children are located instead of using the document's layout string field + pinDoc.treeView_ExpandedView = 'data'; // in case the data doc has an expandedView set, this will mask that field and use the 'data' field when expanding the tree view + pinDoc.treeView_HideHeaderIfTemplate = true; // this will force the document to render itself as the tree view header const duration = NumCast(doc[`${Doc.LayoutFieldKey(pinDoc)}_duration`], null); if (pinProps.pinViewport) PresBox.pinDocView(pinDoc, pinProps, anchorDoc ?? doc); if (!pinProps?.audioRange && duration !== undefined) { pinDoc.mediaStart = 'manual'; pinDoc.mediaStop = 'manual'; - pinDoc.presStartTime = NumCast(doc.clipStart); - pinDoc.presEndTime = NumCast(doc.clipEnd, duration); + pinDoc.config_clipStart = NumCast(doc.clipStart); + pinDoc.config_clipEnd = NumCast(doc.clipEnd, duration); } if (pinProps?.activeFrame !== undefined) { - pinDoc.presActiveFrame = pinProps?.activeFrame; + pinDoc.config_activeFrame = pinProps?.activeFrame; pinDoc.title = doc.title + ' (move)'; - pinDoc.presMovement = PresMovement.Pan; + pinDoc.presentation_movement = PresMovement.Pan; } if (pinProps?.currentFrame !== undefined) { - pinDoc.presCurrentFrame = pinProps?.currentFrame; + pinDoc.config_currentFrame = pinProps?.currentFrame; pinDoc.title = doc.title + ' (move)'; - pinDoc.presMovement = PresMovement.Pan; + pinDoc.presentation_movement = PresMovement.Pan; } if (pinDoc.stroke_isInkMask) { - pinDoc.presHideAfter = true; - pinDoc.presHideBefore = true; - pinDoc.presMovement = PresMovement.None; + pinDoc.presentation_hideAfter = true; + pinDoc.presentation_hideBefore = true; + pinDoc.presentation_movement = PresMovement.None; } - if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true; + if (curPres.expandBoolean) pinDoc.presentation_expandInlineButton = true; Doc.AddDocToList(curPres, 'data', pinDoc, PresBox.Instance?.sortArray()?.lastElement()); PresBox.Instance?.clearSelectedArray(); pinDoc && PresBox.Instance?.addToSelectedArray(pinDoc); //Update selected array @@ -393,7 +394,7 @@ export class TabDocView extends React.Component { }; getCurrentFrame = () => { - return NumCast(Cast(PresBox.Instance.activeItem.presentationTargetDoc, Doc, null)._currentFrame); + return NumCast(Cast(PresBox.Instance.activeItem.presentation_targetDoc, Doc, null)._currentFrame); }; static Activate = (tabDoc: Doc) => { const tab = Array.from(CollectionDockingView.Instance?.tabMap!).find(tab => tab.DashDoc === tabDoc && !tab.contentItem.config.props.keyValue); diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 25a547066..27f9ebc49 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -87,8 +87,8 @@ export enum TreeSort { * Renders a treeView of a collection of documents * * special fields: - * treeViewOpen : flag denoting whether the documents sub-tree (contents) is visible or hidden - * treeViewExpandedView : name of field whose contents are being displayed as the document's subtree + * treeView_Open : flag denoting whether the documents sub-tree (contents) is visible or hidden + * treeView_ExpandedView : name of field whose contents are being displayed as the document's subtree */ @observer export class TreeView extends React.Component { @@ -104,16 +104,16 @@ export class TreeView extends React.Component { private _treedropDisposer?: DragManager.DragDropDisposer; get treeViewOpenIsTransient() { - return this.props.treeView.doc.treeViewOpenIsTransient || Doc.IsDataProto(this.doc); + return this.props.treeView.doc.treeView_OpenIsTransient || Doc.IsDataProto(this.doc); } set treeViewOpen(c: boolean) { if (this.treeViewOpenIsTransient) this._transientOpenState = c; else { - this.doc.treeViewOpen = c; + this.doc.treeView_Open = c; this._transientOpenState = false; } } - @observable _transientOpenState = false; // override of the treeViewOpen field allowing the display state to be independent of the document's state + @observable _transientOpenState = false; // override of the treeView_Open field allowing the display state to be independent of the document's state @observable _editTitle: boolean = false; @observable _dref: DocumentView | undefined | null; get displayName() { @@ -132,29 +132,29 @@ export class TreeView extends React.Component { ? this.fieldKey : Doc.noviceMode ? 'layout' - : StrCast(this.props.treeView.doc.treeViewExpandedView, 'fields'); + : StrCast(this.props.treeView.doc.treeView_ExpandedView, 'fields'); } @computed get doc() { return this.props.document; } @computed get treeViewOpen() { - return (!this.treeViewOpenIsTransient && Doc.GetT(this.doc, 'treeViewOpen', 'boolean', true)) || this._transientOpenState; + return (!this.treeViewOpenIsTransient && Doc.GetT(this.doc, 'treeView_Open', 'boolean', true)) || this._transientOpenState; } @computed get treeViewExpandedView() { - return this.validExpandViewTypes.includes(StrCast(this.doc.treeViewExpandedView)) ? StrCast(this.doc.treeViewExpandedView) : this.defaultExpandedView; + return this.validExpandViewTypes.includes(StrCast(this.doc.treeView_ExpandedView)) ? StrCast(this.doc.treeView_ExpandedView) : this.defaultExpandedView; } @computed get MAX_EMBED_HEIGHT() { return NumCast(this.props.treeViewParent.maxEmbedHeight, 200); } @computed get dataDoc() { - return this.props.document.treeViewChildrenOnRoot ? this.doc : this.doc[DocData]; + return this.props.document.treeView_ChildrenOnRoot ? this.doc : this.doc[DocData]; } @computed get layoutDoc() { return Doc.Layout(this.doc); } @computed get fieldKey() { - return StrCast(this.doc._treeViewFieldKey, Doc.LayoutFieldKey(this.doc)); + return StrCast(this.doc._treeView_FieldKey, Doc.LayoutFieldKey(this.doc)); } @computed get childDocs() { return this.childDocList(this.fieldKey); @@ -308,13 +308,13 @@ export class TreeView extends React.Component { const bullet = Docs.Create.TextDocument('', { layout: CollectionView.LayoutString('data'), title: '-title-', - treeViewExpandedViewLock: true, - treeViewExpandedView: 'data', + treeView_ExpandedViewLock: true, + treeView_ExpandedView: 'data', _type_collection: CollectionViewType.Tree, layout_hideLinkButton: true, _layout_showSidebar: true, _layout_fitWidth: true, - treeViewType: TreeViewType.outline, + treeView_Type: TreeViewType.outline, x: 0, y: 0, _xMargin: 0, @@ -395,7 +395,7 @@ export class TreeView extends React.Component { }; const addDoc = inside ? localAdd : parentAddDoc; const move = (!dropAction || dropAction === 'proto' || dropAction === 'move' || dropAction === 'same') && moveDocument; - const canAdd = (!this.props.treeView.outlineMode && !StrCast((inside ? this.props.document : this.props.treeViewParent)?.treeViewFreezeChildren).includes('add')) || forceAdd; + const canAdd = (!this.props.treeView.outlineMode && !StrCast((inside ? this.props.document : this.props.treeViewParent)?.treeView_FreezeChildren).includes('add')) || forceAdd; if (canAdd) { this.props.parentTreeView instanceof TreeView && (this.props.parentTreeView.dropping = true); const res = droppedDocuments.reduce((added, d) => (move ? move(d, undefined, addDoc) || (dropAction === 'proto' ? addDoc(d) : false) : addDoc(d)) || added, false); @@ -438,7 +438,7 @@ export class TreeView extends React.Component { doc && Object.keys(doc).forEach(key => !(key in ids) && doc[key] !== ComputedField.undefined && (ids[key] = key)); for (const key of Object.keys(ids).slice().sort()) { - if (this.props.skipFields?.includes(key) || key === 'title' || key === 'treeViewOpen') continue; + if (this.props.skipFields?.includes(key) || key === 'title' || key === 'treeView_Open') continue; const contents = doc[key]; let contentElement: (JSX.Element | null)[] | JSX.Element = []; @@ -538,7 +538,7 @@ export class TreeView extends React.Component { const expandKey = this.treeViewExpandedView; const sortings = (this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.TreeViewSortings) as { [key: string]: { color: string; icon: JSX.Element | string } }) ?? {}; if (['links', 'annotations', 'embeddings', this.fieldKey].includes(expandKey)) { - const sorting = StrCast(this.doc.treeViewSortCriterion, TreeSort.None); + const sorting = StrCast(this.doc.treeView_SortCriterion, TreeSort.None); const sortKeys = Object.keys(sortings); const curSortIndex = Math.max( 0, @@ -550,7 +550,7 @@ export class TreeView extends React.Component { const localAdd = (doc: Doc, addBefore?: Doc, before?: boolean) => { // if there's a sort ordering specified that can be modified on drop (eg, zorder can be modified, alphabetical can't), // then the modification would be done here - const ordering = StrCast(this.doc.treeViewSortCriterion); + const ordering = StrCast(this.doc.treeView_SortCriterion); if (ordering === TreeSort.Zindex) { const docs = TreeView.sortDocs(this.childDocs || ([] as Doc[]), ordering); doc.zIndex = addBefore ? NumCast(addBefore.zIndex) + (before ? -0.5 : 0.5) : 1000; @@ -590,7 +590,7 @@ export class TreeView extends React.Component { }} onClick={undoable(e => { if (this.props.isContentActive() && Math.abs(e.clientX - downX) < 3 && Math.abs(e.clientY - downY) < 3) { - !this.props.treeView.outlineMode && (this.doc.treeViewSortCriterion = sortKeys[(curSortIndex + 1) % sortKeys.length]); + !this.props.treeView.outlineMode && (this.doc.treeView_SortCriterion = sortKeys[(curSortIndex + 1) % sortKeys.length]); e.stopPropagation(); } }, 'sort order')} @@ -601,7 +601,7 @@ export class TreeView extends React.Component { style={{ cursor: 'inherit' }} key={expandKey + 'more'} title="click to change sort order" - className={''} //this.doc.treeViewHideTitle ? 'no-indent' : ''} + className={''} //this.doc.treeView_HideTitle ? 'no-indent' : ''} onPointerDown={e => { downX = e.clientX; downY = e.clientY; @@ -609,7 +609,7 @@ export class TreeView extends React.Component { }} onClick={undoable(e => { if (this.props.isContentActive() && Math.abs(e.clientX - downX) < 3 && Math.abs(e.clientY - downY) < 3) { - !this.props.treeView.outlineMode && (this.doc.treeViewSortCriterion = sortKeys[(curSortIndex + 1) % sortKeys.length]); + !this.props.treeView.outlineMode && (this.doc.treeView_SortCriterion = sortKeys[(curSortIndex + 1) % sortKeys.length]); e.stopPropagation(); } }, 'sort order')}> @@ -683,7 +683,7 @@ export class TreeView extends React.Component { { this: this.doc.isTemplateForField && this.props.dataDoc ? this.props.dataDoc : this.doc, heading: this.props.treeViewParent.title, - checked: this.doc.treeViewChecked === 'check' ? 'x' : this.doc.treeViewChecked === 'x' ? 'remove' : 'check', + checked: this.doc.treeView_Checked === 'check' ? 'x' : this.doc.treeView_Checked === 'x' ? 'remove' : 'check', containingTreeView: this.props.treeView.props.Document, }, console.log @@ -698,7 +698,7 @@ export class TreeView extends React.Component { TraceMobx(); const iconType = this.props.treeView.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.TreeViewIcon + (this.treeViewOpen ? ':open' : !this.childDocs.length ? ':empty' : '')) || 'question'; const color = StrCast(Doc.UserDoc().userColor); - const checked = this.onCheckedClick ? this.doc.treeViewChecked ?? 'unchecked' : undefined; + const checked = this.onCheckedClick ? this.doc.treeView_Checked ?? 'unchecked' : undefined; return (
{ } @action expandNextviewType = () => { - if (this.treeViewOpen && !this.doc.isFolder && !this.props.treeView.outlineMode && !this.doc.treeViewExpandedViewLock) { + if (this.treeViewOpen && !this.doc.isFolder && !this.props.treeView.outlineMode && !this.doc.treeView_ExpandedViewLock) { const next = (modes: any[]) => modes[(modes.indexOf(StrCast(this.treeViewExpandedView)) + 1) % modes.length]; - this.doc.treeViewExpandedView = next(this.validExpandViewTypes); + this.doc.treeView_ExpandedView = next(this.validExpandViewTypes); } this.treeViewOpen = true; }; @@ -759,7 +759,7 @@ export class TreeView extends React.Component { @computed get titleButtons() { const customHeaderButtons = this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.Decorations); const color = StrCast(Doc.UserDoc().userColor); - return this.props.treeViewHideHeaderFields() || this.doc.treeViewHideHeaderFields ? null : ( + return this.props.treeViewHideHeaderFields() || this.doc.treeView_HideHeaderFields ? null : ( <> {customHeaderButtons} {/* e.g.,. hide button is set by dashboardStyleProvider */} { e.stopPropagation(); }} /> - {Doc.noviceMode ? null : this.doc.treeViewExpandedViewLock || Doc.IsSystem(this.doc) ? null : ( + {Doc.noviceMode ? null : this.doc.treeView_ExpandedViewLock || Doc.IsSystem(this.doc) ? null : ( {this.treeViewExpandedView} @@ -815,7 +815,7 @@ export class TreeView extends React.Component { onChildClick = () => this.props.onChildClick?.() ?? (this._editTitleScript?.() || ScriptField.MakeFunction(`DocFocusOrOpen(self)`)!); - onChildDoubleClick = () => ScriptCast(this.props.treeView.Document.treeViewChildDoubleClick, !this.props.treeView.outlineMode ? this._openScript?.() : null); + onChildDoubleClick = () => ScriptCast(this.props.treeView.Document.treeView_ChildDoubleClick, !this.props.treeView.outlineMode ? this._openScript?.() : null); refocus = () => this.props.treeView.props.focus(this.props.treeView.props.Document, {}); ignoreEvent = (e: any) => { @@ -861,7 +861,7 @@ export class TreeView extends React.Component { return this.props?.treeView?.props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView }; onKeyDown = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => { - if (this.doc.treeViewHideHeader || (this.doc.treeViewHideHeaderIfTemplate && this.props.treeView.props.childLayoutTemplate?.()) || this.props.treeView.outlineMode) { + if (this.doc.treeView_HideHeader || (this.doc.treeView_HideHeaderIfTemplate && this.props.treeView.props.childLayoutTemplate?.()) || this.props.treeView.outlineMode) { switch (e.key) { case 'Tab': e.stopPropagation?.(); @@ -1068,7 +1068,7 @@ export class TreeView extends React.Component { // renders the text version of a document as the header. This is used in the file system mode and in other vanilla tree views. @computed get renderTitleAsHeader() { - return this.props.treeView.Document.treeViewHideUnrendered && this.doc.layout_unrendered && !this.doc.treeViewFieldKey ? ( + return this.props.treeView.Document.treeView_HideUnrendered && this.doc.layout_unrendered && !this.doc.treeView_FieldKey ? (
) : ( <> @@ -1089,7 +1089,7 @@ export class TreeView extends React.Component { }; @computed get renderBorder() { - const sorting = StrCast(this.doc.treeViewSortCriterion, TreeSort.None); + const sorting = StrCast(this.doc.treeView_SortCriterion, TreeSort.None); const sortings = (this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.TreeViewSortings) ?? {}) as { [key: string]: { color: string; label: string } }; return (
@@ -1109,7 +1109,7 @@ export class TreeView extends React.Component { render() { TraceMobx(); - const hideTitle = this.doc.treeViewHideHeader || (this.doc.treeViewHideHeaderIfTemplate && this.props.treeView.props.childLayoutTemplate?.()) || this.props.treeView.outlineMode; + const hideTitle = this.doc.treeView_HideHeader || (this.doc.treeView_HideHeaderIfTemplate && this.props.treeView.props.childLayoutTemplate?.()) || this.props.treeView.outlineMode; return this.props.renderedIds?.indexOf(this.doc[Id]) !== -1 ? ( '<' + this.doc.title + '>' // just print the title of documents we've previously rendered in this hierarchical path to avoid cycles ) : ( @@ -1121,9 +1121,9 @@ export class TreeView extends React.Component { // onKeyDown={this.onKeyDown} >
  • - {hideTitle && this.doc.type !== DocumentType.RTF && !this.doc.treeViewRenderAsBulletHeader // should test for prop 'treeViewRenderDocWithBulletAsHeader" + {hideTitle && this.doc.type !== DocumentType.RTF && !this.doc.treeView_RenderAsBulletHeader // should test for prop 'treeView_RenderDocWithBulletAsHeader" ? this.renderEmbeddedDocument(false, returnFalse) - : this.renderBulletHeader(hideTitle ? this.renderDocumentAsHeader(!this.doc.treeViewRenderAsBulletHeader) : this.renderTitleAsHeader, this._editTitle)} + : this.renderBulletHeader(hideTitle ? this.renderDocumentAsHeader(!this.doc.treeView_RenderAsBulletHeader) : this.renderTitleAsHeader, this._editTitle)}
  • ); @@ -1162,7 +1162,7 @@ export class TreeView extends React.Component { childDocs: Doc[], treeView: CollectionTreeView, parentTreeView: CollectionTreeView | TreeView | undefined, - treeViewParent: Doc, + treeView_Parent: Doc, dataDoc: Doc | undefined, parentCollectionDoc: Doc | undefined, containerPrevSibling: Doc | undefined, @@ -1176,7 +1176,7 @@ export class TreeView extends React.Component { isContentActive: (outsideReaction?: boolean) => boolean, panelWidth: () => number, renderDepth: number, - treeViewHideHeaderFields: () => boolean, + treeView_HideHeaderFields: () => boolean, renderedIds: string[], onCheckedClick: undefined | (() => ScriptField), onChildClick: undefined | (() => ScriptField), @@ -1193,19 +1193,19 @@ export class TreeView extends React.Component { hierarchyIndex?: number[], renderCount?: number ) { - const viewSpecScript = Cast(treeViewParent.viewSpecScript, ScriptField); + const viewSpecScript = Cast(treeView_Parent.viewSpecScript, ScriptField); if (viewSpecScript) { childDocs = childDocs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result); } - const docs = TreeView.sortDocs(childDocs, StrCast(treeViewParent.treeViewSortCriterion, TreeSort.None)); + const docs = TreeView.sortDocs(childDocs, StrCast(treeView_Parent.treeView_SortCriterion, TreeSort.None)); const rowWidth = () => panelWidth() - treeBulletWidth() * (treeView.props.NativeDimScaling?.() || 1); - const treeViewRefs = new Map(); + const treeView_Refs = new Map(); return docs .filter(child => child instanceof Doc) .map((child, i) => { if (renderCount && i > renderCount) return null; - const pair = Doc.GetLayoutDataDocPair(treeViewParent, dataDoc, child); + const pair = Doc.GetLayoutDataDocPair(treeView_Parent, dataDoc, child); if (!pair.layout || pair.data instanceof Promise) { return null; } @@ -1218,11 +1218,11 @@ export class TreeView extends React.Component { FormattedTextBox.SelectOnLoad = child[Id]; TreeView._editTitleOnLoad = editTitle ? { id: child[Id], parent } : undefined; Doc.AddDocToList(newParent, fieldKey, child, addAfter, false); - newParent.treeViewOpen = true; + newParent.treeView_Open = true; Doc.SetContainer(child, treeView.Document); } }; - const indent = i === 0 ? undefined : (editTitle: boolean) => dentDoc(editTitle, docs[i - 1], undefined, treeViewRefs.get(docs[i - 1])); + const indent = i === 0 ? undefined : (editTitle: boolean) => dentDoc(editTitle, docs[i - 1], undefined, treeView_Refs.get(docs[i - 1])); const outdent = !parentCollectionDoc ? undefined : (editTitle: boolean) => dentDoc(editTitle, parentCollectionDoc, containerPrevSibling, parentTreeView instanceof TreeView ? parentTreeView.props.parentTreeView : undefined); const addDocument = (doc: Doc | Doc[], annotationKey?: string, relativeTo?: Doc, before?: boolean) => add(doc, relativeTo ?? docs[i], before !== undefined ? before : false); const childLayout = Doc.Layout(pair.layout); @@ -1233,10 +1233,10 @@ export class TreeView extends React.Component { return ( treeViewRefs.set(child, r ? r : undefined)} + ref={r => treeView_Refs.set(child, r ? r : undefined)} document={pair.layout} dataDoc={pair.data} - treeViewParent={treeViewParent} + treeViewParent={treeView_Parent} prevSibling={docs[i]} // TODO: [AL] add these hierarchyIndex={hierarchyIndex ? [...hierarchyIndex, i + 1] : undefined} @@ -1248,7 +1248,7 @@ export class TreeView extends React.Component { onCheckedClick={onCheckedClick} onChildClick={onChildClick} renderDepth={renderDepth} - removeDoc={StrCast(treeViewParent.treeViewFreezeChildren).includes('remove') ? undefined : remove} + removeDoc={StrCast(treeView_Parent.treeView_FreezeChildren).includes('remove') ? undefined : remove} addDocument={addDocument} styleProvider={styleProvider} panelWidth={rowWidth} @@ -1259,7 +1259,7 @@ export class TreeView extends React.Component { addDocTab={addDocTab} ScreenToLocalTransform={screenToLocalXf} isContentActive={isContentActive} - treeViewHideHeaderFields={treeViewHideHeaderFields} + treeViewHideHeaderFields={treeView_HideHeaderFields} renderedIds={renderedIds} skipFields={skipFields} firstLevel={firstLevel} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss index c6419885b..e4ae251c8 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss @@ -153,7 +153,12 @@ overflow-y: auto; overflow-x: hidden; } - +.collectionFreeFormView-brushView { + pointer-events: none; + position: absolute; + transition: opacity 0.5s; + z-index: 1000; +} .collectionfreeformview-container { // touch action none means that the browser will handle none of the touch actions. this allows us to implement our own actions. touch-action: none; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index e1455525e..ffcf0999c 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -319,7 +319,7 @@ export class CollectionFreeFormView extends CollectionSubView { if (this.Document._isGroup || !this.isContentActive()) return; // group style collections neither pan nor zoom PresBox.Instance?.pauseAutoPres(); - if (this.layoutDoc._Transform || this.props.Document.treeViewOutlineMode === TreeViewType.outline) return; + if (this.layoutDoc._Transform || this.props.Document.treeView_OutlineMode === TreeViewType.outline) return; e.stopPropagation(); const docHeight = NumCast(this.rootDoc[Doc.LayoutFieldKey(this.rootDoc) + '_nativeHeight'], this.nativeHeight); const scrollable = NumCast(this.layoutDoc[this.scaleFieldKey], 1) === 1 && docHeight > this.props.PanelHeight() / this.nativeDimScaling + 1e-4; @@ -1318,7 +1319,7 @@ export class CollectionFreeFormView extends CollectionSubView ); } @@ -1537,7 +1538,7 @@ export class CollectionFreeFormView extends CollectionSubView { // create an anchor that saves information about the current state of the freeform view (pan, zoom, view type) - const anchor = Docs.Create.ConfigDocument({ title: 'ViewSpec - ' + StrCast(this.layoutDoc._type_collection), layout_unrendered: true, presTransition: 500, annotationOn: this.rootDoc }); + const anchor = Docs.Create.ConfigDocument({ title: 'ViewSpec - ' + StrCast(this.layoutDoc._type_collection), layout_unrendered: true, presentation_transition: 500, annotationOn: this.rootDoc }); PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), pannable: !this.Document._isGroup, type_collection: true, filters: true } }, this.rootDoc); if (addAsAnnotation) { @@ -1866,6 +1867,7 @@ export class CollectionFreeFormView extends CollectionSubView (CollectionFreeFormView.ShowPresPaths ? PresBox.Instance.getPaths(this.rootDoc) : null); + brushedView = () => this._brushedView; @computed get marqueeView() { TraceMobx(); return ( @@ -1908,13 +1910,13 @@ export class CollectionFreeFormView extends CollectionSubView ) : null} {this.children} @@ -1945,19 +1947,19 @@ export class CollectionFreeFormView extends CollectionSubView { - this._brushedView = { ...viewport, panX: viewport.panX - viewport.width / 2, panY: viewport.panY - viewport.height / 2, opacity: 1 }; + brushView = (viewport: { width: number; height: number; panX: number; panY: number }, transTime: number) => { this._brushtimer1 && clearTimeout(this._brushtimer1); this._brushtimer && clearTimeout(this._brushtimer); + this._brushedView = { width: 0, height: 0, panX: 0, panY: 0, opacity: 0 }; this._brushtimer1 = setTimeout( action(() => { - this._brushedView.opacity = 0; + this._brushedView = { ...viewport, panX: viewport.panX - viewport.width / 2, panY: viewport.panY - viewport.height / 2, opacity: 1 }; this._brushtimer = setTimeout( - action(() => (this._brushedView = { width: 0, height: 0, panX: 0, panY: 0, opacity: 0 })), - 500 + action(() => (this._brushedView.opacity = 0)), + 2500 ); }), - 1000 + transTime + 1 ); }; lightboxPanelWidth = () => Math.max(0, this.props.PanelWidth() - 30); @@ -2084,7 +2086,7 @@ interface CollectionFreeFormViewPannableContentsProps { presPinView?: boolean; isAnnotationOverlay: boolean | undefined; isAnnotationOverlayScrollable: boolean | undefined; - brushView: { panX: number; panY: number; width: number; height: number; opacity: number }; + brushedView: () => { panX: number; panY: number; width: number; height: number; opacity: number }; } @observer @@ -2156,6 +2158,7 @@ class CollectionFreeFormViewPannableContents extends React.Component {this.props.children} - {!this.props.brushView.width ? null : ( + {
    - )} + } {this.presPaths}
    ); diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx index 737d675aa..a81707ea4 100644 --- a/src/client/views/linking/LinkMenuItem.tsx +++ b/src/client/views/linking/LinkMenuItem.tsx @@ -84,7 +84,7 @@ export class LinkMenuItem extends React.Component { }, emptyFunction, action(() => { - const trail = DocCast(this.props.docView.rootDoc.presTrail); + const trail = DocCast(this.props.docView.rootDoc.presentationTrail); if (trail) { Doc.ActivePresentation = trail; DocumentViewInternal.addDocTabFunc(trail, OpenWhere.replaceRight); diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index 0cc73f32f..059c39c68 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -20,7 +20,7 @@ export enum DataVizView { TABLE = 'table', LINECHART = 'lineChart', HISTOGRAM = 'histogram', - PIECHART = 'pieChart' + PIECHART = 'pieChart', } @observer @@ -39,20 +39,22 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { // current displayed chart type @computed get dataVizView(): DataVizView { - return StrCast(this.layoutDoc._dataVizView, 'table') as DataVizView; + return StrCast(this.layoutDoc._dataViz, 'table') as DataVizView; } @action // pinned / linked anchor doc includes selected rows, graph titles, and graph colors restoreView = (data: Doc) => { - const changedView = this.dataVizView !== data.presDataVizView && (this.layoutDoc._dataVizView = data.presDataVizView); - const changedAxes = this.axes.join('') !== StrListCast(data.presDataVizAxes).join('') && (this.layoutDoc._data_vizAxes = new List(StrListCast(data.presDataVizAxes))); - this.layoutDoc.selected = Field.Copy(data.selected); + const changedView = this.dataVizView !== data.config_dataViz && (this.layoutDoc._dataViz = data.config_dataViz); + const changedAxes = this.axes.join('') !== StrListCast(data.config_dataVizAxes).join('') && (this.layoutDoc._dataViz_axes = new List(StrListCast(data.config_dataVizAxes))); + this.layoutDoc.dataViz_selectedRows = Field.Copy(data.dataViz_selectedRows); this.layoutDoc.histogramBarColors = Field.Copy(data.histogramBarColors); this.layoutDoc.defaultHistogramColor = data.defaultHistogramColor; this.layoutDoc.pieSliceColors = Field.Copy(data.pieSliceColors); Object.keys(this.layoutDoc).map(key => { - if (key.startsWith('histogram-title') || key.startsWith('lineChart-title') || key.startsWith('pieChart-title')){ this.layoutDoc['_'+key] = data[key]; } - }) + if (key.startsWith('histogram_title') || key.startsWith('lineChart_title') || key.startsWith('pieChart_title')) { + this.layoutDoc['_' + key] = data[key]; + } + }); const func = () => this._chartRenderer?.restoreView(data); if (changedView || changedAxes) { setTimeout(func, 100); @@ -69,23 +71,25 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { // this is for when we want the whole doc (so when the chartBox getAnchor returns without a marker) /*put in some options*/ }); - anchor.presDataVizView = this.dataVizView; - anchor.presDataVizAxes = this.axes.length ? new List(this.axes) : undefined; - anchor.selected = Field.Copy(this.layoutDoc.selected); + anchor.config_dataViz = this.dataVizView; + anchor.config_dataVizAxes = this.axes.length ? new List(this.axes) : undefined; + anchor.dataViz_selectedRows = Field.Copy(this.layoutDoc.dataViz_selectedRows); anchor.histogramBarColors = Field.Copy(this.layoutDoc.histogramBarColors); anchor.defaultHistogramColor = this.layoutDoc.defaultHistogramColor; anchor.pieSliceColors = Field.Copy(this.layoutDoc.pieSliceColors); Object.keys(this.layoutDoc).map(key => { - if (key.startsWith('histogram-title') || key.startsWith('lineChart-title') || key.startsWith('pieChart-title')){ anchor[key] = this.layoutDoc[key]; } - }) + if (key.startsWith('histogram_title') || key.startsWith('lineChart_title') || key.startsWith('pieChart_title')) { + anchor[key] = this.layoutDoc[key]; + } + }); this.addDocument(anchor); return anchor; }; @computed.struct get axes() { - return StrListCast(this.layoutDoc.data_vizAxes); + return StrListCast(this.layoutDoc.dataViz_axes); } - selectAxes = (axes: string[]) => (this.layoutDoc.data_vizAxes = new List(axes)); + selectAxes = (axes: string[]) => (this.layoutDoc.dataViz_axes = new List(axes)); // toggles for user to decide which chart type to view the data in @computed get selectView() { @@ -94,10 +98,53 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { const margin = { top: 10, right: 25, bottom: 75, left: 45 }; if (!this.pairs) return 'no data'; switch (this.dataVizView) { - case DataVizView.TABLE: return ; - case DataVizView.LINECHART: return (this._chartRenderer = r ?? undefined)} height={height} width={width} fieldKey={this.fieldKey} margin={margin} rootDoc={this.rootDoc} axes={this.axes} pairs={this.pairs} dataDoc={this.dataDoc} />; - case DataVizView.HISTOGRAM: return (this._chartRenderer = r ?? undefined)} height={height} width={width} fieldKey={this.fieldKey} margin={margin} rootDoc={this.rootDoc} axes={this.axes} pairs={this.pairs} dataDoc={this.dataDoc} />; - case DataVizView.PIECHART: return (this._chartRenderer = r ?? undefined)} height={height} width={width} fieldKey={this.fieldKey} margin={margin} rootDoc={this.rootDoc} axes={this.axes} pairs={this.pairs} dataDoc={this.dataDoc} />; + case DataVizView.TABLE: + return ; + case DataVizView.LINECHART: + return ( + (this._chartRenderer = r ?? undefined)} + height={height} + width={width} + fieldKey={this.fieldKey} + margin={margin} + rootDoc={this.rootDoc} + axes={this.axes} + pairs={this.pairs} + dataDoc={this.dataDoc} + /> + ); + case DataVizView.HISTOGRAM: + return ( + (this._chartRenderer = r ?? undefined)} + height={height} + width={width} + fieldKey={this.fieldKey} + margin={margin} + rootDoc={this.rootDoc} + axes={this.axes} + pairs={this.pairs} + dataDoc={this.dataDoc} + /> + ); + case DataVizView.PIECHART: + return ( + (this._chartRenderer = r ?? undefined)} + height={height} + width={width} + fieldKey={this.fieldKey} + margin={margin} + rootDoc={this.rootDoc} + axes={this.axes} + pairs={this.pairs} + dataDoc={this.dataDoc} + /> + ); } } @@ -118,14 +165,10 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { } render() { - if (!this.layoutDoc._dataVizView) this.layoutDoc._dataVizView = this.dataVizView; + if (!this.layoutDoc._dataViz) this.layoutDoc._dataViz = this.dataVizView; return !this.pairs?.length ? ( // displays how to get data into the DataVizBox if its empty -
    - To create a DataViz box, either import / drag a CSV file into your canvas - or copy a data table and use the command 'ctrl + p' to bring the data table - to your canvas. -
    +
    To create a DataViz box, either import / drag a CSV file into your canvas or copy a data table and use the command 'ctrl + p' to bring the data table to your canvas.
    ) : (
    () { ) }>
    - this.layoutDoc._dataVizView = DataVizView.TABLE} - toggleStatus={this.layoutDoc._dataVizView == DataVizView.TABLE} - /> - this.layoutDoc._dataVizView = DataVizView.LINECHART} - toggleStatus={this.layoutDoc._dataVizView == DataVizView.LINECHART} - /> - this.layoutDoc._dataVizView = DataVizView.HISTOGRAM} - toggleStatus={this.layoutDoc._dataVizView == DataVizView.HISTOGRAM} - /> - this.layoutDoc._dataVizView = DataVizView.PIECHART} - toggleStatus={this.layoutDoc._dataVizView == DataVizView.PIECHART} - /> + (this.layoutDoc._dataViz = DataVizView.TABLE)} toggleStatus={this.layoutDoc._dataViz == DataVizView.TABLE} /> + (this.layoutDoc._dataViz = DataVizView.LINECHART)} toggleStatus={this.layoutDoc._dataViz == DataVizView.LINECHART} /> + (this.layoutDoc._dataViz = DataVizView.HISTOGRAM)} toggleStatus={this.layoutDoc._dataViz == DataVizView.HISTOGRAM} /> + (this.layoutDoc._dataViz = DataVizView.PIECHART)} toggleStatus={this.layoutDoc._dataViz == DataVizView.PIECHART} />
    {this.selectView}
    diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx index df6aac6bc..086db2a47 100644 --- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx +++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx @@ -1,20 +1,20 @@ -import { observer } from "mobx-react"; -import { Doc, StrListCast } from "../../../../../fields/Doc"; +import { observer } from 'mobx-react'; +import { Doc, StrListCast } from '../../../../../fields/Doc'; import * as React from 'react'; import * as d3 from 'd3'; -import { IReactionDisposer, action, computed, observable, reaction } from "mobx"; -import { LinkManager } from "../../../../util/LinkManager"; -import { Cast, DocCast, StrCast} from "../../../../../fields/Types"; -import { PinProps, PresBox } from "../../trails"; -import { Docs } from "../../../../documents/Documents"; -import { List } from "../../../../../fields/List"; +import { IReactionDisposer, action, computed, observable, reaction } from 'mobx'; +import { LinkManager } from '../../../../util/LinkManager'; +import { Cast, DocCast, StrCast } from '../../../../../fields/Types'; +import { PinProps, PresBox } from '../../trails'; +import { Docs } from '../../../../documents/Documents'; +import { List } from '../../../../../fields/List'; import './Chart.scss'; -import { ColorPicker, EditableText, IconButton, Size, Type } from "browndash-components"; -import { FaFillDrip } from "react-icons/fa"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { listSpec } from "../../../../../fields/Schema"; -import { scaleCreatorNumerical, yAxisCreator } from "../utils/D3Utils"; -import { undoBatch, undoable } from "../../../../util/UndoManager"; +import { ColorPicker, EditableText, IconButton, Size, Type } from 'browndash-components'; +import { FaFillDrip } from 'react-icons/fa'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { listSpec } from '../../../../../fields/Schema'; +import { scaleCreatorNumerical, yAxisCreator } from '../utils/D3Utils'; +import { undoBatch, undoable } from '../../../../util/UndoManager'; export interface HistogramProps { rootDoc: Doc; @@ -35,7 +35,6 @@ export interface HistogramProps { @observer export class Histogram extends React.Component { - private _disposers: { [key: string]: IReactionDisposer } = {}; private _histogramRef: React.RefObject = React.createRef(); private _histogramSvg: d3.Selection | undefined; @@ -49,32 +48,37 @@ export class Histogram extends React.Component { // filters all data to just display selected data if brushed (created from an incoming link) @computed get _histogramData() { - var guids = StrListCast(this.props.layoutDoc.rowGuids); + var guids = StrListCast(this.props.layoutDoc.dataViz_rowGuids); if (this.props.axes.length < 1) return []; if (this.props.axes.length < 2) { var ax0 = this.props.axes[0]; - if (/\d/.test(this.props.pairs[0][ax0])){ this.numericalXData = true } + if (/\d/.test(this.props.pairs[0][ax0])) { + this.numericalXData = true; + } return this.props.pairs - ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(guids[this.props.pairs.indexOf(pair)]))) - .map(pair => ({ [ax0]: (pair[this.props.axes[0]])})) - }; + ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.dataViz_selectedRows && StrListCast(this.incomingLinks[0].dataViz_selectedRows).includes(guids[this.props.pairs.indexOf(pair)]))) + .map(pair => ({ [ax0]: pair[this.props.axes[0]] })); + } var ax0 = this.props.axes[0]; var ax1 = this.props.axes[1]; - if (/\d/.test(this.props.pairs[0][ax0])) { this.numericalXData = true;} - if (/\d/.test(this.props.pairs[0][ax1]) ) { this.numericalYData = true;} + if (/\d/.test(this.props.pairs[0][ax0])) { + this.numericalXData = true; + } + if (/\d/.test(this.props.pairs[0][ax1])) { + this.numericalYData = true; + } return this.props.pairs - ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(guids[this.props.pairs.indexOf(pair)]))) - .map(pair => ({ [ax0]: (pair[this.props.axes[0]]), [ax1]: (pair[this.props.axes[1]]) })) + ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.dataViz_selectedRows && StrListCast(this.incomingLinks[0].dataViz_selectedRows).includes(guids[this.props.pairs.indexOf(pair)]))) + .map(pair => ({ [ax0]: pair[this.props.axes[0]], [ax1]: pair[this.props.axes[1]] })); } - @computed get defaultGraphTitle(){ + @computed get defaultGraphTitle() { var ax0 = this.props.axes[0]; - var ax1 = (this.props.axes.length>1)? this.props.axes[1] : undefined; - if (this.props.axes.length<2 || !ax1 || !/\d/.test(this.props.pairs[0][ax1]) || !this.numericalYData){ - return ax0 + " Histogram"; - } - else return ax0 + " by " + ax1 + " Histogram"; - } + var ax1 = this.props.axes.length > 1 ? this.props.axes[1] : undefined; + if (this.props.axes.length < 2 || !ax1 || !/\d/.test(this.props.pairs[0][ax1]) || !this.numericalYData) { + return ax0 + ' Histogram'; + } else return ax0 + ' by ' + ax1 + ' Histogram'; + } @computed get incomingLinks() { return LinkManager.Instance.getAllRelatedLinks(this.props.rootDoc) // out of all links @@ -83,11 +87,11 @@ export class Histogram extends React.Component { } @computed get rangeVals(): { xMin?: number; xMax?: number; yMin?: number; yMax?: number } { - if (this.numericalXData){ + if (this.numericalXData) { const data = this.data(this._histogramData); - return {xMin: Math.min.apply(null, data), xMax: Math.max.apply(null, data), yMin:0, yMax:0} + return { xMin: Math.min.apply(null, data), xMax: Math.max.apply(null, data), yMin: 0, yMax: 0 }; } - return {xMin:0, xMax:0, yMin:0, yMax:0} + return { xMin: 0, xMax: 0, yMin: 0, yMax: 0 }; } componentWillUnmount() { @@ -97,7 +101,7 @@ export class Histogram extends React.Component { this._disposers.chartData = reaction( () => ({ dataSet: this._histogramData, w: this.width, h: this.height }), ({ dataSet, w, h }) => { - if (dataSet!.length>0) { + if (dataSet!.length > 0) { this.drawChart(dataSet, w, h); } }, @@ -113,7 +117,7 @@ export class Histogram extends React.Component { // title: 'histogram doc selection' + this._currSelected, }); - PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this.props.dataDoc); + PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this.props.rootDoc); return anchor; }; @@ -127,20 +131,22 @@ export class Histogram extends React.Component { // cleans data by converting numerical data to numbers and taking out empty cells data = (dataSet: any) => { - var validData = dataSet.filter((d: { [x: string]: unknown; }) => { + var validData = dataSet.filter((d: { [x: string]: unknown }) => { var valid = true; Object.keys(dataSet[0]).map(key => { if (!d[key] || Number.isNaN(d[key])) valid = false; - }) + }); return valid; - }) - var field = dataSet[0]? Object.keys(dataSet[0])[0] : undefined; - const data = validData.map((d: { [x: string]: any; }) => { - if (this.numericalXData) { return +d[field!].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { + if (this.numericalXData) { + return +d[field!].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { @@ -148,35 +154,31 @@ export class Histogram extends React.Component { var barCounter = -1; const selected = svg.selectAll('.histogram-bar').filter((d: any) => { barCounter++; // uses the order of bars and width of each bar to find which one the pointer is over - if ((barCounter*eachRectWidth ) <= pointerX && pointerX <= ((barCounter+1)*eachRectWidth)){ - var showSelected = this.numericalYData? this._histogramData.filter((data: { [x: string]: any; }) => StrCast(data[xAxisTitle]).replace(/\$/g, '').replace(/\%/g, '').replace(/\ data[xAxisTitle].replace(/\$/g, '').replace(/\%/g, '').replace(/\ StrCast(data[xAxisTitle]).replace(/\$/g, '').replace(/\%/g, '').replace(/\ data[xAxisTitle].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { @@ -184,306 +186,338 @@ export class Histogram extends React.Component { d3.select(this._histogramRef.current).select('.tooltip').remove(); var data = this.data(dataSet); - var xAxisTitle = Object.keys(dataSet[0])[0] + var xAxisTitle = Object.keys(dataSet[0])[0]; var yAxisTitle = this.numericalYData ? Object.keys(dataSet[0])[1] : 'frequency'; - let uniqueArr: unknown[] = [...new Set(data)] - var numBins = (this.numericalXData && Number.isInteger(data[0]))? (this.rangeVals.xMax! - this.rangeVals.xMin! ) : uniqueArr.length - var translateXAxis = !this.numericalXData || numBinsthis.maxBins) numBins = this.maxBins; - var startingPoint = this.numericalXData? this.rangeVals.xMin! : 0; - var endingPoint = this.numericalXData? this.rangeVals.xMax! : numBins; + let uniqueArr: unknown[] = [...new Set(data)]; + var numBins = this.numericalXData && Number.isInteger(data[0]) ? this.rangeVals.xMax! - this.rangeVals.xMin! : uniqueArr.length; + var translateXAxis = !this.numericalXData || numBins < this.maxBins ? width / (numBins + 1) / 2 : 0; + if (numBins > this.maxBins) numBins = this.maxBins; + var startingPoint = this.numericalXData ? this.rangeVals.xMin! : 0; + var endingPoint = this.numericalXData ? this.rangeVals.xMax! : numBins; // converts data into Objects - var histDataSet = dataSet.filter((d: { [x: string]: unknown; }) => { + var histDataSet = dataSet.filter((d: { [x: string]: unknown }) => { var valid = true; Object.keys(dataSet[0]).map(key => { if (!d[key] || Number.isNaN(d[key])) valid = false; - }) + }); return valid; }); if (!this.numericalXData) { - var histStringDataSet: { [x: string]: unknown; }[] = []; - if (this.numericalYData){ - for (let i=0; i each[xAxisTitle]==data[i]) - histStringDataSet.filter(each => each[xAxisTitle]==data[i])[0][yAxisTitle] = Number(barData[0][yAxisTitle]) + 1; + for (let i = 0; i < data.length; i++) { + let barData = histStringDataSet.filter(each => each[xAxisTitle] == data[i]); + histStringDataSet.filter(each => each[xAxisTitle] == data[i])[0][yAxisTitle] = Number(barData[0][yAxisTitle]) + 1; } } - histDataSet = histStringDataSet + histDataSet = histStringDataSet; } // initial graph and binning data for histogram var svg = (this._histogramSvg = d3 .select(this._histogramRef.current) - .append("svg") - .attr("class", "graph") - .attr("width", width + this.props.margin.right + this.props.margin.left) - .attr("height", height + this.props.margin.top + this.props.margin.bottom) - .append("g") - .attr("transform", - "translate(" + this.props.margin.left + "," + this.props.margin.top + ")")); - var x = d3.scaleLinear() - .domain(this.numericalXData? [startingPoint!, endingPoint!] : [0, numBins]) - .range([0, width ]); - var histogram = d3.histogram() - .value(function(d) {return d}) + .append('svg') + .attr('class', 'graph') + .attr('width', width + this.props.margin.right + this.props.margin.left) + .attr('height', height + this.props.margin.top + this.props.margin.bottom) + .append('g') + .attr('transform', 'translate(' + this.props.margin.left + ',' + this.props.margin.top + ')')); + var x = d3 + .scaleLinear() + .domain(this.numericalXData ? [startingPoint!, endingPoint!] : [0, numBins]) + .range([0, width]); + var histogram = d3 + .histogram() + .value(function (d) { + return d; + }) .domain([startingPoint!, endingPoint!]) - .thresholds(x.ticks(numBins)) - var bins = histogram(data) - var eachRectWidth = width/(bins.length) - var graphStartingPoint = (bins[0].x1 && bins[1])? bins[0].x1! - (bins[1].x1! - bins[1].x0!) : 0; + .thresholds(x.ticks(numBins)); + var bins = histogram(data); + var eachRectWidth = width / bins.length; + var graphStartingPoint = bins[0].x1 && bins[1] ? bins[0].x1! - (bins[1].x1! - bins[1].x0!) : 0; bins[0].x0 = graphStartingPoint; - x = x.domain([graphStartingPoint, endingPoint]) - .range([0, Number.isInteger(this.rangeVals.xMin!)? (width-eachRectWidth) : width ]) + x = x.domain([graphStartingPoint, endingPoint]).range([0, Number.isInteger(this.rangeVals.xMin!) ? width - eachRectWidth : width]); var xAxis; // more calculations based on bins // x-axis - if (!this.numericalXData) { // reorganize to match data if the data is strings rather than numbers + if (!this.numericalXData) { + // reorganize to match data if the data is strings rather than numbers // uniqueArr.sort() - histDataSet.sort() - for (let i=0; i d.x0 = d.x0!) - xAxis = d3.axisBottom(x) - .ticks(bins.length>1? bins.length-1: 1) - .tickFormat( i => uniqueArr[i.valueOf()] as string) - .tickPadding(10) - x.range([0, width-eachRectWidth]) - x.domain([0, bins.length-1]) + eachRectWidth = width / bins.length; + bins.forEach(d => (d.x0 = d.x0!)); + xAxis = d3 + .axisBottom(x) + .ticks(bins.length > 1 ? bins.length - 1 : 1) + .tickFormat(i => uniqueArr[i.valueOf()] as string) + .tickPadding(10); + x.range([0, width - eachRectWidth]); + x.domain([0, bins.length - 1]); translateXAxis = eachRectWidth / 2; - } - else { + } else { var allSame = true; - for (var i=0; i=2? (bins[bins.length-2].x1!-bins[bins.length-2].x0!): 0) + eachRectWidth = width / bins.length; + } else { + eachRectWidth = width / (bins.length + 1); + var tickDiff = bins.length >= 2 ? bins[bins.length - 2].x1! - bins[bins.length - 2].x0! : 0; var curDomain = x.domain(); - x.domain([curDomain[0], curDomain[0] + tickDiff*bins.length]) + x.domain([curDomain[0], curDomain[0] + tickDiff * bins.length]); } - xAxis = d3.axisBottom(x) - .ticks(bins.length-1) - x.range([0, width-eachRectWidth]) + xAxis = d3.axisBottom(x).ticks(bins.length - 1); + x.range([0, width - eachRectWidth]); } // y-axis - const maxFrequency = this.numericalYData? d3.max(histDataSet, function(d: any) { - return d[yAxisTitle]? Number(d[yAxisTitle]!.replace(/\$/g, '').replace(/\%/g, '').replace(/\ this.highlightSelectedBar(true, svg, eachRectWidth, d3.pointer(e)[0], xAxisTitle, yAxisTitle, histDataSet)); const onHover = action((e: any) => { - const selected = this.highlightSelectedBar(false, svg, eachRectWidth, d3.pointer(e)[0], xAxisTitle, yAxisTitle, histDataSet) + const selected = this.highlightSelectedBar(false, svg, eachRectWidth, d3.pointer(e)[0], xAxisTitle, yAxisTitle, histDataSet); updateHighlights(); - }) + }); const mouseOut = action((e: any) => { this.hoverOverData = undefined; updateHighlights(); - }) + }); const updateHighlights = () => { const hoverOverBar = this.hoverOverData; const selectedData = this.selectedData; - svg.selectAll('rect').attr("class", function(d: any) { return ((hoverOverBar && hoverOverBar[0]==d[0]) || selectedData && selectedData[0]==d[0])? 'histogram-bar hover' : 'histogram-bar'; }) - } - svg.on('click', onPointClick) - .on('mouseover', onHover) - .on('mouseout', mouseOut) + svg.selectAll('rect').attr('class', function (d: any) { + return (hoverOverBar && hoverOverBar[0] == d[0]) || (selectedData && selectedData[0] == d[0]) ? 'histogram-bar hover' : 'histogram-bar'; + }); + }; + svg.on('click', onPointClick).on('mouseover', onHover).on('mouseout', mouseOut); // axis titles - svg.append("text") - .attr("transform", "translate(" + (width/2) + " ," + (height+40) + ")") - .style("text-anchor", "middle") + svg.append('text') + .attr('transform', 'translate(' + width / 2 + ' ,' + (height + 40) + ')') + .style('text-anchor', 'middle') .text(xAxisTitle); - svg.append("text") - .attr("transform", "rotate(-90)" + " " + "translate( 0, " + -10 + ")") - .attr("x", -(height/2)) - .attr("y", -20) - .style("text-anchor", "middle") + svg.append('text') + .attr('transform', 'rotate(-90)' + ' ' + 'translate( 0, ' + -10 + ')') + .attr('x', -(height / 2)) + .attr('y', -20) + .style('text-anchor', 'middle') .text(yAxisTitle); - d3.format('.0f') + d3.format('.0f'); // draw bars var selected = this.selectedData; - svg.selectAll("rect") + svg.selectAll('rect') .data(bins) .enter() - .append("rect") - .attr("transform", this.numericalYData? - function (d) { - var eachData = histDataSet.filter((data: { [x: string]: number; }) => {return data[xAxisTitle]==d[0]}) - var length = eachData.length? eachData[0][yAxisTitle].replace(/\$/g, '').replace(/\%/g, '').replace(/\ {return data[xAxisTitle]==d[0]}) - var length = eachData.length? eachData[0][yAxisTitle].replace(/\$/g, '').replace(/\%/g, '').replace(/\{ + .append('rect') + .attr( + 'transform', + this.numericalYData + ? function (d) { + var eachData = histDataSet.filter((data: { [x: string]: number }) => { + return data[xAxisTitle] == d[0]; + }); + var length = eachData.length ? eachData[0][yAxisTitle].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { + return data[xAxisTitle] == d[0]; + }); + var length = eachData.length ? eachData[0][yAxisTitle].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { var barColor; var barColors = StrListCast(this.props.layoutDoc.histogramBarColors).map(each => each.split('::')); - barColors.map(each => { - if (d[0] && d[0].toString() && each[0]==d[0].toString()) barColor = each[1]; + barColors.map(each => { + if (d[0] && d[0].toString() && each[0] == d[0].toString()) barColor = each[1]; else { - var range = StrCast(each[0]).split(" to "); - if (Number(range[0])<=d[0] && d[0]<=Number(range[1])) barColor = each[1]; + var range = StrCast(each[0]).split(' to '); + if (Number(range[0]) <= d[0] && d[0] <= Number(range[1])) barColor = each[1]; } }); - return barColor? StrCast(barColor) : StrCast(this.props.layoutDoc.defaultHistogramColor)}) + return barColor ? StrCast(barColor) : StrCast(this.props.layoutDoc.defaultHistogramColor); + }); }; @action changeSelectedColor = (color: string) => { - this.curBarSelected.attr("fill", color); - var barName = StrCast(this._currSelected[this.props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { if (each.split('::')[0] == barName) barColors.splice(barColors.indexOf(each), 1) }); + const barColors = Cast(this.props.layoutDoc.histogramBarColors, listSpec('string'), null); + barColors.map(each => { + if (each.split('::')[0] == barName) barColors.splice(barColors.indexOf(each), 1); + }); barColors.push(StrCast(barName + '::' + color)); }; - - @action eraseSelectedColor= () => { - this.curBarSelected.attr("fill", this.props.layoutDoc.defaultHistogramColor); - var barName = StrCast(this._currSelected[this.props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { if (each.split('::')[0] == barName) barColors.splice(barColors.indexOf(each), 1) }); + @action eraseSelectedColor = () => { + this.curBarSelected.attr('fill', this.props.layoutDoc.defaultHistogramColor); + var barName = StrCast(this._currSelected[this.props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { + if (each.split('::')[0] == barName) barColors.splice(barColors.indexOf(each), 1); + }); }; render() { - this._histogramData - var curSelectedBarName; - var titleAccessor: any=''; - if (this.props.axes.length==2) titleAccessor = 'histogram-title-'+this.props.axes[0]+'-'+this.props.axes[1]; - else if (this.props.axes.length>0) titleAccessor = 'histogram-title-'+this.props.axes[0]; + this._histogramData; + var curSelectedBarName = ''; + var titleAccessor: any = ''; + if (this.props.axes.length == 2) titleAccessor = 'dataViz_title_histogram_' + this.props.axes[0] + '-' + this.props.axes[1]; + else if (this.props.axes.length > 0) titleAccessor = 'dataViz_title_histogram_' + this.props.axes[0]; if (!this.props.layoutDoc[titleAccessor]) this.props.layoutDoc[titleAccessor] = this.defaultGraphTitle; if (!this.props.layoutDoc.defaultHistogramColor) this.props.layoutDoc.defaultHistogramColor = '#69b3a2'; if (!this.props.layoutDoc.histogramBarColors) this.props.layoutDoc.histogramBarColors = new List(); var selected: string; - if (this._currSelected){ - curSelectedBarName = StrCast(this._currSelected![this.props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { - key!=''? selected += key + ': ' + this._currSelected[key] + ', ': ''; - }) - selected = selected.substring(0, selected.length-2); + key != '' ? (selected += key + ': ' + this._currSelected[key] + ', ') : ''; + }); + selected = selected.substring(0, selected.length - 2); selected += ' }'; - } - else selected = 'none'; + } else selected = 'none'; var selectedBarColor; var barColors = StrListCast(this.props.layoutDoc.histogramBarColors).map(each => each.split('::')); - barColors.map(each => {if (each[0]==curSelectedBarName!) selectedBarColor = each[1]}); + barColors.map(each => { + if (each[0] == curSelectedBarName!) selectedBarColor = each[1]; + }); this.componentDidMount(); - if (this._histogramData.length>0){ - return ( - this.props.axes.length >= 1 ? ( -
    -
    + if (this._histogramData.length > 0) { + return this.props.axes.length >= 1 ? ( +
    +
    this.props.layoutDoc[titleAccessor] = val as string), "Change Graph Title")} - color={"black"} + setVal={undoable( + action(val => (this.props.layoutDoc[titleAccessor] = val as string)), + 'Change Graph Title' + )} + color={'black'} size={Size.LARGE} fillWidth /> -     +     } + tooltip={'Change Default Bar Color'} + type={Type.SEC} + icon={} selectedColor={StrCast(this.props.layoutDoc.defaultHistogramColor)} - setSelectedColor={undoable (color => this.props.layoutDoc.defaultHistogramColor = color, "Change Default Bar Color")} + setFinalColor={undoable(color => (this.props.layoutDoc.defaultHistogramColor = color), 'Change Default Bar Color')} + setSelectedColor={undoable(color => (this.props.layoutDoc.defaultHistogramColor = color), 'Change Default Bar Color')} size={Size.XSMALL} />
    - {selected != 'none' ? + {selected != 'none' ? (
    Selected: {selected}     } - selectedColor={selectedBarColor? selectedBarColor : this.curBarSelected.attr("fill")} - setSelectedColor={undoable (color => this.changeSelectedColor(color), "Change Selected Bar Color")} + tooltip={'Change Bar Color'} + type={Type.SEC} + icon={} + selectedColor={selectedBarColor ? selectedBarColor : this.curBarSelected.attr('fill')} + setFinalColor={undoable(color => this.changeSelectedColor(color), 'Change Selected Bar Color')} + setSelectedColor={undoable(color => this.changeSelectedColor(color), 'Change Selected Bar Color')} size={Size.XSMALL} />   } - size={Size.XSMALL} - color={'black'} + icon={} + size={Size.XSMALL} + color={'black'} type={Type.SEC} tooltip={'Revert to the default bar color'} - onClick={undoable (action(() => this.eraseSelectedColor()), "Change Selected Bar Color")} + onClick={undoable( + action(() => this.eraseSelectedColor()), + 'Change Selected Bar Color' + )} />
    - : null} + ) : null}
    - ) : {'first use table view to select a column to graph'} + ) : ( + {'first use table view to select a column to graph'} + ); + } else + return ( + // when it is a brushed table and the incoming table doesn't have any rows selected +
    Selected rows of data from the incoming DataVizBox to display.
    ); - } - else return ( - // when it is a brushed table and the incoming table doesn't have any rows selected -
    - Selected rows of data from the incoming DataVizBox to display. -
    - ) } -} \ No newline at end of file +} diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx index 8bace941f..8e549adbe 100644 --- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx @@ -50,20 +50,21 @@ export class LineChart extends React.Component { // TODO: nda - some sort of mapping that keeps track of the annotated points so we can easily remove when annotations list updates @computed get _lineChartData() { - var guids = StrListCast(this.props.layoutDoc.rowGuids); + var guids = StrListCast(this.props.layoutDoc.dataViz_rowGuids); if (this.props.axes.length <= 1) return []; return this.props.pairs - ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(guids[this.props.pairs.indexOf(pair)]))) + ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.dataViz_selectedRows && StrListCast(this.incomingLinks[0].dataViz_selectedRows).includes(guids[this.props.pairs.indexOf(pair)]))) .map(pair => ({ x: Number(pair[this.props.axes[0]]), y: Number(pair[this.props.axes[1]]) })) .sort((a, b) => (a.x < b.x ? -1 : 1)); } - @computed get graphTitle(){ - return this.props.axes[1] + " vs. " + this.props.axes[0] + " Line Chart"; - } + @computed get graphTitle() { + return this.props.axes[1] + ' vs. ' + this.props.axes[0] + ' Line Chart'; + } @computed get incomingLinks() { return LinkManager.Instance.getAllRelatedLinks(this.props.rootDoc) // out of all links .filter(link => { - return link.link_anchor_1 == this.props.rootDoc.draggedFrom}) // get links where this chart doc is the target of the link + return link.link_anchor_1 == this.props.rootDoc.draggedFrom; + }) // get links where this chart doc is the target of the link .map(link => DocCast(link.link_anchor_1)); // then return the source of the link } @computed get incomingSelected() { @@ -158,7 +159,7 @@ export class LineChart extends React.Component { @action restoreView = (data: Doc) => { - const coords = Cast(data.presDataVizSelection, listSpec('number'), null); + const coords = Cast(data.config_dataVizSelection, listSpec('number'), null); if (coords?.length > 1 && (this._currSelected?.x !== coords[0] || this._currSelected?.y !== coords[1])) { this.setCurrSelected(coords[0], coords[1]); return true; @@ -176,8 +177,8 @@ export class LineChart extends React.Component { // title: 'line doc selection' + this._currSelected?.x, }); - PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this.props.dataDoc); - anchor.presDataVizSelection = this._currSelected ? new List([this._currSelected.x, this._currSelected.y]) : undefined; + PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this.props.rootDoc); + anchor.config_dataVizSelection = this._currSelected ? new List([this._currSelected.x, this._currSelected.y]) : undefined; return anchor; }; @@ -189,14 +190,13 @@ export class LineChart extends React.Component { return this.props.width - this.props.margin.left - this.props.margin.right; } - @computed get defaultGraphTitle(){ + @computed get defaultGraphTitle() { var ax0 = this.props.axes[0]; - var ax1 = (this.props.axes.length>1)? this.props.axes[1] : undefined; - if (this.props.axes.length<2 || !/\d/.test(this.props.pairs[0][ax0]) || !ax1){ - return ax0 + " Line Chart"; - } - else return ax1 + " by " + ax0 + " Line Chart"; - } + var ax1 = this.props.axes.length > 1 ? this.props.axes[1] : undefined; + if (this.props.axes.length < 2 || !/\d/.test(this.props.pairs[0][ax0]) || !ax1) { + return ax0 + ' Line Chart'; + } else return ax1 + ' by ' + ax0 + ' Line Chart'; + } setupTooltip() { return d3 @@ -215,7 +215,7 @@ export class LineChart extends React.Component { @action setCurrSelected(x?: number, y?: number) { // TODO: nda - get rid of svg element in the list? - if (this._currSelected && this._currSelected.x==x && this._currSelected.y==y) this._currSelected = undefined; + if (this._currSelected && this._currSelected.x == x && this._currSelected.y == y) this._currSelected = undefined; else this._currSelected = x !== undefined && y !== undefined ? { x, y } : undefined; this.props.pairs.forEach(pair => pair[this.props.axes[0]] === x && pair[this.props.axes[1]] === y && (pair.selected = true)); } @@ -256,7 +256,7 @@ export class LineChart extends React.Component { const svg = (this._lineChartSvg = d3 .select(this._lineChartRef.current) .append('svg') - .attr("class", "graph") + .attr('class', 'graph') .attr('width', `${width + margin.left + margin.right}`) .attr('height', `${height + margin.top + margin.bottom}`) .append('g') @@ -271,13 +271,13 @@ export class LineChart extends React.Component { // get valid data points const data = dataSet[0]; const lineGen = createLineGenerator(xScale, yScale); - var validData = data.filter((d => { + var validData = data.filter(d => { var valid = true; Object.keys(data[0]).map(key => { if (!d[key] || Number.isNaN(d[key])) valid = false; - }) + }); return valid; - })) + }); // draw the plot line drawLine(svg.append('path'), validData, lineGen); // draw the datapoint circle @@ -321,17 +321,17 @@ export class LineChart extends React.Component { .on('click', onPointClick); // axis titles - svg.append("text") - .attr("transform", "translate(" + (width/2) + " ," + (height+40) + ")") - .style("text-anchor", "middle") + svg.append('text') + .attr('transform', 'translate(' + width / 2 + ' ,' + (height + 40) + ')') + .style('text-anchor', 'middle') .text(this.props.axes[0]); - svg.append("text") - .attr("transform", "rotate(-90)" + " " + "translate( 0, " + -10 + ")") - .attr("x", -(height/2)) - .attr("y", -20) - .attr("height", 20) - .attr("width", 20) - .style("text-anchor", "middle") + svg.append('text') + .attr('transform', 'rotate(-90)' + ' ' + 'translate( 0, ' + -10 + ')') + .attr('x', -(height / 2)) + .attr('y', -20) + .attr('height', 20) + .attr('width', 20) + .style('text-anchor', 'middle') .text(this.props.axes[1]); }; @@ -348,42 +348,41 @@ export class LineChart extends React.Component { tooltip .html(() => `(${d0.x},${d0.y})`) // text content for tooltip .style('pointer-events', 'none') - .style('transform', `translate(${xScale(d0.x)-this.width}px,${yScale(d0.y)}px)`); + .style('transform', `translate(${xScale(d0.x) - this.width}px,${yScale(d0.y)}px)`); } render() { this.componentDidMount(); - var titleAccessor:any = ''; - if (this.props.axes.length==2) titleAccessor = 'lineChart-title-'+this.props.axes[0]+'-'+this.props.axes[1]; - else if (this.props.axes.length>0) titleAccessor = 'lineChart-title-'+this.props.axes[0]; + var titleAccessor: any = ''; + if (this.props.axes.length == 2) titleAccessor = 'dataViz_title_lineChart_' + this.props.axes[0] + '-' + this.props.axes[1]; + else if (this.props.axes.length > 0) titleAccessor = 'dataViz_title_lineChart_' + this.props.axes[0]; if (!this.props.layoutDoc[titleAccessor]) this.props.layoutDoc[titleAccessor] = this.defaultGraphTitle; const selectedPt = this._currSelected ? `{ ${this.props.axes[0]}: ${this._currSelected.x} ${this.props.axes[1]}: ${this._currSelected.y} }` : 'none'; - if (this._lineChartData.length>0){ - return ( - this.props.axes.length>=2 && /\d/.test(this.props.pairs[0][this.props.axes[0]]) && /\d/.test(this.props.pairs[0][this.props.axes[1]]) ? ( -
    -
    + if (this._lineChartData.length > 0) { + return this.props.axes.length >= 2 && /\d/.test(this.props.pairs[0][this.props.axes[0]]) && /\d/.test(this.props.pairs[0][this.props.axes[1]]) ? ( +
    +
    this.props.layoutDoc[titleAccessor] = val as string), "Change Graph Title")} - color={"black"} + setVal={undoable( + action(val => (this.props.layoutDoc[titleAccessor] = val as string)), + 'Change Graph Title' + )} + color={'black'} size={Size.LARGE} fillWidth />
    - {selectedPt!='none'? -
    {`Selected: ${selectedPt}`}
    - : null} + {selectedPt != 'none' ?
    {`Selected: ${selectedPt}`}
    : null}
    - ) : {'first use table view to select two numerical axes to plot'} + ) : ( + {'first use table view to select two numerical axes to plot'} + ); + } else + return ( + // when it is a brushed table and the incoming table doesn't have any rows selected +
    Selected rows of data from the incoming DataVizBox to display.
    ); - } - else return ( - // when it is a brushed table and the incoming table doesn't have any rows selected -
    - Selected rows of data from the incoming DataVizBox to display. -
    - ) } } diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx index 0c54d0a4e..fe77293f0 100644 --- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx @@ -1,18 +1,18 @@ -import { observer } from "mobx-react"; -import { Doc, StrListCast } from "../../../../../fields/Doc"; +import { observer } from 'mobx-react'; +import { Doc, StrListCast } from '../../../../../fields/Doc'; import * as React from 'react'; import * as d3 from 'd3'; -import { IReactionDisposer, action, computed, observable, reaction } from "mobx"; -import { LinkManager } from "../../../../util/LinkManager"; -import { Cast, DocCast, StrCast} from "../../../../../fields/Types"; -import { PinProps, PresBox } from "../../trails"; -import { Docs } from "../../../../documents/Documents"; -import { List } from "../../../../../fields/List"; +import { IReactionDisposer, action, computed, observable, reaction } from 'mobx'; +import { LinkManager } from '../../../../util/LinkManager'; +import { Cast, DocCast, StrCast } from '../../../../../fields/Types'; +import { PinProps, PresBox } from '../../trails'; +import { Docs } from '../../../../documents/Documents'; +import { List } from '../../../../../fields/List'; import './Chart.scss'; -import { ColorPicker, EditableText, Size, Type } from "browndash-components"; -import { FaFillDrip } from "react-icons/fa"; -import { listSpec } from "../../../../../fields/Schema"; -import { undoable } from "../../../../util/UndoManager"; +import { ColorPicker, EditableText, Size, Type } from 'browndash-components'; +import { FaFillDrip } from 'react-icons/fa'; +import { listSpec } from '../../../../../fields/Schema'; +import { undoable } from '../../../../util/UndoManager'; export interface PieChartProps { rootDoc: Doc; @@ -33,7 +33,6 @@ export interface PieChartProps { @observer export class PieChart extends React.Component { - private _disposers: { [key: string]: IReactionDisposer } = {}; private _piechartRef: React.RefObject = React.createRef(); private _piechartSvg: d3.Selection | undefined; @@ -45,31 +44,34 @@ export class PieChart extends React.Component { // filters all data to just display selected data if brushed (created from an incoming link) @computed get _piechartData() { - var guids = StrListCast(this.props.layoutDoc.rowGuids); + var guids = StrListCast(this.props.layoutDoc.dataViz_rowGuids); if (this.props.axes.length < 1) return []; if (this.props.axes.length < 2) { var ax0 = this.props.axes[0]; - if (/\d/.test(this.props.pairs[0][ax0])){ this.byCategory = false } + if (/\d/.test(this.props.pairs[0][ax0])) { + this.byCategory = false; + } return this.props.pairs - ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(guids[this.props.pairs.indexOf(pair)]))) - .map(pair => ({ [ax0]: (pair[this.props.axes[0]])})) - }; + ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.dataViz_selectedRows && StrListCast(this.incomingLinks[0].dataViz_selectedRows).includes(guids[this.props.pairs.indexOf(pair)]))) + .map(pair => ({ [ax0]: pair[this.props.axes[0]] })); + } var ax0 = this.props.axes[0]; var ax1 = this.props.axes[1]; - if (/\d/.test(this.props.pairs[0][ax0])) { this.byCategory = false; } + if (/\d/.test(this.props.pairs[0][ax0])) { + this.byCategory = false; + } return this.props.pairs - ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(guids[this.props.pairs.indexOf(pair)]))) - .map(pair => ({ [ax0]: (pair[this.props.axes[0]]), [ax1]: (pair[this.props.axes[1]]) })) + ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.dataViz_selectedRows && StrListCast(this.incomingLinks[0].dataViz_selectedRows).includes(guids[this.props.pairs.indexOf(pair)]))) + .map(pair => ({ [ax0]: pair[this.props.axes[0]], [ax1]: pair[this.props.axes[1]] })); } - @computed get defaultGraphTitle(){ + @computed get defaultGraphTitle() { var ax0 = this.props.axes[0]; - var ax1 = (this.props.axes.length>1)? this.props.axes[1] : undefined; - if (this.props.axes.length<2 || !/\d/.test(this.props.pairs[0][ax0]) || !ax1){ - return ax0 + " Pie Chart"; - } - else return ax1 + " by " + ax0 + " Pie Chart"; - } + var ax1 = this.props.axes.length > 1 ? this.props.axes[1] : undefined; + if (this.props.axes.length < 2 || !/\d/.test(this.props.pairs[0][ax0]) || !ax1) { + return ax0 + ' Pie Chart'; + } else return ax1 + ' by ' + ax0 + ' Pie Chart'; + } @computed get incomingLinks() { return LinkManager.Instance.getAllRelatedLinks(this.props.rootDoc) // out of all links @@ -84,7 +86,7 @@ export class PieChart extends React.Component { this._disposers.chartData = reaction( () => ({ dataSet: this._piechartData, w: this.width, h: this.height }), ({ dataSet, w, h }) => { - if (dataSet!.length>0) { + if (dataSet!.length > 0) { this.drawChart(dataSet, w, h); } }, @@ -100,7 +102,7 @@ export class PieChart extends React.Component { // title: 'piechart doc selection' + this._currSelected, }); - PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this.props.dataDoc); + PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this.props.rootDoc); return anchor; }; @@ -114,167 +116,177 @@ export class PieChart extends React.Component { // cleans data by converting numerical data to numbers and taking out empty cells data = (dataSet: any) => { - var validData = dataSet.filter((d: { [x: string]: unknown; }) => { + var validData = dataSet.filter((d: { [x: string]: unknown }) => { var valid = true; Object.keys(dataSet[0]).map(key => { if (!d[key] || Number.isNaN(d[key])) valid = false; - }) + }); return valid; - }) - var field = dataSet[0]? Object.keys(dataSet[0])[0] : undefined; - const data = validData.map((d: { [x: string]: any; }) => { - if (!this.byCategory) { return +d[field!].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { + if (!this.byCategory) { + return +d[field!].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { - var index = -1; - var sameAsCurrent: boolean; - const selected = svg.selectAll('.slice').filter((d: any) => { - index++; - var p1 = [0,0]; // center of pie - var p3 = [arc.centroid(d)[0]*2, arc.centroid(d)[1]*2]; // outward peak of arc - var p2 = [radius*Math.sin(d.startAngle), -radius*Math.cos(d.startAngle)]; // start of arc - var p4 = [radius*Math.sin(d.endAngle), -radius*Math.cos(d.endAngle)]; // end of arc + var index = -1; + var sameAsCurrent: boolean; + const selected = svg.selectAll('.slice').filter((d: any) => { + index++; + var p1 = [0, 0]; // center of pie + var p3 = [arc.centroid(d)[0] * 2, arc.centroid(d)[1] * 2]; // outward peak of arc + var p2 = [radius * Math.sin(d.startAngle), -radius * Math.cos(d.startAngle)]; // start of arc + var p4 = [radius * Math.sin(d.endAngle), -radius * Math.cos(d.endAngle)]; // end of arc - // draw an imaginary horizontal line from the pointer to see how many times it crosses a slice edge - var lineCrossCount = 0; - // if for all 4 lines - if (Math.min(p1[1], p2[1])<=pointer[1] && pointer[1]<=Math.max(p1[1], p2[1])){ // within y bounds - if (pointer[0] <= (pointer[1]-p1[1])*(p2[0]-p1[0])/(p2[1]-p1[1])+p1[0]) lineCrossCount++; } // intercepts x - if (Math.min(p2[1], p3[1])<=pointer[1] && pointer[1]<=Math.max(p2[1], p3[1])){ - if (pointer[0] <= (pointer[1]-p2[1])*(p3[0]-p2[0])/(p3[1]-p2[1])+p2[0]) lineCrossCount++; } - if (Math.min(p3[1], p4[1])<=pointer[1] && pointer[1]<=Math.max(p3[1], p4[1])){ - if (pointer[0] <= (pointer[1]-p3[1])*(p4[0]-p3[0])/(p4[1]-p3[1])+p3[0]) lineCrossCount++; } - if (Math.min(p4[1], p1[1])<=pointer[1] && pointer[1]<=Math.max(p4[1], p1[1])){ - if (pointer[0] <= (pointer[1]-p4[1])*(p1[0]-p4[0])/(p1[1]-p4[1])+p4[0]) lineCrossCount++; } - if (lineCrossCount % 2 != 0) { // inside the slice of it crosses an odd number of edges - var showSelected = this.byCategory? pieDataSet[index] : this._piechartData[index]; - if (changeSelectedVariables){ - // for when a bar is selected - not just hovered over - sameAsCurrent = (this._currSelected)? - (showSelected[Object.keys(showSelected)[0]]==this._currSelected![Object.keys(showSelected)[0]] - && showSelected[Object.keys(showSelected)[1]]==this._currSelected![Object.keys(showSelected)[1]]) - : - this._currSelected===showSelected; - this._currSelected = sameAsCurrent? undefined: showSelected; - this.selectedData = sameAsCurrent? undefined: d; - } - else this.hoverOverData = d; - return true; - } - return false; - }); - if (changeSelectedVariables){ - if (sameAsCurrent!) this.curSliceSelected = undefined; - else this.curSliceSelected = selected; + // draw an imaginary horizontal line from the pointer to see how many times it crosses a slice edge + var lineCrossCount = 0; + // if for all 4 lines + if (Math.min(p1[1], p2[1]) <= pointer[1] && pointer[1] <= Math.max(p1[1], p2[1])) { + // within y bounds + if (pointer[0] <= ((pointer[1] - p1[1]) * (p2[0] - p1[0])) / (p2[1] - p1[1]) + p1[0]) lineCrossCount++; + } // intercepts x + if (Math.min(p2[1], p3[1]) <= pointer[1] && pointer[1] <= Math.max(p2[1], p3[1])) { + if (pointer[0] <= ((pointer[1] - p2[1]) * (p3[0] - p2[0])) / (p3[1] - p2[1]) + p2[0]) lineCrossCount++; } - } + if (Math.min(p3[1], p4[1]) <= pointer[1] && pointer[1] <= Math.max(p3[1], p4[1])) { + if (pointer[0] <= ((pointer[1] - p3[1]) * (p4[0] - p3[0])) / (p4[1] - p3[1]) + p3[0]) lineCrossCount++; + } + if (Math.min(p4[1], p1[1]) <= pointer[1] && pointer[1] <= Math.max(p4[1], p1[1])) { + if (pointer[0] <= ((pointer[1] - p4[1]) * (p1[0] - p4[0])) / (p1[1] - p4[1]) + p4[0]) lineCrossCount++; + } + if (lineCrossCount % 2 != 0) { + // inside the slice of it crosses an odd number of edges + var showSelected = this.byCategory ? pieDataSet[index] : this._piechartData[index]; + if (changeSelectedVariables) { + // for when a bar is selected - not just hovered over + sameAsCurrent = this._currSelected + ? showSelected[Object.keys(showSelected)[0]] == this._currSelected![Object.keys(showSelected)[0]] && showSelected[Object.keys(showSelected)[1]] == this._currSelected![Object.keys(showSelected)[1]] + : this._currSelected === showSelected; + this._currSelected = sameAsCurrent ? undefined : showSelected; + this.selectedData = sameAsCurrent ? undefined : d; + } else this.hoverOverData = d; + return true; + } + return false; + }); + if (changeSelectedVariables) { + if (sameAsCurrent!) this.curSliceSelected = undefined; + else this.curSliceSelected = selected; + } + }; // draws the pie chart drawChart = (dataSet: any, width: number, height: number) => { d3.select(this._piechartRef.current).select('svg').remove(); d3.select(this._piechartRef.current).select('.tooltip').remove(); - - var percentField = Object.keys(dataSet[0])[0] - var descriptionField = Object.keys(dataSet[0])[1]! - var radius = Math.min(width, height-this.props.margin.top-this.props.margin.bottom) /2 + + var percentField = Object.keys(dataSet[0])[0]; + var descriptionField = Object.keys(dataSet[0])[1]!; + var radius = Math.min(width, height - this.props.margin.top - this.props.margin.bottom) / 2; // converts data into Objects var data = this.data(dataSet); - var pieDataSet = dataSet.filter((d: { [x: string]: unknown; }) => { + var pieDataSet = dataSet.filter((d: { [x: string]: unknown }) => { var valid = true; Object.keys(dataSet[0]).map(key => { if (!d[key] || Number.isNaN(d[key])) valid = false; - }) + }); return valid; }); - if (this.byCategory){ - let uniqueCategories = [...new Set(data)] + if (this.byCategory) { + let uniqueCategories = [...new Set(data)]; var pieStringDataSet: { frequency: number }[] = []; - for (let i=0; i each[percentField]==data[i]) + for (let i = 0; i < data.length; i++) { + let sliceData = pieStringDataSet.filter((each: any) => each[percentField] == data[i]); sliceData[0].frequency = sliceData[0].frequency + 1; } - pieDataSet = pieStringDataSet - percentField = Object.keys(pieDataSet[0])[0] - descriptionField = Object.keys(pieDataSet[0])[1]! - data = this.data(pieStringDataSet) + pieDataSet = pieStringDataSet; + percentField = Object.keys(pieDataSet[0])[0]; + descriptionField = Object.keys(pieDataSet[0])[1]!; + data = this.data(pieStringDataSet); } - var trackDuplicates : {[key: string]: any} = {}; - data.forEach((eachData: any) => !trackDuplicates[eachData]? trackDuplicates[eachData] = 0: null) + var trackDuplicates: { [key: string]: any } = {}; + data.forEach((eachData: any) => (!trackDuplicates[eachData] ? (trackDuplicates[eachData] = 0) : null)); // initial chart var svg = (this._piechartSvg = d3 .select(this._piechartRef.current) - .append("svg") - .attr("class", "graph") - .attr("width", width + this.props.margin.right + this.props.margin.left) - .attr("height", height + this.props.margin.top + this.props.margin.bottom) - .append("g")); - let g = svg.append("g") - .attr("transform", - "translate(" + (width/2 + this.props.margin.left) + "," + height/2 + ")"); + .append('svg') + .attr('class', 'graph') + .attr('width', width + this.props.margin.right + this.props.margin.left) + .attr('height', height + this.props.margin.top + this.props.margin.bottom) + .append('g')); + let g = svg.append('g').attr('transform', 'translate(' + (width / 2 + this.props.margin.left) + ',' + height / 2 + ')'); var pie = d3.pie(); - var arc = d3.arc() - .innerRadius(0) - .outerRadius(radius); + var arc = d3.arc().innerRadius(0).outerRadius(radius); // click/hover const onPointClick = action((e: any) => this.highlightSelectedSlice(true, svg, arc, radius, d3.pointer(e), pieDataSet)); const onHover = action((e: any) => { - const selected = this.highlightSelectedSlice(false, svg, arc, radius, d3.pointer(e), pieDataSet) + const selected = this.highlightSelectedSlice(false, svg, arc, radius, d3.pointer(e), pieDataSet); updateHighlights(); - }) + }); const mouseOut = action((e: any) => { this.hoverOverData = undefined; updateHighlights(); - }) + }); const updateHighlights = () => { const hoverOverSlice = this.hoverOverData; const selectedData = this.selectedData; - svg.selectAll('path').attr("class", function(d: any) { - return ((selectedData && d.startAngle==selectedData.startAngle && d.endAngle==selectedData.endAngle) - || ((hoverOverSlice && d.startAngle==hoverOverSlice.startAngle && d.endAngle==hoverOverSlice.endAngle)))? 'slice hover' : 'slice'; }) - } + svg.selectAll('path').attr('class', function (d: any) { + return (selectedData && d.startAngle == selectedData.startAngle && d.endAngle == selectedData.endAngle) || (hoverOverSlice && d.startAngle == hoverOverSlice.startAngle && d.endAngle == hoverOverSlice.endAngle) + ? 'slice hover' + : 'slice'; + }); + }; // drawing the slices var selected = this.selectedData; - var arcs = g.selectAll("arc") - .data(pie(data)) - .enter() - .append("g") - arcs.append("path") - .attr("fill", (d, i)=>{ - var possibleDataPoints = pieDataSet.filter((each: { [x: string]: any | { valueOf(): number; }; }) => { + var arcs = g.selectAll('arc').data(pie(data)).enter().append('g'); + arcs.append('path') + .attr('fill', (d, i) => { + var possibleDataPoints = pieDataSet.filter((each: { [x: string]: any | { valueOf(): number } }) => { try { - return Number(each[percentField].replace(/\$/g, '').replace(/\%/g, '').replace(/\ each.split('::')); - sliceColors.map(each => {if (each[0]==StrCast(accessByName)) sliceColor = each[1]}); + sliceColors.map(each => { + if (each[0] == StrCast(accessByName)) sliceColor = each[1]; + }); } - return sliceColor? StrCast(sliceColor) : d3.schemeSet3[i]? d3.schemeSet3[i]: d3.schemeSet3[i%(d3.schemeSet3.length)] }) - .attr("class", selected? - function(d) { - return (selected && d.startAngle==selected.startAngle && d.endAngle==selected.endAngle)? 'slice hover' : 'slice'; - }: function(d) {return 'slice'}) + return sliceColor ? StrCast(sliceColor) : d3.schemeSet3[i] ? d3.schemeSet3[i] : d3.schemeSet3[i % d3.schemeSet3.length]; + }) + .attr( + 'class', + selected + ? function (d) { + return selected && d.startAngle == selected.startAngle && d.endAngle == selected.endAngle ? 'slice hover' : 'slice'; + } + : function (d) { + return 'slice'; + } + ) .attr('d', arc) .on('click', onPointClick) .on('mouseover', onHover) @@ -282,99 +294,106 @@ export class PieChart extends React.Component { // adding labels trackDuplicates = {}; - data.forEach((eachData: any) => !trackDuplicates[eachData]? trackDuplicates[eachData] = 0: null) - arcs.append("text") - .attr("transform",function(d){ - var centroid = arc.centroid(d as unknown as d3.DefaultArcObject) - var heightOffset = (centroid[1]/radius) * Math.abs(centroid[1]) - return "translate("+ (centroid[0]+centroid[0]/(radius*.02)) + "," + (centroid[1]+heightOffset) + ")"; }) - .attr("text-anchor", "middle") - .text(function(d){ - var possibleDataPoints = pieDataSet.filter((each: { [x: string]: any | { valueOf(): number; }; }) => { + data.forEach((eachData: any) => (!trackDuplicates[eachData] ? (trackDuplicates[eachData] = 0) : null)); + arcs.append('text') + .attr('transform', function (d) { + var centroid = arc.centroid(d as unknown as d3.DefaultArcObject); + var heightOffset = (centroid[1] / radius) * Math.abs(centroid[1]); + return 'translate(' + (centroid[0] + centroid[0] / (radius * 0.02)) + ',' + (centroid[1] + heightOffset) + ')'; + }) + .attr('text-anchor', 'middle') + .text(function (d) { + var possibleDataPoints = pieDataSet.filter((each: { [x: string]: any | { valueOf(): number } }) => { try { - return Number(each[percentField].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { - this.curSliceSelected.attr("fill", color); - var sliceName = this._currSelected[this.props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { if (each.split('::')[0] == sliceName) sliceColors.splice(sliceColors.indexOf(each), 1) }); + this.curSliceSelected.attr('fill', color); + var sliceName = this._currSelected[this.props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { + if (each.split('::')[0] == sliceName) sliceColors.splice(sliceColors.indexOf(each), 1); + }); sliceColors.push(StrCast(sliceName + '::' + color)); }; render() { this.componentDidMount(); - var titleAccessor: any=''; - if (this.props.axes.length==2) titleAccessor = 'pieChart-title-'+this.props.axes[0]+'-'+this.props.axes[1]; - else if (this.props.axes.length>0) titleAccessor = 'pieChart-title-'+this.props.axes[0]; + var titleAccessor: any = ''; + if (this.props.axes.length == 2) titleAccessor = 'dataViz_title_pieChart_' + this.props.axes[0] + '-' + this.props.axes[1]; + else if (this.props.axes.length > 0) titleAccessor = 'dataViz_title_pieChart_' + this.props.axes[0]; if (!this.props.layoutDoc[titleAccessor]) this.props.layoutDoc[titleAccessor] = this.defaultGraphTitle; if (!this.props.layoutDoc.pieSliceColors) this.props.layoutDoc.pieSliceColors = new List(); var selected: string; - var curSelectedSliceName; - if (this._currSelected){ - curSelectedSliceName = StrCast(this._currSelected![this.props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\ { - key!=''? selected += key + ': ' + this._currSelected[key] + ', ': ''; - }) - selected = selected.substring(0, selected.length-2); + key != '' ? (selected += key + ': ' + this._currSelected[key] + ', ') : ''; + }); + selected = selected.substring(0, selected.length - 2); selected += ' }'; - } - else selected = 'none'; + } else selected = 'none'; var selectedSliceColor; var sliceColors = StrListCast(this.props.layoutDoc.pieSliceColors).map(each => each.split('::')); - sliceColors.map(each => {if (each[0]==curSelectedSliceName!) selectedSliceColor = each[1]}); + sliceColors.map(each => { + if (each[0] == curSelectedSliceName!) selectedSliceColor = each[1]; + }); - if (this._piechartData.length>0){ - return ( - this.props.axes.length >= 1 ? ( + if (this._piechartData.length > 0) { + return this.props.axes.length >= 1 ? (
    -
    +
    this.props.layoutDoc[titleAccessor] = val as string), "Change Graph Title")} - color={"black"} + setVal={undoable( + action(val => (this.props.layoutDoc[titleAccessor] = val as string)), + 'Change Graph Title' + )} + color={'black'} size={Size.LARGE} fillWidth />
    - {selected != 'none' ? + {selected != 'none' ? (
    Selected: {selected}     } - selectedColor={selectedSliceColor? selectedSliceColor : this.curSliceSelected.attr("fill")} - setSelectedColor={undoable (color => this.changeSelectedColor(color), "Change Selected Slice Color")} + tooltip={'Change Slice Color'} + type={Type.SEC} + icon={} + selectedColor={selectedSliceColor ? selectedSliceColor : this.curSliceSelected.attr('fill')} + setFinalColor={undoable(color => this.changeSelectedColor(color), 'Change Selected Slice Color')} + setSelectedColor={undoable(color => this.changeSelectedColor(color), 'Change Selected Slice Color')} size={Size.XSMALL} />
    - : null} + ) : null}
    - ) : {'first use table view to select a column to graph'} + ) : ( + {'first use table view to select a column to graph'} + ); + } else + return ( + // when it is a brushed table and the incoming table doesn't have any rows selected +
    Selected rows of data from the incoming DataVizBox to display.
    ); - } - else return ( - // when it is a brushed table and the incoming table doesn't have any rows selected -
    - Selected rows of data from the incoming DataVizBox to display. -
    - ) } - -} \ No newline at end of file +} diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index f56d34fa6..5579d6d80 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -1,4 +1,4 @@ -import { action, computed, } from 'mobx'; +import { action, computed } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, Field, StrListCast } from '../../../../../fields/Doc'; @@ -31,44 +31,45 @@ interface TableBoxProps { @observer export class TableBox extends React.Component { - // filters all data to just display selected data if brushed (created from an incoming link) @computed get _tableData() { if (this.incomingLinks.length! <= 0) return this.props.pairs; - var guids = StrListCast(this.props.layoutDoc.rowGuids); - return this.props.pairs?.filter(pair => this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(guids[this.props.pairs.indexOf(pair)])) + var guids = StrListCast(this.props.layoutDoc.dataViz_rowGuids); + return this.props.pairs?.filter(pair => this.incomingLinks[0]!.dataViz_selectedRows && StrListCast(this.incomingLinks[0].dataViz_selectedRows).includes(guids[this.props.pairs.indexOf(pair)])); } @computed get incomingLinks() { return LinkManager.Instance.getAllRelatedLinks(this.props.rootDoc) // out of all links .filter(link => { - return link.link_anchor_1 == this.props.rootDoc.draggedFrom}) // get links where this chart doc is the target of the link + return link.link_anchor_1 == this.props.rootDoc.draggedFrom; + }) // get links where this chart doc is the target of the link .map(link => DocCast(link.link_anchor_1)); // then return the source of the link } @computed get columns() { - if (!this.props.layoutDoc.rowGuids) this.props.layoutDoc.rowGuids = new List(); - const guids = Cast(this.props.layoutDoc.rowGuids, listSpec("string"), null); - if (guids.length==0) this.props.pairs.map(row => guids.push(Utils.GenerateGuid())); - return this._tableData.length ? Array.from(Object.keys(this._tableData[0])).filter(header => header!='' && header!=undefined) : []; + if (!this.props.layoutDoc.dataViz_rowGuids) this.props.layoutDoc.dataViz_rowGuids = new List(); + const guids = Cast(this.props.layoutDoc.dataViz_rowGuids, listSpec('string'), null); + if (guids.length == 0) this.props.pairs.map(row => guids.push(Utils.GenerateGuid())); + return this._tableData.length ? Array.from(Object.keys(this._tableData[0])).filter(header => header != '' && header != undefined) : []; } // updates the 'selected' field to no longer include rows that aren't in the table filterSelectedRowsDown() { - if (!this.props.layoutDoc.selected) this.props.layoutDoc.selected = new List(); - const selected = Cast(this.props.layoutDoc.selected, listSpec("string"), null); - const incomingSelected = this.incomingLinks.length? StrListCast(this.incomingLinks[0].selected) : undefined; - if (incomingSelected){ + if (!this.props.layoutDoc.dataViz_selectedRows) this.props.layoutDoc.dataViz_selectedRows = new List(); + const selected = Cast(this.props.layoutDoc.dataViz_selectedRows, listSpec('string'), null); + const incomingSelected = this.incomingLinks.length ? StrListCast(this.incomingLinks[0].dataViz_selectedRows) : undefined; + if (incomingSelected) { selected.map(guid => { - if (!incomingSelected.includes(guid)) selected.splice(selected.indexOf(guid), 1)}); // filters through selected to remove guids that were removed in the incoming data + if (!incomingSelected.includes(guid)) selected.splice(selected.indexOf(guid), 1); + }); // filters through selected to remove guids that were removed in the incoming data } } render() { this.filterSelectedRowsDown(); - if (this._tableData.length>0){ + if (this._tableData.length > 0) { return ( -
    +
    @@ -83,7 +84,8 @@ export class TableBox extends React.Component { style={{ color: this.props.axes.slice().reverse().lastElement() === col ? 'darkgreen' : this.props.axes.lastElement() === col ? 'darkred' : undefined, background: this.props.axes.slice().reverse().lastElement() === col ? '#E3fbdb' : this.props.axes.lastElement() === col ? '#Fbdbdb' : undefined, - fontWeight: 'bolder', border: '3px solid black' + fontWeight: 'bolder', + border: '3px solid black', }} onPointerDown={e => { const downX = e.clientX; @@ -91,12 +93,13 @@ export class TableBox extends React.Component { setupMoveUpEvents( {}, e, - e => { // dragging off a column to create a brushed DataVizBox + e => { + // dragging off a column to create a brushed DataVizBox const sourceAnchorCreator = () => this.props.docView?.()!.rootDoc!; const targetCreator = (annotationOn: Doc | undefined) => { const embedding = Doc.MakeEmbedding(this.props.docView?.()!.rootDoc!); - embedding._dataVizView = DataVizView.TABLE; - embedding._data_vizAxes = new List([col, col]); + embedding._dataViz = DataVizView.TABLE; + embedding._dataViz_axes = new List([col, col]); embedding._draggedFrom = this.props.docView?.()!.rootDoc!; embedding.annotationOn = annotationOn; //this.props.docView?.()!.rootDoc!; embedding.histogramBarColors = Field.Copy(this.props.layoutDoc.histogramBarColors); @@ -142,25 +145,33 @@ export class TableBox extends React.Component { {this._tableData?.map((p, i) => { var containsData = false; - var guid = StrListCast(this.props.layoutDoc.rowGuids)![this.props.pairs.indexOf(p)] - this.columns.map(col => {if (p[col]!='' && p[col]!=null && p[col]!=undefined) containsData = true}) - if (containsData){ + var guid = StrListCast(this.props.layoutDoc.dataViz_rowGuids)![this.props.pairs.indexOf(p)]; + this.columns.map(col => { + if (p[col] != '' && p[col] != null && p[col] != undefined) containsData = true; + }); + if (containsData) { return ( - { + { // selecting a row - const selected = Cast(this.props.layoutDoc.selected, listSpec("string"), null); + const selected = Cast(this.props.layoutDoc.dataViz_selectedRows, listSpec('string'), null); if (selected.includes(guid)) selected.splice(selected.indexOf(guid), 1); else { - selected.push(guid)}; - })} style={{ background: StrListCast(this.props.layoutDoc.selected).includes(guid) ? 'lightgrey' : '', width: '110%' }}> + selected.push(guid); + } + })} + style={{ background: StrListCast(this.props.layoutDoc.dataViz_selectedRows).includes(guid) ? 'lightgrey' : '', width: '110%' }}> {this.columns.map(col => { - // each cell - var colSelected = this.props.axes[0]==col || this.props.axes[1]==col; - return ( - - )})} + ); + })} ); } @@ -169,12 +180,10 @@ export class TableBox extends React.Component {
    + // each cell + var colSelected = this.props.axes[0] == col || this.props.axes[1] == col; + return ( + {p[col]}
    ); - } - else return ( - // when it is a brushed table and the incoming table doesn't have any rows selected -
    - Selected rows of data from the incoming DataVizBox to display. -
    - ) + } else + return ( + // when it is a brushed table and the incoming table doesn't have any rows selected +
    Selected rows of data from the incoming DataVizBox to display.
    + ); } } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 90fb55290..c5dead708 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -113,7 +113,7 @@ export interface DocComponentView { getAnchor?: (addAsAnnotation: boolean, pinData?: PinProps) => Doc; // returns an Anchor Doc that represents the current state of the doc's componentview (e.g., the current playhead location of a an audio/video box) restoreView?: (viewSpec: Doc) => boolean; scrollPreview?: (docView: DocumentView, doc: Doc, focusSpeed: number, options: DocFocusOptions) => Opt; // returns the duration of the focus - brushView?: (view: { width: number; height: number; panX: number; panY: number }) => void; + brushView?: (view: { width: number; height: number; panX: number; panY: number }, transTime: number) => void; getView?: (doc: Doc) => Promise>; // returns a nested DocumentView for the specified doc or undefined addDocTab?: (doc: Doc, where: OpenWhere) => boolean; // determines how to add a document - used in following links to open the target ina local lightbox addDocument?: (doc: Doc | Doc[], annotationKey?: string) => boolean; // add a document (used only by collections) @@ -1095,6 +1095,8 @@ export class DocumentViewInternal extends DocComponent ); const targetDoc = showTitle?.startsWith('_') ? this.layoutDoc : this.rootDoc; - const background = StrCast( - SharingManager.Instance.users.find(u => u.user.email === this.dataDoc.author)?.sharingDoc.headingColor, - Doc.UserDoc().layout_showTitle && [DocumentType.RTF, DocumentType.COL].includes(this.rootDoc.type as any) ? StrCast(Doc.SharingDoc().headingColor) : SettingsManager.Instance.userVariantColor - ); + const background = StrCast(SharingManager.Instance.users.find(u => u.user.email === this.dataDoc.author)?.sharingDoc.headingColor, StrCast(Doc.SharingDoc().headingColor, SettingsManager.Instance.userVariantColor)); const sidebarWidthPercent = +StrCast(this.layoutDoc.layout_sidebarWidthPercent).replace('%', ''); const titleView = !showTitle ? null : (
    , root: Doc) { - const dir = presEffectDoc?.presEffectDirection ?? presEffectDoc?.followLinkAnimDirection; + const dir = presEffectDoc?.presentation_effectDirection ?? presEffectDoc?.followLinkAnimDirection; const effectProps = { left: dir === PresEffectDirection.Left, right: dir === PresEffectDirection.Right, @@ -1212,10 +1211,10 @@ export class DocumentViewInternal extends DocComponent{renderDoc}; @@ -1543,7 +1542,7 @@ export class DocumentView extends React.Component {
    console.log('PARSE error', e)} renderInWrapper={false} jsx={StrCast(this.textHtmlOverlay)} />
    , - { presEffect: this.htmlOverlayEffect ?? 'Zoom' } as any as Doc, + { presentation_effect: this.htmlOverlayEffect ?? 'Zoom' } as any as Doc, this.rootDoc )}{' '} diff --git a/src/client/views/nodes/FontIconBox/FontIconBox.tsx b/src/client/views/nodes/FontIconBox/FontIconBox.tsx index 1b2209224..bf3c79cf9 100644 --- a/src/client/views/nodes/FontIconBox/FontIconBox.tsx +++ b/src/client/views/nodes/FontIconBox/FontIconBox.tsx @@ -267,7 +267,7 @@ export class FontIconBox extends DocComponent() { return ScriptCast(this.rootDoc.script); } - colorBatch:UndoManager.Batch|undefined; + colorBatch: UndoManager.Batch | undefined; /** * Color button */ @@ -285,7 +285,7 @@ export class FontIconBox extends DocComponent() { setFinalColor={value => { this.colorScript?.script.run({ this: this.layoutDoc, self: this.rootDoc, value: value, _readOnly_: false }); this.colorBatch?.end(); - this.colorBatch= undefined; + this.colorBatch = undefined; }} selectedColor={curColor} type={Type.PRIM} diff --git a/src/client/views/nodes/FunctionPlotBox.tsx b/src/client/views/nodes/FunctionPlotBox.tsx index 61711417f..40f48dafe 100644 --- a/src/client/views/nodes/FunctionPlotBox.tsx +++ b/src/client/views/nodes/FunctionPlotBox.tsx @@ -48,8 +48,8 @@ export class FunctionPlotBox extends ViewBoxAnnotatableComponent annotationOn: this.rootDoc, }); PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), datarange: true } }, this.rootDoc); - anchor.presXRange = new List(Array.from(this._plot.options.xAxis.domain)); - anchor.presYRange = new List(Array.from(this._plot.options.yAxis.domain)); + anchor.config_xRange = new List(Array.from(this._plot.options.xAxis.domain)); + anchor.config_yRange = new List(Array.from(this._plot.options.yAxis.domain)); if (addAsAnnotation) this.addDocument(anchor); return anchor; }; diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index d763753a5..c7ccd1ea0 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -22,7 +22,6 @@ import { DocumentType } from '../../documents/DocumentTypes'; import { Networking } from '../../Network'; import { DocumentManager } from '../../util/DocumentManager'; import { DragManager } from '../../util/DragManager'; -import { SnappingManager } from '../../util/SnappingManager'; import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from '../../views/ContextMenu'; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; @@ -80,10 +79,10 @@ export class ImageBox extends ViewBoxAnnotatableComponent { const self = this; const keys = Object.keys(ids).slice(); //for (const key of [...keys.filter(id => id !== 'layout' && !id.includes('_')).sort(), ...keys.filter(id => id === 'layout' || id.includes('_')).sort()]) { - for (const key of keys.sort()) { + for (const key of keys.sort((a: string, b: string) => { + const a_ = a.split('_')[0]; + const b_ = b.split('_')[0]; + if (a_ < b_) return -1; + if (a_ > b_) return 1; + if (a === a_) return -1; + if (b === b_) return 1; + return a === b ? 0 : a < b ? -1 : 1; + })) { rows.push( () { this.props.setContentView?.(this); } render() { - if (this.dataDoc.treeViewOpen === undefined) setTimeout(() => (this.dataDoc.treeViewOpen = true)); + if (this.dataDoc.treeView_Open === undefined) setTimeout(() => (this.dataDoc.treeView_Open = true)); return (
    void); @computed get inlineTextAnnotations() { - return this.allMapMarkers.filter(a => a.textInlineAnnotations); + return this.allMapMarkers.filter(a => a.text_inlineAnnotations); } @observable private _map: google.maps.Map = null as unknown as google.maps.Map; diff --git a/src/client/views/nodes/MapBox/MapBox2.tsx b/src/client/views/nodes/MapBox/MapBox2.tsx index a9154c5bb..b3ae8242d 100644 --- a/src/client/views/nodes/MapBox/MapBox2.tsx +++ b/src/client/views/nodes/MapBox/MapBox2.tsx @@ -100,7 +100,7 @@ export class MapBox2 extends ViewBoxAnnotatableComponent void); @computed get inlineTextAnnotations() { - return this.allMapMarkers.filter(a => a.textInlineAnnotations); + return this.allMapMarkers.filter(a => a.text_inlineAnnotations); } @observable private _map: google.maps.Map = null as unknown as google.maps.Map; diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index fd4c6366b..758b49655 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -213,7 +213,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent this._pdfViewer?.brushView(view); + brushView = (view: { width: number; height: number; panX: number; panY: number }, transTime: number) => this._pdfViewer?.brushView(view, transTime); sidebarAddDocTab = (doc: Doc, where: OpenWhere) => { if (DocListCast(this.props.Document[this.props.fieldKey + '_sidebar']).includes(doc) && !this.SidebarShown) { @@ -224,7 +224,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent { this._initialScrollTarget = anchor; - return this._pdfViewer?.scrollFocus(anchor, NumCast(anchor.y, NumCast(anchor.presViewScroll)), options); + return this._pdfViewer?.scrollFocus(anchor, NumCast(anchor.y, NumCast(anchor.config_scrollTop)), options); }; getView = async (doc: Doc) => { @@ -247,7 +247,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent void); - private _setBrushViewer: undefined | ((view: { width: number; height: number; panX: number; panY: number }) => void); + private _setBrushViewer: undefined | ((view: { width: number; height: number; panX: number; panY: number }, transTime: number) => void); private _mainCont: React.RefObject = React.createRef(); private _outerRef: React.RefObject = React.createRef(); private _disposers: { [name: string]: IReactionDisposer } = {}; @@ -91,7 +91,7 @@ export class WebBox extends ViewBoxAnnotatableComponent a.textInlineAnnotations); + return this.allAnnotations.filter(a => a.text_inlineAnnotations); } @computed get webField() { return Cast(this.rootDoc[this.props.fieldKey], WebField)?.url; @@ -133,7 +133,7 @@ export class WebBox extends ViewBoxAnnotatableComponent void) => (this._setBrushViewer = func); - brushView = (view: { width: number; height: number; panX: number; panY: number }) => this._setBrushViewer?.(view); + setBrushViewer = (func?: (view: { width: number; height: number; panX: number; panY: number }, transTime: number) => void) => (this._setBrushViewer = func); + brushView = (view: { width: number; height: number; panX: number; panY: number }, transTime: number) => this._setBrushViewer?.(view, transTime); focus = (anchor: Doc, options: DocFocusOptions) => { if (anchor !== this.rootDoc && this._outerRef.current) { const windowHeight = this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1); @@ -303,7 +303,7 @@ export class WebBox extends ViewBoxAnnotatableComponent { if (Doc.AreProtosEqual(doc, this.rootDoc)) return new Promise>(res => res(this.props.DocumentView?.())); if (this.rootDoc.layout_fieldKey === 'layout_icon') this.props.DocumentView?.().iconify(); - const webUrl = WebCast(doc.presData)?.url; + const webUrl = WebCast(doc.config_data)?.url; if (this._url && webUrl && webUrl.href !== this._url) this.setData(webUrl.href); if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) this.toggleSidebar(false); return new Promise>(res => DocumentManager.Instance.AddViewRenderedCb(doc, dv => res(dv))); @@ -334,7 +334,7 @@ export class WebBox extends ViewBoxAnnotatableComponent { - (doc instanceof Doc ? [doc] : doc).forEach(doc => (doc.presData = new WebField(this._url))); + (doc instanceof Doc ? [doc] : doc).forEach(doc => (doc.config_data = new WebField(this._url))); return this.addDocument(doc, annotationKey); }; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 1dcc445e8..eea4f513e 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -417,7 +417,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent (tr = this.hyperlinkTerm(tr, term, newAutoLinks))); tr = tr.setSelection(isNodeSel && false ? new NodeSelection(tr.doc.resolve(f)) : new TextSelection(tr.doc.resolve(f), tr.doc.resolve(t))); this._editorView?.dispatch(tr); - this.prepareForTyping(); + // this.prepareForTyping(); } oldAutoLinks.filter(oldLink => !newAutoLinks.has(oldLink) && oldLink.link_anchor_2 !== this.rootDoc).forEach(LinkManager.Instance.deleteLink); }; @@ -730,7 +730,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - const trail = DocCast(anchor.presTrail); + const trail = DocCast(anchor.presentationTrail); if (trail) { Doc.ActivePresentation = trail; this.props.addDocTab(trail, OpenWhere.replaceRight); @@ -1237,7 +1237,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent this.props.isSelected(), action(selected => { - selected && this.prepareForTyping(); + //selected && setTimeout(() => this.prepareForTyping()); if (FormattedTextBox._globalHighlights.has('Bold Text')) { this.layoutDoc[DocCss] = this.layoutDoc[DocCss] + 1; // css change happens outside of mobx/react, so this will notify anyone interested in the layout that it has changed } @@ -1550,18 +1550,17 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - this._editorView?.dispatch( - this._editorView?.state.tr.setStoredMarks([ - ...(this._editorView.state.storedMarks?.filter(mark => ![schema.marks.em, schema.marks.underline, schema.marks.pFontFamily, schema.marks.pFontSize, schema.marks.strong, schema.marks.pFontColor].includes(mark.type)) ?? []), - ...[schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) })], - ...(Doc.UserDoc().fontColor !== 'transparent' && Doc.UserDoc().fontColor ? [schema.mark(schema.marks.pFontColor, { color: StrCast(Doc.UserDoc().fontColor) })] : []), - ...(Doc.UserDoc().fontStyle === 'italics' ? [schema.mark(schema.marks.em)] : []), - ...(Doc.UserDoc().textDecoration === 'underline' ? [schema.mark(schema.marks.underline)] : []), - ...(Doc.UserDoc().fontFamily ? [schema.mark(schema.marks.pFontFamily, { family: this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.FontFamily) })] : []), - ...(Doc.UserDoc().fontSize ? [schema.mark(schema.marks.pFontSize, { fontSize: this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.FontSize) })] : []), - ...(Doc.UserDoc().fontWeight === 'bold' ? [schema.mark(schema.marks.strong)] : []), - ]) - ); + if (!this._editorView) return; + const docDefaultMarks = [ + ...(Doc.UserDoc().fontColor !== 'transparent' && Doc.UserDoc().fontColor ? [schema.mark(schema.marks.pFontColor, { color: StrCast(Doc.UserDoc().fontColor) })] : []), + ...(Doc.UserDoc().fontStyle === 'italics' ? [schema.mark(schema.marks.em)] : []), + ...(Doc.UserDoc().textDecoration === 'underline' ? [schema.mark(schema.marks.underline)] : []), + ...(Doc.UserDoc().fontFamily ? [schema.mark(schema.marks.pFontFamily, { family: this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.FontFamily) })] : []), + ...(Doc.UserDoc().fontSize ? [schema.mark(schema.marks.pFontSize, { fontSize: this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.FontSize) })] : []), + ...(Doc.UserDoc().fontWeight === 'bold' ? [schema.mark(schema.marks.strong)] : []), + ...[schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) })], + ]; + this._editorView?.dispatch(this._editorView?.state.tr.setStoredMarks(docDefaultMarks)); }; @action diff --git a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts index 112a0d87e..ec11079b4 100644 --- a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts +++ b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts @@ -334,7 +334,7 @@ export function buildKeymap>(schema: S, props: any, mapKey //Command to create a blank space bind('Space', (state: EditorState, dispatch: (tx: Transaction) => void) => { - if (GetEffectiveAcl(props.DataDoc) != AclEdit && GetEffectiveAcl(props.DataDoc) != AclAugment && GetEffectiveAcl(props.DataDoc) != AclAdmin) return true; + if (props.DataDoc && GetEffectiveAcl(props.DataDoc) != AclEdit && GetEffectiveAcl(props.DataDoc) != AclAugment && GetEffectiveAcl(props.DataDoc) != AclAdmin) return true; const marks = state.storedMarks || (state.selection.$to.parentOffset && state.selection.$from.marks()); dispatch(splitMetadata(marks, state.tr)); return false; diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index 7c3e4baad..9c46459b0 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -104,7 +104,7 @@ export class RichTextMenu extends AntimodeMenu { _disposer: IReactionDisposer | undefined; componentDidMount() { this._disposer = reaction( - () => SelectionManager.Views(), + () => SelectionManager.Views().slice(), views => this.updateMenu(undefined, undefined, undefined) ); } diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index aaedffc77..05f59d8fe 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -74,7 +74,7 @@ export class PresBox extends ViewBoxBaseComponent() { constructor(props: any) { super(props); if (!PresBox.navigateToDocScript) { - PresBox.navigateToDocScript = ScriptField.MakeFunction('navigateToDoc(self.presentationTargetDoc, self)')!; + PresBox.navigateToDocScript = ScriptField.MakeFunction('navigateToDoc(self.presentation_targetDoc, self)')!; } } @@ -116,7 +116,7 @@ export class PresBox extends ViewBoxBaseComponent() { return DocListCast(this.rootDoc[this.presFieldKey]); } @computed get tagDocs() { - return this.childDocs.map(doc => Cast(doc.presentationTargetDoc, Doc, null)); + return this.childDocs.map(doc => Cast(doc.presentation_targetDoc, Doc, null)); } @computed get itemIndex() { return NumCast(this.rootDoc._itemIndex); @@ -125,10 +125,10 @@ export class PresBox extends ViewBoxBaseComponent() { return DocCast(this.childDocs[NumCast(this.rootDoc._itemIndex)]); } @computed get targetDoc() { - return Cast(this.activeItem?.presentationTargetDoc, Doc, null); + return Cast(this.activeItem?.presentation_targetDoc, Doc, null); } public static targetRenderedDoc = (doc: Doc) => { - const targetDoc = Cast(doc?.presentationTargetDoc, Doc, null); + const targetDoc = Cast(doc?.presentation_targetDoc, Doc, null); return targetDoc?.layout_unrendered ? DocCast(targetDoc.annotationOn) : targetDoc; }; @computed get scrollable() { @@ -149,7 +149,7 @@ export class PresBox extends ViewBoxBaseComponent() { @computed get selectedDoc() { return this.selectedDocumentView?.rootDoc; } - isActiveItemTarget = (layoutDoc: Doc) => this.activeItem?.presentationTargetDoc === layoutDoc; + isActiveItemTarget = (layoutDoc: Doc) => this.activeItem?.presentation_targetDoc === layoutDoc; clearSelectedArray = () => this.selectedArray.clear(); addToSelectedArray = action((doc: Doc) => this.selectedArray.add(doc)); removeFromSelectedArray = action((doc: Doc) => this.selectedArray.delete(doc)); @@ -196,18 +196,18 @@ export class PresBox extends ViewBoxBaseComponent() { } this.turnOffEdit(true); this._disposers.selection = reaction( - () => SelectionManager.Views(), + () => SelectionManager.Views().slice(), views => (!PresBox.Instance || views.some(view => view.props.Document === this.rootDoc)) && this.updateCurrentPresentation(), { fireImmediately: true } ); this._disposers.editing = reaction( - () => this.layoutDoc.presStatus === PresStatus.Edit, + () => this.layoutDoc.presentation_status === PresStatus.Edit, editing => { if (editing) { this.childDocs.forEach(doc => { - if (doc.presIndexed !== undefined) { + if (doc.presentation_indexed !== undefined) { this.progressivizedItems(doc)?.forEach(indexedDoc => (indexedDoc.opacity = undefined)); - doc.presIndexed = Math.min(this.progressivizedItems(doc)?.length ?? 0, 1); + doc.presentation_indexed = Math.min(this.progressivizedItems(doc)?.length ?? 0, 1); } }); } @@ -224,10 +224,10 @@ export class PresBox extends ViewBoxBaseComponent() { _mediaTimer!: [NodeJS.Timeout, Doc]; // 'Play on next' for audio or video therefore first navigate to the audio/video before it should be played startTempMedia = (targetDoc: Doc, activeItem: Doc) => { - const duration: number = NumCast(activeItem.presEndTime) - NumCast(activeItem.presStartTime); + const duration: number = NumCast(activeItem.config_clipEnd) - NumCast(activeItem.config_clipStart); if ([DocumentType.VID, DocumentType.AUDIO].includes(targetDoc.type as any)) { const targMedia = DocumentManager.Instance.getDocumentView(targetDoc); - targMedia?.ComponentView?.playFrom?.(NumCast(activeItem.presStartTime), NumCast(activeItem.presStartTime) + duration); + targMedia?.ComponentView?.playFrom?.(NumCast(activeItem.config_clipStart), NumCast(activeItem.config_clipStart) + duration); } }; @@ -251,12 +251,12 @@ export class PresBox extends ViewBoxBaseComponent() { (nextSelected: number, force = false) => () => { if (nextSelected < this.childDocs.length) { - if (force || this.childDocs[nextSelected].groupWithUp) { + if (force || this.childDocs[nextSelected].presentation_groupWithUp) { this.addToSelectedArray(this.childDocs[nextSelected]); - const serial = nextSelected + 1 < this.childDocs.length && NumCast(this.childDocs[nextSelected + 1].groupWithUp) > 1; + const serial = nextSelected + 1 < this.childDocs.length && NumCast(this.childDocs[nextSelected + 1].presentation_groupWithUp) > 1; if (serial) { this.gotoDocument(nextSelected, this.activeItem, true, async () => { - const waitTime = NumCast(this.activeItem.presDuration) - NumCast(this.activeItem.presTransition); + const waitTime = NumCast(this.activeItem.presentation_duration) - NumCast(this.activeItem.presentation_transition); await new Promise(res => setTimeout(() => res(), Math.max(0, waitTime))); doGroupWithUp(nextSelected + 1)(); }); @@ -274,7 +274,7 @@ export class PresBox extends ViewBoxBaseComponent() { // docs within a slide target that will be progressively revealed progressivizedItems = (doc: Doc) => { const targetList = PresBox.targetRenderedDoc(doc); - if (doc.presIndexed !== undefined && targetList) { + if (doc.presentation_indexed !== undefined && targetList) { const listItems = (Cast(targetList[Doc.LayoutFieldKey(targetList)], listSpec(Doc), null)?.filter(d => d instanceof Doc) as Doc[]) ?? DocListCast(targetList[Doc.LayoutFieldKey(targetList) + '_annotations']); return listItems.filter(doc => !doc.layout_unrendered); } @@ -283,7 +283,7 @@ export class PresBox extends ViewBoxBaseComponent() { @action next = () => { const progressiveReveal = (first: boolean) => { - const presIndexed = Cast(this.activeItem?.presIndexed, 'number', null); + const presIndexed = Cast(this.activeItem?.presentation_indexed, 'number', null); if (presIndexed !== undefined) { const targetRenderedDoc = PresBox.targetRenderedDoc(this.activeItem); targetRenderedDoc._dataTransition = 'all 1s'; @@ -296,8 +296,8 @@ export class PresBox extends ViewBoxBaseComponent() { const targetView = listItems && DocumentManager.Instance.getFirstDocumentView(listItemDoc); Doc.linkFollowUnhighlight(); Doc.HighlightDoc(listItemDoc); - listItemDoc.presEffect = this.activeItem.presBulletEffect; - listItemDoc.presTransition = 500; + listItemDoc.presentation_effect = this.activeItem.presBulletEffect; + listItemDoc.presentation_transition = 500; targetView?.setAnimEffect(listItemDoc, 500); if (targetView?.docView && this.activeItem.presBulletExpand) { targetView.docView._animateScalingTo = 1.2; @@ -308,7 +308,7 @@ export class PresBox extends ViewBoxBaseComponent() { }); } listItemDoc.opacity = undefined; - this.activeItem.presIndexed = presIndexed + 1; + this.activeItem.presentation_indexed = presIndexed + 1; } return true; } @@ -322,7 +322,7 @@ export class PresBox extends ViewBoxBaseComponent() { this.nextSlide(curLast + 1 === this.childDocs.length ? (this.layoutDoc.presLoop ? 0 : curLast) : curLast + 1); progressiveReveal(true); // shows first progressive document, but without a transition effect } else { - if (this.childDocs[this.itemIndex + 1] === undefined && (this.layoutDoc.presLoop || this.layoutDoc.presStatus === PresStatus.Edit)) { + if (this.childDocs[this.itemIndex + 1] === undefined && (this.layoutDoc.presLoop || this.layoutDoc.presentation_status === PresStatus.Edit)) { // Case 2: Last slide and presLoop is toggled ON or it is in Edit mode this.nextSlide(0); progressiveReveal(true); // shows first progressive document, but without a transition effect @@ -338,9 +338,9 @@ export class PresBox extends ViewBoxBaseComponent() { const activeItem: Doc = this.activeItem; let prevSelected = this.itemIndex; // Functionality for group with up - let didZoom = activeItem.presMovement; - for (; prevSelected > 0 && this.childDocs[Math.max(0, prevSelected - 1)].groupWithUp; prevSelected--) { - didZoom = didZoom === 'none' ? this.childDocs[prevSelected].presMovement : didZoom; + let didZoom = activeItem.presentation_movement; + for (; prevSelected > 0 && this.childDocs[Math.max(0, prevSelected - 1)].presentation_groupWithUp; prevSelected--) { + didZoom = didZoom === 'none' ? this.childDocs[prevSelected].presentation_movement : didZoom; } if (activeItem && this.childDocs[this.itemIndex - 1] !== undefined) { // Case 2: There are no other frames so it should go to the previous slide @@ -361,20 +361,20 @@ export class PresBox extends ViewBoxBaseComponent() { Doc.UnBrushAllDocs(); if (index >= 0 && index < this.childDocs.length) { this.rootDoc._itemIndex = index; - if (from?.mediaStopTriggerList && this.layoutDoc.presStatus !== PresStatus.Edit) { + if (from?.mediaStopTriggerList && this.layoutDoc.presentation_status !== PresStatus.Edit) { DocListCast(from.mediaStopTriggerList).forEach(this.stopTempMedia); } - if (from?.mediaStop === 'auto' && this.layoutDoc.presStatus !== PresStatus.Edit) { - this.stopTempMedia(from.presentationTargetDoc); + if (from?.mediaStop === 'auto' && this.layoutDoc.presentation_status !== PresStatus.Edit) { + this.stopTempMedia(from.presentation_targetDoc); } // If next slide is audio / video 'Play automatically' then the next slide should be played - if (this.layoutDoc.presStatus !== PresStatus.Edit && (this.targetDoc.type === DocumentType.AUDIO || this.targetDoc.type === DocumentType.VID) && this.activeItem.mediaStart === 'auto') { + if (this.layoutDoc.presentation_status !== PresStatus.Edit && (this.targetDoc.type === DocumentType.AUDIO || this.targetDoc.type === DocumentType.VID) && this.activeItem.mediaStart === 'auto') { this.startTempMedia(this.targetDoc, this.activeItem); } if (!group) this.clearSelectedArray(); this.childDocs[index] && this.addToSelectedArray(this.childDocs[index]); //Update selected array this.turnOffEdit(); - this.navigateToActiveItem(finished); //Handles movement to element only when presTrail is list + this.navigateToActiveItem(finished); //Handles movement to element only when presentationTrail is list this.doHideBeforeAfter(); //Handles hide after/before } }); @@ -398,33 +398,33 @@ export class PresBox extends ViewBoxBaseComponent() { @action playAnnotation = (anno: AudioField) => {}; @action - static restoreTargetDocView(bestTargetView: Opt, activeItem: Doc, transTime: number, pinDocLayout: boolean = BoolCast(activeItem.presPinLayout), pinDataTypes?: pinDataTypes, targetDoc?: Doc) { + static restoreTargetDocView(bestTargetView: Opt, activeItem: Doc, transTime: number, pinDocLayout: boolean = BoolCast(activeItem.config_pinLayout), pinDataTypes?: pinDataTypes, targetDoc?: Doc) { const bestTarget = bestTargetView?.rootDoc ?? (targetDoc?.layout_unrendered ? DocCast(targetDoc?.annotationOn) : targetDoc); if (!bestTarget) return; let changed = false; if (pinDocLayout) { if ( - bestTarget.x !== NumCast(activeItem.presX, NumCast(bestTarget.x)) || - bestTarget.y !== NumCast(activeItem.presY, NumCast(bestTarget.y)) || - bestTarget.rotation !== NumCast(activeItem.presRotation, NumCast(bestTarget.rotation)) || - bestTarget.width !== NumCast(activeItem.presWidth, NumCast(bestTarget.width)) || - bestTarget.height !== NumCast(activeItem.presHeight, NumCast(bestTarget.height)) + bestTarget.x !== NumCast(activeItem.config_x, NumCast(bestTarget.x)) || + bestTarget.y !== NumCast(activeItem.config_y, NumCast(bestTarget.y)) || + bestTarget.rotation !== NumCast(activeItem.config_rotation, NumCast(bestTarget.rotation)) || + bestTarget.width !== NumCast(activeItem.config_width, NumCast(bestTarget.width)) || + bestTarget.height !== NumCast(activeItem.config_height, NumCast(bestTarget.height)) ) { bestTarget._dataTransition = `all ${transTime}ms`; - bestTarget.x = NumCast(activeItem.presX, NumCast(bestTarget.x)); - bestTarget.y = NumCast(activeItem.presY, NumCast(bestTarget.y)); - bestTarget.rotation = NumCast(activeItem.presRotation, NumCast(bestTarget.rotation)); - bestTarget.width = NumCast(activeItem.presWidth, NumCast(bestTarget.width)); - bestTarget.height = NumCast(activeItem.presHeight, NumCast(bestTarget.height)); + bestTarget.x = NumCast(activeItem.config_x, NumCast(bestTarget.x)); + bestTarget.y = NumCast(activeItem.config_y, NumCast(bestTarget.y)); + bestTarget.rotation = NumCast(activeItem.config_rotation, NumCast(bestTarget.rotation)); + bestTarget.width = NumCast(activeItem.config_width, NumCast(bestTarget.width)); + bestTarget.height = NumCast(activeItem.config_height, NumCast(bestTarget.height)); setTimeout(() => (bestTarget._dataTransition = undefined), transTime + 10); changed = true; } } - const activeFrame = activeItem.presActiveFrame ?? activeItem.presCurrentFrame; + const activeFrame = activeItem.config_activeFrame ?? activeItem.config_currentFrame; if (activeFrame !== undefined) { - const transTime = NumCast(activeItem.presTransition, 500); - const acontext = activeItem.presActiveFrame !== undefined ? DocCast(DocCast(activeItem.presentationTargetDoc).embedContainer) : DocCast(activeItem.presentationTargetDoc); + const transTime = NumCast(activeItem.presentation_transition, 500); + const acontext = activeItem.config_activeFrame !== undefined ? DocCast(DocCast(activeItem.presentation_targetDoc).embedContainer) : DocCast(activeItem.presentation_targetDoc); const context = DocCast(acontext)?.annotationOn ? DocCast(DocCast(acontext).annotationOn) : acontext; if (context) { const ffview = DocumentManager.Instance.getFirstDocumentView(context)?.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView; @@ -434,73 +434,73 @@ export class PresBox extends ViewBoxBaseComponent() { } } } - if ((pinDataTypes?.dataview && activeItem.presData !== undefined) || (!pinDataTypes && activeItem.presData !== undefined)) { + if ((pinDataTypes?.dataview && activeItem.config_data !== undefined) || (!pinDataTypes && activeItem.config_data !== undefined)) { bestTarget._dataTransition = `all ${transTime}ms`; const fkey = Doc.LayoutFieldKey(bestTarget); const setData = bestTargetView?.ComponentView?.setData; - if (setData) setData(activeItem.presData); - else Doc.GetProto(bestTarget)[fkey] = activeItem.presData instanceof ObjectField ? activeItem.presData[Copy]() : activeItem.presData; - bestTarget[fkey + '_usePath'] = activeItem.presUsePath; + if (setData) setData(activeItem.config_data); + else Doc.GetProto(bestTarget)[fkey] = activeItem.config_data instanceof ObjectField ? activeItem.config_data[Copy]() : activeItem.config_data; + bestTarget[fkey + '_usePath'] = activeItem.config_usePath; setTimeout(() => (bestTarget._dataTransition = undefined), transTime + 10); } - if (pinDataTypes?.datarange || (!pinDataTypes && activeItem.presXRange !== undefined)) { - if (bestTarget.xRange !== activeItem.presXRange) { - bestTarget.xRange = (activeItem.presXRange as ObjectField)?.[Copy](); + if (pinDataTypes?.datarange || (!pinDataTypes && activeItem.config_xRange !== undefined)) { + if (bestTarget.xRange !== activeItem.config_xRange) { + bestTarget.xRange = (activeItem.config_xRange as ObjectField)?.[Copy](); changed = true; } - if (bestTarget.yRange !== activeItem.presYRange) { - bestTarget.yRange = (activeItem.presYRange as ObjectField)?.[Copy](); + if (bestTarget.yRange !== activeItem.config_yRange) { + bestTarget.yRange = (activeItem.config_yRange as ObjectField)?.[Copy](); changed = true; } } - if (pinDataTypes?.clippable || (!pinDataTypes && activeItem.presClipWidth !== undefined)) { + if (pinDataTypes?.clippable || (!pinDataTypes && activeItem.config_clipWidth !== undefined)) { const fkey = '_' + Doc.LayoutFieldKey(bestTarget); - if (bestTarget[fkey + '_clipWidth'] !== activeItem.presClipWidth) { - bestTarget[fkey + '_clipWidth'] = activeItem.presClipWidth; + if (bestTarget[fkey + '_clipWidth'] !== activeItem.config_clipWidth) { + bestTarget[fkey + '_clipWidth'] = activeItem.config_clipWidth; changed = true; } } - if (pinDataTypes?.temporal || (!pinDataTypes && activeItem.presStartTime !== undefined)) { - if (bestTarget._layout_currentTimecode !== activeItem.presStartTime) { - bestTarget._layout_currentTimecode = activeItem.presStartTime; + if (pinDataTypes?.temporal || (!pinDataTypes && activeItem.config_clipStart !== undefined)) { + if (bestTarget._layout_currentTimecode !== activeItem.config_clipStart) { + bestTarget._layout_currentTimecode = activeItem.config_clipStart; changed = true; } } - if (pinDataTypes?.inkable || (!pinDataTypes && (activeItem.presFillColor !== undefined || activeItem.color !== undefined))) { - if (bestTarget.fillColor !== activeItem.presFillColor) { - Doc.GetProto(bestTarget).fillColor = activeItem.presFillColor; + if (pinDataTypes?.inkable || (!pinDataTypes && (activeItem.config_fillColor !== undefined || activeItem.color !== undefined))) { + if (bestTarget.fillColor !== activeItem.config_fillColor) { + Doc.GetProto(bestTarget).fillColor = activeItem.config_fillColor; changed = true; } - if (bestTarget.color !== activeItem.presColor) { - Doc.GetProto(bestTarget).color = activeItem.presColor; + if (bestTarget.color !== activeItem.config_color) { + Doc.GetProto(bestTarget).color = activeItem.config_color; changed = true; } if (bestTarget.width !== activeItem.width) { - bestTarget._width = NumCast(activeItem.presWidth, NumCast(bestTarget.width)); + bestTarget._width = NumCast(activeItem.config_width, NumCast(bestTarget.width)); changed = true; } if (bestTarget.height !== activeItem.height) { - bestTarget._height = NumCast(activeItem.presHeight, NumCast(bestTarget.height)); + bestTarget._height = NumCast(activeItem.config_height, NumCast(bestTarget.height)); changed = true; } } - if ((pinDataTypes?.type_collection && activeItem.presViewType !== undefined) || (!pinDataTypes && activeItem.presViewType !== undefined)) { - if (bestTarget._type_collection !== activeItem.presViewType) { - bestTarget._type_collection = activeItem.presViewType; + if ((pinDataTypes?.type_collection && activeItem.config_viewType !== undefined) || (!pinDataTypes && activeItem.config_viewType !== undefined)) { + if (bestTarget._type_collection !== activeItem.config_viewType) { + bestTarget._type_collection = activeItem.config_viewType; changed = true; } } - if ((pinDataTypes?.filters && activeItem.presDocFilters !== undefined) || (!pinDataTypes && activeItem.presDocFilters !== undefined)) { - if (bestTarget.childFilters !== activeItem.presDocFilters) { - bestTarget.childFilters = ObjectField.MakeCopy(activeItem.presDocFilters as ObjectField) || new List([]); + if ((pinDataTypes?.filters && activeItem.config_docFilters !== undefined) || (!pinDataTypes && activeItem.config_docFilters !== undefined)) { + if (bestTarget.childFilters !== activeItem.config_docFilters) { + bestTarget.childFilters = ObjectField.MakeCopy(activeItem.config_docFilters as ObjectField) || new List([]); changed = true; } } - if ((pinDataTypes?.pivot && activeItem.presPivotField !== undefined) || (!pinDataTypes && activeItem.presPivotField !== undefined)) { - if (bestTarget.pivotField !== activeItem.presPivotField) { - bestTarget.pivotField = activeItem.presPivotField; + if ((pinDataTypes?.pivot && activeItem.config_pivotField !== undefined) || (!pinDataTypes && activeItem.config_pivotField !== undefined)) { + if (bestTarget.pivotField !== activeItem.config_pivotField) { + bestTarget.pivotField = activeItem.config_pivotField; bestTarget._prevFilterIndex = 1; // need to revisit this...see CollectionTimeView changed = true; } @@ -509,21 +509,21 @@ export class PresBox extends ViewBoxBaseComponent() { changed = true; } - if (pinDataTypes?.scrollable || (!pinDataTypes && activeItem.presViewScroll !== undefined)) { - if (bestTarget._layout_scrollTop !== activeItem.presViewScroll) { - bestTarget._layout_scrollTop = activeItem.presViewScroll; + if (pinDataTypes?.scrollable || (!pinDataTypes && activeItem.config_scrollTop !== undefined)) { + if (bestTarget._layout_scrollTop !== activeItem.config_scrollTop) { + bestTarget._layout_scrollTop = activeItem.config_scrollTop; changed = true; - const contentBounds = Cast(activeItem.presPinViewBounds, listSpec('number')); + const contentBounds = Cast(activeItem.config_viewBounds, listSpec('number')); if (contentBounds) { const dv = DocumentManager.Instance.getDocumentView(bestTarget)?.ComponentView; - dv?.brushView?.({ panX: (contentBounds[0] + contentBounds[2]) / 2, panY: (contentBounds[1] + contentBounds[3]) / 2, width: contentBounds[2] - contentBounds[0], height: contentBounds[3] - contentBounds[1] }); + dv?.brushView?.({ panX: (contentBounds[0] + contentBounds[2]) / 2, panY: (contentBounds[1] + contentBounds[3]) / 2, width: contentBounds[2] - contentBounds[0], height: contentBounds[3] - contentBounds[1] }, transTime); } } } - if (pinDataTypes?.dataannos || (!pinDataTypes && activeItem.presAnnotations !== undefined)) { + if (pinDataTypes?.dataannos || (!pinDataTypes && activeItem.config_annotations !== undefined)) { const fkey = Doc.LayoutFieldKey(bestTarget); const oldItems = DocListCast(bestTarget[fkey + '_annotations']).filter(doc => doc.layout_unrendered); - const newItems = DocListCast(activeItem.presAnnotations).map(doc => { + const newItems = DocListCast(activeItem.config_annotations).map(doc => { doc.hidden = false; return doc; }); @@ -536,11 +536,11 @@ export class PresBox extends ViewBoxBaseComponent() { const newList = new List([...oldItems, ...hiddenItems, ...newItems]); Doc.GetProto(bestTarget)[fkey + '_annotations'] = newList; } - if (pinDataTypes?.poslayoutview || (!pinDataTypes && activeItem.presPinLayoutData !== undefined)) { + if (pinDataTypes?.poslayoutview || (!pinDataTypes && activeItem.config_pinLayoutData !== undefined)) { changed = true; const layoutField = Doc.LayoutFieldKey(bestTarget); const transitioned = new Set(); - StrListCast(activeItem.presPinLayoutData) + StrListCast(activeItem.config_pinLayoutData) .map(str => JSON.parse(str) as { id: string; x: number; y: number; back: string; fill: string; w: number; h: number; data: string; text: string }) .forEach(async data => { const doc = DocCast(DocServer.GetCachedRefField(data.id)); @@ -562,8 +562,8 @@ export class PresBox extends ViewBoxBaseComponent() { }); setTimeout(() => Array.from(transitioned).forEach(action(doc => (doc._dataTransition = undefined))), transTime + 10); } - if ((pinDataTypes?.pannable || (!pinDataTypes && (activeItem.presPinViewBounds !== undefined || activeItem.presPanX !== undefined || activeItem.presViewScale !== undefined))) && !bestTarget._isGroup) { - const contentBounds = Cast(activeItem.presPinViewBounds, listSpec('number')); + if ((pinDataTypes?.pannable || (!pinDataTypes && (activeItem.config_viewBounds !== undefined || activeItem.config_panX !== undefined || activeItem.config_viewScale !== undefined))) && !bestTarget._isGroup) { + const contentBounds = Cast(activeItem.config_viewBounds, listSpec('number')); if (contentBounds) { const viewport = { panX: (contentBounds[0] + contentBounds[2]) / 2, panY: (contentBounds[1] + contentBounds[3]) / 2, width: contentBounds[2] - contentBounds[0], height: contentBounds[3] - contentBounds[1] }; bestTarget._freeform_panX = viewport.panX; @@ -572,14 +572,14 @@ export class PresBox extends ViewBoxBaseComponent() { if (dv) { changed = true; const computedScale = NumCast(activeItem.presZoom, 1) * Math.min(dv.props.PanelWidth() / viewport.width, dv.props.PanelHeight() / viewport.height); - activeItem.presMovement === PresMovement.Zoom && (bestTarget._freeform_scale = computedScale); - dv.ComponentView?.brushView?.(viewport); + activeItem.presentation_movement === PresMovement.Zoom && (bestTarget._freeform_scale = computedScale); + dv.ComponentView?.brushView?.(viewport, transTime); } } else { - if (bestTarget._freeform_panX !== activeItem.presPanX || bestTarget._freeform_panY !== activeItem.presPanY || bestTarget._freeform_scale !== activeItem.presViewScale) { - bestTarget._freeform_panX = activeItem.presPanX ?? bestTarget._freeform_panX; - bestTarget._freeform_panY = activeItem.presPanY ?? bestTarget._freeform_panY; - bestTarget._freeform_scale = activeItem.presViewScale ?? bestTarget._freeform_scale; + if (bestTarget._freeform_panX !== activeItem.config_panX || bestTarget._freeform_panY !== activeItem.config_panY || bestTarget._freeform_scale !== activeItem.config_viewScale) { + bestTarget._freeform_panX = activeItem.config_panX ?? bestTarget._freeform_panX; + bestTarget._freeform_panY = activeItem.config_panY ?? bestTarget._freeform_panY; + bestTarget._freeform_scale = activeItem.config_viewScale ?? bestTarget._freeform_scale; changed = true; } } @@ -594,17 +594,19 @@ export class PresBox extends ViewBoxBaseComponent() { /// target doc when navigating to it. @action static pinDocView(pinDoc: Doc, pinProps: PinProps, targetDoc: Doc) { + pinDoc.presentation = true; + pinDoc.config = ''; if (pinProps.pinDocLayout) { - pinDoc.presPinLayout = true; - pinDoc.presX = NumCast(targetDoc.x); - pinDoc.presY = NumCast(targetDoc.y); - pinDoc.presRotation = NumCast(targetDoc.rotation); - pinDoc.presWidth = NumCast(targetDoc.width); - pinDoc.presHeight = NumCast(targetDoc.height); + pinDoc.config_pinLayout = true; + pinDoc.config_x = NumCast(targetDoc.x); + pinDoc.config_y = NumCast(targetDoc.y); + pinDoc.config_rotation = NumCast(targetDoc.rotation); + pinDoc.config_width = NumCast(targetDoc.width); + pinDoc.config_height = NumCast(targetDoc.height); } if (pinProps.pinAudioPlay) pinDoc.presPlayAudio = true; if (pinProps.pinData) { - pinDoc.presPinData = + pinDoc.config_pinData = pinProps.pinData.scrollable || pinProps.pinData.temporal || pinProps.pinData.pannable || @@ -616,30 +618,30 @@ export class PresBox extends ViewBoxBaseComponent() { pinProps?.activeFrame !== undefined; const fkey = Doc.LayoutFieldKey(targetDoc); if (pinProps.pinData.dataview) { - pinDoc.presUsePath = targetDoc[fkey + '_usePath']; - pinDoc.presData = targetDoc[fkey] instanceof ObjectField ? (targetDoc[fkey] as ObjectField)[Copy]() : targetDoc.data; + pinDoc.config_usePath = targetDoc[fkey + '_usePath']; + pinDoc.config_data = targetDoc[fkey] instanceof ObjectField ? (targetDoc[fkey] as ObjectField)[Copy]() : targetDoc.data; } if (pinProps.pinData.dataannos) { const fkey = Doc.LayoutFieldKey(targetDoc); - pinDoc.presAnnotations = new List(DocListCast(Doc.GetProto(targetDoc)[fkey + '_annotations']).filter(doc => !doc.layout_unrendered)); + pinDoc.config_annotations = new List(DocListCast(Doc.GetProto(targetDoc)[fkey + '_annotations']).filter(doc => !doc.layout_unrendered)); } if (pinProps.pinData.inkable) { - pinDoc.presFillColor = targetDoc.fillColor; - pinDoc.presColor = targetDoc.color; - pinDoc.presWidth = targetDoc._width; - pinDoc.presHeight = targetDoc._height; + pinDoc.config_fillColor = targetDoc.fillColor; + pinDoc.config_color = targetDoc.color; + pinDoc.config_width = targetDoc._width; + pinDoc.config_height = targetDoc._height; } - if (pinProps.pinData.scrollable) pinDoc.presViewScroll = targetDoc._layout_scrollTop; + if (pinProps.pinData.scrollable) pinDoc.config_scrollTop = targetDoc._layout_scrollTop; if (pinProps.pinData.clippable) { const fkey = Doc.LayoutFieldKey(targetDoc); - pinDoc.presClipWidth = targetDoc[fkey + '_clipWidth']; + pinDoc.config_clipWidth = targetDoc[fkey + '_clipWidth']; } if (pinProps.pinData.datarange) { - pinDoc.presXRange = undefined; //targetDoc?.xrange; - pinDoc.presYRange = undefined; //targetDoc?.yrange; + pinDoc.config_xRange = undefined; //targetDoc?.xrange; + pinDoc.config_yRange = undefined; //targetDoc?.yrange; } if (pinProps.pinData.poslayoutview) - pinDoc.presPinLayoutData = new List( + pinDoc.config_pinLayoutData = new List( DocListCast(targetDoc[fkey] as ObjectField).map(d => JSON.stringify({ id: d[Id], @@ -654,28 +656,28 @@ export class PresBox extends ViewBoxBaseComponent() { }) ) ); - if (pinProps.pinData.type_collection) pinDoc.presViewType = targetDoc._type_collection; - if (pinProps.pinData.filters) pinDoc.presDocFilters = ObjectField.MakeCopy(targetDoc.childFilters as ObjectField); - if (pinProps.pinData.pivot) pinDoc.presPivotField = targetDoc._pivotField; + if (pinProps.pinData.type_collection) pinDoc.config_viewType = targetDoc._type_collection; + if (pinProps.pinData.filters) pinDoc.config_docFilters = ObjectField.MakeCopy(targetDoc.childFilters as ObjectField); + if (pinProps.pinData.pivot) pinDoc.config_pivotField = targetDoc._pivotField; if (pinProps.pinData.pannable) { - pinDoc.presPanX = NumCast(targetDoc._freeform_panX); - pinDoc.presPanY = NumCast(targetDoc._freeform_panY); - pinDoc.presViewScale = NumCast(targetDoc._freeform_scale, 1); + pinDoc.config_panX = NumCast(targetDoc._freeform_panX); + pinDoc.config_panY = NumCast(targetDoc._freeform_panY); + pinDoc.config_viewScale = NumCast(targetDoc._freeform_scale, 1); } if (pinProps.pinData.temporal) { - pinDoc.presStartTime = targetDoc._layout_currentTimecode; - const duration = NumCast(pinDoc[`${Doc.LayoutFieldKey(pinDoc)}_duration`], NumCast(targetDoc.presStartTime) + 0.1); - pinDoc.presEndTime = NumCast(targetDoc.clipEnd, duration); + pinDoc.config_clipStart = targetDoc._layout_currentTimecode; + const duration = NumCast(pinDoc[`${Doc.LayoutFieldKey(pinDoc)}_duration`], NumCast(targetDoc.config_clipStart) + 0.1); + pinDoc.config_clipEnd = NumCast(targetDoc.clipEnd, duration); } } if (pinProps?.pinViewport) { // If pinWithView option set then update scale and x / y props of slide const bounds = pinProps.pinViewport; - pinDoc.presPinView = true; - pinDoc.presViewScale = NumCast(targetDoc._freeform_scale, 1); - pinDoc.presPanX = bounds.left + bounds.width / 2; - pinDoc.presPanY = bounds.top + bounds.height / 2; - pinDoc.presPinViewBounds = new List([bounds.left, bounds.top, bounds.left + bounds.width, bounds.top + bounds.height]); + pinDoc.config_pinView = true; + pinDoc.config_viewScale = NumCast(targetDoc._freeform_scale, 1); + pinDoc.config_panX = bounds.left + bounds.width / 2; + pinDoc.config_panY = bounds.top + bounds.height / 2; + pinDoc.config_viewBounds = new List([bounds.left, bounds.top, bounds.left + bounds.width, bounds.top + bounds.height]); } } /** @@ -712,23 +714,23 @@ export class PresBox extends ViewBoxBaseComponent() { }; static NavigateToTarget(targetDoc: Doc, activeItem: Doc, finished?: () => void) { - if (activeItem.presMovement === PresMovement.None && targetDoc.type === DocumentType.SCRIPTING) { + if (activeItem.presentation_movement === PresMovement.None && targetDoc.type === DocumentType.SCRIPTING) { (DocumentManager.Instance.getFirstDocumentView(targetDoc)?.ComponentView as ScriptingBox)?.onRun?.(); return; } - const effect = activeItem.presEffect && activeItem.presEffect !== PresEffect.None ? activeItem.presEffect : undefined; - const presTime = NumCast(activeItem.presTransition, effect ? 750 : 500); + const effect = activeItem.presentation_effect && activeItem.presentation_effect !== PresEffect.None ? activeItem.presentation_effect : undefined; + const presTime = NumCast(activeItem.presentation_transition, effect ? 750 : 500); const options: DocFocusOptions = { - willPan: activeItem.presMovement !== PresMovement.None, - willZoomCentered: activeItem.presMovement === PresMovement.Zoom || activeItem.presMovement === PresMovement.Jump || activeItem.presMovement === PresMovement.Center, - zoomScale: activeItem.presMovement === PresMovement.Center ? 0 : NumCast(activeItem.presZoom, 1), - zoomTime: activeItem.presMovement === PresMovement.Jump ? 0 : Math.min(Math.max(effect ? 750 : 500, (effect ? 0.2 : 1) * presTime), presTime), + willPan: activeItem.presentation_movement !== PresMovement.None, + willZoomCentered: activeItem.presentation_movement === PresMovement.Zoom || activeItem.presentation_movement === PresMovement.Jump || activeItem.presentation_movement === PresMovement.Center, + zoomScale: activeItem.presentation_movement === PresMovement.Center ? 0 : NumCast(activeItem.presZoom, 1), + zoomTime: activeItem.presentation_movement === PresMovement.Jump ? 0 : Math.min(Math.max(effect ? 750 : 500, (effect ? 0.2 : 1) * presTime), presTime), effect: activeItem, noSelect: true, openLocation: OpenWhere.addLeft, anchorDoc: activeItem, easeFunc: StrCast(activeItem.presEaseFunc, 'ease') as any, - zoomTextSelections: BoolCast(activeItem.presZoomText), + zoomTextSelections: BoolCast(activeItem.presentation_zoomText), playAudio: BoolCast(activeItem.presPlayAudio), }; if (activeItem.presOpenInLightbox) { @@ -738,7 +740,7 @@ export class PresBox extends ViewBoxBaseComponent() { } } if (targetDoc) { - if (activeItem.presentationTargetDoc instanceof Doc) activeItem.presentationTargetDoc[Animation] = undefined; + if (activeItem.presentation_targetDoc instanceof Doc) activeItem.presentation_targetDoc[Animation] = undefined; DocumentManager.Instance.AddViewRenderedCb(LightboxView.LightboxDoc, dv => { // if target or the doc it annotates is not in the lightbox, then close the lightbox @@ -761,16 +763,16 @@ export class PresBox extends ViewBoxBaseComponent() { const tagDoc = PresBox.targetRenderedDoc(curDoc); const itemIndexes: number[] = this.getAllIndexes(this.tagDocs, tagDoc); let opacity: Opt = index === this.itemIndex ? 1 : undefined; - if (curDoc.presHide) { + if (curDoc.presentation_hide) { if (index !== this.itemIndex) { opacity = 1; } } const hidingIndBef = itemIndexes.find(item => item >= this.itemIndex) ?? itemIndexes.slice().reverse().lastElement(); - if (curDoc.presHideBefore && index === hidingIndBef) { + if (curDoc.presentation_hideBefore && index === hidingIndBef) { if (index > this.itemIndex) { opacity = 0; - } else if (index === this.itemIndex || !curDoc.presHideAfter) { + } else if (index === this.itemIndex || !curDoc.presentation_hideAfter) { opacity = 1; setTimeout(() => (tagDoc._dataTransition = undefined), 1000); } @@ -780,15 +782,15 @@ export class PresBox extends ViewBoxBaseComponent() { .slice() .reverse() .find(item => item <= this.itemIndex) ?? itemIndexes.lastElement(); - if (curDoc.presHideAfter && index === hidingIndAft) { + if (curDoc.presentation_hideAfter && index === hidingIndAft) { if (index < this.itemIndex) { opacity = 0; - } else if (index === this.itemIndex || !curDoc.presHideBefore) { + } else if (index === this.itemIndex || !curDoc.presentation_hideBefore) { opacity = 1; } } const hidingInd = itemIndexes.find(item => item === this.itemIndex); - if (curDoc.presHide && index === hidingInd) { + if (curDoc.presentation_hide && index === hidingInd) { if (index === this.itemIndex) { opacity = 0; } @@ -846,9 +848,9 @@ export class PresBox extends ViewBoxBaseComponent() { // The function pauses the auto presentation @action pauseAutoPres = () => { - if (this.layoutDoc.presStatus === PresStatus.Autoplay) { + if (this.layoutDoc.presentation_status === PresStatus.Autoplay) { if (this._presTimer) clearTimeout(this._presTimer); - this.layoutDoc.presStatus = PresStatus.Manual; + this.layoutDoc.presentation_status = PresStatus.Manual; this.childDocs.forEach(this.stopTempMedia); } }; @@ -879,23 +881,23 @@ export class PresBox extends ViewBoxBaseComponent() { runInAction(() => (this._expandBoolean = !this._expandBoolean)); this.rootDoc.expandBoolean = this._expandBoolean; this.childDocs.forEach(doc => { - doc.presExpandInlineButton = this._expandBoolean; + doc.presentation_expandInlineButton = this._expandBoolean; }); }; initializePresState = (startIndex: number) => { this.childDocs.forEach((doc, index) => { const tagDoc = PresBox.targetRenderedDoc(doc); - if (doc.presHideBefore && index > startIndex) tagDoc.opacity = 0; - if (doc.presHideAfter && index < startIndex) tagDoc.opacity = 0; - if (doc.presIndexed !== undefined && index >= startIndex) { - const startInd = NumCast(doc.presIndexedStart); + if (doc.presentation_hideBefore && index > startIndex) tagDoc.opacity = 0; + if (doc.presentation_hideAfter && index < startIndex) tagDoc.opacity = 0; + if (doc.presentation_indexed !== undefined && index >= startIndex) { + const startInd = NumCast(doc.presentation_indexedStart); this.progressivizedItems(doc) ?.slice(startInd) .forEach(indexedDoc => (indexedDoc.opacity = 0)); - doc.presIndexed = Math.min(this.progressivizedItems(doc)?.length ?? 0, startInd); + doc.presentation_indexed = Math.min(this.progressivizedItems(doc)?.length ?? 0, startInd); } - // if (doc.presHide && this.childDocs.indexOf(doc) === startIndex) tagDoc.opacity = 0; + // if (doc.presentation_hide && this.childDocs.indexOf(doc) === startIndex) tagDoc.opacity = 0; }); }; @@ -909,13 +911,13 @@ export class PresBox extends ViewBoxBaseComponent() { PresBox.Instance = this; clearTimeout(this._presTimer); if (this.childDocs.length) { - this.layoutDoc.presStatus = PresStatus.Autoplay; + this.layoutDoc.presentation_status = PresStatus.Autoplay; this.initializePresState(startIndex); const func = () => { - const delay = NumCast(this.activeItem.presDuration, this.activeItem.type === DocumentType.SCRIPTING ? 0 : 2500) + NumCast(this.activeItem.presTransition); + const delay = NumCast(this.activeItem.presentation_duration, this.activeItem.type === DocumentType.SCRIPTING ? 0 : 2500) + NumCast(this.activeItem.presentation_transition); this._presTimer = setTimeout(() => { - if (!this.next()) this.layoutDoc.presStatus = this._exitTrail?.() ?? PresStatus.Manual; - this.layoutDoc.presStatus === PresStatus.Autoplay && func(); + if (!this.next()) this.layoutDoc.presentation_status = this._exitTrail?.() ?? PresStatus.Manual; + this.layoutDoc.presentation_status === PresStatus.Autoplay && func(); }, delay); }; this.gotoDocument(startIndex, this.activeItem, undefined, func); @@ -949,7 +951,7 @@ export class PresBox extends ViewBoxBaseComponent() { doc._width = PresBox.minimizedWidth; Doc.AddToMyOverlay(doc); PresBox.Instance?.initializePresState(PresBox.Instance.itemIndex); - return (doc.presStatus = PresStatus.Manual); + return (doc.presentation_status = PresStatus.Manual); } /** @@ -993,34 +995,34 @@ export class PresBox extends ViewBoxBaseComponent() { }); movementName = action((activeItem: Doc) => { - if (![PresMovement.Zoom, PresMovement.Pan, PresMovement.Center, PresMovement.Jump, PresMovement.None].includes(StrCast(activeItem.presMovement) as any)) { + if (![PresMovement.Zoom, PresMovement.Pan, PresMovement.Center, PresMovement.Jump, PresMovement.None].includes(StrCast(activeItem.presentation_movement) as any)) { return PresMovement.Zoom; } - return StrCast(activeItem.presMovement); + return StrCast(activeItem.presentation_movement); }); whenChildContentsActiveChanged = action((isActive: boolean) => this.props.whenChildContentsActiveChanged((this._isChildActive = isActive))); // For dragging documents into the presentation trail addDocumentFilter = (docs: Doc[]) => { docs.forEach((doc, i) => { - if (doc.presentationTargetDoc) return true; + if (doc.presentation_targetDoc) return true; if (doc.type === DocumentType.LABEL) { const audio = Cast(doc.annotationOn, Doc, null); if (audio) { audio.mediaStart = 'manual'; audio.mediaStop = 'manual'; - audio.presStartTime = NumCast(doc._timecodeToShow /* audioStart */, NumCast(doc._timecodeToShow /* videoStart */)); - audio.presEndTime = NumCast(doc._timecodeToHide /* audioEnd */, NumCast(doc._timecodeToHide /* videoEnd */)); - audio.presDuration = audio.presStartTime - audio.presEndTime; + audio.config_clipStart = NumCast(doc._timecodeToShow /* audioStart */, NumCast(doc._timecodeToShow /* videoStart */)); + audio.config_clipEnd = NumCast(doc._timecodeToHide /* audioEnd */, NumCast(doc._timecodeToHide /* videoEnd */)); + audio.presentation_duration = audio.config_clipStart - audio.config_clipEnd; TabDocView.PinDoc(audio, { audioRange: true }); setTimeout(() => this.removeDocument(doc), 0); return false; } } else { - if (!doc.presentationTargetDoc) doc.title = doc.title + ' - Slide'; - doc.presentationTargetDoc = doc.createdFrom; // dropped document will be a new embedding of an embedded document somewhere else. - doc.presMovement = PresMovement.Zoom; - if (this._expandBoolean) doc.presExpandInlineButton = true; + if (!doc.presentation_targetDoc) doc.title = doc.title + ' - Slide'; + doc.presentation_targetDoc = doc.createdFrom; // dropped document will be a new embedding of an embedded document somewhere else. + doc.presentation_movement = PresMovement.Zoom; + if (this._expandBoolean) doc.presentation_expandInlineButton = true; } }); return true; @@ -1040,7 +1042,7 @@ export class PresBox extends ViewBoxBaseComponent() { @computed get listOfSelected() { return Array.from(this.selectedArray).map((doc: Doc, index: any) => { const curDoc = Cast(doc, Doc, null); - const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null); + const tagDoc = Cast(curDoc.presentation_targetDoc, Doc, null); if (curDoc && curDoc === this.activeItem) return (
    @@ -1146,7 +1148,7 @@ export class PresBox extends ViewBoxBaseComponent() { if (anchorNode && anchorNode.className?.includes('lm_title')) return; switch (e.key) { case 'Backspace': - if (this.layoutDoc.presStatus === 'edit') { + if (this.layoutDoc.presentation_status === 'edit') { undoBatch( action(() => { for (const doc of this.selectedArray) { @@ -1163,11 +1165,11 @@ export class PresBox extends ViewBoxBaseComponent() { case 'Escape': if (Doc.IsInMyOverlay(this.layoutDoc)) { this.exitClicked(); - } else if (this.layoutDoc.presStatus === PresStatus.Edit) { + } else if (this.layoutDoc.presentation_status === PresStatus.Edit) { this.clearSelectedArray(); this._eleArray.length = this._dragArray.length = 0; } else { - this.layoutDoc.presStatus = PresStatus.Edit; + this.layoutDoc.presentation_status = PresStatus.Edit; } if (this._presTimer) clearTimeout(this._presTimer); handled = true; @@ -1184,7 +1186,7 @@ export class PresBox extends ViewBoxBaseComponent() { this.next(); if (this._presTimer) { clearTimeout(this._presTimer); - this.layoutDoc.presStatus = PresStatus.Manual; + this.layoutDoc.presentation_status = PresStatus.Manual; } } handled = true; @@ -1201,19 +1203,19 @@ export class PresBox extends ViewBoxBaseComponent() { this.back(); if (this._presTimer) { clearTimeout(this._presTimer); - this.layoutDoc.presStatus = PresStatus.Manual; + this.layoutDoc.presentation_status = PresStatus.Manual; } } handled = true; break; case 'Spacebar': case ' ': - if (this.layoutDoc.presStatus === PresStatus.Manual) this.startOrPause(true); - else if (this.layoutDoc.presStatus === PresStatus.Autoplay) if (this._presTimer) clearTimeout(this._presTimer); + if (this.layoutDoc.presentation_status === PresStatus.Manual) this.startOrPause(true); + else if (this.layoutDoc.presentation_status === PresStatus.Autoplay) if (this._presTimer) clearTimeout(this._presTimer); handled = true; break; case 'a': - if ((e.metaKey || e.altKey) && this.layoutDoc.presStatus === 'edit') { + if ((e.metaKey || e.altKey) && this.layoutDoc.presentation_status === 'edit') { this.clearSelectedArray(); this.childDocs.forEach(doc => this.addToSelectedArray(doc)); handled = true; @@ -1236,9 +1238,9 @@ export class PresBox extends ViewBoxBaseComponent() { const presCollection = DocumentManager.GetContextPath(this.activeItem).reverse().lastElement(); const dv = DocumentManager.Instance.getDocumentView(presCollection); this.childDocs - .filter(doc => Cast(doc.presentationTargetDoc, Doc, null)) + .filter(doc => Cast(doc.presentation_targetDoc, Doc, null)) .forEach((doc, index) => { - const tagDoc = Cast(doc.presentationTargetDoc, Doc, null); + const tagDoc = Cast(doc.presentation_targetDoc, Doc, null); const srcContext = Cast(tagDoc.embedContainer, Doc, null); const width = NumCast(tagDoc._width) / 10; const height = Math.max(NumCast(tagDoc._height) / 10, 15); @@ -1271,17 +1273,17 @@ export class PresBox extends ViewBoxBaseComponent() {
    ); } - } else if (doc.presPinView && presCollection === tagDoc && dv) { + } else if (doc.config_pinView && presCollection === tagDoc && dv) { // Case B: Document is presPinView and is presCollection - const scale: number = 1 / NumCast(doc.presViewScale); + const scale: number = 1 / NumCast(doc.config_viewScale); const height: number = dv.props.PanelHeight() * scale; const width: number = dv.props.PanelWidth() * scale; const indWidth = width / 10; const indHeight = Math.max(height / 10, 15); const indEdge = Math.max(indWidth, indHeight); const indFontSize = indEdge * 0.8; - const xLoc: number = NumCast(doc.presPanX) - width / 2; - const yLoc: number = NumCast(doc.presPanY) - height / 2; + const xLoc: number = NumCast(doc.config_panX) - width / 2; + const yLoc: number = NumCast(doc.config_panY) - height / 2; docs.push(tagDoc); order.push( <> @@ -1307,15 +1309,15 @@ export class PresBox extends ViewBoxBaseComponent() { @computed get paths() { let pathPoints = ''; this.childDocs.forEach((doc, index) => { - const tagDoc = Cast(doc.presentationTargetDoc, Doc, null); + const tagDoc = Cast(doc.presentation_targetDoc, Doc, null); if (tagDoc) { const n1x = NumCast(tagDoc.x) + NumCast(tagDoc._width) / 2; const n1y = NumCast(tagDoc.y) + NumCast(tagDoc._height) / 2; if ((index = 0)) pathPoints = n1x + ',' + n1y; else pathPoints = pathPoints + ' ' + n1x + ',' + n1y; - } else if (doc.presPinView) { - const n1x = NumCast(doc.presPanX); - const n1y = NumCast(doc.presPanY); + } else if (doc.config_pinView) { + const n1x = NumCast(doc.config_panX); + const n1y = NumCast(doc.config_panY); if ((index = 0)) pathPoints = n1x + ',' + n1y; else pathPoints = pathPoints + ' ' + n1x + ',' + n1y; } @@ -1339,7 +1341,7 @@ export class PresBox extends ViewBoxBaseComponent() { } getPaths = (collection: Doc) => this.paths; // needs to be smarter and figure out the paths to draw for this specific collection. or better yet, draw everything in an overlay layer instad of within a collection - // Converts seconds to ms and updates presTransition + // Converts seconds to ms and updates presentation_transition public static SetTransitionTime = (number: String, setter: (timeInMS: number) => void, change?: number) => { let timeInMS = Number(number) * 1000; if (change) timeInMS += change; @@ -1350,10 +1352,10 @@ export class PresBox extends ViewBoxBaseComponent() { @undoBatch updateTransitionTime = (number: String, change?: number) => { - PresBox.SetTransitionTime(number, (timeInMS: number) => this.selectedArray.forEach(doc => (doc.presTransition = timeInMS)), change); + PresBox.SetTransitionTime(number, (timeInMS: number) => this.selectedArray.forEach(doc => (doc.presentation_transition = timeInMS)), change); }; - // Converts seconds to ms and updates presTransition + // Converts seconds to ms and updates presentation_transition @undoBatch updateZoom = (number: String, change?: number) => { let scale = Number(number) / 100; @@ -1364,7 +1366,7 @@ export class PresBox extends ViewBoxBaseComponent() { }; /* - * Converts seconds to ms and updates presDuration + * Converts seconds to ms and updates presentation_duration */ @undoBatch updateDurationTime = (number: String, change?: number) => { @@ -1372,31 +1374,31 @@ export class PresBox extends ViewBoxBaseComponent() { if (change) timeInMS += change; if (timeInMS < 100) timeInMS = 100; if (timeInMS > 20000) timeInMS = 20000; - this.selectedArray.forEach(doc => (doc.presDuration = timeInMS)); + this.selectedArray.forEach(doc => (doc.presentation_duration = timeInMS)); }; @undoBatch - updateMovement = action((movement: PresMovement, all?: boolean) => (all ? this.childDocs : this.selectedArray).forEach(doc => (doc.presMovement = movement))); + updateMovement = action((movement: PresMovement, all?: boolean) => (all ? this.childDocs : this.selectedArray).forEach(doc => (doc.presentation_movement = movement))); @undoBatch @action updateHideBefore = (activeItem: Doc) => { - activeItem.presHideBefore = !activeItem.presHideBefore; - this.selectedArray.forEach(doc => (doc.presHideBefore = activeItem.presHideBefore)); + activeItem.presentation_hideBefore = !activeItem.presentation_hideBefore; + this.selectedArray.forEach(doc => (doc.presentation_hideBefore = activeItem.presentation_hideBefore)); }; @undoBatch @action updateHide = (activeItem: Doc) => { - activeItem.presHide = !activeItem.presHide; - this.selectedArray.forEach(doc => (doc.presHide = activeItem.presHide)); + activeItem.presentation_hide = !activeItem.presentation_hide; + this.selectedArray.forEach(doc => (doc.presentation_hide = activeItem.presentation_hide)); }; @undoBatch @action updateHideAfter = (activeItem: Doc) => { - activeItem.presHideAfter = !activeItem.presHideAfter; - this.selectedArray.forEach(doc => (doc.presHideAfter = activeItem.presHideAfter)); + activeItem.presentation_hideAfter = !activeItem.presentation_hideAfter; + this.selectedArray.forEach(doc => (doc.presentation_hideAfter = activeItem.presentation_hideAfter)); }; @undoBatch @@ -1415,11 +1417,11 @@ export class PresBox extends ViewBoxBaseComponent() { @undoBatch @action - updateEffectDirection = (effect: PresEffectDirection, all?: boolean) => (all ? this.childDocs : this.selectedArray).forEach(doc => (doc.presEffectDirection = effect)); + updateEffectDirection = (effect: PresEffectDirection, all?: boolean) => (all ? this.childDocs : this.selectedArray).forEach(doc => (doc.presentation_effectDirection = effect)); @undoBatch @action - updateEffect = (effect: PresEffect, bullet: boolean, all?: boolean) => (all ? this.childDocs : this.selectedArray).forEach(doc => (bullet ? (doc.presBulletEffect = effect) : (doc.presEffect = effect))); + updateEffect = (effect: PresEffect, bullet: boolean, all?: boolean) => (all ? this.childDocs : this.selectedArray).forEach(doc => (bullet ? (doc.presBulletEffect = effect) : (doc.presentation_effect = effect))); static _sliderBatch: any; public static inputter = (min: string, step: string, max: string, value: number, active: boolean, change: (val: string) => void, hmargin?: number) => { @@ -1449,16 +1451,16 @@ export class PresBox extends ViewBoxBaseComponent() { @undoBatch @action applyTo = (array: Doc[]) => { - this.updateMovement(this.activeItem.presMovement as PresMovement, true); - this.updateEffect(this.activeItem.presEffect as PresEffect, false, true); + this.updateMovement(this.activeItem.presentation_movement as PresMovement, true); + this.updateEffect(this.activeItem.presentation_effect as PresEffect, false, true); this.updateEffect(this.activeItem.presBulletEffect as PresEffect, true, true); - this.updateEffectDirection(this.activeItem.presEffectDirection as PresEffectDirection, true); - const { presTransition, presDuration, presHideBefore, presHideAfter } = this.activeItem; + this.updateEffectDirection(this.activeItem.presentation_effectDirection as PresEffectDirection, true); + const { presentation_transition, presentation_duration, presentation_hideBefore, presentation_hideAfter } = this.activeItem; array.forEach(curDoc => { - curDoc.presTransition = presTransition; - curDoc.presDuration = presDuration; - curDoc.presHideBefore = presHideBefore; - curDoc.presHideAfter = presHideAfter; + curDoc.presentation_transition = presentation_transition; + curDoc.presentation_duration = presentation_duration; + curDoc.presentation_hideBefore = presentation_hideBefore; + curDoc.presentation_hideAfter = presentation_hideAfter; }); }; @@ -1466,24 +1468,24 @@ export class PresBox extends ViewBoxBaseComponent() { const activeItem = this.activeItem; if (activeItem && this.targetDoc) { const targetType = this.targetDoc.type; - let duration = activeItem.presDuration ? NumCast(activeItem.presDuration) / 1000 : 0; + let duration = activeItem.presentation_duration ? NumCast(activeItem.presentation_duration) / 1000 : 0; if (activeItem.type === DocumentType.AUDIO) duration = NumCast(activeItem.duration); return (
    {'Hide before presented'}
    }> -
    this.updateHideBefore(activeItem)}> +
    this.updateHideBefore(activeItem)}> Hide before
    {'Hide while presented'}
    }> -
    this.updateHide(activeItem)}> +
    this.updateHide(activeItem)}> Hide
    {'Hide after presented'}
    }> -
    this.updateHideAfter(activeItem)}> +
    this.updateHideAfter(activeItem)}> Hide after
    @@ -1532,7 +1534,10 @@ export class PresBox extends ViewBoxBaseComponent() { if (activeItem && this.targetDoc) { const effect = activeItem.presBulletEffect ? activeItem.presBulletEffect : PresMovement.None; const bulletEffect = (effect: PresEffect) => ( -
    this.updateEffect(effect, true)}> +
    this.updateEffect(effect, true)}> {effect}
    ); @@ -1545,25 +1550,31 @@ export class PresBox extends ViewBoxBaseComponent() { style={{ margin: 10 }} type="checkbox" onChange={() => { - activeItem.presIndexed = activeItem.presIndexed === undefined ? 0 : undefined; - activeItem.presHideBefore = activeItem.presIndexed !== undefined; + activeItem.presentation_indexed = activeItem.presentation_indexed === undefined ? 0 : undefined; + activeItem.presentation_hideBefore = activeItem.presentation_indexed !== undefined; const tagDoc = PresBox.targetRenderedDoc(this.activeItem); const type = DocCast(tagDoc?.annotationOn)?.type ?? tagDoc.type; - activeItem.presIndexedStart = type === DocumentType.COL ? 1 : 0; + activeItem.presentation_indexedStart = type === DocumentType.COL ? 1 : 0; // a progressivized slide doesn't have sub-slides, but rather iterates over the data list of the target being progressivized. // to avoid creating a new slide to correspond to each of the target's data list, we create a computedField to refernce the target's data list. let dataField = Doc.LayoutFieldKey(tagDoc); if (Cast(tagDoc[dataField], listSpec(Doc), null)?.filter(d => d instanceof Doc) === undefined) dataField = dataField + '_annotations'; - if (DocCast(activeItem.presentationTargetDoc).annotationOn) activeItem.data = ComputedField.MakeFunction(`self.presentationTargetDoc.annotationOn["${dataField}"]`); - else activeItem.data = ComputedField.MakeFunction(`self.presentationTargetDoc["${dataField}"]`); + if (DocCast(activeItem.presentation_targetDoc).annotationOn) activeItem.data = ComputedField.MakeFunction(`self.presentation_targetDoc.annotationOn["${dataField}"]`); + else activeItem.data = ComputedField.MakeFunction(`self.presentation_targetDoc["${dataField}"]`); }} - checked={Cast(activeItem.presIndexed, 'number', null) !== undefined ? true : false} + checked={Cast(activeItem.presentation_indexed, 'number', null) !== undefined ? true : false} />
    Progressivize First Bullet
    - (activeItem.presIndexedStart = activeItem.presIndexedStart ? 0 : 1)} checked={!NumCast(activeItem.presIndexedStart)} /> + (activeItem.presentation_indexedStart = activeItem.presentation_indexedStart ? 0 : 1)} + checked={!NumCast(activeItem.presentation_indexedStart)} + />
    Expand Current Bullet
    @@ -1598,18 +1609,21 @@ export class PresBox extends ViewBoxBaseComponent() { } @computed get transitionDropdown() { const activeItem = this.activeItem; - const presEffect = (effect: PresEffect) => ( -
    this.updateEffect(effect, false)}> + const preseEffect = (effect: PresEffect) => ( +
    this.updateEffect(effect, false)}> {effect}
    ); const presMovement = (movement: PresMovement) => ( -
    this.updateMovement(movement)}> +
    this.updateMovement(movement)}> {movement}
    ); const presDirection = (direction: PresEffectDirection, icon: string, gridColumn: number, gridRow: number, opts: object) => { - const color = activeItem.presEffectDirection === direction || (direction === PresEffectDirection.Center && !activeItem.presEffectDirection) ? Colors.LIGHT_BLUE : 'black'; + const color = activeItem.presentation_effectDirection === direction || (direction === PresEffectDirection.Center && !activeItem.presentation_effectDirection) ? Colors.LIGHT_BLUE : 'black'; return ( {direction}
    }>
    () { ); }; if (activeItem && this.targetDoc) { - const transitionSpeed = activeItem.presTransition ? NumCast(activeItem.presTransition) / 1000 : 0.5; + const transitionSpeed = activeItem.presentation_transition ? NumCast(activeItem.presentation_transition) / 1000 : 0.5; const zoom = NumCast(activeItem.presZoom, 1) * 100; - const effect = activeItem.presEffect ? activeItem.presEffect : PresMovement.None; + const effect = activeItem.presentation_effect ? activeItem.presentation_effect : PresMovement.None; return (
    { @@ -1654,7 +1668,7 @@ export class PresBox extends ViewBoxBaseComponent() { {presMovement(PresMovement.Jump)}
    -
    +
    Zoom (% screen filled)
    this.updateZoom(e.target.value)} />% @@ -1668,7 +1682,7 @@ export class PresBox extends ViewBoxBaseComponent() {
    - {PresBox.inputter('0', '1', '100', zoom, activeItem.presMovement === PresMovement.Zoom, this.updateZoom)} + {PresBox.inputter('0', '1', '100', zoom, activeItem.presentation_movement === PresMovement.Zoom, this.updateZoom)}
    Transition Time
    @@ -1698,7 +1712,13 @@ export class PresBox extends ViewBoxBaseComponent() {
    Zoom Text Selections
    - (activeItem.presZoomText = !BoolCast(activeItem.presZoomText))} checked={BoolCast(activeItem.presZoomText)} /> + (activeItem.presentation_zoomText = !BoolCast(activeItem.presentation_zoomText))} + checked={BoolCast(activeItem.presentation_zoomText)} + />
    () { {effect?.toString()}
    e.stopPropagation()}> - {presEffect(PresEffect.None)} - {presEffect(PresEffect.Fade)} - {presEffect(PresEffect.Flip)} - {presEffect(PresEffect.Rotate)} - {presEffect(PresEffect.Bounce)} - {presEffect(PresEffect.Roll)} + {preseEffect(PresEffect.None)} + {preseEffect(PresEffect.Fade)} + {preseEffect(PresEffect.Flip)} + {preseEffect(PresEffect.Rotate)} + {preseEffect(PresEffect.Bounce)} + {preseEffect(PresEffect.Roll)}
    Effect direction
    -
    {StrCast(this.activeItem.presEffectDirection)}
    +
    {StrCast(this.activeItem.presentation_effectDirection)}
    {presDirection(PresEffectDirection.Left, 'angle-right', 1, 2, {})} @@ -1760,10 +1780,10 @@ export class PresBox extends ViewBoxBaseComponent() { style={{ textAlign: 'center', width: '100%', height: 15, fontSize: 10 }} type="number" readOnly={true} - value={NumCast(activeItem.presStartTime).toFixed(2)} + value={NumCast(activeItem.config_clipStart).toFixed(2)} onKeyDown={e => e.stopPropagation()} onChange={action((e: React.ChangeEvent) => { - activeItem.presStartTime = Number(e.target.value); + activeItem.config_clipStart = Number(e.target.value); })} />
    @@ -1773,7 +1793,7 @@ export class PresBox extends ViewBoxBaseComponent() { Duration (s)
    - {Math.round((NumCast(activeItem.presEndTime) - NumCast(activeItem.presStartTime)) * 10) / 10} + {Math.round((NumCast(activeItem.config_clipEnd) - NumCast(activeItem.config_clipStart)) * 10) / 10}
    @@ -1787,9 +1807,9 @@ export class PresBox extends ViewBoxBaseComponent() { style={{ textAlign: 'center', width: '100%', height: 15, fontSize: 10 }} type="number" readOnly={true} - value={NumCast(activeItem.presEndTime).toFixed(2)} + value={NumCast(activeItem.config_clipEnd).toFixed(2)} onChange={action((e: React.ChangeEvent) => { - activeItem.presEndTime = Number(e.target.value); + activeItem.config_clipEnd = Number(e.target.value); })} />
    @@ -1801,12 +1821,12 @@ export class PresBox extends ViewBoxBaseComponent() { step="0.1" min={clipStart} max={clipEnd} - value={NumCast(activeItem.presEndTime)} + value={NumCast(activeItem.config_clipEnd)} style={{ gridColumn: 1, gridRow: 1 }} className={`toolbar-slider ${'end'}`} id="toolbar-slider" onPointerDown={e => { - this._batch = UndoManager.StartBatch('presEndTime'); + this._batch = UndoManager.StartBatch('config_clipEnd'); const endBlock = document.getElementById('endTime'); if (endBlock) { endBlock.style.color = Colors.LIGHT_GRAY; @@ -1824,7 +1844,7 @@ export class PresBox extends ViewBoxBaseComponent() { }} onChange={(e: React.ChangeEvent) => { e.stopPropagation(); - activeItem.presEndTime = Number(e.target.value); + activeItem.config_clipEnd = Number(e.target.value); }} /> () { step="0.1" min={clipStart} max={clipEnd} - value={NumCast(activeItem.presStartTime)} + value={NumCast(activeItem.config_clipStart)} style={{ gridColumn: 1, gridRow: 1 }} className={`toolbar-slider ${'start'}`} id="toolbar-slider" onPointerDown={e => { - this._batch = UndoManager.StartBatch('presStartTime'); + this._batch = UndoManager.StartBatch('config_clipStart'); const startBlock = document.getElementById('startTime'); if (startBlock) { startBlock.style.color = Colors.LIGHT_GRAY; @@ -1855,7 +1875,7 @@ export class PresBox extends ViewBoxBaseComponent() { }} onChange={(e: React.ChangeEvent) => { e.stopPropagation(); - activeItem.presStartTime = Number(e.target.value); + activeItem.config_clipStart = Number(e.target.value); }} />
    @@ -1916,7 +1936,7 @@ export class PresBox extends ViewBoxBaseComponent() { return (
    e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}> @@ -2053,10 +2073,10 @@ export class PresBox extends ViewBoxBaseComponent() { if (doc) { const tabMap = CollectionDockingView.Instance?.tabMap; const tab = tabMap && Array.from(tabMap).find(tab => tab.DashDoc.type === DocumentType.COL)?.DashDoc; - const presCollection = DocumentManager.GetContextPath(this.activeItem).reverse().lastElement().presentationTargetDoc ?? tab; + const presCollection = DocumentManager.GetContextPath(this.activeItem).reverse().lastElement().presentation_targetDoc ?? tab; const data = Cast(presCollection?.data, listSpec(Doc)); - const presData = Cast(this.rootDoc.data, listSpec(Doc)); - if (data && presData) { + const config_data = Cast(this.rootDoc.data, listSpec(Doc)); + if (data && config_data) { data.push(doc); TabDocView.PinDoc(doc, {}); this.gotoDocument(this.childDocs.length, this.activeItem); @@ -2105,7 +2125,7 @@ export class PresBox extends ViewBoxBaseComponent() { className="dropdown-play-button" onClick={undoBatch( action(() => { - this.layoutDoc.presStatus = 'manual'; + this.layoutDoc.presentation_status = 'manual'; this.initializePresState(this.itemIndex); this.turnOffEdit(true); this.gotoDocument(this.itemIndex, this.activeItem); @@ -2181,7 +2201,7 @@ export class PresBox extends ViewBoxBaseComponent() { className={`presBox-buttons${Doc.IsInMyOverlay(this.rootDoc) ? ' inOverlay' : ''}`} style={{ background: Doc.ActivePresentation === this.rootDoc ? Colors.LIGHT_BLUE : undefined, display: !this.rootDoc._chromeHidden ? 'none' : undefined }}> {isMini ? null : ( - e.stopPropagation()} onChange={this.viewChanged} value={mode}> @@ -2196,12 +2216,12 @@ export class PresBox extends ViewBoxBaseComponent() { )}
    - +
    { if (this.childDocs.length) { - this.layoutDoc.presStatus = 'manual'; + this.layoutDoc.presentation_status = 'manual'; this.initializePresState(this.itemIndex); this.gotoDocument(this.itemIndex, this.activeItem); } @@ -2227,12 +2247,15 @@ export class PresBox extends ViewBoxBaseComponent() { } @computed get playButtons() { - const presEnd = !this.layoutDoc.presLoop && this.itemIndex === this.childDocs.length - 1 && (this.activeItem.presIndexed === undefined || NumCast(this.activeItem.presIndexed) === (this.progressivizedItems(this.activeItem)?.length ?? 0)); + const presEnd = + !this.layoutDoc.presLoop && + this.itemIndex === this.childDocs.length - 1 && + (this.activeItem.presentation_indexed === undefined || NumCast(this.activeItem.presentation_indexed) === (this.progressivizedItems(this.activeItem)?.length ?? 0)); const presStart: boolean = !this.layoutDoc.presLoop && this.itemIndex === 0; const inOverlay = Doc.IsInMyOverlay(this.rootDoc); // Case 1: There are still other frames and should go through all frames before going to next slide return ( -
    +
    {'Loop'}
    }>
    () { this.back(); if (this._presTimer) { clearTimeout(this._presTimer); - this.layoutDoc.presStatus = PresStatus.Manual; + this.layoutDoc.presentation_status = PresStatus.Manual; } e.stopPropagation(); }, @@ -2265,9 +2288,9 @@ export class PresBox extends ViewBoxBaseComponent() { }>
    - {this.layoutDoc.presStatus === PresStatus.Autoplay ? 'Pause' : 'Autoplay'}
    }> + {this.layoutDoc.presentation_status === PresStatus.Autoplay ? 'Pause' : 'Autoplay'}
    }>
    setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => this.startOrPause(true), false, false)}> - +
    () { this.next(); if (this._presTimer) { clearTimeout(this._presTimer); - this.layoutDoc.presStatus = PresStatus.Manual; + this.layoutDoc.presentation_status = PresStatus.Manual; } e.stopPropagation(); }, @@ -2316,7 +2339,7 @@ export class PresBox extends ViewBoxBaseComponent() {
    this.gotoDocument(0, this.activeItem)} style={{ display: inOverlay || this.props.PanelWidth() > 250 ? 'inline-flex' : 'none' }}> {inOverlay ? '' : 'Slide'} {this.itemIndex + 1} - {this.activeItem?.presIndexed !== undefined ? `(${this.activeItem.presIndexed}/${this.progressivizedItems(this.activeItem)?.length})` : ''} / {this.childDocs.length} + {this.activeItem?.presentation_indexed !== undefined ? `(${this.activeItem.presentation_indexed}/${this.progressivizedItems(this.activeItem)?.length})` : ''} / {this.childDocs.length}
    {this.props.PanelWidth() > 250 ? ( @@ -2324,7 +2347,7 @@ export class PresBox extends ViewBoxBaseComponent() { className="presPanel-button-text" onClick={undoBatch( action(() => { - this.layoutDoc.presStatus = PresStatus.Edit; + this.layoutDoc.presentation_status = PresStatus.Edit; clearTimeout(this._presTimer); }) )}> @@ -2342,7 +2365,7 @@ export class PresBox extends ViewBoxBaseComponent() { @action startOrPause = (makeActive = true) => { makeActive && this.updateCurrentPresentation(); - if (!this.layoutDoc.presStatus || this.layoutDoc.presStatus === PresStatus.Manual || this.layoutDoc.presStatus === PresStatus.Edit) this.startPresentation(this.itemIndex); + if (!this.layoutDoc.presentation_status || this.layoutDoc.presentation_status === PresStatus.Manual || this.layoutDoc.presentation_status === PresStatus.Edit) this.startPresentation(this.itemIndex); else this.pauseAutoPres(); }; @@ -2351,7 +2374,7 @@ export class PresBox extends ViewBoxBaseComponent() { this.back(); if (this._presTimer) { clearTimeout(this._presTimer); - this.layoutDoc.presStatus = PresStatus.Manual; + this.layoutDoc.presentation_status = PresStatus.Manual; } }; @@ -2360,19 +2383,19 @@ export class PresBox extends ViewBoxBaseComponent() { this.next(); if (this._presTimer) { clearTimeout(this._presTimer); - this.layoutDoc.presStatus = PresStatus.Manual; + this.layoutDoc.presentation_status = PresStatus.Manual; } }; @undoBatch @action exitClicked = () => { - this.layoutDoc.presStatus = this._exitTrail?.() ?? this.exitMinimize(); + this.layoutDoc.presentation_status = this._exitTrail?.() ?? this.exitMinimize(); clearTimeout(this._presTimer); }; AddToMap = (treeViewDoc: Doc, index: number[]) => { - if (!treeViewDoc.presentationTargetDoc) return this.childDocs; // if treeViewDoc is not a pres elements, then it's a sub-bullet of a progressivized slide which isn't added to the linearized list of pres elements since it's not really a pres element. + if (!treeViewDoc.presentation_targetDoc) return this.childDocs; // if treeViewDoc is not a pres elements, then it's a sub-bullet of a progressivized slide which isn't added to the linearized list of pres elements since it's not really a pres element. var indexNum = 0; for (let i = 0; i < index.length; i++) { indexNum += index[i] * 10 ** -i; @@ -2388,20 +2411,23 @@ export class PresBox extends ViewBoxBaseComponent() { }; RemFromMap = (treeViewDoc: Doc, index: number[]) => { - if (!treeViewDoc.presentationTargetDoc) return this.childDocs; // if treeViewDoc is not a pres elements, then it's a sub-bullet of a progressivized slide which isn't added to the linearized list of pres elements since it's not really a pres element. + if (!treeViewDoc.presentation_targetDoc) return this.childDocs; // if treeViewDoc is not a pres elements, then it's a sub-bullet of a progressivized slide which isn't added to the linearized list of pres elements since it's not really a pres element. if (!this._unmounting && this.isTree) { this._treeViewMap.delete(treeViewDoc); this.dataDoc[this.presFieldKey] = new List(this.sort(this._treeViewMap)); } }; - sort = (treeViewMap: Map) => [...treeViewMap.entries()].sort((a: [Doc, number], b: [Doc, number]) => (a[1] > b[1] ? 1 : a[1] < b[1] ? -1 : 0)).map(kv => kv[0]); + sort = (treeView_Map: Map) => [...treeView_Map.entries()].sort((a: [Doc, number], b: [Doc, number]) => (a[1] > b[1] ? 1 : a[1] < b[1] ? -1 : 0)).map(kv => kv[0]); render() { // needed to ensure that the childDocs are loaded for looking up fields this.childDocs.slice(); const mode = StrCast(this.rootDoc._type_collection) as CollectionViewType; - const presEnd = !this.layoutDoc.presLoop && this.itemIndex === this.childDocs.length - 1 && (this.activeItem.presIndexed === undefined || NumCast(this.activeItem.presIndexed) === (this.progressivizedItems(this.activeItem)?.length ?? 0)); + const presEnd = + !this.layoutDoc.presLoop && + this.itemIndex === this.childDocs.length - 1 && + (this.activeItem.presentation_indexed === undefined || NumCast(this.activeItem.presentation_indexed) === (this.progressivizedItems(this.activeItem)?.length ?? 0)); const presStart = !this.layoutDoc.presLoop && this.itemIndex === 0; return this.props.addDocTab === returnFalse ? ( // bcz: hack!! - addDocTab === returnFalse only when this is being rendered by the OverlayView which means the doc is a mini player
    e.stopPropagation()} onPointerEnter={action(e => (this._forceKeyEvents = true))}> @@ -2420,9 +2446,9 @@ export class PresBox extends ViewBoxBaseComponent() {
    setupMoveUpEvents(this, e, returnFalse, returnFalse, this.prevClicked, false, false)}>
    - {this.layoutDoc.presStatus === PresStatus.Autoplay ? 'Pause' : 'Autoplay'}
    }> + {this.layoutDoc.presentation_status === PresStatus.Autoplay ? 'Pause' : 'Autoplay'}
    }>
    setupMoveUpEvents(this, e, returnFalse, returnFalse, () => this.startOrPause(true), false, false)}> - +
    setupMoveUpEvents(this, e, returnFalse, returnFalse, this.nextClicked, false, false)}> @@ -2436,7 +2462,7 @@ export class PresBox extends ViewBoxBaseComponent() {
    Slide {this.itemIndex + 1} - {this.activeItem?.presIndexed !== undefined ? `(${this.activeItem.presIndexed}/${this.progressivizedItems(this.activeItem)?.length})` : ''} / {this.childDocs.length} + {this.activeItem?.presentation_indexed !== undefined ? `(${this.activeItem.presentation_indexed}/${this.progressivizedItems(this.activeItem)?.length})` : ''} / {this.childDocs.length}
    setupMoveUpEvents(this, e, returnFalse, returnFalse, this.exitClicked, false, false)}> @@ -2460,6 +2486,7 @@ export class PresBox extends ViewBoxBaseComponent() { moveDocument={returnFalse} ignoreUnrendered={true} childDragAction="move" + setContentView={emptyFunction} //childLayoutFitWidth={returnTrue} childOpacity={returnOne} childClickScript={PresBox.navigateToDocScript} diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index f31cf6147..aa514be3b 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -58,13 +58,13 @@ export class PresElementBox extends ViewBoxBaseComponent() { return this.props.DocumentView?.().props.docViewPath().lastElement()?.rootDoc; } @computed get targetDoc() { - return Cast(this.rootDoc.presentationTargetDoc, Doc, null) || this.rootDoc; + return Cast(this.rootDoc.presentation_targetDoc, Doc, null) || this.rootDoc; } componentDidMount() { this.layoutDoc.layout_hideLinkButton = true; this._heightDisposer = reaction( - () => ({ expand: this.rootDoc.presExpandInlineButton, height: this.collapsedHeight }), + () => ({ expand: this.rootDoc.presentation_expandInlineButton, height: this.collapsedHeight }), ({ expand, height }) => (this.layoutDoc._height = height + (expand ? this.expandViewHeight : 0)), { fireImmediately: true } ); @@ -79,7 +79,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { ScreenToLocalListTransform = (xCord: number, yCord: number) => [xCord, yCord]; @action - presExpandDocumentClick = () => (this.rootDoc.presExpandInlineButton = !this.rootDoc.presExpandInlineButton); + presExpandDocumentClick = () => (this.rootDoc.presentation_expandInlineButton = !this.rootDoc.presentation_expandInlineButton); embedHeight = (): number => this.collapsedHeight + this.expandViewHeight; // embedWidth = () => this.props.PanelWidth(); @@ -94,7 +94,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { * presentation element. */ @computed get renderEmbeddedInline() { - return !this.rootDoc.presExpandInlineButton || !this.targetDoc ? null : ( + return !this.rootDoc.presentation_expandInlineButton || !this.targetDoc ? null : (
    () { @computed get transition() { let transitionInS: number; - if (this.rootDoc.presTransition) transitionInS = NumCast(this.rootDoc.presTransition) / 1000; + if (this.rootDoc.presentation_transition) transitionInS = NumCast(this.rootDoc.presentation_transition) / 1000; else transitionInS = 0.5; - return this.rootDoc.presMovement === PresMovement.Jump || this.rootDoc.presMovement === PresMovement.None ? null : 'M: ' + transitionInS + 's'; + return this.rootDoc.presentation_movement === PresMovement.Jump || this.rootDoc.presentation_movement === PresMovement.None ? null : 'M: ' + transitionInS + 's'; } private _itemRef: React.RefObject = React.createRef(); @@ -238,7 +238,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { onPointerMove = (e: PointerEvent) => { const slide = this._itemRef.current!; - const dragIsPresItem = DragManager.docsBeingDragged.some(d => d.presentationTargetDoc); + const dragIsPresItem = DragManager.docsBeingDragged.some(d => d.presentation_targetDoc); if (slide && dragIsPresItem) { const rect = slide.getBoundingClientRect(); const y = e.clientY - rect.top; //y position within the element. @@ -296,12 +296,12 @@ export class PresElementBox extends ViewBoxBaseComponent() { @action updateCapturedContainerLayout = (presTargetDoc: Doc, activeItem: Doc) => { const targetDoc = DocCast(presTargetDoc.annotationOn) ?? presTargetDoc; - activeItem.presX = NumCast(targetDoc.x); - activeItem.presY = NumCast(targetDoc.y); - activeItem.presRotation = NumCast(targetDoc.rotation); - activeItem.presWidth = NumCast(targetDoc.width); - activeItem.presHeight = NumCast(targetDoc.height); - activeItem.presPinLayout = true; + activeItem.config_x = NumCast(targetDoc.x); + activeItem.config_y = NumCast(targetDoc.y); + activeItem.config_rotation = NumCast(targetDoc.rotation); + activeItem.config_width = NumCast(targetDoc.width); + activeItem.config_height = NumCast(targetDoc.height); + activeItem.config_pinLayout = true; }; /** * Method called for updating the view of the currently selected document @@ -421,7 +421,7 @@ export class PresElementBox extends ViewBoxBaseComponent() {
    setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => this.updateCapturedContainerLayout(targetDoc, activeItem), true)} - style={{ opacity: activeItem.presPinLayout ? 1 : 0.5, fontWeight: 700, display: 'flex' }}> + style={{ opacity: activeItem.config_pinLayout ? 1 : 0.5, fontWeight: 700, display: 'flex' }}> L
    @@ -431,7 +431,7 @@ export class PresElementBox extends ViewBoxBaseComponent() {
    setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => this.updateCapturedViewContents(targetDoc, activeItem))} - style={{ opacity: activeItem.presPinData || activeItem.presPinView ? 1 : 0.5, fontWeight: 700, display: 'flex' }}> + style={{ opacity: activeItem.config_pinData || activeItem.config_pinView ? 1 : 0.5, fontWeight: 700, display: 'flex' }}> C
    @@ -445,19 +445,19 @@ export class PresElementBox extends ViewBoxBaseComponent() { ); if (this.indexInPres !== 0) { items.push( - {activeItem.groupWithUp ? 'Ungroup' : 'Group with up'}
    }> + {activeItem.presentation_groupWithUp ? 'Ungroup' : 'Group with up'}
    }>
    (activeItem.groupWithUp = (NumCast(activeItem.groupWithUp) + 1) % 3)} + onClick={() => (activeItem.presentation_groupWithUp = (NumCast(activeItem.presentation_groupWithUp) + 1) % 3)} style={{ zIndex: 1000 - this.indexInPres, fontWeight: 700, - backgroundColor: activeItem.groupWithUp ? (presColorBool ? presBoxColor : Colors.MEDIUM_BLUE) : undefined, - outline: NumCast(activeItem.groupWithUp) > 1 ? 'solid black 1px' : undefined, - height: activeItem.groupWithUp ? 53 : 18, - transform: activeItem.groupWithUp ? 'translate(0, -17px)' : undefined, + backgroundColor: activeItem.presentation_groupWithUp ? (presColorBool ? presBoxColor : Colors.MEDIUM_BLUE) : undefined, + outline: NumCast(activeItem.presentation_groupWithUp) > 1 ? 'solid black 1px' : undefined, + height: activeItem.presentation_groupWithUp ? 53 : 18, + transform: activeItem.presentation_groupWithUp ? 'translate(0, -17px)' : undefined, }}> -
    +
    e.stopPropagation()} />
    @@ -465,14 +465,14 @@ export class PresElementBox extends ViewBoxBaseComponent() { ); } items.push( - {this.rootDoc.presExpandInlineButton ? 'Minimize' : 'Expand'}
    }> + {this.rootDoc.presentation_expandInlineButton ? 'Minimize' : 'Expand'}
    }>
    { e.stopPropagation(); this.presExpandDocumentClick(); }}> - e.stopPropagation()} /> + e.stopPropagation()} />
    ); @@ -534,7 +534,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { style={{ display: 'inline-flex', pointerEvents: isSelected ? undefined : 'none', - width: `calc(100% ${this.rootDoc.presExpandInlineButton ? '- 50%' : ''} - ${this.presButtons.length * 22}px`, + width: `calc(100% ${this.rootDoc.presentation_expandInlineButton ? '- 50%' : ''} - ${this.presButtons.length * 22}px`, cursor: isSelected ? 'text' : 'grab', }}>
    { render() { return (
    - {DocListCast(this.props.anno.textInlineAnnotations).map(a => ( + {DocListCast(this.props.anno.text_inlineAnnotations).map(a => ( ))}
    @@ -61,7 +61,7 @@ class RegionAnnotation extends React.Component { isTargetToggler = () => BoolCast(this.annoTextRegion.followLinkToggle); @undoBatch showTargetTrail = (anchor: Doc) => { - const trail = DocCast(anchor.presTrail); + const trail = DocCast(anchor.presentationTrail); if (trail) { Doc.ActivePresentation = trail; this.props.addDocTab(trail, OpenWhere.replaceRight); diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 1319a236d..395fbd1ca 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -68,7 +68,7 @@ export class PDFViewer extends React.Component { private _styleRule: any; // stylesheet rule for making hyperlinks clickable private _retries = 0; // number of times tried to create the PDF viewer private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean, hide: boolean) => void); - private _setBrushViewer: undefined | ((view: { width: number; height: number; panX: number; panY: number }) => void); + private _setBrushViewer: undefined | ((view: { width: number; height: number; panX: number; panY: number }, transTime: number) => void); private _annotationLayer: React.RefObject = React.createRef(); private _disposers: { [name: string]: IReactionDisposer } = {}; private _viewer: React.RefObject = React.createRef(); @@ -95,7 +95,7 @@ export class PDFViewer extends React.Component { return DocUtils.FilterDocs(DocListCast(this.props.dataDoc[this.props.fieldKey + '_annotations']), this.props.childFilters(), this.props.childFiltersByRanges()); } @computed get inlineTextAnnotations() { - return this.allAnnotations.filter(a => a.textInlineAnnotations); + return this.allAnnotations.filter(a => a.text_inlineAnnotations); } componentDidMount = async () => { @@ -195,7 +195,7 @@ export class PDFViewer extends React.Component { return focusSpeed; }; crop = (region: Doc | undefined, addCrop?: boolean) => this.props.crop(region, addCrop); - brushView = (view: { width: number; height: number; panX: number; panY: number }) => this._setBrushViewer?.(view); + brushView = (view: { width: number; height: number; panX: number; panY: number }, transTime: number) => this._setBrushViewer?.(view, transTime); @action setupPdfJsViewer = async () => { @@ -470,7 +470,7 @@ export class PDFViewer extends React.Component { }; setPreviewCursor = (func?: (x: number, y: number, drag: boolean, hide: boolean) => void) => (this._setPreviewCursor = func); - setBrushViewer = (func?: (view: { width: number; height: number; panX: number; panY: number }) => void) => (this._setBrushViewer = func); + setBrushViewer = (func?: (view: { width: number; height: number; panX: number; panY: number }, transTime: number) => void) => (this._setBrushViewer = func); @action onZoomWheel = (e: React.WheelEvent) => { diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index eb52cff88..d3912b8a0 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -1363,9 +1363,9 @@ export namespace Doc { UnhighlightWatchers.push(watcher); } else watcher(); } - export function linkFollowHighlight(destDoc: Doc | Doc[], dataAndDisplayDocs = true, presEffect?: Doc) { + export function linkFollowHighlight(destDoc: Doc | Doc[], dataAndDisplayDocs = true, presentation_effect?: Doc) { linkFollowUnhighlight(); - (destDoc instanceof Doc ? [destDoc] : destDoc).forEach(doc => Doc.HighlightDoc(doc, dataAndDisplayDocs, presEffect)); + (destDoc instanceof Doc ? [destDoc] : destDoc).forEach(doc => Doc.HighlightDoc(doc, dataAndDisplayDocs, presentation_effect)); document.removeEventListener('pointerdown', linkFollowUnhighlight); document.addEventListener('pointerdown', linkFollowUnhighlight); if (UnhighlightTimer) clearTimeout(UnhighlightTimer); @@ -1380,11 +1380,11 @@ export namespace Doc { if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(Doc.GetProto(doc)) === AclPrivate || doc.opacity === 0) return false; return doc[Highlight] || Doc.GetProto(doc)[Highlight]; } - export function HighlightDoc(doc: Doc, dataAndDisplayDocs = true, presEffect?: Doc) { + export function HighlightDoc(doc: Doc, dataAndDisplayDocs = true, presentation_effect?: Doc) { runInAction(() => { highlightedDocs.add(doc); doc[Highlight] = true; - doc[Animation] = presEffect; + doc[Animation] = presentation_effect; if (dataAndDisplayDocs) { highlightedDocs.add(Doc.GetProto(doc)); Doc.GetProto(doc)[Highlight] = true; diff --git a/src/fields/documentSchemas.ts b/src/fields/documentSchemas.ts index 76b287be7..e33a17416 100644 --- a/src/fields/documentSchemas.ts +++ b/src/fields/documentSchemas.ts @@ -72,11 +72,11 @@ export const documentSchema = createSchema({ stroke_endMarker: 'string', stroke_dash: 'string', textTransform: 'string', - treeViewOpen: 'boolean', // flag denoting whether the documents sub-tree (contents) is visible or hidden - treeViewExpandedView: 'string', // name of field whose contents are being displayed as the document's subtree - treeViewExpandedViewLock: 'boolean', // whether the expanded view can be changed - treeViewOpenIsTransient: 'boolean', // ignores the treeViewOpen flag (for allowing a view to not be slaved to other views of the document) - treeViewType: 'string', // whether tree view is an outline, file syste or (default) hierarchy. For outline, clicks edit document titles immediately since double-click opening is turned off + treeView_Open: 'boolean', // flag denoting whether the documents sub-tree (contents) is visible or hidden + treeView_ExpandedView: 'string', // name of field whose contents are being displayed as the document's subtree + treeView_ExpandedViewLock: 'boolean', // whether the expanded view can be changed + treeView_OpenIsTransient: 'boolean', // ignores the treeView_Open flag (for allowing a view to not be slaved to other views of the document) + treeView_Type: 'string', // whether tree view is an outline, file syste or (default) hierarchy. For outline, clicks edit document titles immediately since double-click opening is turned off // interaction and linking properties ignoreClick: 'boolean', // whether documents ignores input clicks (but does not ignore manipulation and other events) -- cgit v1.2.3-70-g09d2 From d3ecace5f03233e5d5ab2354c3f482418287ca9a Mon Sep 17 00:00:00 2001 From: Sophie Zhang Date: Thu, 17 Aug 2023 16:14:53 -0400 Subject: broken version --- package-lock.json | 97 +++++++++++++++-- src/client/util/CurrentUserUtils.ts | 2 + src/client/views/MainView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 1 + src/client/views/global/globalScripts.ts | 8 +- src/client/views/nodes/FontIconBox/FontIconBox.tsx | 28 +++++ src/client/views/nodes/ImageBox.tsx | 6 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 76 +++++++------- .../views/nodes/generativeFill/GenerativeFill.tsx | 115 +++++++++++++-------- .../nodes/generativeFill/GenerativeFillButtons.tsx | 6 +- src/client/views/pdf/AnchorMenu.tsx | 1 + src/client/views/pdf/GPTPopup/GPTPopup.scss | 2 + src/client/views/pdf/GPTPopup/GPTPopup.tsx | 99 +++++++++--------- src/client/views/pdf/PDFViewer.tsx | 4 - 14 files changed, 301 insertions(+), 146 deletions(-) (limited to 'src/client/views/nodes/formattedText') diff --git a/package-lock.json b/package-lock.json index 658e783f9..20d582e5b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6507,9 +6507,9 @@ } }, "browndash-components": { - "version": "0.0.92", - "resolved": "https://registry.npmjs.org/browndash-components/-/browndash-components-0.0.92.tgz", - "integrity": "sha512-eE/6WQNZiLnaXUKyoaMm0PDYjExUsFJ9VTAIIxROpYPosIBKWNZ743xaOfmehib5us9hEXJb0CvUFJQb8rzDVw==", + "version": "0.0.93", + "resolved": "https://registry.npmjs.org/browndash-components/-/browndash-components-0.0.93.tgz", + "integrity": "sha512-JL9Hi7Nq+zHZtjLCQSuGhID0Hd7X6sARutyJqbECfsLWACsIC/JfeEQZdUeH5CqO+R7pJKeoWM82AIkWGtN2Xw==", "requires": { "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", @@ -7063,12 +7063,97 @@ "strip-ansi": "^7.0.1" } }, + "string-width-cjs": { + "version": "npm:string-width@4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + } + } + }, "strip-ansi": { "version": "7.1.0", "bundled": true, "requires": { "ansi-regex": "^6.0.1" } + }, + "strip-ansi-cjs": { + "version": "npm:strip-ansi@6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + } + } + }, + "wrap-ansi-cjs": { + "version": "npm:wrap-ansi@7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + } + } } } }, @@ -8573,7 +8658,7 @@ } }, "string-width-cjs": { - "version": "npm:string-width@4.2.3", + "version": "npm:string-width-cjs@4.2.3", "bundled": true, "requires": { "emoji-regex": "^8.0.0", @@ -8596,7 +8681,7 @@ } }, "strip-ansi-cjs": { - "version": "npm:strip-ansi@6.0.1", + "version": "npm:strip-ansi-cjs@6.0.1", "bundled": true, "requires": { "ansi-regex": "^5.0.1" @@ -8755,7 +8840,7 @@ } }, "wrap-ansi-cjs": { - "version": "npm:wrap-ansi@7.0.0", + "version": "npm:wrap-ansi-cjs@7.0.0", "bundled": true, "requires": { "ansi-styles": "^4.0.0", diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index c9a5175bb..6592ecffc 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -633,6 +633,8 @@ export class CurrentUserUtils { { title: "Snap", icon: "th", toolTip: "Show Snap Lines", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"snaplines", funcs: {}, scripts: { onClick: '{ return showFreeform(self.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(self.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform { title: "View All", icon: "object-group", toolTip: "Fit all Docs to View", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"viewAll", funcs: {}, scripts: { onClick: '{ return showFreeform(self.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 all Docs to View (persistent)", btnType: ButtonType.IconClickButton, ignoreClick: false, expertMode: false, toolType:"viewAllPersist", funcs: {}, scripts: { onClick: '{ return showFreeform(self.toolType, _readOnly_);}'}}, // 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(self.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(self.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(self.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 60eb64caa..8fba9b886 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -80,7 +80,6 @@ export class MainView extends React.Component { @observable public imageEditorSource: string = ''; @action public setImageEditorSource = (source: string) => (this.imageEditorSource = source); @observable public imageRootDoc: Doc | undefined; - @action public setImageRootDoc = (doc: Doc) => (this.imageRootDoc = doc); @observable public addDoc: ((doc: Doc | Doc[], annotationKey?: string) => boolean) | undefined; @observable public LastButton: Opt; @@ -350,6 +349,7 @@ export class MainView extends React.Component { fa.faMousePointer, fa.faMusic, fa.faObjectGroup, + fa.faArrowsLeftRight, fa.faPause, fa.faPen, fa.faPenNib, diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 29122cb91..f353dfab7 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1599,6 +1599,7 @@ export class CollectionFreeFormView extends CollectionSubView this.rootDoc.fitContentOnce, fitContentOnce => { if (fitContentOnce) this.fitContentOnce(); + this.rootDoc.fitContentOnce = false; }, { fireImmediately: true, name: 'fitContent' } ); diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts index 256377758..38bf1042d 100644 --- a/src/client/views/global/globalScripts.ts +++ b/src/client/views/global/globalScripts.ts @@ -85,10 +85,10 @@ ScriptingGlobals.add(function toggleOverlay(checkResult?: boolean) { selected ? selected.props.CollectionFreeFormDocumentView?.().float() : console.log('[FontIconBox.tsx] toggleOverlay failed'); }); -ScriptingGlobals.add(function showFreeform(attr: 'flashcards' | 'grid' | 'snaplines' | 'clusters' | 'arrange' | 'viewAll', checkResult?: boolean) { +ScriptingGlobals.add(function showFreeform(attr: 'flashcards' | 'grid' | 'snaplines' | 'clusters' | 'arrange' | 'viewAll' | 'viewAllPersist', checkResult?: boolean) { const selected = SelectionManager.Docs().lastElement(); // prettier-ignore - const map: Map<'flashcards' | 'grid' | 'snaplines' | 'clusters' | 'arrange'| 'viewAll', { waitForRender?: boolean, checkResult: (doc:Doc) => any; setDoc: (doc:Doc) => void;}> = new Map([ + const map: Map<'flashcards' | 'grid' | 'snaplines' | 'clusters' | 'arrange'| 'viewAll' | 'viewAllPersist', { waitForRender?: boolean, checkResult: (doc:Doc) => any; setDoc: (doc:Doc) => void;}> = new Map([ ['grid', { checkResult: (doc:Doc) => BoolCast(doc._freeform_backgroundGrid, false), setDoc: (doc:Doc) => doc._freeform_backgroundGrid = !doc._freeform_backgroundGrid, @@ -101,6 +101,10 @@ ScriptingGlobals.add(function showFreeform(attr: 'flashcards' | 'grid' | 'snapli checkResult: (doc:Doc) => BoolCast(doc._freeform_fitContentsToBox, false), setDoc: (doc:Doc) => doc._freeform_fitContentsToBox = !doc._freeform_fitContentsToBox, }], + ['viewAllPersist', { + checkResult: (doc:Doc) => false, + setDoc: (doc:Doc) => doc.fitContentOnce = true + }], ['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 91eac675f..90ec212fc 100644 --- a/src/client/views/nodes/FontIconBox/FontIconBox.tsx +++ b/src/client/views/nodes/FontIconBox/FontIconBox.tsx @@ -29,6 +29,7 @@ export enum ButtonType { DropdownList = 'dropdownList', DropdownButton = 'dropdownBtn', ClickButton = 'clickBtn', + IconClickButton = 'iconClickBtn', ToggleButton = 'toggleBtn', ColorButton = 'colorBtn', ToolButton = 'toolBtn', @@ -346,6 +347,32 @@ export class FontIconBox extends DocComponent() { ); } + @computed get iconClickButton() { + // Determine the type of toggle button + const buttonText: string = StrCast(this.rootDoc.buttonText); + 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 backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor); + + return ( + script.script.run({ this: this.layoutDoc, self: this.rootDoc, value: !toggleStatus, _readOnly_: false })} + /> + ); + } + /** * Default */ @@ -393,6 +420,7 @@ export class FontIconBox extends DocComponent() { case ButtonType.DropdownButton: return this.dropdownButton; case ButtonType.MultiToggleButton: return this.multiToggleButton; case ButtonType.ToggleButton: return this.toggleButton; + case ButtonType.IconClickButton: return this.iconClickButton; case ButtonType.ClickButton: case ButtonType.ToolButton: return ; case ButtonType.TextButton: return
    ))}
    + {!this.loading && ( + <> + } color={StrCast(Doc.UserDoc().userVariantColor)} /> + + )}
    ); }; @@ -227,43 +269,6 @@ export class GPTPopup extends React.Component { ); - editBox = () => { - const hr = this.highlightRange; - return ( - <> -
    - {this.heading('TEXT EDIT SUGGESTIONS')} -
    - {hr && ( -
    - {this.text.slice(0, hr[0])} {this.text.slice(hr[0], hr[1])} {this.text.slice(hr[1])} -
    - )} -
    -
    - {hr && !this.loading && ( - <> -
    - <> - - - -
    - {this.aiWarning()} - - )} - - ); - }; - aiWarning = () => this.done ? (
    @@ -277,14 +282,14 @@ export class GPTPopup extends React.Component { heading = (headingText: string) => (
    - {this.loading ? : } onClick={() => this.setVisible(false)} />} + {this.loading ? : } onClick={() => this.setVisible(false)} />}
    ); render() { return (
    - {this.mode === GPTPopupMode.SUMMARY ? this.summaryBox() : this.mode === GPTPopupMode.IMAGE ? this.imageBox() : this.editBox()} + {this.mode === GPTPopupMode.SUMMARY ? this.summaryBox() : this.mode === GPTPopupMode.IMAGE ? this.imageBox() : <>}
    ); } diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index c9fee4813..1319a236d 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -424,10 +424,6 @@ export class PDFViewer extends React.Component { // Changing which document to add the annotation to (the currently selected PDF) GPTPopup.Instance.setSidebarId('data_sidebar'); - const anchor = this._getAnchor(undefined, false); - if (anchor) { - GPTPopup.Instance.setTargetAnchor(anchor); - } GPTPopup.Instance.addDoc = this.props.sidebarAddDoc; }; -- cgit v1.2.3-70-g09d2 From f0cca82b98e766474f1df49bacec2258b67aae4e Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 17 Aug 2023 19:58:08 -0400 Subject: updated fieldNames for recording dictation --- src/client/views/nodes/AudioBox.tsx | 7 ++++--- src/client/views/nodes/ScreenshotBox.tsx | 7 ++++--- src/client/views/nodes/formattedText/FormattedTextBox.tsx | 6 ++---- 3 files changed, 10 insertions(+), 10 deletions(-) (limited to 'src/client/views/nodes/formattedText') diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 4480de938..7c409c38c 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -359,9 +359,10 @@ export class AudioBox extends ViewBoxAnnotatableComponent { const newDoc = DocUtils.GetNewTextDoc('', NumCast(this.rootDoc.x), NumCast(this.rootDoc.y) + NumCast(this.layoutDoc._height) + 10, NumCast(this.layoutDoc._width), 2 * NumCast(this.layoutDoc._height)); - Doc.GetProto(newDoc).recordingSource = this.dataDoc; - Doc.GetProto(newDoc).recordingStart = ComputedField.MakeFunction(`self.recordingSource["${this.fieldKey}_recordingStart"]`); - Doc.GetProto(newDoc).mediaState = ComputedField.MakeFunction('self.recordingSource.mediaState'); + const textField = Doc.LayoutFieldKey(newDoc); + Doc.GetProto(newDoc)[`${textField}_recordingSource`] = this.dataDoc; + Doc.GetProto(newDoc)[`${textField}_recordingStart`] = ComputedField.MakeFunction(`self.${textField}_recordingSource.${this.fieldKey}_recordingStart`); + Doc.GetProto(newDoc).mediaState = ComputedField.MakeFunction(`self.${textField}_recordingSource.mediaState`); if (Doc.IsInMyOverlay(this.rootDoc)) { newDoc.overlayX = this.rootDoc.x; newDoc.overlayY = NumCast(this.rootDoc.y) + NumCast(this.rootDoc._height); diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx index 8e8a59fd9..0a33a336f 100644 --- a/src/client/views/nodes/ScreenshotBox.tsx +++ b/src/client/views/nodes/ScreenshotBox.tsx @@ -272,11 +272,12 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent { if (this.dataDoc[this.fieldKey + '_dictation']) return; const dictationText = DocUtils.GetNewTextDoc('dictation', NumCast(this.rootDoc.x), NumCast(this.rootDoc.y) + NumCast(this.layoutDoc._height) + 10, NumCast(this.layoutDoc._width), 2 * NumCast(this.layoutDoc._height)); + const textField = Doc.LayoutFieldKey(dictationText); dictationText._layout_autoHeight = false; const dictationTextProto = Doc.GetProto(dictationText); - dictationTextProto.recordingSource = this.dataDoc; - dictationTextProto.recordingStart = ComputedField.MakeFunction(`self.recordingSource["${this.props.fieldKey}_recordingStart"]`); - dictationTextProto.mediaState = ComputedField.MakeFunction('self.recordingSource.mediaState'); + dictationTextProto[`${textField}_recordingSource`] = this.dataDoc; + dictationTextProto[`${textField}_recordingStart`] = ComputedField.MakeFunction(`self.${textField}_recordingSource.${this.fieldKey}_recordingStart`); + dictationTextProto.mediaState = ComputedField.MakeFunction(`self.${textField}_recordingSource.mediaState`); this.dataDoc[this.fieldKey + '_dictation'] = dictationText; }; videoPanelHeight = () => (NumCast(this.dataDoc[this.fieldKey + '_nativeHeight'], this.layoutDoc[Height]()) / NumCast(this.dataDoc[this.fieldKey + '_nativeWidth'], this.layoutDoc[Width]())) * this.props.PanelWidth(); diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index eea4f513e..2afbbb457 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -156,7 +156,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent this._recording, () => { this.stopDictation(true); - if (this._recording) { - this.recordDictation(); - } + this._recording && this.recordDictation(); } ); if (this._recording) setTimeout(this.recordDictation); -- cgit v1.2.3-70-g09d2 From ad2f3695ddfb4a7bec17ddbdf6e7011862936bc4 Mon Sep 17 00:00:00 2001 From: Sophie Zhang Date: Fri, 18 Aug 2023 17:41:51 -0400 Subject: added gen_fill_children field --- .../views/nodes/formattedText/FormattedTextBox.tsx | 37 ---------------------- .../views/nodes/generativeFill/GenerativeFill.tsx | 24 ++++++++------ src/client/views/pdf/GPTPopup/GPTPopup.tsx | 5 +-- 3 files changed, 16 insertions(+), 50 deletions(-) (limited to 'src/client/views/nodes/formattedText') diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index fd30c43d7..daf8719eb 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -946,46 +946,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { diff --git a/src/client/views/nodes/generativeFill/GenerativeFill.tsx b/src/client/views/nodes/generativeFill/GenerativeFill.tsx index 92ce3a8a8..06819d08c 100644 --- a/src/client/views/nodes/generativeFill/GenerativeFill.tsx +++ b/src/client/views/nodes/generativeFill/GenerativeFill.tsx @@ -12,12 +12,11 @@ import { CiUndo, CiRedo } from 'react-icons/ci'; import { MainView } from '../../MainView'; import { Doc, DocListCast } from '../../../../fields/Doc'; import { Networking } from '../../../Network'; -import { Utils, returnEmptyDoclist } from '../../../../Utils'; +import { Utils } from '../../../../Utils'; import { DocUtils, Docs } from '../../../documents/Documents'; -import { DocCast, NumCast } from '../../../../fields/Types'; +import { NumCast } from '../../../../fields/Types'; import { CollectionDockingView } from '../../collections/CollectionDockingView'; import { OpenWhereMod } from '../DocumentView'; -import { Oval } from 'react-loader-spinner'; import Buttons from './GenerativeFillButtons'; import { List } from '../../../../fields/List'; @@ -314,12 +313,13 @@ const GenerativeFill = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addD const adjustImgPositions = () => { if (!parentDoc.current) return; const startY = NumCast(parentDoc.current.y); - const len = childrenDocs.current.length; + const children = DocListCast(parentDoc.current.gen_fill_children); + const len = children.length; let initialYPositions: number[] = []; for (let i = 0; i < len; i++) { initialYPositions.push(startY + i * offsetDistanceY); } - childrenDocs.current.forEach((doc, i) => { + children.forEach((doc, i) => { if (len % 2 === 1) { doc.y = initialYPositions[i] - Math.floor(len / 2) * offsetDistanceY; } else { @@ -368,9 +368,15 @@ const GenerativeFill = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addD data_nativeWidth: result.nativeWidth, data_nativeHeight: result.nativeHeight, }); - newImg.gen_fill_children = new List([]); - childrenDocs.current.push(newImg); - // DocListCast(parentDoc.current.gen_fill_children).push(newImg); + + const parentList = DocListCast(parentDoc.current.gen_fill_children); + if (parentList.length > 0) { + parentList.push(newImg); + parentDoc.current.gen_fill_children = new List(parentList); + } else { + parentDoc.current.gen_fill_children = new List([newImg]); + } + DocUtils.MakeLink(parentDoc.current, newImg, { link_relationship: `Image edit; Prompt: ${input}`, link_displayLine: true }); adjustImgPositions(); @@ -408,7 +414,7 @@ const GenerativeFill = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addD return (
    -

    AI Image Editor

    +

    Image Editor

    { this.setLoading(true); try { - // make this support multiple images let image_urls = await gptImageCall(this.imgDesc); - console.log(image_urls); if (image_urls && image_urls[0]) { const [result] = await Networking.PostToServer('/uploadRemoteImage', { sources: [image_urls[0]] }); const source = Utils.prepend(result.accessPaths.agnostic.client); -- cgit v1.2.3-70-g09d2 From 6913400a92d518989e831926567429c31703e4b4 Mon Sep 17 00:00:00 2001 From: Sophie Zhang Date: Fri, 18 Aug 2023 18:46:27 -0400 Subject: cleanup --- .../views/nodes/formattedText/FormattedTextBox.tsx | 20 -------------------- 1 file changed, 20 deletions(-) (limited to 'src/client/views/nodes/formattedText') diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 2562c48e4..da277826a 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -907,7 +907,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { if (resIndex < newText.length) { const marks = this._editorView?.state.storedMarks ?? []; - // if (!marks) return; this._editorView?.dispatch(this._editorView.state.tr.setStoredMarks(marks).insertText(newText[resIndex]).setStoredMarks(marks)); setTimeout(() => { this.animateRes(resIndex + 1, newText); @@ -915,19 +914,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - // const state = this._editorView?.state; - // if (!state) return; - // const to = state.selection.to; - // const updated = TextSelection.create(state.doc, to, to); - // this._editorView?.dispatch(state.tr.setSelection(updated).insertText('\n', to)); - // this._editorView?.dispatch(this._editorView.state.tr.setStoredMarks(marks).insertText('\nTesting').setStoredMarks(marks)); - // console.log('After ', this._editorView?.state.storedMarks); try { let res = await gptAPICall((this.dataDoc.text as RichTextField)?.Text, GPTCallType.COMPLETION); if (!res) { @@ -1243,13 +1230,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent Date: Fri, 25 Aug 2023 13:42:41 -0400 Subject: changed icon, added gen ai doc link --- src/client/util/RTFMarkup.tsx | 12 +++++++++- src/client/views/ContextMenuItem.tsx | 28 +++++++++++++++------- src/client/views/MainView.tsx | 3 ++- src/client/views/nodes/DocumentView.tsx | 4 ++-- .../views/nodes/formattedText/FormattedTextBox.tsx | 4 ++-- .../nodes/generativeFill/GenerativeFillButtons.tsx | 4 +++- 6 files changed, 39 insertions(+), 16 deletions(-) (limited to 'src/client/views/nodes/formattedText') diff --git a/src/client/util/RTFMarkup.tsx b/src/client/util/RTFMarkup.tsx index a0fc617ab..78069d323 100644 --- a/src/client/util/RTFMarkup.tsx +++ b/src/client/util/RTFMarkup.tsx @@ -3,6 +3,8 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import { MainViewModal } from '../views/MainViewModal'; import { SettingsManager } from './SettingsManager'; +import { Doc } from '../../fields/Doc'; +import { StrCast } from '../../fields/Types'; @observer export class RTFMarkup extends React.Component<{}> { @@ -133,6 +135,14 @@ export class RTFMarkup extends React.Component<{}> { } render() { - return ; + return ( + + ); } } diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx index daa2c152a..445406a89 100644 --- a/src/client/views/ContextMenuItem.tsx +++ b/src/client/views/ContextMenuItem.tsx @@ -11,7 +11,7 @@ export interface OriginalMenuProps { description: string; event: (stuff?: any) => void; undoable?: boolean; - icon: IconProp; //maybe should be optional (icon?) + icon: IconProp | JSX.Element; //maybe should be optional (icon?) closeMenu?: () => void; } @@ -82,19 +82,28 @@ export class ContextMenuItem extends React.Component {this.props.icon ? ( - - - + this.isJSXElement(this.props.icon) ? ( + {this.props.icon} + ) : ( + + + + ) ) : null}
    {this.props.description.replace(':', '')}
    -
    @@ -110,7 +119,7 @@ export class ContextMenuItem extends React.Component 0 ? '90%' : '20%', marginTop, - background: StrCast(Doc.UserDoc().userBackgroundColor) + background: StrCast(Doc.UserDoc().userBackgroundColor), }}> {this._items.map(prop => ( @@ -141,9 +150,10 @@ export class ContextMenuItem extends React.Component
    -
    {submenu} diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index a785ffd42..8565941fd 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -447,6 +447,7 @@ export class MainView extends React.Component { fa.faSortUp, fa.faSortDown, fa.faTable, + fa.faTableColumns, fa.faTh, fa.faThList, fa.faProjectDiagram, @@ -1019,7 +1020,7 @@ export class MainView extends React.Component { - {/* */} + {/* */}
    ); } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 533a047b1..b72864567 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -748,7 +748,7 @@ export class DocumentViewInternal extends DocComponent (this.rootDoc._raiseWhenDragged = this.rootDoc._raiseWhenDragged === undefined ? false : undefined))), icon: 'hand-point-up', }); - !zorders && cm.addItem({ description: 'Z Order...', addDivider: true, noexpand: true, subitems: zorderItems, icon: 'compass' }); + !zorders && cm.addItem({ description: 'Z Order...', addDivider: true, noexpand: true, subitems: zorderItems, icon: 'layer-group' }); } onClicks.push({ description: 'Enter Portal', event: this.makeIntoPortal, icon: 'window-restore' }); @@ -806,7 +806,7 @@ export class DocumentViewInternal extends DocComponent this.props.addDocTab(this.props.Document, (OpenWhere.addRight.toString() + 'KeyValue') as OpenWhere), icon: 'layer-group' }); + constantItems.push({ description: 'Show Metadata', event: () => this.props.addDocTab(this.props.Document, (OpenWhere.addRight.toString() + 'KeyValue') as OpenWhere), icon: 'table-columns' }); cm.addItem({ description: 'General...', noexpand: false, subitems: constantItems, icon: 'question' }); const help = cm.findByDescription('Help...'); diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index da277826a..200d06a0b 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -71,6 +71,7 @@ import { SummaryView } from './SummaryView'; import applyDevTools = require('prosemirror-dev-tools'); import React = require('react'); import { GPTPopup, GPTPopupMode } from '../../pdf/GPTPopup/GPTPopup'; +import { BsMarkdownFill } from 'react-icons/bs'; const translateGoogleApi = require('translate-google-api'); export const GoogleRef = 'googleDocId'; type PullHandler = (exportState: Opt, dataDoc: Doc) => void; @@ -899,7 +900,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent (this.layoutDoc._layout_autoHeight = !this.layoutDoc._layout_autoHeight), icon: this.Document._layout_autoHeight ? 'lock' : 'unlock', }); - optionItems.push({ description: `show markdown options`, event: RTFMarkup.Instance.open, icon: 'text' }); + optionItems.push({ description: `show markdown options`, event: RTFMarkup.Instance.open, icon: }); !options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'eye' }); this._downX = this._downY = Number.NaN; }; @@ -930,7 +931,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - console.log('Generate image from text: ', (this.dataDoc.text as RichTextField)?.Text); GPTPopup.Instance?.setTextAnchor(this.getAnchor(false)); GPTPopup.Instance?.setImgTargetDoc(this.rootDoc); GPTPopup.Instance.addToCollection = this.props.addDocument; diff --git a/src/client/views/nodes/generativeFill/GenerativeFillButtons.tsx b/src/client/views/nodes/generativeFill/GenerativeFillButtons.tsx index 0dfcebea3..10eca358e 100644 --- a/src/client/views/nodes/generativeFill/GenerativeFillButtons.tsx +++ b/src/client/views/nodes/generativeFill/GenerativeFillButtons.tsx @@ -2,7 +2,8 @@ import './GenerativeFillButtons.scss'; import React = require('react'); import ReactLoading from 'react-loading'; import { activeColor } from './generativeFillUtils/generativeFillConstants'; -import { Button, Type } from 'browndash-components'; +import { Button, IconButton, Type } from 'browndash-components'; +import { AiOutlineInfo } from 'react-icons/ai'; interface ButtonContainerProps { getEdit: () => Promise; @@ -35,6 +36,7 @@ const Buttons = ({ loading, getEdit, onReset }: ButtonContainerProps) => { }} /> )} + } onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/features/generativeai/#editing', '_blank')} />
    ); }; -- cgit v1.2.3-70-g09d2 From 9d6c7f8100de3a952d20ad41ab20872737cb909e Mon Sep 17 00:00:00 2001 From: bobzel Date: Sun, 27 Aug 2023 20:25:55 -0400 Subject: lots of cleanup to streamline import orderings (ie packages should not mutually import each other directly or via a chain). change raiseWhenDragged to be keepZWhenDragged and got rid of system wide default. --- src/Utils.ts | 2 +- src/client/DocServer.ts | 15 ++- src/client/apis/youtube/YoutubeBox.tsx | 6 +- src/client/documents/Documents.ts | 10 +- src/client/util/CurrentUserUtils.ts | 11 +- src/client/util/DictationManager.ts | 2 +- src/client/util/DocumentManager.ts | 22 +++- src/client/util/DragManager.ts | 21 +--- src/client/util/DropConverter.ts | 14 +-- src/client/util/GroupManager.tsx | 4 +- src/client/util/GroupMemberView.tsx | 2 +- src/client/util/SearchUtil.ts | 104 ++++++++++++++- src/client/util/SettingsManager.tsx | 89 ++++++------- src/client/util/SharingManager.tsx | 10 +- src/client/util/reportManager/ReportManager.tsx | 4 +- src/client/views/ContextMenuItem.tsx | 6 +- src/client/views/DocumentDecorations.tsx | 11 +- src/client/views/EditableView.tsx | 1 - src/client/views/FilterPanel.tsx | 23 ++-- src/client/views/LightboxView.tsx | 11 +- src/client/views/Main.tsx | 6 +- src/client/views/MainView.tsx | 38 +++--- src/client/views/PropertiesView.tsx | 20 +-- src/client/views/SidebarAnnos.tsx | 4 +- src/client/views/StyleProvider.tsx | 15 ++- src/client/views/UndoStack.tsx | 2 +- .../views/collections/CollectionDockingView.tsx | 4 +- src/client/views/collections/CollectionMenu.tsx | 2 +- .../collections/CollectionStackedTimeline.tsx | 4 +- src/client/views/collections/TabDocView.tsx | 13 +- src/client/views/collections/TreeSort.ts | 6 + src/client/views/collections/TreeView.tsx | 11 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 4 +- src/client/views/linking/LinkPopup.tsx | 3 +- .../views/newlightbox/ButtonMenu/ButtonMenu.tsx | 19 ++- src/client/views/newlightbox/NewLightboxView.tsx | 139 ++++++++++----------- src/client/views/nodes/DocumentView.tsx | 16 ++- src/client/views/nodes/FontIconBox/FontIconBox.tsx | 17 +-- src/client/views/nodes/LinkDocPreview.tsx | 6 +- src/client/views/nodes/LoadingBox.tsx | 6 +- src/client/views/nodes/ScreenshotBox.tsx | 6 +- src/client/views/nodes/VideoBox.tsx | 5 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 24 ++-- .../views/nodes/generativeFill/GenerativeFill.tsx | 33 +++-- src/client/views/nodes/trails/PresBox.tsx | 4 +- src/client/views/pdf/AnchorMenu.tsx | 15 +-- src/client/views/search/IconBar.tsx | 28 +++-- src/client/views/search/SearchBox.tsx | 110 +--------------- src/client/views/topbar/TopBar.tsx | 16 ++- src/client/views/webcam/DashWebRTCVideo.tsx | 6 +- src/fields/Doc.ts | 26 +++- src/fields/RichTextUtils.ts | 10 +- 52 files changed, 492 insertions(+), 494 deletions(-) create mode 100644 src/client/views/collections/TreeSort.ts (limited to 'src/client/views/nodes/formattedText') diff --git a/src/Utils.ts b/src/Utils.ts index 7f83ab8f5..9a94694a2 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -3,10 +3,10 @@ import v5 = require('uuid/v5'); import { ColorState } from 'react-color'; import * as rp from 'request-promise'; import { Socket } from 'socket.io'; +import { DocumentType } from './client/documents/DocumentTypes'; import { Colors } from './client/views/global/globalEnums'; import { Message } from './server/Message'; import Color = require('color'); -import { DocumentType } from './client/documents/DocumentTypes'; export namespace Utils { export let CLICK_TIME = 300; diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index 53c7b857a..5fdea131b 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -1,6 +1,5 @@ import { runInAction } from 'mobx'; import * as rp from 'request-promise'; -import * as io from 'socket.io-client'; import { Doc, DocListCast, Opt } from '../fields/Doc'; import { UpdatingFromServer } from '../fields/DocSymbols'; import { FieldLoader } from '../fields/FieldLoader'; @@ -8,13 +7,13 @@ import { HandleUpdate, Id, Parent } from '../fields/FieldSymbols'; import { ObjectField } from '../fields/ObjectField'; import { RefField } from '../fields/RefField'; import { DocCast, StrCast } from '../fields/Types'; -import MobileInkOverlay from '../mobile/MobileInkOverlay'; +//import MobileInkOverlay from '../mobile/MobileInkOverlay'; import { emptyFunction, Utils } from '../Utils'; import { GestureContent, MessageStore, MobileDocumentUploadContent, MobileInkOverlayContent, UpdateMobileInkOverlayPositionContent, YoutubeQueryTypes } from './../server/Message'; import { DocumentType } from './documents/DocumentTypes'; import { LinkManager } from './util/LinkManager'; import { SerializationHelper } from './util/SerializationHelper'; -import { GestureOverlay } from './views/GestureOverlay'; +//import { GestureOverlay } from './views/GestureOverlay'; /** * This class encapsulates the transfer and cross-client synchronization of @@ -189,17 +188,17 @@ export namespace DocServer { // mobile ink overlay socket events to communicate between mobile view and desktop view _socket.addEventListener('receiveGesturePoints', (content: GestureContent) => { - MobileInkOverlay.Instance.drawStroke(content); + // MobileInkOverlay.Instance.drawStroke(content); }); _socket.addEventListener('receiveOverlayTrigger', (content: MobileInkOverlayContent) => { - GestureOverlay.Instance.enableMobileInkOverlay(content); - MobileInkOverlay.Instance.initMobileInkOverlay(content); + //GestureOverlay.Instance.enableMobileInkOverlay(content); + // MobileInkOverlay.Instance.initMobileInkOverlay(content); }); _socket.addEventListener('receiveUpdateOverlayPosition', (content: UpdateMobileInkOverlayPositionContent) => { - MobileInkOverlay.Instance.updatePosition(content); + // MobileInkOverlay.Instance.updatePosition(content); }); _socket.addEventListener('receiveMobileDocumentUpload', (content: MobileDocumentUploadContent) => { - MobileInkOverlay.Instance.uploadDocument(content); + // MobileInkOverlay.Instance.uploadDocument(content); }); } diff --git a/src/client/apis/youtube/YoutubeBox.tsx b/src/client/apis/youtube/YoutubeBox.tsx index 05879a247..2da9927c0 100644 --- a/src/client/apis/youtube/YoutubeBox.tsx +++ b/src/client/apis/youtube/YoutubeBox.tsx @@ -6,7 +6,7 @@ import { Cast, NumCast, StrCast } from '../../../fields/Types'; import { Utils } from '../../../Utils'; import { DocServer } from '../../DocServer'; import { Docs } from '../../documents/Documents'; -import { DocumentDecorations } from '../../views/DocumentDecorations'; +import { DocumentView } from '../../views/nodes/DocumentView'; import { FieldView, FieldViewProps } from '../../views/nodes/FieldView'; import '../../views/nodes/WebBox.scss'; import './YoutubeBox.scss'; @@ -355,9 +355,9 @@ export class YoutubeBox extends React.Component {
    ); - const frozen = !this.props.isSelected() || DocumentDecorations.Instance.Interacting; + const frozen = !this.props.isSelected() || DocumentView.Interacting; - const classname = 'webBox-cont' + (this.props.isSelected() && Doc.ActiveTool === InkTool.None && !DocumentDecorations.Instance.Interacting ? '-interactive' : ''); + const classname = 'webBox-cont' + (this.props.isSelected() && Doc.ActiveTool === InkTool.None && !DocumentView.Interacting ? '-interactive' : ''); return ( <>
    {content}
    diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 1186446e1..919958b24 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -19,7 +19,6 @@ import { aggregateBounds, OmitKeys, Utils } from '../../Utils'; import { YoutubeBox } from '../apis/youtube/YoutubeBox'; import { DocServer } from '../DocServer'; import { Networking } from '../Network'; -import { DocumentManager } from '../util/DocumentManager'; import { DragManager, dropActionType } from '../util/DragManager'; import { DirectoryImportBox } from '../util/Import & Export/DirectoryImportBox'; import { FollowLinkScript } from '../util/LinkFollower'; @@ -34,12 +33,12 @@ import { ContextMenuProps } from '../views/ContextMenuItem'; import { DFLT_IMAGE_NATIVE_DIM } from '../views/global/globalCssVariables.scss'; import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, ActiveIsInkMask, InkingStroke } from '../views/InkingStroke'; import { AudioBox } from '../views/nodes/AudioBox'; -import { FontIconBox } from '../views/nodes/FontIconBox/FontIconBox'; import { ColorBox } from '../views/nodes/ColorBox'; import { ComparisonBox } from '../views/nodes/ComparisonBox'; import { DataVizBox } from '../views/nodes/DataVizBox/DataVizBox'; import { EquationBox } from '../views/nodes/EquationBox'; import { FieldViewProps } from '../views/nodes/FieldView'; +import { FontIconBox } from '../views/nodes/FontIconBox/FontIconBox'; import { FormattedTextBox } from '../views/nodes/formattedText/FormattedTextBox'; import { FunctionPlotBox } from '../views/nodes/FunctionPlotBox'; import { ImageBox } from '../views/nodes/ImageBox'; @@ -394,7 +393,7 @@ export class DocumentOptions { onPointerUp?: ScriptField; _forceActive?: BOOLt = new BoolInfo('flag to handle pointer events when not selected (or otherwise active)'); _dragOnlyWithinContainer?: BOOLt = new BoolInfo('whether the document should remain in its collection when someone tries to drag and drop it elsewhere'); - _raiseWhenDragged?: BOOLt = new BoolInfo('whether a document is brought to front when dragged.'); + _keepZWhenDragged?: BOOLt = new BoolInfo('whether a document should keep its z-order when dragged.'); childDragAction?: DROPt = new DAInfo('what should happen to the child documents when they are dragged from the collection'); dropConverter?: ScriptField; // script to run when documents are dropped on this Document. dropAction?: DROPt = new DAInfo("what should happen to this document when it's dropped somewhere else"); @@ -1371,7 +1370,7 @@ export namespace DocUtils { export let ActiveRecordings: { props: FieldViewProps; getAnchor: (addAsAnnotation: boolean) => Doc }[] = []; export function MakeLinkToActiveAudio(getSourceDoc: () => Doc | undefined, broadcastEvent = true) { - broadcastEvent && runInAction(() => (DocumentManager.Instance.RecordingEvent = DocumentManager.Instance.RecordingEvent + 1)); + broadcastEvent && runInAction(() => (Doc.RecordingEvent = Doc.RecordingEvent + 1)); return DocUtils.ActiveRecordings.map(audio => { const sourceDoc = getSourceDoc(); return sourceDoc && DocUtils.MakeLink(sourceDoc, audio.getAnchor(true) || audio.props.Document, { link_displayLine: false, link_relationship: 'recording annotation:linked recording', link_description: 'recording timeline' }); @@ -1380,7 +1379,6 @@ export namespace DocUtils { export function MakeLink(source: Doc, target: Doc, linkSettings: { link_relationship?: string; link_description?: string; link_displayLine?: boolean }, id?: string, showPopup?: number[]) { if (!linkSettings.link_relationship) linkSettings.link_relationship = target.type === DocumentType.RTF ? 'Commentary:Comments On' : 'link'; - const sv = DocumentManager.Instance.getDocumentView(source); if (target.doc === Doc.UserDoc()) return undefined; const makeLink = action((linkDoc: Doc, showPopup?: number[]) => { @@ -1840,8 +1838,6 @@ export namespace DocUtils { } if (overwriteDoc) { Doc.removeCurrentlyLoading(overwriteDoc); - // loading doc icons are just labels. so any icon views of loading docs need to be replaced with the proper icon view. - DocumentManager.Instance.getAllDocumentViews(overwriteDoc).forEach(dv => StrCast(dv.rootDoc.layout_fieldKey) === 'layout_icon' && dv.iconify(() => dv.iconify())); } generatedDocuments.push(doc); } diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index ea995e4af..d52e389d6 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -18,7 +18,6 @@ import { CollectionViewType, DocumentType } from "../documents/DocumentTypes"; import { TreeViewType } from "../views/collections/CollectionTreeView"; import { DashboardView } from "../views/DashboardView"; import { Colors } from "../views/global/globalEnums"; -import { MainView } from "../views/MainView"; import { OpenWhere } from "../views/nodes/DocumentView"; import { ButtonType } from "../views/nodes/FontIconBox/FontIconBox"; import { ImportElementBox } from "../views/nodes/importBox/ImportElementBox"; @@ -621,9 +620,9 @@ export class CurrentUserUtils { static freeTools(): Button[] { return [ - { title: "Bottom", icon: "arrows-down-to-line",toolTip: "Make doc topmost", btnType: ButtonType.ClickButton, expertMode: false, funcs: {}, scripts: { onClick: 'sendToBack()'}}, // Only when floating document is selected in freeform - { title: "Top", icon: "arrows-up-to-line", toolTip: "Make doc bottommost", btnType: ButtonType.ClickButton, expertMode: false, funcs: {}, scripts: { onClick: 'bringToFront()'}}, // Only when floating document is selected in freeform - { title: "Z order", icon: "z", toolTip: "Bring Forward on Drag (double click to set for all)",waitForDoubleClickToClick:true, btnType: ButtonType.ToggleButton, expertMode: false, funcs: {}, scripts: { onClick: 'toggleRaiseOnDrag(false, _readOnly_)', onDoubleClick:`{ return toggleRaiseOnDrag(true, _readOnly_)`}}, // Only when floating document is selected in freeform + { title: "Bottom", icon: "arrows-down-to-line",toolTip: "Make doc topmost", btnType: ButtonType.ClickButton, expertMode: false, funcs: {}, scripts: { onClick: 'sendToBack()'}}, // Only when floating document is selected in freeform + { title: "Top", icon: "arrows-up-to-line", toolTip: "Make doc bottommost", btnType: ButtonType.ClickButton, expertMode: false, funcs: {}, scripts: { onClick: 'bringToFront()'}}, // Only when floating document is selected in freeform + { title: "Z order", icon: "z", toolTip: "Keep Z order on Drag", btnType: ButtonType.ToggleButton, expertMode: false, funcs: {}, scripts: { onClick: '{ return toggleRaiseOnDrag(_readOnly_);}'}}, // Only when floating document is selected in freeform ] } static viewTools(): Button[] { @@ -841,7 +840,6 @@ export class CurrentUserUtils { doc.isSystem ?? (doc.isSystem = true); doc.title ?? (doc.title = Doc.CurrentUserEmail); Doc.noviceMode ?? (Doc.noviceMode = true); - doc._raiseWhenDragged ?? (doc._raiseWhenDragged = true); doc._showLabel ?? (doc._showLabel = true); doc.textAlign ?? (doc.textAlign = "left"); doc.activeTool = InkTool.None; @@ -996,8 +994,5 @@ export class CurrentUserUtils { ScriptingGlobals.add(function MySharedDocs() { return Doc.MySharedDocs; }, "document containing all shared Docs"); ScriptingGlobals.add(function IsNoviceMode() { return Doc.noviceMode; }, "is Dash in novice mode"); ScriptingGlobals.add(function toggleComicMode() { Doc.UserDoc().renderStyle = Doc.UserDoc().renderStyle === "comic" ? undefined : "comic"; }, "switches between comic and normal document rendering"); -ScriptingGlobals.add(function createNewPresentation() { return MainView.Instance.createNewPresentation(); }, "creates a new presentation when called"); -ScriptingGlobals.add(function openPresentation(pres:Doc) { return MainView.Instance.openPresentation(pres); }, "creates a new presentation when called"); -ScriptingGlobals.add(function createNewFolder() { return MainView.Instance.createNewFolder(); }, "creates a new folder in myFiles when called"); ScriptingGlobals.add(function importDocument() { return CurrentUserUtils.importDocument(); }, "imports files from device directly into the import sidebar"); ScriptingGlobals.add(function setInkToolDefaults() { Doc.ActiveTool = InkTool.None; }); \ No newline at end of file diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts index 717473aa1..0fd7e840c 100644 --- a/src/client/util/DictationManager.ts +++ b/src/client/util/DictationManager.ts @@ -11,7 +11,7 @@ import { Utils } from '../../Utils'; import { Docs } from '../documents/Documents'; import { DocumentType } from '../documents/DocumentTypes'; import { DictationOverlay } from '../views/DictationOverlay'; -import { DocumentView, OpenWhere, OpenWhereMod } from '../views/nodes/DocumentView'; +import { DocumentView, OpenWhere } from '../views/nodes/DocumentView'; import { SelectionManager } from './SelectionManager'; import { UndoManager } from './UndoManager'; diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 5b627c2f3..c2827dac7 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -1,4 +1,4 @@ -import { action, computed, observable, ObservableSet } from 'mobx'; +import { action, computed, observable, ObservableSet, observe, reaction } from 'mobx'; import { Doc, DocListCast, Opt } from '../../fields/Doc'; import { AclAdmin, AclEdit, Animation } from '../../fields/DocSymbols'; import { Id } from '../../fields/FieldSymbols'; @@ -23,7 +23,6 @@ export class DocumentManager { //global holds all of the nodes (regardless of which collection they're in) @observable _documentViews = new Set(); @observable public LinkAnchorBoxViews: DocumentView[] = []; - @observable public RecordingEvent = 0; @observable public LinkedDocumentViews: { a: DocumentView; b: DocumentView; l: Doc }[] = []; @computed public get DocumentViews() { return Array.from(this._documentViews).filter(view => !(view.ComponentView instanceof KeyValueBox) && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(view.docViewPath))); @@ -41,7 +40,22 @@ export class DocumentManager { } //private constructor so no other class can create a nodemanager - private constructor() {} + private constructor() { + if (!Doc.CurrentlyLoading) Doc.CurrentlyLoading = []; + observe(Doc.CurrentlyLoading, change => { + // watch CurrentlyLoading-- when something is loaded, it's removed from the list and we have to update its icon if it were iconified since LoadingBox icons are different than the media they become + switch (change.type as any) { + case 'update': + break; + case 'remove': + // DocumentManager.Instance.getAllDocumentViews(change as any).forEach(dv => StrCast(dv.rootDoc.layout_fieldKey) === 'layout_icon' && dv.iconify(() => dv.iconify())); + break; + case 'splice': + (change as any).removed.forEach((doc: Doc) => DocumentManager.Instance.getAllDocumentViews(doc).forEach(dv => StrCast(dv.rootDoc.layout_fieldKey) === 'layout_icon' && dv.iconify(() => dv.iconify()))); + break; + } + }); + } private _viewRenderedCbs: { doc: Doc; func: (dv: DocumentView) => any }[] = []; public AddViewRenderedCb = (doc: Opt, func: (dv: DocumentView) => any) => { @@ -310,7 +324,7 @@ export class DocumentManager { if (viewSpec && docView) { if (docView.ComponentView instanceof FormattedTextBox) docView.ComponentView?.focus(viewSpec, options); PresBox.restoreTargetDocView(docView, viewSpec, options.zoomTime ?? 500); - Doc.linkFollowHighlight(viewSpec ? [docView.rootDoc, viewSpec]: docView.rootDoc, undefined, options.effect); + Doc.linkFollowHighlight(viewSpec ? [docView.rootDoc, viewSpec] : docView.rootDoc, undefined, options.effect); if (options.playAudio) DocumentManager.playAudioAnno(docView.rootDoc); if (options.toggleTarget && (!options.didMove || docView.rootDoc.hidden)) docView.rootDoc.hidden = !docView.rootDoc.hidden; if (options.effect) docView.rootDoc[Animation] = options.effect; diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 489c9df4a..05da5ebed 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -61,12 +61,6 @@ export namespace DragManager { export let StartWindowDrag: Opt<(e: { pageX: number; pageY: number }, dragDocs: Doc[], finishDrag?: (aborted: boolean) => void) => void>; export let CompleteWindowDrag: Opt<(aborted: boolean) => void>; - export function GetRaiseWhenDragged() { - return BoolCast(Doc.UserDoc()._raiseWhenDragged); - } - export function SetRaiseWhenDragged(val: boolean) { - Doc.UserDoc()._raiseWhenDragged = val; - } export function Root() { const root = document.getElementById('root'); if (!root) { @@ -605,18 +599,9 @@ export namespace DragManager { } } -ScriptingGlobals.add(function toggleRaiseOnDrag(forAllDocs: boolean, readOnly?: boolean) { +ScriptingGlobals.add(function toggleRaiseOnDrag(readOnly?: boolean) { if (readOnly) { - if (SelectionManager.Views().length) - return SelectionManager.Views().some(dv => dv.rootDoc.raiseWhenDragged) - ? Colors.MEDIUM_BLUE - : SelectionManager.Views().some(dv => dv.rootDoc.raiseWhenDragged === false) - ? 'transparent' - : DragManager.GetRaiseWhenDragged() - ? Colors.MEDIUM_BLUE_ALT - : Colors.LIGHT_BLUE; - return DragManager.GetRaiseWhenDragged() ? Colors.MEDIUM_BLUE_ALT : 'transparent'; + return SelectionManager.Views().some(dv => dv.rootDoc.keepZWhenDragged); } - if (!forAllDocs) SelectionManager.Views().map(dv => (dv.rootDoc.raiseWhenDragged ? (dv.rootDoc.raiseWhenDragged = undefined) : dv.rootDoc.raiseWhenDragged === false ? (dv.rootDoc.raiseWhenDragged = true) : (dv.rootDoc.raiseWhenDragged = false))); - else DragManager.SetRaiseWhenDragged(!DragManager.GetRaiseWhenDragged()); + SelectionManager.Views().map(dv => (dv.rootDoc.keepZWhenDragged = !dv.rootDoc.keepZWhenDragged)); }); diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts index f235be192..dbdf580cd 100644 --- a/src/client/util/DropConverter.ts +++ b/src/client/util/DropConverter.ts @@ -1,15 +1,15 @@ -import { DragManager } from './DragManager'; import { Doc, DocListCast, Opt } from '../../fields/Doc'; -import { DocumentType } from '../documents/DocumentTypes'; import { ObjectField } from '../../fields/ObjectField'; -import { StrCast, Cast } from '../../fields/Types'; -import { Docs } from '../documents/Documents'; -import { ScriptField, ComputedField } from '../../fields/ScriptField'; import { RichTextField } from '../../fields/RichTextField'; -import { ImageField } from '../../fields/URLField'; -import { ScriptingGlobals } from './ScriptingGlobals'; import { listSpec } from '../../fields/Schema'; +import { ScriptField } from '../../fields/ScriptField'; +import { Cast, StrCast } from '../../fields/Types'; +import { ImageField } from '../../fields/URLField'; +import { Docs } from '../documents/Documents'; +import { DocumentType } from '../documents/DocumentTypes'; import { ButtonType } from '../views/nodes/FontIconBox/FontIconBox'; +import { DragManager } from './DragManager'; +import { ScriptingGlobals } from './ScriptingGlobals'; export function MakeTemplate(doc: Doc, first: boolean = true, rename: Opt = undefined, templateField: string = '') { if (templateField) Doc.GetProto(doc).title = templateField; /// the title determines which field is being templated diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx index c79894032..8973306bf 100644 --- a/src/client/util/GroupManager.tsx +++ b/src/client/util/GroupManager.tsx @@ -282,7 +282,7 @@ export class GroupManager extends React.Component<{}> { */ private get groupCreationModal() { const contents = ( -
    +

    New Group @@ -367,7 +367,7 @@ export class GroupManager extends React.Component<{}> { const groups = this.groupSort === 'ascending' ? this.allGroups.sort(sortGroups) : this.groupSort === 'descending' ? this.allGroups.sort(sortGroups).reverse() : this.allGroups; return ( -

    +
    {this.groupCreationModal} {this.currentGroup ? (this.currentGroup = undefined))} /> : null}
    diff --git a/src/client/util/GroupMemberView.tsx b/src/client/util/GroupMemberView.tsx index 535d8ccc2..7de0f336f 100644 --- a/src/client/util/GroupMemberView.tsx +++ b/src/client/util/GroupMemberView.tsx @@ -29,7 +29,7 @@ export class GroupMemberView extends React.Component { const hasEditAccess = GroupManager.Instance.hasEditAccess(this.props.group); return !this.props.group ? null : ( -
    +
    , query: string) { + const blockedTypes = [DocumentType.PRESELEMENT, DocumentType.CONFIG, DocumentType.KVP, DocumentType.FONTICON, DocumentType.BUTTON, DocumentType.SCRIPTING]; + const blockedKeys = [ + 'x', + 'y', + 'proto', + 'width', + 'layout_autoHeight', + 'acl-Override', + 'acl-Guest', + 'embedContainer', + 'zIndex', + 'height', + 'text_scrollHeight', + 'text_height', + 'cloneFieldFilter', + 'isDataDoc', + 'text_annotations', + 'dragFactory_count', + 'text_noTemplate', + 'proto_embeddings', + 'isSystem', + 'layout_fieldKey', + 'isBaseProto', + 'xMargin', + 'yMargin', + 'links', + 'layout', + 'layout_keyValue', + 'layout_fitWidth', + 'type_collection', + 'title_custom', + 'freeform_panX', + 'freeform_panY', + 'freeform_scale', + ]; + query = query.toLowerCase(); + + const results = new Map(); + if (rootDoc) { + const docs = DocListCast(rootDoc[Doc.LayoutFieldKey(rootDoc)]); + const docIDs: String[] = []; + SearchUtil.foreachRecursiveDoc(docs, (depth: number, doc: Doc) => { + const dtype = StrCast(doc.type) as DocumentType; + if (dtype && !blockedTypes.includes(dtype) && !docIDs.includes(doc[Id]) && depth >= 0) { + const hlights = new Set(); + SearchUtil.documentKeys(doc).forEach( + key => + Field.toString(doc[key] as Field) + .toLowerCase() + .includes(query) && hlights.add(key) + ); + blockedKeys.forEach(key => hlights.delete(key)); + + if (Array.from(hlights.keys()).length > 0) { + results.set(doc, Array.from(hlights.keys())); + } + } + docIDs.push(doc[Id]); + }); + } + return results; + } + /** + * @param {Doc} doc - doc for which keys are returned + * + * This method returns a list of a document doc's keys. + */ + export function documentKeys(doc: Doc) { + const keys: { [key: string]: boolean } = {}; + Doc.GetAllPrototypes(doc).map(proto => Object.keys(proto).forEach(key => (keys[key] = false))); + return Array.from(Object.keys(keys)); + } + + /** + * @param {Doc[]} docs - docs to be searched through recursively + * @param {number, Doc => void} func - function to be called on each doc + * + * This method iterates through an array of docs and all docs within those docs, calling + * the function func on each doc. + */ + export function foreachRecursiveDoc(docs: Doc[], func: (depth: number, doc: Doc) => void) { + let newarray: Doc[] = []; + var depth = 0; + const visited: Doc[] = []; + while (docs.length > 0) { + newarray = []; + docs.filter(d => d && !visited.includes(d)).forEach(d => { + visited.push(d); + const fieldKey = Doc.LayoutFieldKey(d); + const annos = !Field.toString(Doc.LayoutField(d) as Field).includes('CollectionView'); + const data = d[annos ? fieldKey + '_annotations' : fieldKey]; + data && newarray.push(...DocListCast(data)); + const sidebar = d[fieldKey + '_sidebar']; + sidebar && newarray.push(...DocListCast(sidebar)); + func(depth, d); + }); + docs = newarray; + depth++; + } + } export interface IdSearchResult { ids: string[]; lines: string[][]; diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx index bb370e1a4..720badd40 100644 --- a/src/client/util/SettingsManager.tsx +++ b/src/client/util/SettingsManager.tsx @@ -13,7 +13,6 @@ import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager import { DocServer } from '../DocServer'; import { Networking } from '../Network'; import { MainViewModal } from '../views/MainViewModal'; -import { FontIconBox } from '../views/nodes/FontIconBox/FontIconBox'; import { GroupManager } from './GroupManager'; import './SettingsManager.scss'; import { undoBatch } from './UndoManager'; @@ -67,15 +66,15 @@ export class SettingsManager extends React.Component<{}> { } }; - @computed get userColor() { + @computed public static get userColor() { return StrCast(Doc.UserDoc().userColor); } - @computed get userVariantColor() { + @computed public static get userVariantColor() { return StrCast(Doc.UserDoc().userVariantColor); } - @computed get userBackgroundColor() { + @computed public static get userBackgroundColor() { return StrCast(Doc.UserDoc().userBackgroundColor); } @@ -150,35 +149,35 @@ export class SettingsManager extends React.Component<{}> { val: scheme, }))} dropdownType={DropdownType.SELECT} - color={this.userColor} + color={SettingsManager.userColor} fillWidth /> {userTheme === ColorScheme.Custom && ( } - selectedColor={this.userColor} + selectedColor={SettingsManager.userColor} setSelectedColor={this.switchUserColor} setFinalColor={this.switchUserColor} /> } - selectedColor={this.userBackgroundColor} + selectedColor={SettingsManager.userBackgroundColor} setSelectedColor={this.switchUserBackgroundColor} setFinalColor={this.switchUserBackgroundColor} /> } - selectedColor={this.userVariantColor} + selectedColor={SettingsManager.userVariantColor} setSelectedColor={this.switchUserVariantColor} setFinalColor={this.switchUserVariantColor} /> @@ -198,7 +197,7 @@ export class SettingsManager extends React.Component<{}> { onClick={e => (Doc.UserDoc().layout_showTitle = Doc.UserDoc().layout_showTitle ? undefined : 'author_date')} toggleStatus={Doc.UserDoc().layout_showTitle !== undefined} size={Size.XSMALL} - color={this.userColor} + color={SettingsManager.userColor} /> { onClick={e => (Doc.UserDoc()['documentLinksButton-fullMenu'] = !Doc.UserDoc()['documentLinksButton-fullMenu'])} toggleStatus={BoolCast(Doc.UserDoc()['documentLinksButton-fullMenu'])} size={Size.XSMALL} - color={this.userColor} + color={SettingsManager.userColor} /> FontIconBox.SetShowLabels(!FontIconBox.GetShowLabels())} - toggleStatus={FontIconBox.GetShowLabels()} + onClick={e => Doc.SetShowIconLabels(!Doc.GetShowIconLabels())} + toggleStatus={Doc.GetShowIconLabels()} size={Size.XSMALL} - color={this.userColor} + color={SettingsManager.userColor} /> FontIconBox.SetRecognizeGestures(!FontIconBox.GetRecognizeGestures())} - toggleStatus={FontIconBox.GetRecognizeGestures()} + onClick={e => Doc.SetRecognizeGestures(!Doc.GetRecognizeGestures())} + toggleStatus={Doc.GetRecognizeGestures()} size={Size.XSMALL} - color={this.userColor} + color={SettingsManager.userColor} /> { onClick={e => (Doc.UserDoc().activeInkHideTextLabels = !Doc.UserDoc().activeInkHideTextLabels)} toggleStatus={BoolCast(Doc.UserDoc().activeInkHideTextLabels)} size={Size.XSMALL} - color={this.userColor} + color={SettingsManager.userColor} /> { onClick={e => (Doc.UserDoc().openInkInLightbox = !Doc.UserDoc().openInkInLightbox)} toggleStatus={BoolCast(Doc.UserDoc().openInkInLightbox)} size={Size.XSMALL} - color={this.userColor} + color={SettingsManager.userColor} /> { onClick={e => (Doc.UserDoc().showLinkLines = !Doc.UserDoc().showLinkLines)} toggleStatus={BoolCast(Doc.UserDoc().showLinkLines)} size={Size.XSMALL} - color={this.userColor} + color={SettingsManager.userColor} />
    ); @@ -284,7 +283,7 @@ export class SettingsManager extends React.Component<{}> {
    {/* */} - {}} /> + {}} /> { return { @@ -301,7 +300,7 @@ export class SettingsManager extends React.Component<{}> { setSelectedVal={val => { this.changeFontFamily(val as string); }} - color={this.userColor} + color={SettingsManager.userColor} fillWidth /> @@ -329,12 +328,12 @@ export class SettingsManager extends React.Component<{}> { @computed get passwordContent() { return (
    - this.changeVal(val as string, 'curr')} fillWidth password /> - this.changeVal(val as string, 'new')} fillWidth password /> - this.changeVal(val as string, 'conf')} fillWidth password /> + this.changeVal(val as string, 'curr')} fillWidth password /> + this.changeVal(val as string, 'new')} fillWidth password /> + this.changeVal(val as string, 'conf')} fillWidth password /> {!this.passwordResultText ? null :
    {this.passwordResultText}
    } -
    ); } @@ -394,10 +393,10 @@ export class SettingsManager extends React.Component<{}> { dropdownType={DropdownType.SELECT} type={Type.TERT} placement="bottom-start" - color={this.userColor} + color={SettingsManager.userColor} fillWidth /> - +
    Freeform Navigation @@ -422,15 +421,21 @@ export class SettingsManager extends React.Component<{}> { dropdownType={DropdownType.SELECT} type={Type.TERT} placement="bottom-start" - color={this.userColor} + color={SettingsManager.userColor} />
    Permissions
    -
    @@ -449,7 +454,7 @@ export class SettingsManager extends React.Component<{}> { ]; return (
    -
    +
    {tabs.map(tab => { const isActive = this.activeTab === tab.title; @@ -457,8 +462,8 @@ export class SettingsManager extends React.Component<{}> {
    (this.activeTab = tab.title))}> @@ -469,19 +474,19 @@ export class SettingsManager extends React.Component<{}> {
    -
    {DashVersion}
    -
    +
    {DashVersion}
    +
    {Doc.CurrentUserEmail}
    -
    -
    -
    +
    {tabs.map(tab => (
    {tab.ele} diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx index 81ddeb9e3..9a9097bf7 100644 --- a/src/client/util/SharingManager.tsx +++ b/src/client/util/SharingManager.tsx @@ -18,10 +18,10 @@ import { DictationOverlay } from '../views/DictationOverlay'; import { MainViewModal } from '../views/MainViewModal'; import { DocumentView } from '../views/nodes/DocumentView'; import { TaskCompletionBox } from '../views/nodes/TaskCompletedBox'; -import { SearchBox } from '../views/search/SearchBox'; import { DocumentManager } from './DocumentManager'; import { GroupManager, UserOptions } from './GroupManager'; import { GroupMemberView } from './GroupMemberView'; +import { SearchUtil } from './SearchUtil'; import { SelectionManager } from './SelectionManager'; import { SettingsManager } from './SettingsManager'; import './SharingManager.scss'; @@ -446,7 +446,7 @@ export class SharingManager extends React.Component<{}> { if (this.myDocAcls) { const newDocs: Doc[] = []; - SearchBox.foreachRecursiveDoc(docs, (depth, doc) => newDocs.push(doc)); + SearchUtil.foreachRecursiveDoc(docs, (depth, doc) => newDocs.push(doc)); docs = newDocs.filter(doc => GetEffectiveAcl(doc) === AclAdmin); } @@ -527,10 +527,10 @@ export class SharingManager extends React.Component<{}> { const permissions = uniform ? StrCast(targetDoc?.[groupKey]) : '-multiple-'; return !permissions ? null : ( -
    +
    {StrCast(group.title)}
      - {group instanceof Doc ? } size={Size.XSMALL} color={SettingsManager.Instance.userColor} onClick={action(() => (GroupManager.Instance.currentGroup = group))} /> : null} + {group instanceof Doc ? } size={Size.XSMALL} color={SettingsManager.userColor} onClick={action(() => (GroupManager.Instance.currentGroup = group))} /> : null}
    {admin || this.myDocAcls ? ( diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx index c194ede32..a2f9de9ab 100644 --- a/src/client/views/topbar/TopBar.tsx +++ b/src/client/views/topbar/TopBar.tsx @@ -1,13 +1,14 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Button, IconButton, Size, Type, isDark } from 'browndash-components'; +import { Button, IconButton, isDark, Size, Type } from 'browndash-components'; import { action, computed, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { FaBug, FaCamera, FaStamp } from 'react-icons/fa'; +import { FaBug, FaCamera } from 'react-icons/fa'; import { Doc, DocListCast } from '../../../fields/Doc'; import { AclAdmin, DashVersion } from '../../../fields/DocSymbols'; import { StrCast } from '../../../fields/Types'; import { GetEffectiveAcl } from '../../../fields/util'; +import { CurrentUserUtils } from '../../util/CurrentUserUtils'; import { DocumentManager } from '../../util/DocumentManager'; import { PingManager } from '../../util/PingManager'; import { ReportManager } from '../../util/reportManager/ReportManager'; @@ -15,13 +16,12 @@ import { ServerStats } from '../../util/ServerStats'; import { SettingsManager } from '../../util/SettingsManager'; import { SharingManager } from '../../util/SharingManager'; import { UndoManager } from '../../util/UndoManager'; +import { CollectionDockingView } from '../collections/CollectionDockingView'; import { ContextMenu } from '../ContextMenu'; import { DashboardView } from '../DashboardView'; -import { MainView } from '../MainView'; -import { CollectionDockingView } from '../collections/CollectionDockingView'; import { Colors } from '../global/globalEnums'; +import { DocumentView } from '../nodes/DocumentView'; import './TopBar.scss'; -import { CurrentUserUtils } from '../../util/CurrentUserUtils'; /** * ABOUT: This is the topbar in Dash, which included the current Dashboard as well as access to information on the user @@ -43,7 +43,7 @@ export class TopBar extends React.Component { return StrCast(Doc.UserDoc().userVariantColor, Colors.MEDIUM_BLUE); } @computed get backgroundColor() { - return PingManager.Instance.IsBeating ? SettingsManager.Instance.userBackgroundColor : Colors.MEDIUM_GRAY; + return PingManager.Instance.IsBeating ? SettingsManager.userBackgroundColor : Colors.MEDIUM_GRAY; } @observable happyHeart: boolean = PingManager.Instance.IsBeating; @@ -76,9 +76,7 @@ export class TopBar extends React.Component { dash
    )} - {Doc.ActiveDashboard && ( -
    ); } diff --git a/src/client/views/webcam/DashWebRTCVideo.tsx b/src/client/views/webcam/DashWebRTCVideo.tsx index 02e44a793..524492226 100644 --- a/src/client/views/webcam/DashWebRTCVideo.tsx +++ b/src/client/views/webcam/DashWebRTCVideo.tsx @@ -6,8 +6,8 @@ import { observer } from 'mobx-react'; import { Doc } from '../../../fields/Doc'; import { InkTool } from '../../../fields/InkField'; import '../../views/nodes/WebBox.scss'; -import { DocumentDecorations } from '../DocumentDecorations'; import { CollectionFreeFormDocumentViewProps } from '../nodes/CollectionFreeFormDocumentView'; +import { DocumentView } from '../nodes/DocumentView'; import { FieldView, FieldViewProps } from '../nodes/FieldView'; import './DashWebRTCVideo.scss'; import { hangup, initialize, refreshVideos } from './WebCamLogic'; @@ -71,8 +71,8 @@ export class DashWebRTCVideo extends React.Component ); - const frozen = !this.props.isSelected() || DocumentDecorations.Instance.Interacting; - const classname = 'webBox-cont' + (this.props.isSelected() && Doc.ActiveTool === InkTool.None && !DocumentDecorations.Instance.Interacting ? '-interactive' : ''); + const frozen = !this.props.isSelected() || DocumentView.Interacting; + const classname = 'webBox-cont' + (this.props.isSelected() && Doc.ActiveTool === InkTool.None && !DocumentView.Interacting ? '-interactive' : ''); return ( <> diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 4ad38e7fc..f17e10d9e 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -47,7 +47,7 @@ import { FieldId, RefField } from './RefField'; import { RichTextField } from './RichTextField'; import { listSpec } from './Schema'; import { ComputedField, ScriptField } from './ScriptField'; -import { Cast, DocCast, FieldValue, NumCast, StrCast, ToConstructor } from './Types'; +import { BoolCast, Cast, DocCast, FieldValue, NumCast, StrCast, ToConstructor } from './Types'; import { AudioField, CsvField, ImageField, PdfField, VideoField, WebField } from './URLField'; import { containedFieldChangedHandler, deleteProperty, GetEffectiveAcl, getField, getter, makeEditable, makeReadOnly, normalizeEmail, setter, SharingPermissions } from './util'; import JSZip = require('jszip'); @@ -156,7 +156,26 @@ export function updateCachedAcls(doc: Doc) { @scriptingGlobal @Deserializable('Doc', updateCachedAcls, ['id']) export class Doc extends RefField { - @observable public static CurrentlyLoading: Doc[]; + @observable public static RecordingEvent = 0; + + // this isn't really used at the moment, but is intended to indicate whether ink stroke are passed through a gesture recognizer + static GetRecognizeGestures() { + return BoolCast(Doc.UserDoc()._recognizeGestures); + } + static SetRecognizeGestures(show: boolean) { + Doc.UserDoc()._recognizeGestures = show; + } + + // + // This controls whether fontIconButtons will display labels under their icons or not + // + static GetShowIconLabels() { + return BoolCast(Doc.UserDoc()._showLabel); + } + static SetShowIconLabels(show: boolean) { + Doc.UserDoc()._showLabel = show; + } + @observable public static CurrentlyLoading: Doc[] = []; // this assignment doesn't work. the actual assignment happens in DocumentManager's constructor // removes from currently loading display @action public static removeCurrentlyLoading(doc: Doc) { @@ -169,9 +188,6 @@ export class Doc extends RefField { // adds doc to currently loading display @action public static addCurrentlyLoading(doc: Doc) { - if (!Doc.CurrentlyLoading) { - Doc.CurrentlyLoading = []; - } if (Doc.CurrentlyLoading.indexOf(doc) === -1) { Doc.CurrentlyLoading.push(doc); } diff --git a/src/fields/RichTextUtils.ts b/src/fields/RichTextUtils.ts index 24cd078f2..5ecf25e08 100644 --- a/src/fields/RichTextUtils.ts +++ b/src/fields/RichTextUtils.ts @@ -2,20 +2,20 @@ import { AssertionError } from 'assert'; import { docs_v1 } from 'googleapis'; import { Fragment, Mark, Node } from 'prosemirror-model'; import { sinkListItem } from 'prosemirror-schema-list'; -import { Utils, DashColor } from '../Utils'; -import { Docs, DocUtils } from '../client/documents/Documents'; -import { schema } from '../client/views/nodes/formattedText/schema_rts'; +import { EditorState, TextSelection, Transaction } from 'prosemirror-state'; +import { GoogleApiClientUtils } from '../client/apis/google_docs/GoogleApiClientUtils'; import { GooglePhotos } from '../client/apis/google_docs/GooglePhotosClientUtils'; import { DocServer } from '../client/DocServer'; +import { Docs, DocUtils } from '../client/documents/Documents'; import { Networking } from '../client/Network'; import { FormattedTextBox } from '../client/views/nodes/formattedText/FormattedTextBox'; +import { schema } from '../client/views/nodes/formattedText/schema_rts'; +import { DashColor, Utils } from '../Utils'; import { Doc, Opt } from './Doc'; import { Id } from './FieldSymbols'; import { RichTextField } from './RichTextField'; import { Cast, StrCast } from './Types'; import Color = require('color'); -import { EditorState, TextSelection, Transaction } from 'prosemirror-state'; -import { GoogleApiClientUtils } from '../client/apis/google_docs/GoogleApiClientUtils'; export namespace RichTextUtils { const delimiter = '\n'; -- cgit v1.2.3-70-g09d2 From 275e6e699c2fe7665dbe05aeb58fca9337271f28 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 4 Sep 2023 12:33:32 -0400 Subject: fixed undoing highlighting text. --- src/client/views/nodes/formattedText/FormattedTextBox.tsx | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'src/client/views/nodes/formattedText') diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index bd969b527..c9481482f 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -38,7 +38,7 @@ import { LinkManager } from '../../../util/LinkManager'; import { RTFMarkup } from '../../../util/RTFMarkup'; import { SelectionManager } from '../../../util/SelectionManager'; import { SnappingManager } from '../../../util/SnappingManager'; -import { undoBatch, UndoManager } from '../../../util/UndoManager'; +import { undoable, undoBatch, UndoManager } from '../../../util/UndoManager'; import { CollectionFreeFormView } from '../../collections/collectionFreeForm/CollectionFreeFormView'; import { CollectionStackingView } from '../../collections/CollectionStackingView'; import { CollectionTreeView } from '../../collections/CollectionTreeView'; @@ -274,10 +274,13 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - this._editorView?.state && RichTextMenu.Instance.setHighlight(color); - return undefined; - }); + AnchorMenu.Instance.Highlight = undoable( + action((color: string, isLinkButton: boolean) => { + this._editorView?.state && RichTextMenu.Instance.setHighlight(color); + return undefined; + }), + 'highlght text' + ); AnchorMenu.Instance.onMakeAnchor = () => this.getAnchor(true); AnchorMenu.Instance.StartCropDrag = unimplementedFunction; /** -- cgit v1.2.3-70-g09d2 From 34a29cccdb65c6e2d4b1b4fd83c78a70cdfcb686 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 4 Sep 2023 15:54:22 -0400 Subject: improved setting font size on lists. --- .../views/nodes/formattedText/RichTextMenu.tsx | 29 ++++++++++++++++------ 1 file changed, 21 insertions(+), 8 deletions(-) (limited to 'src/client/views/nodes/formattedText') diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index 9c46459b0..e3ac4fb9d 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -21,6 +21,7 @@ import { updateBullets } from './ProsemirrorExampleTransfer'; import './RichTextMenu.scss'; import { schema } from './schema_rts'; import { EquationBox } from '../EquationBox'; +import { numberRange } from '../../../../Utils'; const { toggleMark } = require('prosemirror-commands'); @observer @@ -149,19 +150,31 @@ export class RichTextMenu extends AntimodeMenu { setMark = (mark: Mark, state: EditorState, dispatch: any, dontToggle: boolean = false) => { if (mark) { - const node = (state.selection as NodeSelection).node; + const liFirst = numberRange(state.selection.$from.depth + 1).find(i => state.selection.$from.node(i)?.type === state.schema.nodes.list_item); + const liTo = numberRange(state.selection.$to.depth + 1).find(i => state.selection.$to.node(i)?.type === state.schema.nodes.list_item); + const olFirst = numberRange(state.selection.$from.depth + 1).find(i => state.selection.$from.node(i)?.type === state.schema.nodes.ordered_list); + const nodeOl = (liFirst && liTo && state.selection.$from.node(liFirst) !== state.selection.$to.node(liTo) && olFirst) || (!liFirst && !liTo && olFirst); + const newPos = nodeOl ? numberRange(state.selection.from).findIndex(i => state.doc.nodeAt(i)?.type === state.schema.nodes.ordered_list) : state.selection.from; + const node = (state.selection as NodeSelection).node ?? (newPos >= 0 ? state.doc.nodeAt(newPos) : undefined); if (node?.type === schema.nodes.ordered_list) { let attrs = node.attrs; if (mark.type === schema.marks.pFontFamily) attrs = { ...attrs, fontFamily: mark.attrs.family }; if (mark.type === schema.marks.pFontSize) attrs = { ...attrs, fontSize: mark.attrs.fontSize }; if (mark.type === schema.marks.pFontColor) attrs = { ...attrs, fontColor: mark.attrs.color }; - const tr = updateBullets(state.tr.setNodeMarkup(state.selection.from, node.type, attrs), state.schema); - dispatch(tr.setSelection(new NodeSelection(tr.doc.resolve(state.selection.from)))); - } else if (dontToggle) { - const tr = state.tr.addMark(state.selection.from, state.selection.to, mark); - dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(state.selection.from), tr.doc.resolve(state.selection.to)))); // bcz: need to redo the selection because ctrl-a selections disappear otherwise - } else { - toggleMark(mark.type, mark.attrs)(state, dispatch); + const tr = updateBullets(state.tr.setNodeMarkup(newPos, node.type, attrs), state.schema); + dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(state.selection.from), tr.doc.resolve(state.selection.to)))); + } + { + const state = this.view?.state; + const tr = this.view?.state.tr; + if (tr && state) { + if (dontToggle) { + tr.addMark(state.selection.from, state.selection.to, mark); + dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(state.selection.from), tr.doc.resolve(state.selection.to)))); // bcz: need to redo the selection because ctrl-a selections disappear otherwise + } else { + toggleMark(mark.type, mark.attrs)(state, dispatch); + } + } } } }; -- cgit v1.2.3-70-g09d2 From dc92e167391988b63e3ff15e67bcfad6df21c044 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 6 Sep 2023 13:53:32 -0400 Subject: fixed up audio annotation to add dictation to sidebar note. --- src/client/util/SearchUtil.ts | 4 +- src/client/views/StyleProvider.tsx | 2 +- src/client/views/global/globalScripts.ts | 4 +- src/client/views/nodes/DocumentView.tsx | 33 +++++++++++------ .../views/nodes/formattedText/FormattedTextBox.tsx | 43 +++++++++++++++------- src/client/views/pdf/AnchorMenu.tsx | 18 ++++----- src/fields/Doc.ts | 2 + src/fields/DocSymbols.ts | 1 + 8 files changed, 67 insertions(+), 40 deletions(-) (limited to 'src/client/views/nodes/formattedText') diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts index 64aa7ba9b..560d6b30f 100644 --- a/src/client/util/SearchUtil.ts +++ b/src/client/util/SearchUtil.ts @@ -57,8 +57,8 @@ export namespace SearchUtil { const hlights = new Set(); SearchUtil.documentKeys(doc).forEach( key => - Field.toString(doc[key] as Field) - .toLowerCase() + (Field.toString(doc[key] as Field) + Field.toScriptString(doc[key] as Field)) + .toLowerCase() // .includes(query) && hlights.add(key) ); blockedKeys.forEach(key => hlights.delete(key)); diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index a9e4ac17d..cdf104a18 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -295,7 +295,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt { const audioAnnoState = (doc: Doc) => StrCast(doc.audioAnnoState, 'stopped'); const audioAnnosCount = (doc: Doc) => StrListCast(doc[Doc.LayoutFieldKey(doc) + '_audioAnnotations']).length; - if (!doc || props?.renderDepth === -1 || (!audioAnnosCount(doc) && audioAnnoState(doc) === 'stopped')) return null; + if (!doc || props?.renderDepth === -1 || !audioAnnosCount(doc)) return null; const audioIconColors: { [key: string]: string } = { recording: 'red', playing: 'green', stopped: 'blue' }; return ( {StrListCast(doc[Doc.LayoutFieldKey(doc) + '_audioAnnotations_text']).lastElement()}
    }> diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts index 38bf1042d..9b9cc6d24 100644 --- a/src/client/views/global/globalScripts.ts +++ b/src/client/views/global/globalScripts.ts @@ -182,8 +182,8 @@ ScriptingGlobals.add(function toggleCharStyle(charStyle: attrname, checkResult?: toggle: () => editorView?.state && RichTextMenu.Instance.changeListType(list) }]); // prettier-ignore const attrs:attrfuncs[] = [ - ['dictation', { checkResult: () => textView?._recording ? true:false, - toggle: () => textView && runInAction(() => (textView._recording = !textView._recording)) }], + ['dictation', { checkResult: () => textView?._recordingDictation ? true:false, + toggle: () => textView && runInAction(() => (textView._recordingDictation = !textView._recordingDictation)) }], ['noAutoLink',{ checkResult: () => (editorView ? RichTextMenu.Instance.noAutoLink : false), toggle: () => editorView && RichTextMenu.Instance?.toggleNoAutoLinkAnchor()}], ['bold', { checkResult: () => (editorView ? RichTextMenu.Instance.bold : (Doc.UserDoc().fontWeight === 'bold') ? true:false), diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index ab99f3c6d..dcb2d9d51 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -4,7 +4,7 @@ import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; import { Bounce, Fade, Flip, LightSpeed, Roll, Rotate, Zoom } from 'react-reveal'; import { Doc, DocListCast, Field, Opt, StrListCast } from '../../../fields/Doc'; -import { AclPrivate, Animation, DocData, Width } from '../../../fields/DocSymbols'; +import { AclPrivate, Animation, AudioPlay, DocData, Width } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { InkTool } from '../../../fields/InkField'; import { List } from '../../../fields/List'; @@ -52,6 +52,7 @@ import { LinkAnchorBox } from './LinkAnchorBox'; import { PresEffect, PresEffectDirection } from './trails'; import { PinProps, PresBox } from './trails/PresBox'; import React = require('react'); +import { isThisTypeNode } from 'typescript'; const { Howl } = require('howler'); interface Window { @@ -1054,7 +1055,7 @@ export class DocumentViewInternal extends DocComponent (dataDoc.audioAnnoState = 'recording')); + //runInAction(() => (dataDoc.audioAnnoState = 'recording')); recorder.start(); const stopFunc = () => { recorder.stop(); @@ -1071,16 +1072,24 @@ export class DocumentViewInternal extends DocComponent (self.dataDoc.audioAnnoState = 'stopped')), - }); - this.dataDoc.audioAnnoState = 'playing'; + if (anno instanceof AudioField) { + switch (audioAnnoState) { + case 'stopped': + this.dataDoc[AudioPlay] = new Howl({ + src: [anno.url.href], + format: ['mp3'], + autoplay: true, + loop: false, + volume: 0.5, + onend: action(() => (self.dataDoc.audioAnnoState = 'stopped')), + }); + this.dataDoc.audioAnnoState = 'playing'; + break; + case 'playing': + this.dataDoc[AudioPlay]?.stop(); + this.dataDoc.audioAnnoState = 'stopped'; + break; + } } }; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index c9481482f..58b824159 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -153,10 +153,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { !this.layoutDoc.layout_showSidebar && this.toggleSidebar(); const anchor = this.makeLinkAnchor(undefined, OpenWhere.addRight, undefined, 'Anchored Selection', true, true); + setTimeout(() => { const target = this._sidebarRef.current?.anchorMenuClick(anchor); if (target) { anchor.followLinkAudio = true; - DocumentViewInternal.recordAudioAnnotation(Doc.GetProto(target), Doc.LayoutFieldKey(target)); + let stopFunc: any; + Doc.GetProto(target).mediaState = 'recording'; + Doc.GetProto(target).audioAnnoState = 'recording'; + DocumentViewInternal.recordAudioAnnotation(Doc.GetProto(target), Doc.LayoutFieldKey(target), stop => (stopFunc = stop)); + let reactionDisposer = reaction( + () => target.mediaState, + action(dictation => { + if (!dictation) { + Doc.GetProto(target).audioAnnoState = 'stopped'; + stopFunc(); + reactionDisposer(); + } + }) + ); target.title = ComputedField.MakeFunction(`self["text_audioAnnotations_text"].lastElement()`); } }); @@ -948,14 +962,14 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - if (this._editorView && this._recording) { + if (this._editorView && this._recordingDictation) { this.stopDictation(true); this._break = true; const state = this._editorView.state; const to = state.selection.to; const updated = TextSelection.create(state.doc, to, to); this._editorView.dispatch(state.tr.setSelection(updated).insertText('\n', to)); - if (this._recording) { + if (this._recordingDictation) { this.recordDictation(); } } @@ -1245,13 +1259,14 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent this._recording, + () => this._recordingDictation, () => { this.stopDictation(true); - this._recording && this.recordDictation(); - } + this._recordingDictation && this.recordDictation(); + }, + { fireImmediately: true } ); - if (this._recording) setTimeout(this.recordDictation); + if (this._recordingDictation) setTimeout(this.recordDictation); } var quickScroll: string | undefined = ''; this._disposers.scroll = reaction( @@ -1549,8 +1564,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent disposer?.()); this.endUndoTypingBatch(); @@ -1588,7 +1603,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent @@ -1899,7 +1914,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent (this._recording = !this._recording)) + action(e => (this._recordingDictation = !this._recordingDictation)) ) }> diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx index a52250145..85c1cce8c 100644 --- a/src/client/views/pdf/AnchorMenu.tsx +++ b/src/client/views/pdf/AnchorMenu.tsx @@ -132,7 +132,7 @@ export class AnchorMenu extends AntimodeMenu { tooltip={'Click to Highlight'} onClick={this.highlightClicked} colorPicker={this.highlightColor} - color={StrCast(Doc.UserDoc().userColor)} + color={SettingsManager.userColor} /> @@ -177,7 +177,7 @@ export class AnchorMenu extends AntimodeMenu { tooltip="Summarize with AI" // onPointerDown={this.gptSummarize} icon={} - color={StrCast(Doc.UserDoc().userColor)} + color={SettingsManager.userColor} /> )} {AnchorMenu.Instance.OnAudio === unimplementedFunction ? null : ( @@ -185,7 +185,7 @@ export class AnchorMenu extends AntimodeMenu { tooltip="Click to Record Annotation" // onPointerDown={this.audioDown} icon={} - color={StrCast(Doc.UserDoc().userColor)} + color={SettingsManager.userColor} /> )} { type={Type.PRIM} icon={} popup={} - color={StrCast(Doc.UserDoc().userColor)} + color={SettingsManager.userColor} /> {AnchorMenu.Instance.StartCropDrag === unimplementedFunction ? null : (
    @@ -201,7 +201,7 @@ export class AnchorMenu extends AntimodeMenu { tooltip="Click/Drag to create cropped image" // onPointerDown={this.cropDown} icon={} - color={StrCast(Doc.UserDoc().userColor)} + color={SettingsManager.userColor} />
    )} @@ -213,7 +213,7 @@ export class AnchorMenu extends AntimodeMenu { tooltip="Remove Link Anchor" // onPointerDown={this.Delete} icon={} - color={StrCast(Doc.UserDoc().userColor)} + color={SettingsManager.userColor} /> )} {this.PinToPres !== returnFalse && ( @@ -221,7 +221,7 @@ export class AnchorMenu extends AntimodeMenu { tooltip="Pin to Presentation" // onPointerDown={this.PinToPres} icon={} - color={StrCast(Doc.UserDoc().userColor)} + color={SettingsManager.userColor} /> )} {this.ShowTargetTrail !== returnFalse && ( @@ -229,7 +229,7 @@ export class AnchorMenu extends AntimodeMenu { tooltip="Show Linked Trail" // onPointerDown={this.ShowTargetTrail} icon={} - color={StrCast(Doc.UserDoc().userColor)} + color={SettingsManager.userColor} /> )} {this.IsTargetToggler !== returnFalse && ( @@ -240,7 +240,7 @@ export class AnchorMenu extends AntimodeMenu { toggleStatus={this.IsTargetToggler()} onClick={this.MakeTargetToggle} icon={} - color={StrCast(Doc.UserDoc().userColor)} + color={SettingsManager.userColor} /> )} diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 2a1dfbfc7..dd3f11444 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -20,6 +20,7 @@ import { AclPrivate, AclReadonly, Animation, + AudioPlay, CachedUpdates, DirectLinks, DocAcl, @@ -349,6 +350,7 @@ export class Doc extends RefField { @observable public [DocAcl]: { [key: string]: symbol } = {}; @observable public [DocCss]: number = 0; // incrementer denoting a change to CSS layout @observable public [DirectLinks] = new ObservableSet(); + @observable public [AudioPlay]: any; // meant to store sound object from Howl @observable public [Animation]: Opt; @observable public [Highlight]: boolean = false; static __Anim(Doc: Doc) { diff --git a/src/fields/DocSymbols.ts b/src/fields/DocSymbols.ts index 5b743f710..bb974ee74 100644 --- a/src/fields/DocSymbols.ts +++ b/src/fields/DocSymbols.ts @@ -3,6 +3,7 @@ export const Self = Symbol('DocSelf'); export const SelfProxy = Symbol('DocSelfProxy'); export const FieldKeys = Symbol('DocFieldKeys'); export const FieldTuples = Symbol('DocFieldTuples'); +export const AudioPlay = Symbol('DocAudioPlay'); export const Width = Symbol('DocWidth'); export const Height = Symbol('DocHeight'); export const Animation = Symbol('DocAnimation'); -- cgit v1.2.3-70-g09d2 From e847215964bc02cf402eace30d6c9e19f5f0f0cf Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 7 Sep 2023 01:28:27 -0400 Subject: truncate link descriptions over link lines. Fix schema view issues with multiline inputs. fix '#' field assignment for title bar of docs. fixed dashFieldView to read fields from texstbox by fixing FindDocByTitle to not match undefind. Don't end link_description input on Enter to allow multiline inputs. --- src/client/DocServer.ts | 8 +++-- src/client/views/EditableView.scss | 4 ++- src/client/views/EditableView.tsx | 40 +++++++++++----------- src/client/views/PropertiesView.tsx | 8 ++--- .../CollectionFreeFormLinkView.tsx | 4 +-- .../collectionLinear/CollectionLinearView.tsx | 10 +++--- src/client/views/linking/LinkMenuItem.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 5 ++- .../views/nodes/formattedText/RichTextRules.ts | 2 +- 9 files changed, 42 insertions(+), 41 deletions(-) (limited to 'src/client/views/nodes/formattedText') diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index 5fdea131b..fc8a9f3d6 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -32,9 +32,11 @@ export namespace DocServer { let _cache: { [id: string]: RefField | Promise> } = {}; export function FindDocByTitle(title: string) { - const foundDocId = Array.from(Object.keys(_cache)) - .filter(key => _cache[key] instanceof Doc) - .find(key => (_cache[key] as Doc).title === title); + const foundDocId = + title && + Array.from(Object.keys(_cache)) + .filter(key => _cache[key] instanceof Doc) + .find(key => (_cache[key] as Doc).title === title); return foundDocId ? (_cache[foundDocId] as Doc) : undefined; } diff --git a/src/client/views/EditableView.scss b/src/client/views/EditableView.scss index 0955ba8ff..f7c03caf9 100644 --- a/src/client/views/EditableView.scss +++ b/src/client/views/EditableView.scss @@ -3,7 +3,8 @@ overflow-wrap: break-word; word-wrap: break-word; hyphens: auto; - overflow: hidden; + overflow: auto; + height: 100%; min-width: 20; text-overflow: ellipsis; } @@ -11,6 +12,7 @@ .editableView-container-editing-oneLine { width: 100%; height: max-content; + overflow: hidden; span { p { diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx index 147921596..ca4ffaf3a 100644 --- a/src/client/views/EditableView.tsx +++ b/src/client/views/EditableView.tsx @@ -231,7 +231,7 @@ export class EditableView extends React.Component { onChange: this.props.autosuggestProps.onChange, }} /> - ) : ( + ) : this.props.oneLine !== false && this.props.GetValue()?.toString().indexOf('\n') === -1 ? ( (this._inputref = r)} @@ -247,31 +247,31 @@ export class EditableView extends React.Component { onClick={this.stopPropagation} onPointerUp={this.stopPropagation} /> + ) : ( +