aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/nodes')
-rw-r--r--src/client/views/nodes/DataVizBox/utils/D3Utils.ts1
-rw-r--r--src/client/views/nodes/DocumentContentsView.tsx4
-rw-r--r--src/client/views/nodes/DocumentView.tsx72
-rw-r--r--src/client/views/nodes/EquationBox.scss9
-rw-r--r--src/client/views/nodes/FontIconBox/FontIconBox.tsx241
-rw-r--r--src/client/views/nodes/LinkDocPreview.tsx2
-rw-r--r--src/client/views/nodes/MapBox/MapBox.tsx1
-rw-r--r--src/client/views/nodes/ScreenshotBox.scss36
-rw-r--r--src/client/views/nodes/ScreenshotBox.tsx12
-rw-r--r--src/client/views/nodes/ScriptingBox.tsx2
-rw-r--r--src/client/views/nodes/WebBox.tsx14
-rw-r--r--src/client/views/nodes/formattedText/DashFieldView.tsx6
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.scss20
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx68
-rw-r--r--src/client/views/nodes/formattedText/RichTextRules.ts26
-rw-r--r--src/client/views/nodes/importBox/ImportElementBox.tsx88
16 files changed, 279 insertions, 323 deletions
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<number, number, never
};
export const xAxisCreator = (g: d3.Selection<SVGGElement, unknown, null, undefined>, height: number, xScale: d3.ScaleLinear<number, number, never>) => {
- 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/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 7e8eef0a5..2d8663c9c 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -18,7 +18,6 @@ import { SearchBox } from '../search/SearchBox';
import { DashWebRTCVideo } from '../webcam/DashWebRTCVideo';
import { YoutubeBox } from './../../apis/youtube/YoutubeBox';
import { AudioBox } from './AudioBox';
-import { FontIconBox } from './FontIconBox/FontIconBox';
import { ColorBox } from './ColorBox';
import { ComparisonBox } from './ComparisonBox';
import { DataVizBox } from './DataVizBox/DataVizBox';
@@ -26,9 +25,11 @@ import { DocumentViewProps } from './DocumentView';
import './DocumentView.scss';
import { EquationBox } from './EquationBox';
import { FieldView, FieldViewProps } from './FieldView';
+import { FontIconBox } from './FontIconBox/FontIconBox';
import { FormattedTextBox } from './formattedText/FormattedTextBox';
import { FunctionPlotBox } from './FunctionPlotBox';
import { ImageBox } from './ImageBox';
+import { ImportElementBox } from './importBox/ImportElementBox';
import { KeyValueBox } from './KeyValueBox';
import { LabelBox } from './LabelBox';
import { LinkAnchorBox } from './LinkAnchorBox';
@@ -269,6 +270,7 @@ export class DocumentContentsView extends React.Component<
LoadingBox,
PhysicsSimulationBox,
SchemaRowBox,
+ ImportElementBox,
}}
bindings={bindings}
jsx={layoutFrame}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 66352678c..bb9f45bdd 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -47,11 +47,11 @@ 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';
import React = require('react');
+import { SettingsManager } from '../../util/SettingsManager';
const { Howl } = require('howler');
interface Window {
@@ -314,7 +314,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
@computed get titleHeight() {
return this.props?.styleProvider?.(this.layoutDoc, this.props, StyleProp.TitleHeight) || 0;
}
- get pointerEvents(): 'none' | 'all' | 'visiblePainted' | undefined {
+ @computed get pointerEvents(): 'none' | 'all' | 'visiblePainted' | undefined {
return this.props.styleProvider?.(this.Document, this.props, StyleProp.PointerEvents + (this.props.isSelected() ? ':selected' : ''));
}
@computed get finalLayoutKey() {
@@ -332,8 +332,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
return (
DocumentView.LongPress ||
onScriptDisable === 'always' ||
- (onScriptDisable !== 'never' && (this.rootSelected() || this.props.isSelected())) ||
- this._componentView?.isAnyChildContentActive?.()
+ (onScriptDisable !== 'never' && (this.rootSelected() || this._componentView?.isAnyChildContentActive?.()))
);
}
@computed get onClickHandler() {
@@ -800,7 +799,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
}
const constantItems: ContextMenuProps[] = [];
if (!Doc.IsSystem(this.rootDoc)) {
- constantItems.push({ description: 'Export as Zip file', icon: 'download', event: async () => Doc.Zip(this.props.Document) });
+ constantItems.push({ description: 'Zip Export', icon: 'download', event: async () => Doc.Zip(this.props.Document) });
(this.rootDoc._type_collection !== CollectionViewType.Docking || !Doc.noviceMode) && constantItems.push({ description: 'Share', event: () => SharingManager.Instance.open(this.props.DocumentView()), icon: 'users' });
if (this.props.removeDocument && Doc.ActiveDashboard !== this.props.Document) {
// need option to gray out menu items ... preferably with a '?' that explains why they're grayed out (eg., no permissions)
@@ -863,34 +862,32 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
cm.displayMenu((e?.pageX || pageX || 0) - 15, (e?.pageY || pageY || 0) - 15);
};
- rootSelected = (outsideReaction?: boolean) => 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.props.isSelected(outsideReaction) ||
- this._componentView?.isAnyChildContentActive?.() ||
- this.props.isContentActive()
+ : 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() &&
@@ -900,12 +897,15 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
((!childHighlighted() && !childOverlayed() && !Doc.isBrushedHighlightedDegree(this.rootDoc)) || this.rootDoc._type_collection === CollectionViewType.Docking)
? true
: false;
- };
+ }
+ thumbShown = () => 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), or if contents are marked inactive
- contentPointerEvents = () => ((!this.disableClickScriptFunc && this.onClickHandler && !this.props.onBrowseClick?.()) || this.isContentActive() === false ? 'none' : this.pointerEvents);
-
+ /// 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
+ @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;
@@ -1088,7 +1088,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
<div
className="documentView-captionWrapper"
style={{
- pointerEvents: this.Document.ignoreClick ? 'none' : this.isContentActive() || this.props.isDocumentActive?.() ? 'all' : undefined,
+ pointerEvents: this.rootDoc.ignoreClick ? 'none' : this.isContentActive() || this.props.isDocumentActive?.() ? 'all' : undefined,
minWidth: 50 * ffscale(),
maxHeight: `max(100%, ${20 * ffscale()}px)`,
}}>
@@ -1110,7 +1110,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
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) : 'rgba(0,0,0,0.4)'
+ Doc.UserDoc().layout_showTitle && [DocumentType.RTF, DocumentType.COL].includes(this.rootDoc.type as any) ? StrCast(Doc.SharingDoc().headingColor) : SettingsManager.Instance.userVariantColor
);
const sidebarWidthPercent = +StrCast(this.layoutDoc.layout_sidebarWidthPercent).replace('%', '');
const titleView = !showTitle ? null : (
@@ -1223,16 +1223,22 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
case PresEffect.Lightspeed: return <LightSpeed {...effectProps}>{renderDoc}</LightSpeed>;
}
}
+ @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',
@@ -1248,9 +1254,9 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
onContextMenu={this.onContextMenu}
onPointerDown={this.onPointerDown}
onClick={this.onClick}
- onPointerEnter={e => (!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/EquationBox.scss b/src/client/views/nodes/EquationBox.scss
index 9714e1bd0..f5871db22 100644
--- a/src/client/views/nodes/EquationBox.scss
+++ b/src/client/views/nodes/EquationBox.scss
@@ -1,8 +1,9 @@
-@import "../global/globalCssVariables.scss";
+@import '../global/globalCssVariables.scss';
.equationBox-cont {
- transform-origin: top left;
+ transform-origin: center;
+ background-color: #e7e7e7;
> span {
- width: 100%;
+ width: 100%;
}
-} \ No newline at end of file
+}
diff --git a/src/client/views/nodes/FontIconBox/FontIconBox.tsx b/src/client/views/nodes/FontIconBox/FontIconBox.tsx
index 3ec53beac..91eac675f 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',
@@ -86,10 +87,10 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
}
Icon = (color: string, iconFalse?: boolean) => {
let icon;
- if (iconFalse ) {
+ if (iconFalse) {
icon = StrCast(this.dataDoc[this.fieldKey ?? 'iconFalse'] ?? this.dataDoc.icon, 'user') as any;
- if (icon) return <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={icon} color={color} />
- else return null
+ if (icon) return <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={icon} color={color} />;
+ else return null;
}
icon = StrCast(this.dataDoc[this.fieldKey ?? 'icon'] ?? this.dataDoc.icon, 'user') as any;
const trailsIcon = () => <img src={`/assets/${'presTrails.png'}`} style={{ width: 30, height: 30, filter: `invert(${color === Colors.DARK_GRAY ? '0%' : '100%'})` }} />;
@@ -124,36 +125,38 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
*/
@computed get numberDropdown() {
let type: NumberDropdownType;
- switch(this.type) {
- case ButtonType.NumberDropdownButton:
- type = 'dropdown'
+ switch (this.type) {
+ case ButtonType.NumberDropdownButton:
+ type = 'dropdown';
break;
case ButtonType.NumberInlineButton:
- type = 'input'
+ type = 'input';
break;
case ButtonType.NumberSliderButton:
default:
- type = 'slider'
+ type = 'slider';
break;
}
- const numScript = (value?: number) => ScriptCast(this.rootDoc.script).script.run({ self: this.rootDoc, value, _readOnly_: value === undefined });
+ const numScript = (value?: number) => ScriptCast(this.rootDoc.script).script.run({ this: this.layoutDoc, self: this.rootDoc, value, _readOnly_: value === undefined });
const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color);
// Script for checking the outcome of the toggle
const checkResult = Number(Number(numScript().result ?? 0).toPrecision(NumCast(this.dataDoc.numPrecision, 3)));
const label = !FontIconBox.GetShowLabels() ? null : <div className="fontIconBox-label">{this.label}</div>;
- return <NumberDropdown
- color={color}
- numberDropdownType={type}
- showPlusMinus={false}
- tooltip={this.label}
- type={Type.PRIM}
- min={NumCast(this.rootDoc.numBtnMin, 0)}
- max={NumCast(this.rootDoc.numBtnMax, 100)}
- number={checkResult}
- setNumber={undoable(value => numScript(value), `${this.rootDoc.title} button set from list`)}
- fillWidth
- />
+ return (
+ <NumberDropdown
+ color={color}
+ numberDropdownType={type}
+ showPlusMinus={false}
+ tooltip={this.label}
+ type={Type.PRIM}
+ min={NumCast(this.rootDoc.numBtnMin, 0)}
+ max={NumCast(this.rootDoc.numBtnMax, 100)}
+ number={checkResult}
+ setNumber={undoable(value => numScript(value), `${this.rootDoc.title} button set from list`)}
+ fillWidth
+ />
+ );
}
/**
@@ -202,84 +205,64 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
let dropdown = true;
let getStyle: (val: string) => any = () => {};
let icon: IconProp = 'caret-down';
- let isViewDropdown: boolean = script?.script.originalScript.startsWith('setView')
+ let isViewDropdown: boolean = script?.script.originalScript.startsWith('setView');
try {
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"
+ text = selectedDocs.length + ' selected';
} else {
text = Utils.cleanDocumentType(StrCast(selected.type) as DocumentType);
icon = Doc.toIcon(selected);
}
- return <Popup
- icon={<FontAwesomeIcon size={'1x'} icon={icon} />}
- text={text}
- type={Type.TERT}
- color={color}
- popup={<SelectedDocView selectedDocs={selectedDocs}/>}
- fillWidth
- />
+ return <Popup icon={<FontAwesomeIcon size={'1x'} icon={icon} />} text={text} type={Type.TERT} color={color} popup={<SelectedDocView selectedDocs={selectedDocs} />} fillWidth />;
}
} else {
dropdown = false;
- return <Button
- text={`None Selected`}
- type={Type.TERT}
- color={color}
- fillWidth
- inactive
- />
+ return <Button text={`None Selected`} type={Type.TERT} color={color} fillWidth inactive />;
}
noviceList = [CollectionViewType.Freeform, CollectionViewType.Schema, CollectionViewType.Stacking, CollectionViewType.NoteTaking];
- } else {
+ } else {
text = StrCast((RichTextMenu.Instance?.TextView?.EditorView ? RichTextMenu.Instance : Doc.UserDoc()).fontFamily);
- getStyle = (val: string) => { return { fontFamily: val } }
+ getStyle = (val: string) => {
+ return { fontFamily: val };
+ };
}
} catch (e) {
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))
- .map(value => (
- {
- text: value.charAt(0).toUpperCase() + value.slice(1),
- val: value,
- style: getStyle(value),
- onClick: undoable(() => script.script.run({ self: this.rootDoc, value }), value)
- // shortcut: '#',
- }
- ));
-
+ .map(value => ({
+ text: value.charAt(0).toUpperCase() + value.slice(1),
+ val: value,
+ style: getStyle(value),
+ onClick: undoable(() => script.script.run({ this: this.layoutDoc, self: this.rootDoc, value }), value),
+ // shortcut: '#',
+ }));
return (
- <Dropdown
+ <Dropdown
selectedVal={text}
- setSelectedVal={undoable((val) => script.script.run({ self: this.rootDoc, val }), `dropdown select ${this.label}`)}
- color={color}
- type={isViewDropdown ? Type.TERT : Type.PRIM}
- dropdownType={DropdownType.SELECT}
+ setSelectedVal={undoable(val => script.script.run({ this: this.layoutDoc, self: this.rootDoc, val }), `dropdown select ${this.label}`)}
+ color={color}
+ type={isViewDropdown ? Type.TERT : Type.PRIM}
+ dropdownType={DropdownType.SELECT}
items={list}
tooltip={this.label}
fillWidth
/>
- )
+ );
}
-
@computed get colorScript() {
return ScriptCast(this.rootDoc.script);
}
@@ -290,14 +273,14 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
@computed get colorButton() {
const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color);
const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor);
- const curColor = this.colorScript?.script.run({ self: this.rootDoc, value: undefined, _readOnly_: true }).result ?? 'transparent';
+ const curColor = this.colorScript?.script.run({ this: this.layoutDoc, self: this.rootDoc, value: undefined, _readOnly_: true }).result ?? 'transparent';
const tooltip: string = StrCast(this.rootDoc.toolTip);
return (
- <ColorPicker
- setSelectedColor={(value) => {
+ <ColorPicker
+ setSelectedColor={value => {
const s = this.colorScript;
- s && undoable(() => s.script.run({ self: this.rootDoc, value: value, _readOnly_: false }).result, `Set ${tooltip} to ${value}`)();
+ s && undoable(() => s.script.run({ this: this.layoutDoc, self: this.rootDoc, value: value, _readOnly_: false }).result, `Set ${tooltip} to ${value}`)();
}}
selectedColor={curColor}
type={Type.PRIM}
@@ -306,7 +289,35 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
tooltip={tooltip}
label={this.label}
/>
- )
+ );
+ }
+ @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 (
+ <MultiToggle
+ tooltip={`Toggle ${tooltip}`}
+ type={Type.PRIM}
+ color={color}
+ label={this.label}
+ items={DocListCast(this.rootDoc.data).map(item => ({
+ icon: <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={StrCast(item.icon) as any} color={color} />,
+ 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() {
@@ -315,25 +326,24 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
const tooltip: string = StrCast(this.rootDoc.toolTip);
const script = ScriptCast(this.rootDoc.onClick);
- const toggleStatus = script ? script.script.run({ self: this.rootDoc, value: undefined, _readOnly_: true }).result : false;
+ 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);
- console.log(tooltip, toggleStatus);
return (
- <Toggle
- tooltip={`Toggle ${tooltip}`}
- toggleType={ToggleType.BUTTON}
- type={Type.PRIM}
- toggleStatus={toggleStatus}
- text={buttonText}
- color={color}
- icon={this.Icon(color)!}
+ <Toggle
+ tooltip={`Toggle ${tooltip}`}
+ toggleType={ToggleType.BUTTON}
+ type={Type.PRIM}
+ toggleStatus={toggleStatus}
+ text={buttonText}
+ color={color}
+ icon={this.Icon(color)!}
label={this.label}
- onPointerDown={() => script.script.run({ self: this.rootDoc, value: !toggleStatus, _readOnly_: false })}
+ onPointerDown={() => script.script.run({ this: this.layoutDoc, self: this.rootDoc, value: !toggleStatus, _readOnly_: false })}
/>
- )
+ );
}
/**
@@ -344,79 +354,50 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor);
const tooltip: string = StrCast(this.rootDoc.toolTip);
- return (
- <IconButton tooltip={tooltip} icon={this.Icon(color)!} label={this.label}/>
- )
+ return <IconButton tooltip={tooltip} icon={this.Icon(color)!} label={this.label} />;
}
@computed get editableText() {
// Script for running the toggle
const script = ScriptCast(this.rootDoc.script);
// Function to run the script
- const checkResult = script?.script.run({ value: '', _readOnly_: true }).result;
+ const checkResult = script?.script.run({ this: this.layoutDoc, self: this.rootDoc, value: '', _readOnly_: true }).result;
+
+ const setValue = (value: string, shiftDown?: boolean): boolean => script?.script.run({ this: this.layoutDoc, self: this.rootDoc, value, _readOnly_: false }).result;
+
+ return <EditableText editing={false} setEditing={(editing: boolean) => {}} />;
- const setValue = (value: string, shiftDown?: boolean): boolean => script?.script.run({ value, _readOnly_: false }).result;
-
- return <EditableText
- editing={false} setEditing={(editing: boolean) => {}}
- />
-
return (
<div className="menuButton editableText">
<FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={'lock'} />
<div style={{ width: 'calc(100% - .875em)', paddingLeft: '4px' }}>
- <EditableView GetValue={() => script?.script.run({ value: '', _readOnly_: true }).result} SetValue={setValue} oneLine={true} contents={checkResult} />
+ <EditableView GetValue={() => script?.script.run({ this: this.layoutDoc, self: this.rootDoc, value: '', _readOnly_: true }).result} SetValue={setValue} oneLine={true} contents={checkResult} />
</div>
</div>
);
}
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;
+ const tooltip = StrCast(this.rootDoc.toolTip);
+ const scriptFunc = () => ScriptCast(this.rootDoc.onClick)?.script.run({ this: this.layoutDoc, self: this.rootDoc, _readOnly_: false });
+ const btnProps = { tooltip, icon: this.Icon(color)!, label: this.label };
// prettier-ignore
switch (this.type) {
- case ButtonType.EditableText:
- button = this.editableText;
- break;
- case ButtonType.DropdownList:
- button = this.dropdownListButton;
- break;
- case ButtonType.ColorButton:
- button = this.colorButton;
- break;
case ButtonType.NumberDropdownButton:
case ButtonType.NumberInlineButton:
- case ButtonType.NumberSliderButton:
- button = this.numberDropdown;
- break;
- case ButtonType.DropdownButton:
- button = this.dropdownButton;
- break;
- case ButtonType.ToggleButton: button = this.toggleButton; break;
+ case ButtonType.NumberSliderButton: return this.numberDropdown;
+ case ButtonType.EditableText: return this.editableText;
+ case ButtonType.DropdownList: return this.dropdownListButton;
+ case ButtonType.ColorButton: return this.colorButton;
+ case ButtonType.DropdownButton: return this.dropdownButton;
+ case ButtonType.MultiToggleButton: return this.multiToggleButton;
+ case ButtonType.ToggleButton: return this.toggleButton;
case ButtonType.ClickButton:
- case ButtonType.ToolButton:
- button = (
- <IconButton tooltip={tooltip} onPointerDown={() => onClickScript?.script.run({ _readOnly_: false })} color={color} icon={this.Icon(color)!} label={this.label}/>
- );
- break;
- case ButtonType.TextButton:
- button = (
- <Button tooltip={tooltip} icon={this.Icon(color)!} text={StrCast(this.rootDoc.buttonText)} label={this.label}/>
- );
- break;
- case ButtonType.MenuButton: button = (
- <IconButton tooltip={tooltip} onPointerDown={() => onClickScript?.script.run({ self: this.rootDoc, _readOnly_: false })} tooltipPlacement='right' size={Size.LARGE} color={color} icon={this.Icon(color)!} label={this.label}/>
- );
- break;
+ case ButtonType.ToolButton: return <IconButton {...btnProps} size={Size.LARGE} color={color} />;
+ case ButtonType.TextButton: return <Button {...btnProps} text={StrCast(this.rootDoc.buttonText)}/>;
+ case ButtonType.MenuButton: return <IconButton {...btnProps} color={color} size={Size.LARGE} tooltipPlacement='right' onPointerDown={scriptFunc} />;
}
-
- return button;
+ return this.defaultButton;
}
}
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.scss b/src/client/views/nodes/ScreenshotBox.scss
index 6fb5ea7b3..1e9b64a0b 100644
--- a/src/client/views/nodes/ScreenshotBox.scss
+++ b/src/client/views/nodes/ScreenshotBox.scss
@@ -1,6 +1,5 @@
.screenshotBox {
transform-origin: top left;
- background: white;
color: black;
// .screenshotBox-viewer {
// opacity: 0.99; // hack! overcomes some kind of Chrome weirdness where buttons (e.g., snapshot) disappear at some point as the video is resized larger
@@ -12,46 +11,39 @@
#CANCAN {
canvas {
- width:100% !important;
+ width: 100% !important;
height: 100% !important;
}
}
-.screenshotBox-content, .screenshotBox-content-interactive, .screenshotBox-cont-fullScreen {
+.screenshotBox-content,
+.screenshotBox-content-interactive,
+.screenshotBox-cont-fullScreen {
width: 100%;
z-index: -1; // 0; // logically this should be 0 (or unset) which would give us transparent brush strokes over videos. However, this makes Chrome crawl to a halt
position: absolute;
}
-.screenshotBox-content, .screenshotBox-content-interactive, .screenshotBox-content-fullScreen {
- height: Auto;
+.screenshotBox-content,
+.screenshotBox-content-interactive,
+.screenshotBox-content-fullScreen {
+ height: Auto;
}
.screenshotBox-uiButtons {
- background:dimgray;
- border: orange solid 1px;
position: absolute;
right: 25;
top: 0;
- width:25;
+ width: 22;
height: 25;
- .screenshotBox-snapshot{
- color : white;
- top :0px;
- right : 5px;
- position: absolute;
- background-color:rgba(50, 50, 50, 0.2);
- transform-origin: left top;
- pointer-events:all;
- }
- .screenshotBox-recorder{
- color : white;
- top :0px;
+ .screenshotBox-recorder {
+ color: white;
+ top: 4px;
left: 5px;
position: absolute;
- background-color:rgba(50, 50, 50, 0.2);
+ background-color: rgba(50, 50, 50, 0.2);
transform-origin: left top;
- pointer-events:all;
+ pointer-events: all;
}
}
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index 312b3c619..271ff3cf8 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -25,6 +25,7 @@ import { FieldView, FieldViewProps } from './FieldView';
import { FormattedTextBox } from './formattedText/FormattedTextBox';
import './ScreenshotBox.scss';
import { VideoBox } from './VideoBox';
+import { SettingsManager } from '../../util/SettingsManager';
declare class MediaRecorder {
constructor(e: any, options?: any); // whatever MediaRecorder has
@@ -224,7 +225,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
const aud_chunks: any = [];
this._audioRec.ondataavailable = (e: any) => 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 +236,8 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
this._videoRec.onstart = () => (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
@@ -313,7 +313,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
</>
</CollectionFreeFormView>
</div>
- <div style={{ background: 'white', position: 'relative', height: this.formattedPanelHeight() }}>
+ <div style={{ background: SettingsManager.Instance.userColor, position: 'relative', height: this.formattedPanelHeight() }}>
{!(this.dataDoc[this.fieldKey + '-dictation'] instanceof Doc) ? null : (
<FormattedTextBox
{...this.props}
@@ -335,8 +335,8 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
</div>
</div>
{!this.props.isSelected() ? null : (
- <div className="screenshotBox-uiButtons">
- <div className="screenshotBox-recorder" key="snap" onPointerDown={this.toggleRecording}>
+ <div className="screenshotBox-uiButtons" style={{ background: SettingsManager.Instance.userColor }}>
+ <div className="screenshotBox-recorder" style={{ color: SettingsManager.Instance.userBackgroundColor, background: SettingsManager.Instance.userVariantColor }} key="snap" onPointerDown={this.toggleRecording}>
<FontAwesomeIcon icon="file" size="lg" />
</div>
</div>
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<ViewBoxAnnotatable
' ': {
dataProvider: (token: any) => 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<ViewBoxAnnotatable
'.': {
dataProvider: (token: any) => 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/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 5cdd6b5f2..07b931312 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -125,11 +125,15 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
this._searchRef.current?.setRangeText(searchString);
});
}
- if (clear) {
- this._iframe?.contentWindow?.getSelection()?.empty();
- }
- if (searchString) {
- (this._iframe?.contentWindow as any)?.find(searchString, false, bwd, true);
+ try {
+ if (clear) {
+ this._iframe?.contentWindow?.getSelection()?.empty();
+ }
+ if (searchString) {
+ (this._iframe?.contentWindow as any)?.find(searchString, false, bwd, true);
+ }
+ } catch (e) {
+ console.log("WebBox search error", e)
}
return true;
};
diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx
index b4fb7a44e..d5ad128fe 100644
--- a/src/client/views/nodes/formattedText/DashFieldView.tsx
+++ b/src/client/views/nodes/formattedText/DashFieldView.tsx
@@ -17,6 +17,7 @@ import { OpenWhere } from '../DocumentView';
import './DashFieldView.scss';
import { FormattedTextBox } from './FormattedTextBox';
import React = require('react');
+import { Transform } from '../../../util/Transform';
export class DashFieldView {
dom: HTMLDivElement; // container for label and value
@@ -113,6 +114,7 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
componentWillUnmount() {
this._reactionDisposer?.();
}
+ return100 = () => 100;
// set the display of the field's value (checkbox for booleans, span of text for strings)
@computed get fieldValueContent() {
@@ -123,7 +125,7 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
col={0}
deselectCell={emptyFunction}
selectCell={emptyFunction}
- maxWidth={this.props.hideKey ? undefined : () => 100}
+ maxWidth={this.props.hideKey ? undefined : this.return100}
columnWidth={this.props.hideKey ? () => this.props.tbox.props.PanelWidth() - 20 : returnZero}
selectedCell={() => [this._dashDoc!, 0]}
fieldKey={this._fieldKey}
@@ -135,6 +137,8 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
allowCRs={true}
oneLine={!this._expanded}
finishEdit={action(() => (this._expanded = false))}
+ transform={Transform.Identity}
+ menuTarget={null}
/>
</div>
);
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.scss b/src/client/views/nodes/formattedText/FormattedTextBox.scss
index 109b62e6f..348bdd79e 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.scss
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.scss
@@ -84,7 +84,6 @@ audiotag:hover {
height: 11;
}
-.formattedTextBox-outer-selected,
.formattedTextBox-outer {
position: relative;
overflow: auto;
@@ -92,9 +91,6 @@ audiotag:hover {
width: 100%;
height: unset;
}
-.formattedTextBox-outer-selected {
- cursor: text;
-}
.formattedTextBox-sidebar-handle {
position: absolute;
@@ -148,10 +144,8 @@ audiotag:hover {
}
.formattedTextBox-inner-rounded,
-.formattedTextBox-inner-rounded-selected,
.formattedTextBox-inner,
-.formattedTextBox-inner-minimal,
-.formattedTextBox-inner-selected {
+.formattedTextBox-inner-minimal {
height: 100%;
white-space: pre-wrap;
.ProseMirror:hover {
@@ -169,17 +163,6 @@ audiotag:hover {
border-width: 1px;
}
}
-.formattedTextBox-inner-rounded-selected,
-.formattedTextBox-inner-selected {
- > .ProseMirror {
- padding: 10px;
- }
-}
-.formattedTextBox-outer-selected {
- > .ProseMirror:hover {
- background: unset;
- }
-}
.gpt-typing-wrapper {
padding: 10px;
@@ -640,7 +623,6 @@ footnote::before {
}
}
- .formattedTextBox-outer-selected,
.formattedTextBox-outer {
position: relative;
overflow: auto;
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 072977150..332f0f467 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -97,6 +97,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
private _scrollRef: React.RefObject<HTMLDivElement> = React.createRef();
private _editorView: Opt<EditorView>;
public _applyingChange: string = '';
+ private _finishingLink = false;
private _searchIndex = 0;
private _lastTimedMark: Mark | undefined = undefined;
private _cachedLinks: Doc[] = [];
@@ -246,7 +247,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
if (!pinProps && this._editorView?.state.selection.empty) return this.rootDoc;
const anchor = Docs.Create.ConfigDocument({ title: StrCast(this.rootDoc.title), annotationOn: this.rootDoc });
this.addDocument(anchor);
+ this._finishingLink = true;
this.makeLinkAnchor(anchor, OpenWhere.addRight, undefined, 'Anchored Selection', false, addAsAnnotation);
+ this._finishingLink = false;
PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), scrollable: true } }, this.rootDoc);
return anchor;
};
@@ -327,7 +330,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
textChange && (dataDoc[this.fieldKey + '_modificationDate'] = new DateField(new Date(Date.now())));
if ((!prevData && !protoData) || newText || (!newText && !templateData)) {
// if no template, or there's text that didn't come from the layout template, write it to the document. (if this is driven by a template, then this overwrites the template text which is intended)
- if (this.props.isContentActive() && removeSelection(newJson) !== removeSelection(prevData?.Data)) {
+ if ((this._finishingLink || this.props.isContentActive()) && removeSelection(newJson) !== removeSelection(prevData?.Data)) {
const numstring = NumCast(dataDoc[this.fieldKey], null);
dataDoc[this.fieldKey] = numstring !== undefined ? Number(newText) : new RichTextField(newJson, newText);
dataDoc[this.fieldKey + '_noTemplate'] = true; // mark the data field as being split from the template if it has been edited
@@ -458,8 +461,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
if (node.firstChild === null && !node.marks.find((m: Mark) => 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 ?? []));
@@ -841,7 +848,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
const appearance = cm.findByDescription('Appearance...');
const appearanceItems = appearance && 'subitems' in appearance ? appearance.subitems : [];
- appearanceItems.push({ description: 'Change Perspective...', noexpand: true, subitems: changeItems, icon: 'external-link-alt' });
+ appearanceItems.push({ description: 'Change Style...', noexpand: true, subitems: changeItems, icon: 'external-link-alt' });
// this.rootDoc.isTemplateDoc && appearanceItems.push({ description: "Make Default Layout", event: async () => Doc.UserDoc().defaultTextLayout = new PrefetchProxy(this.rootDoc), icon: "eye" });
!Doc.noviceMode &&
@@ -1589,7 +1596,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
);
};
+ @action
componentWillUnmount() {
+ if (this._recording) {
+ this._recording = !this._recording;
+ }
Object.values(this._disposers).forEach(disposer => disposer?.());
this.endUndoTypingBatch();
FormattedTextBox.LiveTextUndo?.end();
@@ -1628,8 +1639,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
}
if (this._recording && !e.ctrlKey && e.button === 0) {
this.breakupDictation();
- e.preventDefault();
- e.stopPropagation();
}
this._downX = e.clientX;
this._downY = e.clientY;
@@ -2026,12 +2035,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
}
cycleAlternateText = () => {
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 (
<Tooltip
title={
@@ -2075,17 +2084,25 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
}
};
_oldWheel: any;
+ @computed get fontColor() {
+ return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color);
+ }
+ @computed get fontSize() {
+ return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.FontSize);
+ }
+ @computed get fontFamily() {
+ return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.FontFamily);
+ }
+ @computed get fontWeight() {
+ return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.FontWeight);
+ }
render() {
TraceMobx();
- const active = this.props.isContentActive();
const scale = (this.props.NativeDimScaling?.() || 1) * NumCast(this.layoutDoc._freeform_scale, 1);
const rounded = StrCast(this.layoutDoc.layout_borderRounding) === '100%' ? '-rounded' : '';
- if (!active && FormattedTextBoxComment.textBox === this) setTimeout(FormattedTextBoxComment.Hide);
- const minimal = this.props.ignoreAutoHeight;
+ setTimeout(() => !this.props.isContentActive() && FormattedTextBoxComment.textBox === this && FormattedTextBoxComment.Hide);
const paddingX = NumCast(this.layoutDoc._xMargin, this.props.xPadding || 0);
const paddingY = NumCast(this.layoutDoc._yMargin, this.props.yPadding || 0);
- const selPad = (active && !this.layoutDoc._createDocOnCR) || minimal ? Math.min(paddingY, Math.min(paddingX, 10)) : 0;
- const selPaddingClass = active && !this.layoutDoc._createDocOnCR && paddingY >= 10 ? '-selected' : '';
const styleFromLayoutString = Doc.styleFromLayoutString(this.rootDoc, this.layoutDoc, this.props, scale); // this converts any expressions in the format string to style props. e.g., <FormattedTextBox height='{this._headerHeight}px' >
return styleFromLayoutString?.height === '0px' ? null : (
<div
@@ -2102,23 +2119,23 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
? {}
: {
transform: `scale(${scale})`,
- transformOrigin: 'top left',
width: `${100 / scale}%`,
height: `${100 / scale}%`,
}),
- display: !this.props.isContentActive() && this.props.thumbShown?.() ? 'none' : undefined,
+ // display: !this.props.isContentActive() && this.props.thumbShown?.() ? 'none' : undefined,
transition: 'inherit',
// overflowY: this.layoutDoc._layout_autoHeight ? "hidden" : undefined,
- color: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color),
- fontSize: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.FontSize),
- fontFamily: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.FontFamily),
- fontWeight: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.FontWeight),
+ color: this.fontColor,
+ fontSize: this.fontSize,
+ fontFamily: this.fontFamily,
+ fontWeight: this.fontWeight,
...styleFromLayoutString,
}}>
<div
className="formattedTextBox-cont"
ref={this._ref}
style={{
+ cursor: this.props.isContentActive() ? 'text' : undefined,
overflow: this.layout_autoHeight && this.props.CollectionFreeFormDocumentView?.() ? 'hidden' : undefined, //x this breaks viewing an layout_autoHeight doc in its own tab, or in the lightbox
height: this.props.height || (this.layout_autoHeight && this.props.renderDepth && !this.props.suppressSetHeight ? 'max-content' : undefined),
pointerEvents: Doc.ActiveTool === InkTool.None && !this.props.onBrowseClick?.() ? undefined : 'none',
@@ -2133,7 +2150,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
onPointerDown={this.onPointerDown}
onDoubleClick={this.onDoubleClick}>
<div
- className={`formattedTextBox-outer${active ? '-selected' : ''}`}
+ className={`formattedTextBox-outer`}
ref={this._scrollRef}
style={{
width: this.props.dontSelectOnLoad ? '100%' : `calc(100% - ${this.layout_sidebarWidthPercent})`,
@@ -2142,15 +2159,14 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
onScroll={this.onScroll}
onDrop={this.ondrop}>
<div
- className={minimal ? 'formattedTextBox-minimal' : `formattedTextBox-inner${rounded}${selPaddingClass}`}
+ className={`formattedTextBox-inner${rounded}`}
ref={this.createDropTarget}
style={{
padding: StrCast(this.layoutDoc._textBoxPadding),
- paddingLeft: StrCast(this.layoutDoc._textBoxPaddingX, `${paddingX - selPad}px`),
- paddingRight: StrCast(this.layoutDoc._textBoxPaddingX, `${paddingX - selPad}px`),
- paddingTop: StrCast(this.layoutDoc._textBoxPaddingY, `${paddingY - selPad}px`),
- paddingBottom: StrCast(this.layoutDoc._textBoxPaddingY, `${paddingY - selPad}px`),
- // pointerEvents: !active && IsFollowLinkScript(this.layoutDoc.onClick) ? 'none' : undefined,
+ paddingLeft: StrCast(this.layoutDoc._textBoxPaddingX, `${paddingX}px`),
+ paddingRight: StrCast(this.layoutDoc._textBoxPaddingX, `${paddingX}px`),
+ paddingTop: StrCast(this.layoutDoc._textBoxPaddingY, `${paddingY}px`),
+ paddingBottom: StrCast(this.layoutDoc._textBoxPaddingY, `${paddingY}px`),
}}
/>
</div>
diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts
index ac1e7ce5d..8bafc2cef 100644
--- a/src/client/views/nodes/formattedText/RichTextRules.ts
+++ b/src/client/views/nodes/formattedText/RichTextRules.ts
@@ -243,13 +243,13 @@ export class RichTextRules {
// create a text display of a metadata field on this or another document, or create a hyperlink portal to another document
// [[<fieldKey> : <Doc>]]
- // [[: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/nodes/importBox/ImportElementBox.tsx b/src/client/views/nodes/importBox/ImportElementBox.tsx
index a5d21cc8e..58f0b29e4 100644
--- a/src/client/views/nodes/importBox/ImportElementBox.tsx
+++ b/src/client/views/nodes/importBox/ImportElementBox.tsx
@@ -1,13 +1,13 @@
-import { observer } from "mobx-react";
-import { ViewBoxBaseComponent } from "../../DocComponent";
-import { FieldView, FieldViewProps } from "../FieldView";
-import { computed } from "mobx";
-import { Id } from "../../../../fields/FieldSymbols";
-import React from "react";
-import { EditableView } from "../../EditableView";
-import { DocListCast } from "../../../../fields/Doc";
-import { StrCast } from "../../../../fields/Types";
-
+import { computed } from 'mobx';
+import { observer } from 'mobx-react';
+import { Doc } from '../../../../fields/Doc';
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, returnTrue } from '../../../../Utils';
+import { Transform } from '../../../util/Transform';
+import { ViewBoxBaseComponent } from '../../DocComponent';
+import { DefaultStyleProvider } from '../../StyleProvider';
+import { DocumentView, DocumentViewInternal } from '../DocumentView';
+import { FieldView, FieldViewProps } from '../FieldView';
+import React = require('react');
@observer
export class ImportElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
@@ -15,56 +15,24 @@ export class ImportElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
return FieldView.LayoutString(ImportElementBox, fieldKey);
}
- private _itemRef: React.RefObject<HTMLDivElement> = React.createRef();
- private _dragRef: React.RefObject<HTMLDivElement> = React.createRef();
- private _titleRef: React.RefObject<EditableView> = React.createRef();
-
- @computed importBoxVoew() {
- return this.props.DocumentView?.()?.props.docViewPath().lastElement()?.ComponentView as PresBox;
- }
-
- @computed get indexInPres() {
- return DocListCast(this.presBox?.[StrCast(this.presBox.presFieldKey, 'data')]).indexOf(this.rootDoc);
+ screenToLocalXf = () => this.props.ScreenToLocalTransform().scale(1 * (this.props.NativeDimScaling?.() || 1));
+ @computed get mainItem() {
+ return (
+ <div style={{ backgroundColor: 'pink' }}>
+ <DocumentView
+ {...this.props} //
+ LayoutTemplateString={undefined}
+ Document={this.rootDoc}
+ isContentActive={returnFalse}
+ DataDoc={undefined}
+ addDocument={returnFalse}
+ ScreenToLocalTransform={this.screenToLocalXf}
+ hideResizeHandles={true}
+ />
+ </div>
+ );
}
-
- @computed get presBox() {
- return this.props.DocumentView?.().props.docViewPath().lastElement()?.rootDoc;
+ render() {
+ return !(this.rootDoc instanceof Doc) ? null : this.mainItem;
}
-
- // @computed get selectedArray() {
- // return this.presBoxView?.selectedArray;
- // }
-
-@computed get mainItem() {
- const isCurrent: boolean = this.presBox?._itemIndex === this.indexInPres;
- //const isSelected: boolean = this.selectedArray?.has(this.rootDoc) ? true : false;
- // const activeItem: Doc = this.rootDoc;
-
- return(
- <div
- className = {`presItem-container`}
- // key={this.props.Document[Id] + this.indexInPres}
- style = {{backgroundColor: 'pink'}}
-
- >
- <div
- ref = {this._dragRef}
- className = {`presItem-slide ${isCurrent ? 'active' : ''}`}
- style = {{
- backgroundColor: 'green'
- }}>
- <div
- className="presItem-number"
- title = "select without navigation"
-
- >
- {/* <EditableView ref={this._titleRef} oneLine={true} editing={!isSelected ? false : undefined} contents={activeItem.title} overflow={'ellipsis'} GetValue={() => StrCast(activeItem.title)} SetValue={this.onSetValue} /> */}
-
- </div>
- </div>
-
- </div>
- )
}
-
-} \ No newline at end of file