aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ClientUtils.ts18
-rw-r--r--src/client/documents/DocFromField.ts16
-rw-r--r--src/client/documents/Documents.ts16
-rw-r--r--src/client/util/DocumentManager.ts24
-rw-r--r--src/client/util/SettingsManager.tsx4
-rw-r--r--src/client/util/SnappingManager.ts3
-rw-r--r--src/client/util/request-image-size.ts1
-rw-r--r--src/client/views/GestureOverlay.tsx12
-rw-r--r--src/client/views/MainView.tsx6
-rw-r--r--src/client/views/StyleProvider.tsx2
-rw-r--r--src/client/views/collections/CollectionCarousel3DView.tsx1
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx2
-rw-r--r--src/client/views/collections/CollectionMenu.tsx23
-rw-r--r--src/client/views/collections/CollectionStackedTimeline.tsx2
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx4
-rw-r--r--src/client/views/collections/TreeView.tsx10
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx51
-rw-r--r--src/client/views/collections/collectionSchema/CollectionSchemaView.tsx1
-rw-r--r--src/client/views/global/globalScripts.ts57
-rw-r--r--src/client/views/nodes/ChatBox/MessageComponent.scss10
-rw-r--r--src/client/views/nodes/ChatBox/MessageComponent.tsx110
-rw-r--r--src/client/views/nodes/CollectionFreeFormDocumentView.tsx11
-rw-r--r--src/client/views/nodes/ComparisonBox.scss2
-rw-r--r--src/client/views/nodes/ComparisonBox.tsx142
-rw-r--r--src/client/views/nodes/DataVizBox/components/TableBox.tsx1
-rw-r--r--src/client/views/nodes/DocumentView.tsx158
-rw-r--r--src/client/views/nodes/ImageBox.tsx5
-rw-r--r--src/client/views/nodes/LabelBigText.js270
-rw-r--r--src/client/views/nodes/LabelBox.tsx223
-rw-r--r--src/client/views/nodes/PDFBox.tsx8
-rw-r--r--src/client/views/nodes/WebBox.tsx1
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx12
-rw-r--r--src/client/views/pdf/Annotation.tsx1
-rw-r--r--src/client/views/pdf/PDFViewer.tsx9
-rw-r--r--src/fields/Doc.ts49
35 files changed, 458 insertions, 807 deletions
diff --git a/src/ClientUtils.ts b/src/ClientUtils.ts
index a72e3ffaa..d64210ce2 100644
--- a/src/ClientUtils.ts
+++ b/src/ClientUtils.ts
@@ -86,6 +86,7 @@ export function returnEmptyDoclist() {
return [] as any[];
}
+// eslint-disable-next-line @typescript-eslint/no-namespace
export namespace ClientUtils {
export const CLICK_TIME = 300;
export const DRAG_THRESHOLD = 4;
@@ -471,30 +472,29 @@ export function smoothScrollHorizontal(duration: number, element: HTMLElement |
animateScroll();
}
-export function addStyleSheet(styleType: string = 'text/css') {
+export function addStyleSheet() {
const style = document.createElement('style');
- style.type = styleType;
const sheets = document.head.appendChild(style);
- return (sheets as any).sheet;
+ return sheets.sheet;
}
-export function addStyleSheetRule(sheet: any, selector: any, css: any, selectorPrefix = '.') {
+export function addStyleSheetRule(sheet: CSSStyleSheet | null, selector: string, css: string | {[key:string]: string}, selectorPrefix = '.') {
const propText =
typeof css === 'string'
? css
: Object.keys(css)
.map(p => p + ':' + (p === 'content' ? "'" + css[p] + "'" : css[p]))
.join(';');
- return sheet.insertRule(selectorPrefix + selector + '{' + propText + '}', sheet.cssRules.length);
+ return sheet?.insertRule(selectorPrefix + selector + '{' + propText + '}', sheet.cssRules.length);
}
-export function removeStyleSheetRule(sheet: any, rule: number) {
- if (sheet.rules.length) {
+export function removeStyleSheetRule(sheet: CSSStyleSheet|null, rule: number) {
+ if (sheet?.rules.length) {
sheet.removeRule(rule);
return true;
}
return false;
}
-export function clearStyleSheetRules(sheet: any) {
- if (sheet.rules.length) {
+export function clearStyleSheetRules(sheet: CSSStyleSheet|null) {
+ if (sheet?.rules.length) {
numberRange(sheet.rules.length).map(() => sheet.removeRule(0));
return true;
}
diff --git a/src/client/documents/DocFromField.ts b/src/client/documents/DocFromField.ts
index b65bbbdf5..9acb9c225 100644
--- a/src/client/documents/DocFromField.ts
+++ b/src/client/documents/DocFromField.ts
@@ -1,5 +1,4 @@
import { Doc, DocListCast } from '../../fields/Doc';
-import { InkField } from '../../fields/InkField';
import { List } from '../../fields/List';
import { StrCast } from '../../fields/Types';
import { AudioField, ImageField, PdfField, VideoField } from '../../fields/URLField';
@@ -12,7 +11,17 @@ export function ResetLayoutFieldKey(doc: Doc, fieldKey: string) {
doc.layout = StrCast(doc.layout).replace(/={'.*'}/, `={'${fieldKey}'}`);
return doc;
}
-export function DocumentFromField(target: Doc, fieldKey: string, proto?: Doc, options?: DocumentOptions): Doc | undefined {
+/**
+ * Creates a new document based on the type of (and containing the) data in the specified field of an existing document.
+ * If the field contains a list, then it may be useful to specify a classProto to indicate the type of
+ * collection Doc that gets created.
+ * @param target document to retrive field from
+ * @param fieldKey field key to retrieve
+ * @param classProto optionally a class proto to set on the new document
+ * @param options metadata configuration for new document
+ * @returns
+ */
+export function DocumentFromField(target: Doc, fieldKey: string, classProto?: Doc, options?: DocumentOptions): Doc | undefined {
const field = target[fieldKey];
const resolved = options ?? {};
const nonDocFieldToDoc = () => {
@@ -20,12 +29,11 @@ export function DocumentFromField(target: Doc, fieldKey: string, proto?: Doc, op
if (field instanceof VideoField) return Docs.Create.VideoDocument(field.url.href, resolved);
if (field instanceof PdfField) return Docs.Create.PdfDocument(field.url.href, resolved);
if (field instanceof AudioField) return Docs.Create.AudioDocument(field.url.href, resolved);
- if (field instanceof InkField) return Docs.Create.InkDocument(field.inkData, resolved);
if (field instanceof List && field[0] instanceof Doc) return Docs.Create.StackingDocument(DocListCast(field), resolved);
return Docs.Create.TextDocument('', { ...{ _width: 200, _height: 25, _layout_autoHeight: true }, ...resolved });
};
const created = field instanceof Doc ? field : ResetLayoutFieldKey(nonDocFieldToDoc(), fieldKey);
created.title = fieldKey;
- proto && created.proto && (created.proto = Doc.GetProto(proto));
+ classProto && created.proto && (created.proto = classProto);
return created;
}
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index dc649ec4e..751fe6d91 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -5,7 +5,7 @@ import { reaction } from 'mobx';
import { basename } from 'path';
import { ClientUtils, OmitKeys } from '../../ClientUtils';
import { DateField } from '../../fields/DateField';
-import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, ActiveIsInkMask, CreateLinkToActiveAudio, Doc, FieldType, Opt, updateCachedAcls } from '../../fields/Doc';
+import { CreateLinkToActiveAudio, Doc, FieldType, Opt, updateCachedAcls } from '../../fields/Doc';
import { Initializing } from '../../fields/DocSymbols';
import { HtmlField } from '../../fields/HtmlField';
import { InkField } from '../../fields/InkField';
@@ -837,18 +837,7 @@ export namespace Docs {
return linkDoc;
}
- export function InkDocument(
- points: PointData[],
- options: DocumentOptions = {},
- strokeWidth = ActiveInkWidth(),
- color = ActiveInkColor(),
- strokeBezier = ActiveInkBezierApprox(),
- fillColor = ActiveFillColor(),
- arrowStart = ActiveArrowStart(),
- arrowEnd = ActiveArrowEnd(),
- dash = ActiveDash(),
- isInkMask = ActiveIsInkMask()
- ) {
+ export function InkDocument(points: PointData[], options: DocumentOptions = {}, strokeWidth: number, color: string, strokeBezier: string, fillColor: string, arrowStart: string, arrowEnd: string, dash: string, isInkMask: boolean) {
const ink = InstanceFromProto(Prototypes.get(DocumentType.INK), '', { title: 'ink', ...options });
const I = Doc.GetProto(ink);
// I.layout_hideOpenButton = true; // don't show open full screen button when selected
@@ -864,6 +853,7 @@ export namespace Docs {
I.text_align = 'center';
I.rotation = 0;
I.defaultDoubleClick = 'ignore';
+ I.keepZWhenDragged = true;
I.author_date = new DateField();
I.acl_Guest = Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.View;
// I.acl_Override = SharingPermissions.Unset;
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 487187dfe..ca288303d 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -352,20 +352,22 @@ export class DocumentManager {
// if there's an options.effect, it will be handled from linkFollowHighlight. We delay the start of
// the highlight so that the target document can be somewhat centered so that the effect/highlight will be seen
// bcz: should this delay be an options parameter?
- setTimeout(() => Doc.linkFollowHighlight(viewSpec ? [docView.Document, viewSpec] : docView.Document, undefined, options.effect), (options.zoomTime ?? 0) * 0.5);
+ setTimeout(() => {
+ Doc.linkFollowHighlight(viewSpec ? [docView.Document, viewSpec] : docView.Document, undefined, options.effect);
+ if (options.zoomTextSelections && Doc.IsUnhighlightTimerSet() && contextView && targetDoc.text_html) {
+ // if the docView is a text anchor, the contextView is the PDF/Web/Text doc
+ contextView.setTextHtmlOverlay(StrCast(targetDoc.text_html), options.effect);
+ DocumentManager._overlayViews.add(contextView);
+ }
+ Doc.AddUnHighlightWatcher(() => {
+ docView.Document[Animation] = undefined;
+ DocumentManager.removeOverlayViews();
+ });
+ }, (options.zoomTime ?? 0) * 0.5);
if (options.playMedia) docView.ComponentView?.playFrom?.(NumCast(docView.Document._layout_currentTimecode));
if (options.playAudio) DocumentManager.playAudioAnno(docView.Document);
if (options.toggleTarget && (!options.didMove || docView.Document.hidden)) docView.Document.hidden = !docView.Document.hidden;
-
- if (options.zoomTextSelections && Doc.IsUnhighlightTimerSet() && contextView && targetDoc.text_html) {
- // if the docView is a text anchor, the contextView is the PDF/Web/Text doc
- contextView.setTextHtmlOverlay(StrCast(targetDoc.text_html), options.effect);
- DocumentManager._overlayViews.add(contextView);
- }
- Doc.AddUnHighlightWatcher(() => {
- docView.Document[Animation] = undefined;
- DocumentManager.removeOverlayViews();
- });
+ Doc.AddUnHighlightWatcher(() => docView.Document[Animation] = undefined);
}
}
}
diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx
index d3c10f9f4..278931cdd 100644
--- a/src/client/util/SettingsManager.tsx
+++ b/src/client/util/SettingsManager.tsx
@@ -29,7 +29,7 @@ export enum ColorScheme {
}
@observer
-export class SettingsManager extends React.Component<{}> {
+export class SettingsManager extends React.Component<object> {
// eslint-disable-next-line no-use-before-define
public static Instance: SettingsManager;
static _settingsStyle = addStyleSheet();
@@ -123,7 +123,7 @@ export class SettingsManager extends React.Component<{}> {
'change color scheme'
);
- constructor(props: {}) {
+ constructor(props: object) {
super(props);
makeObservable(this);
SettingsManager.Instance = this;
diff --git a/src/client/util/SnappingManager.ts b/src/client/util/SnappingManager.ts
index 1337d271f..cc0366c5b 100644
--- a/src/client/util/SnappingManager.ts
+++ b/src/client/util/SnappingManager.ts
@@ -11,6 +11,7 @@ export class SnappingManager {
return SnappingManager._manager ?? new SnappingManager();
}
+ @observable _longPress = false;
@observable _shiftKey = false;
@observable _ctrlKey = false;
@observable _metaKey = false;
@@ -43,6 +44,7 @@ export class SnappingManager {
public static get HorizSnapLines() { return this.Instance._horizSnapLines; } // prettier-ignore
public static get VertSnapLines() { return this.Instance._vertSnapLines; } // prettier-ignore
+ public static get LongPress() { return this.Instance._longPress; } // prettier-ignore
public static get ShiftKey() { return this.Instance._shiftKey; } // prettier-ignore
public static get CtrlKey() { return this.Instance._ctrlKey; } // prettier-ignore
public static get MetaKey() { return this.Instance._metaKey; } // prettier-ignore
@@ -58,6 +60,7 @@ export class SnappingManager {
public static get PropertiesWidth(){ return this.Instance._propertyWid; } // prettier-ignore
public static get PrintToConsole() { return this.Instance._printToConsole; } // prettier-ignore
+ public static SetLongPress = (press: boolean) => runInAction(() => {this.Instance._longPress = press}); // prettier-ignore
public static SetShiftKey = (down: boolean) => runInAction(() => {this.Instance._shiftKey = down}); // prettier-ignore
public static SetCtrlKey = (down: boolean) => runInAction(() => {this.Instance._ctrlKey = down}); // prettier-ignore
public static SetMetaKey = (down: boolean) => runInAction(() => {this.Instance._metaKey = down}); // prettier-ignore
diff --git a/src/client/util/request-image-size.ts b/src/client/util/request-image-size.ts
index 0f98a2710..48cb6e3a5 100644
--- a/src/client/util/request-image-size.ts
+++ b/src/client/util/request-image-size.ts
@@ -54,6 +54,7 @@ module.exports = function requestImageSize(options: any) {
}
} catch (err) {
/* empty */
+ console.log("Error: ", err)
}
});
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 2f26bdaef..e3e252593 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -4,25 +4,23 @@ import { observer } from 'mobx-react';
import * as React from 'react';
import { returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, setupMoveUpEvents } from '../../ClientUtils';
import { emptyFunction } from '../../Utils';
+import { Doc, Opt } from '../../fields/Doc';
+import { InkData, InkField, InkTool } from '../../fields/InkField';
+import { NumCast } from '../../fields/Types';
import {
ActiveArrowEnd,
ActiveArrowScale,
ActiveArrowStart,
ActiveDash,
- ActiveFillColor,
ActiveInkBezierApprox,
ActiveInkColor,
ActiveInkWidth,
- Doc,
- Opt,
SetActiveArrowStart,
SetActiveDash,
SetActiveFillColor,
SetActiveInkColor,
SetActiveInkWidth,
-} from '../../fields/Doc';
-import { InkData, InkField, InkTool } from '../../fields/InkField';
-import { NumCast } from '../../fields/Types';
+} from './nodes/DocumentView';
// import MobileInkOverlay from '../../mobile/MobileInkOverlay';
import { Gestures } from '../../pen-gestures/GestureTypes';
import { GestureUtils } from '../../pen-gestures/GestureUtils';
@@ -32,7 +30,7 @@ import { ScriptingGlobals } from '../util/ScriptingGlobals';
import { Transform } from '../util/Transform';
import './GestureOverlay.scss';
import { ObservableReactComponent } from './ObservableReactComponent';
-import { DocumentView } from './nodes/DocumentView';
+import { ActiveFillColor, DocumentView } from './nodes/DocumentView';
export enum ToolglassTools {
InkToText = 'inktotext',
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index eb4f4761e..dd5884cf2 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -566,16 +566,16 @@ export class MainView extends ObservableReactComponent<{}> {
private longPressTimer: NodeJS.Timeout | undefined;
globalPointerClick = action(() => {
this.longPressTimer && clearTimeout(this.longPressTimer);
- DocumentView.LongPress = false;
+ SnappingManager.SetLongPress(false);
});
globalPointerMove = action((e: PointerEvent) => {
if (e.movementX > 3 || e.movementY > 3) this.longPressTimer && clearTimeout(this.longPressTimer);
});
globalPointerDown = action((e: PointerEvent) => {
- DocumentView.LongPress = false;
+ SnappingManager.SetLongPress(false);
this.longPressTimer = setTimeout(
action(() => {
- DocumentView.LongPress = true;
+ SnappingManager.SetLongPress(true);
}),
1000
);
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index b7f8a3170..8c100f238 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -152,7 +152,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps &
case StyleProp.DocContents: return undefined;
case StyleProp.WidgetColor: return isAnnotated ? Colors.LIGHT_BLUE : 'dimgrey';
case StyleProp.Opacity: return componentView?.isUnstyledView?.() ? 1 : Cast(doc?._opacity, "number", Cast(doc?.opacity, 'number', null));
- case StyleProp.FontColor: return StrCast(doc?.[fieldKey + 'fontColor'], StrCast(Doc.UserDoc().fontColor, color()));
+ case StyleProp.FontColor: return StrCast(doc?.[fieldKey + 'fontColor'], isCaption ? lightOrDark(backgroundCol()) : StrCast(Doc.UserDoc().fontColor, color()));
case StyleProp.FontSize: return StrCast(doc?.[fieldKey + 'fontSize'], StrCast(Doc.UserDoc().fontSize));
case StyleProp.FontFamily: return StrCast(doc?.[fieldKey + 'fontFamily'], StrCast(Doc.UserDoc().fontFamily));
case StyleProp.FontWeight: return StrCast(doc?.[fieldKey + 'fontWeight'], StrCast(Doc.UserDoc().fontWeight));
diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx
index 27c85533f..38f681e87 100644
--- a/src/client/views/collections/CollectionCarousel3DView.tsx
+++ b/src/client/views/collections/CollectionCarousel3DView.tsx
@@ -17,6 +17,7 @@ import { FocusViewOptions } from '../nodes/FocusViewOptions';
import './CollectionCarousel3DView.scss';
import { CollectionSubView } from './CollectionSubView';
+// eslint-disable-next-line @typescript-eslint/no-var-requires
const { CAROUSEL3D_CENTER_SCALE, CAROUSEL3D_SIDE_SCALE, CAROUSEL3D_TOP } = require('../global/globalCssVariables.module.scss');
@observer
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 73179a266..2a36e96bf 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -58,7 +58,7 @@ export class CollectionDockingView extends CollectionSubView() {
return this._goldenLayout._maximisedItem !== null;
}
private _goldenLayout: any = null;
- static _highlightStyleSheet: any = addStyleSheet();
+ static _highlightStyleSheet = addStyleSheet();
constructor(props: any) {
super(props);
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 3eb3008c4..b2f0280a5 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -17,7 +17,7 @@ import { DocData } from '../../../fields/DocSymbols';
import { List } from '../../../fields/List';
import { ObjectField } from '../../../fields/ObjectField';
import { RichTextField } from '../../../fields/RichTextField';
-import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../fields/Types';
+import { BoolCast, Cast, NumCast, StrCast } from '../../../fields/Types';
import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes';
import { DragManager } from '../../util/DragManager';
import { dropActionType } from '../../util/DropActionTypes';
@@ -47,7 +47,7 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
private _docBtnRef = React.createRef<HTMLDivElement>();
- constructor(props: any) {
+ constructor(props: CollectionMenuProps) {
super(props);
makeObservable(this);
CollectionMenu.Instance = this;
@@ -279,8 +279,8 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewMenu
initialize: (button: Doc) => {
const activeDash = Doc.ActiveDashboard;
if (activeDash) {
- button.target_childFilters = (Doc.MySearcher._childFilters || activeDash._childFilters) instanceof ObjectField ? ObjectField.MakeCopy((Doc.MySearcher._childFilters || activeDash._childFilters) as any as ObjectField) : undefined;
- button.target_searchFilterDocs = activeDash._searchFilterDocs instanceof ObjectField ? ObjectField.MakeCopy(activeDash._searchFilterDocs as any as ObjectField) : undefined;
+ button.target_childFilters = (Doc.MySearcher._childFilters || activeDash._childFilters) instanceof ObjectField ? ObjectField.MakeCopy((Doc.MySearcher._childFilters || activeDash._childFilters) as ObjectField) : undefined;
+ button.target_searchFilterDocs = activeDash._searchFilterDocs instanceof ObjectField ? ObjectField.MakeCopy(activeDash._searchFilterDocs) : undefined;
}
},
};
@@ -338,15 +338,9 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewMenu
this._currentKey = this._currentKey || (this._buttonizableCommands?.length ? this._buttonizableCommands[0]?.title : '');
});
- @undoBatch
- viewChanged = (e: React.ChangeEvent) => {
- const target = this.document !== Doc.MyLeftSidebarPanel ? this.document : DocCast(this.document.proto);
- target._type_collection = (e.target as any).selectedOptions[0].value;
- };
-
- commandChanged = (e: React.ChangeEvent) => {
+ commandChanged = (e: React.ChangeEvent<HTMLSelectElement>) => {
runInAction(() => {
- this._currentKey = (e.target as any).selectedOptions[0].value;
+ this._currentKey = e.target.selectedOptions[0].value;
});
};
@@ -485,7 +479,7 @@ export class CollectionNoteTakingViewChrome extends React.Component<CollectionVi
};
@action
- onKeyChange = (e: React.ChangeEvent, { newValue }: { newValue: string }) => {
+ onKeyChange = (e: React.FormEvent<Element>, { newValue }: { newValue: string }) => {
this._currentKey = newValue;
};
@@ -538,7 +532,6 @@ export class CollectionNoteTakingViewChrome extends React.Component<CollectionVi
autosuggestProps: {
inputProps: {
value: this._currentKey,
- // @ts-ignore
onChange: this.onKeyChange,
},
getSuggestionValue: this.getSuggestionValue,
@@ -733,7 +726,7 @@ export class CollectionGridViewChrome extends React.Component<CollectionViewMenu
onChange={this.changeCompactType}
value={StrCast(this.document.gridStartCompaction, StrCast(this.document.gridCompaction))}>
{['vertical', 'horizontal', 'none'].map(type => (
- <option className="collectionGridViewChrome-viewOption" onPointerDown={stopPropagation} value={type}>
+ <option key={type} className="collectionGridViewChrome-viewOption" onPointerDown={stopPropagation} value={type}>
{this.resize ? type[0].toUpperCase() + type.substring(1) : 'Compact: ' + type}
</option>
))}
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index fac885300..b03f0cffa 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -850,7 +850,7 @@ class StackedTimelineAnchor extends ObservableReactComponent<StackedTimelineAnch
styleProvider={this._props.styleProvider}
renderDepth={this._props.renderDepth + 1}
LayoutTemplate={undefined}
- LayoutTemplateString={LabelBox.LayoutStringWithTitle('data', this.computeTitle())}
+ LayoutTemplateString={LabelBox.LayoutString('data')}
isDocumentActive={this._props.isDocumentActive}
PanelWidth={width}
PanelHeight={height}
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index c39df2c76..285598600 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -52,7 +52,6 @@ export type collectionTreeViewProps = {
export class CollectionTreeView extends CollectionSubView<Partial<collectionTreeViewProps>>() {
public static AddTreeFunc = 'addTreeFolder(this.embedContainer)';
private _treedropDisposer?: DragManager.DragDropDisposer;
- private _mainEle?: HTMLDivElement;
private _titleRef?: HTMLDivElement | HTMLInputElement | null;
private _disposers: { [name: string]: IReactionDisposer } = {};
private _isDisposing = false; // notes that instance is in process of being disposed
@@ -83,8 +82,6 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
@observable _titleHeight = 0; // height of the title bar
- MainEle = () => this._mainEle;
-
// these should stay in synch with counterparts in DocComponent.ts ViewBoxAnnotatableComponent
@observable _isAnyChildContentActive = false;
whenChildContentsActiveChanged = action((isActive: boolean) => {
@@ -134,7 +131,6 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
};
protected createTreeDropTarget = (ele: HTMLDivElement) => {
this._treedropDisposer?.();
- this._mainEle = ele;
if (ele) this._treedropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.Document, this.onInternalPreDrop.bind(this));
};
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index b82421e6b..f69aea2a7 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -469,14 +469,12 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
return false;
}
- refTransform = (ref: HTMLDivElement | undefined | null) => {
+ refTransform = (ref: HTMLElement | undefined | null) => {
if (!ref) return this.ScreenToLocalTransform();
- const { translateX, translateY } = ClientUtils.GetScreenTransform(ref);
- const outerXf = ClientUtils.GetScreenTransform(this.treeView.MainEle());
- const offset = this.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY);
- return this.ScreenToLocalTransform().translate(offset[0], offset[1]);
+ const { translateX, translateY, scale } = ClientUtils.GetScreenTransform(ref);
+ return new Transform(-translateX, -translateY, 1).scale(1/scale);
};
- docTransform = () => this.refTransform(this._dref?.ContentRef?.current);
+ docTransform = () => this.refTransform(this._dref?.ContentDiv);
getTransform = () => this.refTransform(this._tref.current);
embeddedPanelWidth = () => this._props.panelWidth() / (this.treeView._props.NativeDimScaling?.() || 1);
embeddedPanelHeight = () => {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index b6e1fca77..5b7f09be3 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -9,7 +9,8 @@ import { computedFn } from 'mobx-utils';
import * as React from 'react';
import { ClientUtils, DashColor, lightOrDark, OmitKeys, returnFalse, returnZero, setupMoveUpEvents, UpdateIcon } from '../../../../ClientUtils';
import { DateField } from '../../../../fields/DateField';
-import { ActiveEraserWidth, ActiveInkWidth, Doc, DocListCast, Field, FieldType, Opt, SetActiveInkColor, SetActiveInkWidth } from '../../../../fields/Doc';
+import { Doc, DocListCast, Field, FieldType, Opt } from '../../../../fields/Doc';
+import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveEraserWidth, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, ActiveIsInkMask, SetActiveInkColor, SetActiveInkWidth } from '../../nodes/DocumentView';
import { DocData, Height, Width } from '../../../../fields/DocSymbols';
import { Id } from '../../../../fields/FieldSymbols';
import { InkData, InkField, InkTool, Segment } from '../../../../fields/InkField';
@@ -38,7 +39,7 @@ import { ContextMenu } from '../../ContextMenu';
import { InkingStroke } from '../../InkingStroke';
import { CollectionFreeFormDocumentView } from '../../nodes/CollectionFreeFormDocumentView';
import { SchemaCSVPopUp } from '../../nodes/DataVizBox/SchemaCSVPopUp';
-import { DocumentView } from '../../nodes/DocumentView';
+import { ActiveFillColor, DocumentView } from '../../nodes/DocumentView';
import { FieldViewProps } from '../../nodes/FieldView';
import { FocusViewOptions } from '../../nodes/FocusViewOptions';
import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox';
@@ -87,8 +88,10 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
}
private _clusters = new CollectionFreeFormClusters(this);
- private _oldWheel: any;
- private _panZoomTransitionTimer: any;
+ private _oldWheel: HTMLDivElement | null = null;
+ private _panZoomTransitionTimer: NodeJS.Timeout | undefined = undefined;
+ private _brushtimer: NodeJS.Timeout | undefined = undefined;
+ private _brushtimer1: NodeJS.Timeout | undefined = undefined;
private _lastX: number = 0;
private _lastY: number = 0;
private _downX: number = 0;
@@ -97,8 +100,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
private _disposers: { [name: string]: IReactionDisposer } = {};
private _renderCutoffData = observable.map<string, boolean>();
private _batch: UndoManager.Batch | undefined = undefined;
- private _brushtimer: any;
- private _brushtimer1: any;
private _keyTimer: NodeJS.Timeout | undefined; // timer for turning off transition flag when key frame change has completed. Need to clear this if you do a second navigation before first finishes, or else first timer can go off during second naviation.
private _presEaseFunc: string = 'ease';
@@ -129,7 +130,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
@observable _eraserX: number = 0;
@observable _eraserY: number = 0;
@observable _showEraserCircle: boolean = false; // to determine whether the radius eraser should show
- constructor(props: any) {
+ constructor(props: collectionFreeformViewProps) {
super(props);
makeObservable(this);
}
@@ -550,7 +551,14 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
_width: B.width + inkWidth,
_height: B.height + inkWidth,
stroke_showLabel: BoolCast(Doc.UserDoc().activeInkHideTextLabels)}, // prettier-ignore
- inkWidth
+ inkWidth,
+ ActiveInkColor(),
+ ActiveInkBezierApprox(),
+ ActiveFillColor(),
+ ActiveArrowStart(),
+ ActiveArrowEnd(),
+ ActiveDash(),
+ ActiveIsInkMask()
);
if (Doc.ActiveTool === InkTool.Write) {
this.unprocessedDocs.push(inkDoc);
@@ -634,7 +642,14 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
_width: B.width + inkWidth,
_height: B.height + inkWidth,
stroke_showLabel: BoolCast(Doc.UserDoc().activeInkHideTextLabels)}, // prettier-ignore
- inkWidth
+ inkWidth,
+ ActiveInkColor(),
+ ActiveInkBezierApprox(),
+ ActiveFillColor(),
+ ActiveArrowStart(),
+ ActiveArrowEnd(),
+ ActiveDash(),
+ ActiveIsInkMask()
);
});
newStrokes && this.addDocument?.(newStrokes);
@@ -684,8 +699,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
return false;
};
- forceStrokeGesture = (e: PointerEvent, gesture: Gestures, points: InkData, text?: any) => {
- this.onGesture(e, new GestureUtils.GestureEvent(gesture, points, InkField.getBounds(points), text));
+ forceStrokeGesture = (e: PointerEvent, gesture: Gestures, points: InkData) => {
+ this.onGesture(e, new GestureUtils.GestureEvent(gesture, points, InkField.getBounds(points)));
};
onPointerMove = (e: PointerEvent) => {
@@ -1639,7 +1654,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
* since rendering a large collection of documents can be slow, at startup, docs are rendered in batches.
* each doc's render() method will call the cutoff provider which will let the doc know if it should render itself yet, or wait
*/
- renderCutoffProvider = computedFn((doc: Doc) => (this.Document.isTemplateDoc ? false : !this._renderCutoffData.get(doc[Id] + '')));
+ renderCutoffProvider = computedFn((doc: Doc) => (this.Document.isTemplateDoc || this.Document.isTemplateForField ? false : !this._renderCutoffData.get(doc[Id] + '')));
doEngineLayout(
poolData: Map<string, PoolData>,
@@ -1673,7 +1688,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
.forEach(entry =>
elements.push({
ele: this.getChildDocView(entry[1]),
- bounds: (entry[1].opacity === 0 ? { ...entry[1], width: 0, height: 0 } : { ...entry[1] }) as any,
+ bounds: (entry[1].opacity === 0 ? { payload:undefined, type:"", ...entry[1], width: 0, height: 0 } : { payload:undefined, type:"",...entry[1] }),
inkMask: BoolCast(entry[1].pair.layout.stroke_isInkMask) ? NumCast(entry[1].pair.layout.opacity, 1) : -1,
})
);
@@ -1795,10 +1810,11 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
Object.values(this._disposers).forEach(disposer => disposer?.());
}
- updateIcon = () =>
- UpdateIcon(
+ updateIcon = () => {
+ const contentDiv = this.DocumentView?.().ContentDiv;
+ contentDiv && UpdateIcon(
this.layoutDoc[Id] + '-icon' + new Date().getTime(),
- this.DocumentView?.().ContentDiv!,
+ contentDiv,
NumCast(this.layoutDoc._width),
NumCast(this.layoutDoc._height),
this._props.PanelWidth(),
@@ -1813,6 +1829,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
this.dataDoc.icon_nativeHeight = nativeHeight;
}
);
+ }
@action
onCursorMove = (e: React.PointerEvent) => {
@@ -1993,7 +2010,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
incrementalRender = action(() => {
if (!DocumentView.LightboxDoc() || DocumentView.LightboxContains(this.DocumentView?.())) {
const layoutUnrendered = this.childDocs.filter(doc => !this._renderCutoffData.get(doc[Id]));
- const loadIncrement = this.Document.isTemplateDoc ? Number.MAX_VALUE : 5;
+ const loadIncrement = this.Document.isTemplateDoc || this.Document.isTemplateForField ? Number.MAX_VALUE : 5;
for (let i = 0; i < Math.min(layoutUnrendered.length, loadIncrement); i++) {
this._renderCutoffData.set(layoutUnrendered[i][Id] + '', true);
}
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index cc8b0fc7e..12c342b9f 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -46,6 +46,7 @@ import { SchemaCellField } from './SchemaCellField';
import { threadId } from 'worker_threads';
import { FontIconBox } from '../../nodes/FontIconBox/FontIconBox';
+// eslint-disable-next-line @typescript-eslint/no-var-requires
const { SCHEMA_NEW_NODE_HEIGHT } = require('../../global/globalCssVariables.module.scss'); // prettier-ignore
export const FInfotoColType: { [key: string]: ColumnType } = {
diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts
index 95f83bc5c..6f9afe165 100644
--- a/src/client/views/global/globalScripts.ts
+++ b/src/client/views/global/globalScripts.ts
@@ -1,25 +1,10 @@
import { Colors } from 'browndash-components';
import { action, runInAction } from 'mobx';
import { aggregateBounds } from '../../../Utils';
-import {
- ActiveFillColor,
- ActiveEraserWidth,
- ActiveInkColor,
- ActiveInkHideTextLabels,
- ActiveInkWidth,
- ActiveIsInkMask,
- Doc,
- DocListCast,
- Opt,
- SetActiveFillColor,
- SetActiveInkColor,
- SetActiveInkHideTextLabels,
- SetActiveInkWidth,
- SetActiveIsInkMask,
- SetEraserWidth,
-} from '../../../fields/Doc';
+import { Doc, DocListCast, NumListCast, Opt } from '../../../fields/Doc';
import { DocData } from '../../../fields/DocSymbols';
import { InkTool } from '../../../fields/InkField';
+import { List } from '../../../fields/List';
import { BoolCast, Cast, NumCast, StrCast } from '../../../fields/Types';
import { WebField } from '../../../fields/URLField';
import { Gestures } from '../../../pen-gestures/GestureTypes';
@@ -31,13 +16,25 @@ import { GestureOverlay } from '../GestureOverlay';
import { InkingStroke } from '../InkingStroke';
import { CollectionFreeFormView } from '../collections/collectionFreeForm';
import { CollectionFreeFormDocumentView } from '../nodes/CollectionFreeFormDocumentView';
-import { DocumentView } from '../nodes/DocumentView';
+import {
+ ActiveEraserWidth,
+ ActiveFillColor,
+ ActiveInkColor,
+ ActiveInkHideTextLabels,
+ ActiveInkWidth,
+ ActiveIsInkMask,
+ DocumentView,
+ SetActiveFillColor,
+ SetActiveInkColor,
+ SetActiveInkHideTextLabels,
+ SetActiveInkWidth,
+ SetActiveIsInkMask,
+ SetEraserWidth,
+} from '../nodes/DocumentView';
import { ImageBox } from '../nodes/ImageBox';
import { VideoBox } from '../nodes/VideoBox';
import { WebBox } from '../nodes/WebBox';
import { RichTextMenu } from '../nodes/formattedText/RichTextMenu';
-import { NumListCast } from '../../../fields/Doc';
-import { List } from '../../../fields/List';
// import { InkTranscription } from '../InkTranscription';
@@ -59,7 +56,7 @@ ScriptingGlobals.add(function setView(view: string, getSelected: boolean) {
// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function setBackgroundColor(color?: string, checkResult?: boolean) {
const selectedViews = DocumentView.Selected();
- if (Doc.ActiveTool !== InkTool.None) {
+ if (Doc.ActiveTool !== InkTool.None && !selectedViews.lastElement()?.Document._layout_isSvg) {
if (checkResult) {
return ActiveFillColor();
}
@@ -452,15 +449,19 @@ function setActiveTool(tool: InkTool | Gestures, keepPrim: boolean, checkResult?
GestureOverlay.Instance.InkShape = tool as Gestures;
}
} else if (tool) {
- if ([InkTool.StrokeEraser, InkTool.RadiusEraser, InkTool.SegmentEraser].includes(tool as any)) {
- Doc.UserDoc().activeEraserTool = tool;
- }
- // pen or eraser
- if (Doc.ActiveTool === tool && !GestureOverlay.Instance.InkShape && !keepPrim) {
+ if (Doc.UserDoc().ActiveTool === tool) {
Doc.ActiveTool = InkTool.None;
} else {
- Doc.ActiveTool = tool as any;
- GestureOverlay.Instance.InkShape = undefined;
+ if ([InkTool.StrokeEraser, InkTool.RadiusEraser, InkTool.SegmentEraser].includes(tool as any)) {
+ Doc.UserDoc().activeEraserTool = tool;
+ }
+ // pen or eraser
+ if (Doc.ActiveTool === tool && !GestureOverlay.Instance.InkShape && !keepPrim) {
+ Doc.ActiveTool = InkTool.None;
+ } else {
+ Doc.ActiveTool = tool as any;
+ GestureOverlay.Instance.InkShape = undefined;
+ }
}
} else {
Doc.ActiveTool = InkTool.None;
diff --git a/src/client/views/nodes/ChatBox/MessageComponent.scss b/src/client/views/nodes/ChatBox/MessageComponent.scss
new file mode 100644
index 000000000..6fcc0e5e7
--- /dev/null
+++ b/src/client/views/nodes/ChatBox/MessageComponent.scss
@@ -0,0 +1,10 @@
+MessageComponent-citation {
+ color: lightblue;
+ vertical-align: super;
+ font-size: smaller;
+}
+MessageComponent-file_path {
+ color: lightblue;
+ vertical-align: baseline;
+ font-size: inherit;
+}
diff --git a/src/client/views/nodes/ChatBox/MessageComponent.tsx b/src/client/views/nodes/ChatBox/MessageComponent.tsx
index fced0b4d5..f27a18891 100644
--- a/src/client/views/nodes/ChatBox/MessageComponent.tsx
+++ b/src/client/views/nodes/ChatBox/MessageComponent.tsx
@@ -1,11 +1,25 @@
+/* eslint-disable jsx-a11y/control-has-associated-label */
/* eslint-disable react/require-default-props */
-import React from 'react';
-import { observer } from 'mobx-react';
import { MathJax, MathJaxContext } from 'better-react-mathjax';
+import { observer } from 'mobx-react';
+import React from 'react';
+import * as Tb from 'react-icons/tb';
import ReactMarkdown from 'react-markdown';
-import { TbCircle0Filled, TbCircle1Filled, TbCircle2Filled, TbCircle3Filled, TbCircle4Filled, TbCircle5Filled, TbCircle6Filled, TbCircle7Filled, TbCircle8Filled, TbCircle9Filled } from 'react-icons/tb';
+import './MessageComponent.scss';
import { AssistantMessage } from './types';
+const TbCircles = [
+ Tb.TbCircleNumber0Filled,
+ Tb.TbCircleNumber1Filled,
+ Tb.TbCircleNumber2Filled,
+ Tb.TbCircleNumber3Filled,
+ Tb.TbCircleNumber4Filled,
+ Tb.TbCircleNumber5Filled,
+ Tb.TbCircleNumber6Filled,
+ Tb.TbCircleNumber7Filled,
+ Tb.TbCircleNumber8Filled,
+ Tb.TbCircleNumber9Filled,
+];
interface MessageComponentProps {
message: AssistantMessage;
toggleToolLogs: (index: number) => void;
@@ -17,89 +31,41 @@ interface MessageComponentProps {
isCurrent?: boolean;
}
-const MessageComponent: React.FC<MessageComponentProps> = function ({ message, toggleToolLogs, expandedLogIndex, goToLinkedDoc, index, showModal, setCurrentFile, isCurrent = false }) {
- // const messageClass = `${message.role} ${isCurrent ? 'current-message' : ''}`;
-
- const LinkRenderer = ({ href, children }: { href: string; children: React.ReactNode }) => {
- // console.log(href + " " + children)
- const regex = /([a-zA-Z0-9_.!-]+)~~~(citation|file_path)/;
- const matches = href.match(regex);
- // console.log(href)
- // console.log(matches)
- const url = matches ? matches[1] : href;
- const linkType = matches ? matches[2] : null;
- if (linkType === 'citation') {
- switch (children) {
- case '0':
- children = <TbCircle0Filled />;
- break;
- case '1':
- children = <TbCircle1Filled />;
- break;
- case '2':
- children = <TbCircle2Filled />;
- break;
- case '3':
- children = <TbCircle3Filled />;
- break;
- case '4':
- children = <TbCircle4Filled />;
- break;
- case '5':
- children = <TbCircle5Filled />;
- break;
- case '6':
- children = <TbCircle6Filled />;
- break;
- case '7':
- children = <TbCircle7Filled />;
- break;
- case '8':
- children = <TbCircle8Filled />;
- break;
- case '9':
- children = <TbCircle9Filled />;
- break;
- default:
- break;
- }
- }
- // console.log(linkType)
- const style = {
- color: 'lightblue',
- verticalAlign: linkType === 'citation' ? 'super' : 'baseline',
- fontSize: linkType === 'citation' ? 'smaller' : 'inherit',
- };
-
- return (
- <a
+const LinkRendererWrapper = (goToLinkedDoc: (url: string) => void, showModal: () => void, setCurrentFile: (file: { url: string }) => void) =>
+ function LinkRenderer({ href, children }: { href?: string; children?: React.ReactNode }) {
+ const Children = TbCircles[Number(children)]; // pascal case variable needed to convert IconType to JSX.Element tag
+ const [, aurl, linkType] = href?.match(/([a-zA-Z0-9_.!-]+)~~~(citation|file_path)/) ?? [undefined, href, null];
+ const renderType = (content: JSX.Element | null, click: (url: string) => void):JSX.Element => (
+ // eslint-disable-next-line jsx-a11y/anchor-is-valid
+ <a className={`MessageComponent-${linkType}`}
href="#"
onClick={e => {
e.preventDefault();
- if (linkType === 'citation') {
- goToLinkedDoc(url);
- } else if (linkType === 'file_path') {
- showModal();
- setCurrentFile({ url });
- }
- }}
- style={style}>
- {children}
- </a>
- );
+ aurl && click(aurl);
+ }}>
+ {content}
+ </a>
+ ); // prettier-ignore
+ switch (linkType) {
+ case 'citation': return renderType(<Children />, (url: string) => goToLinkedDoc(url));
+ case 'file_path': return renderType(null, (url: string) => { showModal(); setCurrentFile({ url }); });
+ default: return null;
+ } // prettier-ignore
};
+const MessageComponent: React.FC<MessageComponentProps> = function ({ message, toggleToolLogs, expandedLogIndex, goToLinkedDoc, index, showModal, setCurrentFile, isCurrent = false }) {
+ // const messageClass = `${message.role} ${isCurrent ? 'current-message' : ''}`;
return (
<div className={`message ${message.role}`}>
<MathJaxContext>
<MathJax dynamic hideUntilTypeset="every">
- <ReactMarkdown components={{ a: LinkRenderer }}>{message.text ? message.text : ''}</ReactMarkdown>
+ <ReactMarkdown components={{ a: LinkRendererWrapper(goToLinkedDoc, showModal, setCurrentFile) }}>{message.text}</ReactMarkdown>
</MathJax>
</MathJaxContext>
{message.image && <img src={message.image} alt="" />}
<div className="message-footer">
{message.tool_logs && (
- <button className="toggle-logs-button" onClick={() => toggleToolLogs(index)}>
+ <button type="button" className="toggle-logs-button" onClick={() => toggleToolLogs(index)}>
{expandedLogIndex === index ? 'Hide Code Interpreter Logs' : 'Show Code Interpreter Logs'}
</button>
)}
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 034a38e9c..ee67dd305 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -20,6 +20,11 @@ import { DocumentView, DocumentViewProps } from './DocumentView';
import { FieldViewProps } from './FieldView';
import { OpenWhere } from './OpenWhere';
+export enum GroupActive { // flags for whether a view is activate because of its relationship to a group
+ group = 'group', // this is a group that is activated because it's on an active canvas, but is not part of some other group
+ child = 'child', // this is a group child that is activated because its containing group is activated
+ inactive = 'inactive', // this is a group child but it is not active
+}
/// Ugh, typescript has no run-time way of iterating through the keys of an interface. so we need
/// manaully keep this list of keys in synch wih the fields of the freeFormProps interface
const freeFormPropsKeys = ['x', 'y', 'z', 'zIndex', 'rotation', 'opacity', 'backgroundColor', 'color', 'highlight', 'width', 'height', 'autoDim', 'transition'];
@@ -274,7 +279,9 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
if (this._props.isAnyChildContentActive()) return undefined;
const backColor = this.BackgroundColor;
const isGroup = this.dataDoc.isGroup && (!backColor || backColor === 'transparent');
- return isGroup ? (this._props.isDocumentActive?.() ? 'group' : this._props.isGroupActive?.() ? 'child' : 'inactive') : this._props.isGroupActive?.() ? 'child' : undefined;
+ return isGroup ? (this._props.isDocumentActive?.() ? GroupActive.group :
+ this._props.isGroupActive?.() ? GroupActive.child : GroupActive.inactive) :
+ this._props.isGroupActive?.() ? GroupActive.child : undefined; // prettier-ignore
};
localRotation = () => this._props.rotation;
render() {
@@ -313,6 +320,6 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
}
}
// eslint-disable-next-line prefer-arrow-callback
-ScriptingGlobals.add(function gotoFrame(doc: any, newFrame: any) {
+ScriptingGlobals.add(function gotoFrame(doc: Doc, newFrame: number) {
CollectionFreeFormDocumentView.gotoKeyFrame(doc, newFrame);
});
diff --git a/src/client/views/nodes/ComparisonBox.scss b/src/client/views/nodes/ComparisonBox.scss
index 093b9c004..08d9e6010 100644
--- a/src/client/views/nodes/ComparisonBox.scss
+++ b/src/client/views/nodes/ComparisonBox.scss
@@ -49,7 +49,6 @@
left: 0;
height: 100%;
overflow: hidden;
- transition: 200ms;
.beforeBox-cont {
height: 100%;
@@ -63,7 +62,6 @@
width: 3px;
display: inline-block;
background: white;
- transition: 200ms;
.slide-handle {
position: absolute;
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index adb380f12..efaf6807a 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -30,41 +30,23 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
return FieldView.LayoutString(ComparisonBox, fieldKey);
}
private _disposers: (DragManager.DragDropDisposer | undefined)[] = [undefined, undefined];
+ private _closeRef = React.createRef<HTMLDivElement>();
+ @observable _inputValue = '';
+ @observable _outputValue = '';
+ @observable _loading = false;
+ @observable _errorMessage = '';
+ @observable _outputMessage = '';
+ @observable _animating = '';
+
constructor(props: FieldViewProps) {
super(props);
makeObservable(this);
}
- @observable inputValue = '';
- @observable outputValue = '';
- @observable loading = false;
- @observable errorMessage = '';
- @observable outputMessage = '';
-
- @action handleInputChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
- this.inputValue = e.target.value;
- console.log(this.inputValue);
- };
-
- @observable _animating = '';
-
- @computed get clipWidth() {
- return NumCast(this.layoutDoc[this.clipWidthKey], 50);
- }
- get clipWidthKey() {
- return '_' + this._props.fieldKey + '_clipWidth';
- }
-
- @computed get clipHeight() {
- return NumCast(this.layoutDoc[this.clipHeightKey], 200);
- }
- get clipHeightKey() {
- return '_' + this._props.fieldKey + '_clipHeight';
- }
-
componentDidMount() {
this._props.setContentViewBox?.(this);
}
+
protected createDropTarget = (ele: HTMLDivElement | null, fieldKey: string, disposerId: number) => {
this._disposers[disposerId]?.();
if (ele) {
@@ -72,7 +54,19 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
}
};
- private internalDrop = undoable((e: Event, dropEvent: DragManager.DropEvent, fieldKey: string) => {
+ @computed get revealOp() { return this.layoutDoc[`_${this.fieldKey}_revealOp`] as ('flip'|'hover'|undefined); } // prettier-ignore
+ @computed get clipWidth() { return NumCast(this.layoutDoc[`_${this.fieldKey}_clipWidth`], 50); } // prettier-ignore
+ set clipWidth(width: number) { this.layoutDoc[`_${this.fieldKey}_clipWidth`] = width; } // prettier-ignore
+ @computed get useAlternate() { return this.layoutDoc[`_${this.fieldKey}_usePath`] === 'alternate'; } // prettier-ignore
+ set useAlternate(alt: boolean) { this.layoutDoc[`_${this.fieldKey}_usePath`] = alt ? 'alternate' : undefined; } // prettier-ignore
+
+ animateClipWidth = action((clipWidth: number, duration = 200 /* ms */) => {
+ this._animating = `all ${duration}ms`; // turn on clip animation transition, then turn it off at end of animation
+ setTimeout(action(() => { this._animating = ''; }), duration); // prettier-ignore
+ this.clipWidth = clipWidth;
+ });
+
+ internalDrop = undoable((e: Event, dropEvent: DragManager.DropEvent, fieldKey: string) => {
if (dropEvent.complete.docDragData) {
const { droppedDocuments } = dropEvent.complete.docDragData;
const added = dropEvent.complete.docDragData.moveDocument?.(droppedDocuments, this.Document, (doc: Doc | Doc[]) => this.addDoc(toList(doc).lastElement(), fieldKey));
@@ -84,45 +78,34 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
return undefined;
}, 'internal drop');
- private registerSliding = (e: React.PointerEvent<HTMLDivElement>, targetWidth: number) => {
+ registerSliding = (e: React.PointerEvent<HTMLDivElement>, targetWidth: number) => {
if (e.button !== 2) {
setupMoveUpEvents(
this,
e,
this.onPointerMove,
emptyFunction,
- action((moveEv, doubleTap) => {
+ action((clickEv, doubleTap) => {
if (doubleTap) {
this._isAnyChildContentActive = true;
if (!this.dataDoc[this.fieldKey + '_1'] && !this.dataDoc[this.fieldKey]) this.dataDoc[this.fieldKey + '_1'] = DocUtils.copyDragFactory(Doc.UserDoc().emptyNote as Doc);
if (!this.dataDoc[this.fieldKey + '_2'] && !this.dataDoc[this.fieldKey + '_alternate']) this.dataDoc[this.fieldKey + '_2'] = DocUtils.copyDragFactory(Doc.UserDoc().emptyNote as Doc);
+ // DocumentView.addViewRenderedCb(DocCast(this.dataDoc[this.fieldKey + '_1']), dv => {
+ // dv?.select(false);
+ // });
}
}),
- false,
+ true,
undefined,
- action(() => {
- if (this._isAnyChildContentActive) return;
- this._animating = 'all 200ms';
- // on click, animate slider movement to the targetWidth
- this.layoutDoc[this.clipWidthKey] = (targetWidth * 100) / this._props.PanelWidth();
- // this.layoutDoc[this.clipHeightKey] = (targetWidth * 100) / this._props.PanelHeight();
-
- setTimeout(
- action(() => {
- this._animating = '';
- }),
- 200
- );
- })
+ () => !this._isAnyChildContentActive && this.animateClipWidth((targetWidth * 100) / this._props.PanelWidth())
);
}
};
- @action
- private onPointerMove = ({ movementX }: PointerEvent) => {
+ onPointerMove = ({ movementX }: PointerEvent) => {
const width = movementX * this.ScreenToLocalBoxXf().Scale + (this.clipWidth / 100) * this._props.PanelWidth();
- if (width && width > 5 && width < this._props.PanelWidth()) {
- this.layoutDoc[this.clipWidthKey] = (width * 100) / this._props.PanelWidth();
+ if (width > 5 && width < this._props.PanelWidth()) {
+ this.clipWidth = (width * 100) / this._props.PanelWidth();
}
return false;
};
@@ -180,8 +163,10 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
);
};
docStyleProvider = (doc: Opt<Doc>, props: Opt<FieldViewProps>, property: string): any => {
- if (property === StyleProp.PointerEvents) return 'none';
- return this._props.styleProvider?.(doc, props, property);
+ switch (property) {
+ case StyleProp.PointerEvents: return 'none';
+ default: return this._props.styleProvider?.(doc, props, property);
+ } // prettier-ignore
};
moveDoc1 = (docs: Doc | Doc[], targetCol: Doc | undefined, addDoc: any) => toList(docs).reduce((res, doc: Doc) => res && this.moveDoc(doc, addDoc, this.fieldKey + '_1'), true);
moveDoc2 = (docs: Doc | Doc[], targetCol: Doc | undefined, addDoc: any) => toList(docs).reduce((res, doc: Doc) => res && this.moveDoc(doc, addDoc, this.fieldKey + '_2'), true);
@@ -220,36 +205,31 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
return layoutTemplateString;
};
- _closeRef = React.createRef<HTMLDivElement>();
-
/**
* Flips a flashcard to the alternate side for the user to view.
*/
flipFlashcard = () => {
- const usePath = this.layoutDoc[`_${this._props.fieldKey}_usePath`];
- this.layoutDoc[`_${this._props.fieldKey}_usePath`] = usePath === undefined ? 'alternate' : undefined;
+ this.useAlternate = !this.useAlternate;
};
/**
* Changes the view option to hover for a flashcard.
*/
- hoverFlip = (side: string | undefined) => {
- if (this.layoutDoc[`_${this._props.fieldKey}_revealOp`] === 'hover') this.layoutDoc[`_${this._props.fieldKey}_usePath`] = side;
+ hoverFlip = (alternate: boolean) => {
+ if (this.revealOp === 'hover') this.useAlternate = alternate;
};
/**
* Creates the button used to flip the flashcards.
*/
@computed get overlayAlternateIcon() {
- const usepath = this.layoutDoc[`_${this._props.fieldKey}_usePath`];
return (
<Tooltip title={<div className="dash-tooltip">flip</div>}>
<div
className="formattedTextBox-alternateButton"
onPointerDown={e =>
setupMoveUpEvents(e.target, e, returnFalse, emptyFunction, () => {
- console.log(this.layoutDoc[`_${this._props.fieldKey}_revealOp`]);
- if (!this.layoutDoc[`_${this._props.fieldKey}_revealOp`] || this.layoutDoc[`_${this._props.fieldKey}_revealOp`] === 'flip') {
+ if (!this.revealOp || this.revealOp === 'flip') {
this.flipFlashcard();
console.log('Print Front of cards: ' + (RTFCast(DocCast(this.dataDoc[this.fieldKey + '_0']).text)?.Text ?? ''));
console.log('Print Back of cards: ' + (RTFCast(DocCast(this.dataDoc[this.fieldKey + '_1']).text)?.Text ?? ''));
@@ -257,8 +237,8 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
})
}
style={{
- background: usepath === 'alternate' ? 'white' : 'black',
- color: usepath === 'alternate' ? 'black' : 'white',
+ background: this.useAlternate ? 'white' : 'black',
+ color: this.useAlternate ? 'black' : 'white',
}}>
<FontAwesomeIcon icon="turn-up" size="sm" />
</div>
@@ -268,14 +248,14 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
@action handleRenderGPTClick = () => {
// Call the GPT model and get the output
- this.layoutDoc[`_${this._props.fieldKey}_usePath`] = 'alternate';
- this.outputValue = '';
- if (this.inputValue) this.askGPT();
+ this.useAlternate = true;
+ this._outputValue = '';
+ if (this._inputValue) this.askGPT();
};
@action handleRenderClick = () => {
// Call the GPT model and get the output
- this.layoutDoc[`_${this._props.fieldKey}_usePath`] = undefined;
+ this.useAlternate = false;
};
/**
@@ -285,7 +265,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
askGPT = async (): Promise<string | undefined> => {
const questionText = 'Question: ' + StrCast(RTFCast(DocCast(this.dataDoc[this.fieldKey + '_1']).text)?.Text);
const rubricText = ' Rubric: ' + StrCast(RTFCast(DocCast(this.dataDoc[this.fieldKey + '_0']).text)?.Text);
- const queryText = questionText + ' UserAnswer: ' + this.inputValue + '. ' + rubricText;
+ const queryText = questionText + ' UserAnswer: ' + this._inputValue + '. ' + rubricText;
try {
const res = await gptAPICall(queryText, GPTCallType.QUIZ);
@@ -293,8 +273,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
console.error('GPT call failed');
return;
}
- this.outputValue = res;
- console.log(res);
+ this._outputValue = res;
} catch (err) {
console.error('GPT call failed');
}
@@ -355,7 +334,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
);
if (this.Document._layout_isFlashcard) {
- const side = this.layoutDoc[`_${this._props.fieldKey}_usePath`] === 'alternate' ? 1 : 0;
+ const side = this.useAlternate ? 1 : 0;
// add text box to each side when comparison box is first created
if (!(this.dataDoc[this.fieldKey + '_0'] || this.dataDoc[this.fieldKey + '_0'] === 'empty')) {
@@ -383,17 +362,19 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
{/* {StrCast(RTFCast(DocCast(this.dataDoc[this.fieldKey + '_1']).text)?.Text)} */}
<div className="input-box">
<textarea
- value={this.layoutDoc[`_${this._props.fieldKey}_usePath`] === 'alternate' ? this.outputValue : this.inputValue}
- onChange={this.handleInputChange}
- readOnly={this.layoutDoc[`_${this._props.fieldKey}_usePath`] === 'alternate'}
+ value={this.useAlternate ? this._outputValue : this._inputValue}
+ onChange={action(e => {
+ this._inputValue = e.target.value;
+ })}
+ readOnly={this.useAlternate}
/>
</div>
- <div className="submit-button" style={{ display: this.layoutDoc[`_${this._props.fieldKey}_usePath`] === 'alternate' ? 'none' : 'flex' }}>
+ <div className="submit-button" style={{ display: this.useAlternate ? 'none' : 'flex' }}>
<button type="button" onClick={this.handleRenderGPTClick}>
Submit
</button>
</div>
- <div className="submit-button" style={{ display: this.layoutDoc[`_${this._props.fieldKey}_usePath`] === 'alternate' ? 'flex' : 'none' }}>
+ <div className="submit-button" style={{ display: this.useAlternate ? 'flex' : 'none' }}>
<button type="button" onClick={this.handleRenderClick}>
Edit Your Response
</button>
@@ -407,12 +388,8 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
<div
className={`comparisonBox${this._props.isContentActive() ? '-interactive' : ''}`} /* change className to easily disable/enable pointer events in CSS */
style={{ display: 'flex', flexDirection: 'column' }}
- onMouseEnter={() => {
- this.hoverFlip('alternate');
- }}
- onMouseLeave={() => {
- this.hoverFlip(undefined);
- }}>
+ onMouseEnter={() => this.hoverFlip(true)}
+ onMouseLeave={() => this.hoverFlip(false)}>
{displayBox(`${this.fieldKey}_${side === 0 ? 1 : 0}`, side, this._props.PanelWidth() - 3)}
{this.overlayAlternateIcon}
</div>
@@ -430,9 +407,10 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
className="slide-bar"
style={{
left: `calc(${this.clipWidth + '%'} - 0.5px)`,
+ transition: this._animating,
cursor: this.clipWidth < 5 ? 'e-resize' : this.clipWidth / 100 > (this._props.PanelWidth() - 5) / this._props.PanelWidth() ? 'w-resize' : undefined,
}}
- onPointerDown={e => !this._isAnyChildContentActive && this.registerSliding(e, this._props.PanelWidth() / 2)} /* if clicked, return slide-bar to center */
+ onPointerDown={e => this.registerSliding(e, this._props.PanelWidth() / 2)} /* if clicked, return slide-bar to center */
>
<div className="slide-handle" />
</div>
diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
index d484bf5e8..559b8507c 100644
--- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx
+++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
@@ -18,6 +18,7 @@ import { DocumentView } from '../../DocumentView';
import { DataVizView } from '../DataVizBox';
import './Chart.scss';
+// eslint-disable-next-line @typescript-eslint/no-var-requires
const { DATA_VIZ_TABLE_ROW_HEIGHT } = require('../../../global/globalCssVariables.module.scss'); // prettier-ignore
interface TableBoxProps {
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index aff5a3dca..8edb37acc 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -43,6 +43,7 @@ import { ObserverJsxParser } from '../ObservableReactComponent';
import { PinProps } from '../PinFuncs';
import { StyleProp } from '../StyleProp';
import { ViewBoxInterface } from '../ViewBoxInterface';
+import { GroupActive } from './CollectionFreeFormDocumentView';
import { DocumentContentsView } from './DocumentContentsView';
import { DocumentLinksButton } from './DocumentLinksButton';
import './DocumentView.scss';
@@ -52,7 +53,7 @@ import { OpenWhere, OpenWhereMod } from './OpenWhere';
import { FormattedTextBox } from './formattedText/FormattedTextBox';
import { PresEffect, PresEffectDirection } from './trails/PresEnums';
import SpringAnimation from './trails/SlideEffect';
-import { SpringSettings, SpringType, springMappings } from './trails/SpringUtils';
+import { SpringType, springMappings } from './trails/SpringUtils';
interface Window {
MediaRecorder: MediaRecorder;
@@ -153,7 +154,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
@computed get disableClickScriptFunc() {
const onScriptDisable = this._props.onClickScriptDisable ?? this._componentView?.onClickScriptDisable?.() ?? this.layoutDoc.onClickScriptDisable;
- return (DocumentView.LongPress ||
+ return (SnappingManager.LongPress ||
onScriptDisable === 'always' ||
(onScriptDisable !== 'never' && (this.rootSelected() || this._componentView?.isAnyChildContentActive?.()))); // prettier-ignore
}
@@ -297,17 +298,15 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
e.stopPropagation();
};
onClick = action((e: React.MouseEvent | React.PointerEvent) => {
- if (this._props.isGroupActive?.() === 'child' && !this._props.isDocumentActive?.()) return;
- const documentView = this._docView;
- if (documentView && !this.Document.ignoreClick && this._props.renderDepth >= 0 && ClientUtils.isClick(e.clientX, e.clientY, this._downX, this._downY, this._downTime)) {
+ if (this._props.isGroupActive?.() === GroupActive.child && !this._props.isDocumentActive?.()) return;
+ if (this._docView && !this.Document.ignoreClick && this._props.renderDepth >= 0 && ClientUtils.isClick(e.clientX, e.clientY, this._downX, this._downY, this._downTime)) {
let stopPropagate = true;
let preventDefault = true;
- !this.layoutDoc._keepZWhenDragged && this._props.bringToFront?.(this.Document);
const scriptProps = {
this: this.Document,
_readOnly_: false,
scriptContext: this._props.scriptContext,
- documentView,
+ documentView: this._docView,
clientX: e.clientX,
clientY: e.clientY,
shiftKey: e.shiftKey,
@@ -317,44 +316,39 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
};
if (this._doubleTap) {
const defaultDblclick = this._props.defaultDoubleClick?.() || this.Document.defaultDoubleClick;
- if (this.onDoubleClickHdlr?.script) {
- UndoManager.RunInBatch(() => this.onDoubleClickHdlr.script.run(scriptProps, console.log).result?.select && this._props.select(false), 'on double click: ' + this.Document.title);
- } else if (!Doc.IsSystem(this.Document) && defaultDblclick !== 'ignore') {
- UndoManager.RunInBatch(() => this._props.addDocTab(this.Document, OpenWhere.lightboxAlways), 'double tap');
- DocumentView.DeselectAll();
- Doc.UnBrushDoc(this.Document);
- } else {
- this._singleClickFunc?.();
- }
+ undoable(() => {
+ if (this.onDoubleClickHdlr?.script) {
+ this.onDoubleClickHdlr.script.run(scriptProps, console.log).result?.select && this._props.select(false);
+ } else if (!Doc.IsSystem(this.Document) && defaultDblclick !== 'ignore') {
+ this._props.addDocTab(this.Document, OpenWhere.lightboxAlways);
+ DocumentView.DeselectAll();
+ Doc.UnBrushDoc(this.Document);
+ } else this._singleClickFunc?.();
+ }, 'on double click: ' + this.Document.title)();
this._doubleClickTimeout && clearTimeout(this._doubleClickTimeout);
this._doubleClickTimeout = undefined;
this._singleClickFunc = undefined;
} else {
- let clickFunc: undefined | (() => any);
- if (!this.disableClickScriptFunc && this.onClickHdlr?.script) {
- clickFunc = undoable(() => {
- this.onClickHdlr?.script.run(scriptProps, console.log).result?.select && this._props.select(false);
- }, 'click ' + this.Document.title);
- } else {
- // onDragStart implies a button doc that we don't want to select when clicking. RootDocument & isTemplateForField implies we're clicking on part of a template instance and we want to select the whole template, not the part
- if (this.layoutDoc.onDragStart && !(e.ctrlKey || e.button > 0)) {
- stopPropagate = false;
- }
- preventDefault = false;
- }
- const sendToBack = e.altKey ? () => documentView._props.bringToFront?.(this.Document, true) : undefined;
+ const sendToBack = e.altKey ? () => this._props.bringToFront?.(this.Document, true) : undefined;
const selectFunc = () => {
+ !this.layoutDoc._keepZWhenDragged && this._props.bringToFront?.(this.Document);
// selecting a view that is part of a template proxies the selection back to the root of the template
const templateRoot = !(e.ctrlKey || e.button > 0) && this._props.docViewPath?.().reverse().find(dv => !dv._props.TemplateDataDocument); // prettier-ignore
(templateRoot || this._docView)?.select(e.ctrlKey || e.shiftKey, e.metaKey);
};
- this._singleClickFunc = clickFunc ?? sendToBack ?? selectFunc;
- const waitFordblclick = this._props.waitForDoubleClickToClick?.() ?? this.Document.waitForDoubleClickToClick;
- if ((clickFunc && waitFordblclick !== 'never') || waitFordblclick === 'always') {
+ const clickFunc = this.onClickFunc?.()?.script ? () => (this.onClickFunc?.()?.script.run(scriptProps, console.log).result as Opt<{ select: boolean }>)?.select && this._props.select(false) : undefined;
+ if (!clickFunc) {
+ // onDragStart implies a button doc that we don't want to select when clicking. RootDocument & isTemplateForField implies we're clicking on part of a template instance and we want to select the whole template, not the part
+ if (this.layoutDoc.onDragStart && !(e.ctrlKey || e.button > 0)) stopPropagate = false;
+ preventDefault = false;
+ }
+ this._singleClickFunc = undoable(clickFunc ?? sendToBack ?? selectFunc, 'click: ' + this.Document.title);
+ const waitForDblClick = this._props.waitForDoubleClickToClick?.() ?? this.Document.waitForDoubleClickToClick;
+ if ((clickFunc && waitForDblClick !== 'never') || waitForDblClick === 'always') {
this._doubleClickTimeout && clearTimeout(this._doubleClickTimeout);
this._doubleClickTimeout = setTimeout(this._singleClickFunc, 300);
// eslint-disable-next-line no-use-before-define
- } else if (!DocumentView.LongPress) {
+ } else if (!SnappingManager.LongPress) {
this._singleClickFunc();
this._singleClickFunc = undefined;
}
@@ -365,9 +359,9 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
});
onPointerDown = (e: React.PointerEvent): void => {
- if (this._props.isGroupActive?.() === 'child' && !this._props.isDocumentActive?.()) return;
+ if (this._props.isGroupActive?.() === GroupActive.child && !this._props.isDocumentActive?.()) return;
// eslint-disable-next-line no-use-before-define
- this._longPressSelector = setTimeout(() => DocumentView.LongPress && this._props.select(false), 1000);
+ this._longPressSelector = setTimeout(() => SnappingManager.LongPress && this._props.select(false), 1000);
if (!DocumentView.DownDocView) DocumentView.DownDocView = this._docView;
this._downX = e.clientX;
@@ -418,7 +412,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
if (!this.isContentActive()) this._lastTap = Date.now(); // don't want to process the start of a double tap if the doucment is selected
}
// eslint-disable-next-line no-use-before-define
- if (DocumentView.LongPress) e.preventDefault();
+ if (SnappingManager.LongPress) e.preventDefault();
};
toggleFollowLink = undoable((): void => {
@@ -975,8 +969,8 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
* @returns a function that will wrap a JSX animation element wrapping any JSX element
*/
public static AnimationEffect(renderDoc: JSX.Element, presEffectDoc: Opt<Doc>, root: Doc) {
- let dir = (presEffectDoc?.presentation_effectDirection ?? presEffectDoc?.followLinkAnimDirection) as PresEffectDirection;
- const transitionTime = presEffectDoc?.presentation_transition ? NumCast(presEffectDoc?.presentation_transition) : 500;
+ const dir = ((presEffectDoc?.presentation_effectDirection ?? presEffectDoc?.followLinkAnimDirection) || PresEffectDirection.Center) as PresEffectDirection;
+ const duration = Cast(presEffectDoc?.presentation_transition, 'number', Cast(presEffectDoc?.followLinkTransitionTime, 'number', null));
const effectProps = {
left: dir === PresEffectDirection.Left,
right: dir === PresEffectDirection.Right,
@@ -984,26 +978,14 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
bottom: dir === PresEffectDirection.Bottom,
opposite: true,
delay: 0,
- duration: Cast(presEffectDoc?.presentation_transition, 'number', Cast(presEffectDoc?.followLinkTransitionTime, 'number', null)),
+ duration,
};
const timing = StrCast(presEffectDoc?.presentation_effectTiming);
- let timingConfig: SpringSettings | undefined;
- if (timing) {
- timingConfig = JSON.parse(timing);
- }
-
- if (!timingConfig) {
- timingConfig = {
- type: SpringType.GENTLE,
- ...springMappings.gentle,
- };
- }
-
- if (!dir) {
- dir = PresEffectDirection.Center;
- }
-
+ const timingConfig = (timing ? JSON.parse(timing) : undefined) ?? {
+ type: SpringType.GENTLE,
+ ...springMappings.gentle,
+ };
switch (StrCast(presEffectDoc?.presentation_effect, StrCast(presEffectDoc?.followLinkAnimEffect))) {
case PresEffect.Expand: return <SpringAnimation doc={root} startOpacity={0} dir={dir} presEffect={PresEffect.Expand} springSettings={timingConfig}>{renderDoc}</SpringAnimation>
case PresEffect.Flip: return <SpringAnimation doc={root} startOpacity={0} dir={dir} presEffect={PresEffect.Flip} springSettings={timingConfig}>{renderDoc}</SpringAnimation>
@@ -1086,15 +1068,16 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
finished?: (changed: boolean) => void // func called after focusing on target with flag indicating whether anything needed to be done.
) => Promise<void>;
public static linkCommonAncestor: (link: Doc) => DocumentView | undefined;
- // pin func
+ /**
+ * Pins a Doc to the current presentation trail. (see TabDocView for implementation)
+ */
public static PinDoc: (docIn: Doc | Doc[], pinProps: PinProps) => void;
- // gesture
- public static DownDocView: DocumentView | undefined; // the first DocView that receives a pointerdown event. used by GestureOverlay to determine the doc a gesture should apply to.
- // media playing
- @observable public static CurrentlyPlaying: DocumentView[] = [];
+ /**
+ * The DocumentView below the cursor at the start of a gesture (that receives the pointerDown event). Used by GestureOverlay to determine the doc a gesture should apply to.
+ */
+ public static DownDocView: DocumentView | undefined;
public get displayName() { return 'DocumentView(' + (this.Document?.title??"") + ')'; } // prettier-ignore
- public ContentRef = React.createRef<HTMLDivElement>();
private _htmlOverlayEffect: Opt<Doc>;
private _disposers: { [name: string]: IReactionDisposer } = {};
private _viewTimer: NodeJS.Timeout | undefined;
@@ -1125,7 +1108,7 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
@observable private _htmlOverlayText: Opt<string> = undefined;
@observable private _isHovering = false;
@observable private _selected = false;
- @observable public static LongPress = false;
+ @observable public static CurrentlyPlaying: DocumentView[] = []; // audio or video media views that are currently playing
@computed private get shouldNotScale() {
return (this.layout_fitWidth && !this.nativeWidth) || this.ComponentView?.isUnstyledView?.();
@@ -1472,7 +1455,6 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
{!this.Document || !this._props.PanelWidth() ? null : (
<div
className="contentFittingDocumentView-previewDoc"
- ref={this.ContentRef}
style={{
transform: `translate(${this.centeringX}px, ${this.centeringY}px)`,
width: xshift ?? `${this._props.PanelWidth() - this.Xshift * 2}px`,
@@ -1569,6 +1551,56 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
}
}
+export function ActiveFillColor(): string {
+ const dv = DocumentView.Selected().lastElement() ?.Document._layout_isSvg ? DocumentView.Selected().lastElement() : undefined;
+ return StrCast(dv?.Document.fillColor, StrCast(ActiveInkPen()?.activeFillColor, ""));
+} // prettier-ignore
+export function ActiveInkPen(): Doc { return Doc.UserDoc(); } // prettier-ignore
+export function ActiveInkColor(): string { return StrCast(ActiveInkPen()?.activeInkColor, 'black'); } // prettier-ignore
+export function ActiveIsInkMask(): boolean { return BoolCast(ActiveInkPen()?.activeIsInkMask, false); } // prettier-ignore
+export function ActiveInkHideTextLabels(): boolean { return BoolCast(ActiveInkPen().activeInkHideTextLabels, false); } // prettier-ignore
+export function ActiveArrowStart(): string { return StrCast(ActiveInkPen()?.activeArrowStart, ''); } // prettier-ignore
+export function ActiveArrowEnd(): string { return StrCast(ActiveInkPen()?.activeArrowEnd, ''); } // prettier-ignore
+export function ActiveArrowScale(): number { return NumCast(ActiveInkPen()?.activeArrowScale, 1); } // prettier-ignore
+export function ActiveDash(): string { return StrCast(ActiveInkPen()?.activeDash, '0'); } // prettier-ignore
+export function ActiveInkWidth(): number { return Number(ActiveInkPen()?.activeInkWidth); } // prettier-ignore
+export function ActiveInkBezierApprox(): string { return StrCast(ActiveInkPen()?.activeInkBezier); } // prettier-ignore
+export function ActiveEraserWidth(): number { return Number(ActiveInkPen()?.eraserWidth); } // prettier-ignore
+
+export function SetActiveInkWidth(width: string): void {
+ !isNaN(parseInt(width)) && ActiveInkPen() && (ActiveInkPen().activeInkWidth = width);
+}
+export function SetActiveBezierApprox(bezier: string): void {
+ ActiveInkPen() && (ActiveInkPen().activeInkBezier = isNaN(parseInt(bezier)) ? '' : bezier);
+}
+export function SetActiveInkColor(value: string) {
+ ActiveInkPen() && (ActiveInkPen().activeInkColor = value);
+}
+export function SetActiveIsInkMask(value: boolean) {
+ ActiveInkPen() && (ActiveInkPen().activeIsInkMask = value);
+}
+export function SetActiveInkHideTextLabels(value: boolean) {
+ ActiveInkPen() && (ActiveInkPen().activeInkHideTextLabels = value);
+}
+export function SetActiveFillColor(value: string) {
+ ActiveInkPen() && (ActiveInkPen().activeFillColor = value);
+}
+export function SetActiveArrowStart(value: string) {
+ ActiveInkPen() && (ActiveInkPen().activeArrowStart = value);
+}
+export function SetActiveArrowEnd(value: string) {
+ ActiveInkPen() && (ActiveInkPen().activeArrowEnd = value);
+}
+export function SetActiveArrowScale(value: number) {
+ ActiveInkPen() && (ActiveInkPen().activeArrowScale = value);
+}
+export function SetActiveDash(dash: string): void {
+ !isNaN(parseInt(dash)) && ActiveInkPen() && (ActiveInkPen().activeDash = dash);
+}
+export function SetEraserWidth(width: number): void {
+ ActiveInkPen() && (ActiveInkPen().eraserWidth = width);
+}
+
// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function DocFocusOrOpen(docIn: Doc, optionsIn?: FocusViewOptions, containingDoc?: Doc) {
return DocumentView.FocusOrOpen(docIn, optionsIn, containingDoc);
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index b7943f503..92a5a1533 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -448,6 +448,11 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
};
focus = (anchor: Doc, options: FocusViewOptions) => (anchor.type === DocumentType.CONFIG ? undefined : this._ffref.current?.focus(anchor, options));
+ renderedPixelDimensions = async () => {
+ const { nativeWidth: width, nativeHeight: height } = await Networking.PostToServer('/inspectImage', { source: this.paths[0] });
+ return { width, height };
+ };
+
savedAnnotations = () => this._savedAnnotations;
render() {
TraceMobx();
diff --git a/src/client/views/nodes/LabelBigText.js b/src/client/views/nodes/LabelBigText.js
deleted file mode 100644
index 290152cd0..000000000
--- a/src/client/views/nodes/LabelBigText.js
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
-Brorlandi/big-text.js v1.0.0, 2017
-Adapted from DanielHoffmann/jquery-bigtext, v1.3.0, May 2014
-And from Jetroid/bigtext.js v1.0.0, September 2016
-
-Usage:
-BigText("#myElement",{
- rotateText: {Number}, (null)
- fontSizeFactor: {Number}, (0.8)
- maximumFontSize: {Number}, (null)
- limitingDimension: {String}, ("both")
- horizontalAlign: {String}, ("center")
- verticalAlign: {String}, ("center")
- textAlign: {String}, ("center")
- whiteSpace: {String}, ("nowrap")
-});
-
-
-Original Projects:
-https://github.com/DanielHoffmann/jquery-bigtext
-https://github.com/Jetroid/bigtext.js
-
-Options:
-
-rotateText: Rotates the text inside the element by X degrees.
-
-fontSizeFactor: This option is used to give some vertical spacing for letters that overflow the line-height (like 'g', 'Á' and most other accentuated uppercase letters). This does not affect the font-size if the limiting factor is the width of the parent div. The default is 0.8
-
-maximumFontSize: maximum font size to use.
-
-minimumFontSize: minimum font size to use. if font is calculated smaller than this, text will be rendered at this size and wrapped
-
-limitingDimension: In which dimension the font size should be limited. Possible values: "width", "height" or "both". Defaults to both. Using this option with values different than "both" overwrites the element parent width or height.
-
-horizontalAlign: Where to align the text horizontally. Possible values: "left", "center", "right". Defaults to "center".
-
-verticalAlign: Where to align the text vertically. Possible values: "top", "center", "bottom". Defaults to "center".
-
-textAlign: Sets the text align of the element. Possible values: "left", "center", "right". Defaults to "center". This option is only useful if there are linebreaks (<br> tags) inside the text.
-
-whiteSpace: Sets whitespace handling. Possible values: "nowrap", "pre". Defaults to "nowrap". (Can also be set to enable wrapping but this doesn't work well.)
-
-Bruno Orlandi - 2017
-
-Copyright (C) 2013 Daniel Hoffmann Bernardes, Ícaro Technologies
-Copyright (C) 2016 Jet Holt
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-
-function _calculateInnerDimensions(computedStyle) {
- //Calculate the inner width and height
- var innerWidth;
- var innerHeight;
-
- var width = parseInt(computedStyle.getPropertyValue("width"));
- var height = parseInt(computedStyle.getPropertyValue("height"));
- var paddingLeft = parseInt(computedStyle.getPropertyValue("padding-left"));
- var paddingRight = parseInt(computedStyle.getPropertyValue("padding-right"));
- var paddingTop = parseInt(computedStyle.getPropertyValue("padding-top"));
- var paddingBottom = parseInt(computedStyle.getPropertyValue("padding-bottom"));
- var borderLeft = parseInt(computedStyle.getPropertyValue("border-left-width"));
- var borderRight = parseInt(computedStyle.getPropertyValue("border-right-width"));
- var borderTop = parseInt(computedStyle.getPropertyValue("border-top-width"));
- var borderBottom = parseInt(computedStyle.getPropertyValue("border-bottom-width"));
-
- //If box-sizing is border-box, we need to subtract padding and border.
- var parentBoxSizing = computedStyle.getPropertyValue("box-sizing");
- if (parentBoxSizing == "border-box") {
- innerWidth = width - (paddingLeft + paddingRight + borderLeft + borderRight);
- innerHeight = height - (paddingTop + paddingBottom + borderTop + borderBottom);
- } else {
- innerWidth = width;
- innerHeight = height;
- }
- var obj = {};
- obj["width"] = innerWidth;
- obj["height"] = innerHeight;
- return obj;
-}
-
-export default function BigText(element, options) {
-
- if (typeof element === 'string') {
- element = document.querySelector(element);
- } else if (element.length) {
- // Support for array based queries (such as jQuery)
- element = element[0];
- }
-
- var defaultOptions = {
- rotateText: null,
- fontSizeFactor: 0.8,
- maximumFontSize: null,
- limitingDimension: "both",
- horizontalAlign: "center",
- verticalAlign: "center",
- textAlign: "center",
- whiteSpace: "nowrap",
- singleLine: true
- };
-
- //Merge provided options and default options
- options = options || {};
- for (var opt in defaultOptions)
- if (defaultOptions.hasOwnProperty(opt) && !options.hasOwnProperty(opt))
- options[opt] = defaultOptions[opt];
-
- //Get variables which we will reference frequently
- var style = element.style;
- var parent = element.parentNode;
- var parentStyle = parent.style;
- var parentComputedStyle = document.defaultView.getComputedStyle(parent);
-
- //hides the element to prevent "flashing"
- style.visibility = "hidden";
- //Set some properties
- style.display = "inline-block";
- style.clear = "both";
- style.float = "left";
- var fontSize = options.maximumFontSize;
- if (options.singleLine) {
- style.fontSize = (fontSize * options.fontSizeFactor) + "px";
- style.lineHeight = fontSize + "px";
- } else {
- for (; fontSize > options.minimumFontSize; fontSize = fontSize - Math.min(fontSize / 2, Math.max(0, fontSize - 48) + 2)) {
- style.fontSize = (fontSize * options.fontSizeFactor) + "px";
- style.lineHeight = "1";
- if (element.offsetHeight <= +parentComputedStyle.height.replace("px", "")) {
- break;
- }
- }
- }
- style.whiteSpace = options.whiteSpace;
- style.textAlign = options.textAlign;
- style.position = "relative";
- style.padding = 0;
- style.margin = 0;
- style.left = "50%";
- style.top = "50%";
- var computedStyle = document.defaultView.getComputedStyle(element);
-
- //Get properties of parent to allow easier referencing later.
- var parentPadding = {
- top: parseInt(parentComputedStyle.getPropertyValue("padding-top")),
- right: parseInt(parentComputedStyle.getPropertyValue("padding-right")),
- bottom: parseInt(parentComputedStyle.getPropertyValue("padding-bottom")),
- left: parseInt(parentComputedStyle.getPropertyValue("padding-left")),
- };
- var parentBorder = {
- top: parseInt(parentComputedStyle.getPropertyValue("border-top")),
- right: parseInt(parentComputedStyle.getPropertyValue("border-right")),
- bottom: parseInt(parentComputedStyle.getPropertyValue("border-bottom")),
- left: parseInt(parentComputedStyle.getPropertyValue("border-left")),
- };
-
- //Calculate the parent inner width and height
- var parentInnerDimensions = _calculateInnerDimensions(parentComputedStyle);
- var parentInnerWidth = parentInnerDimensions["width"];
- var parentInnerHeight = parentInnerDimensions["height"];
-
- var box = {
- width: element.offsetWidth, //Note: This is slightly larger than the jQuery version
- height: element.offsetHeight,
- };
- if (!box.width || !box.height) return element;
-
-
- if (options.rotateText !== null) {
- if (typeof options.rotateText !== "number")
- throw "bigText error: rotateText value must be a number";
- var rotate = "rotate(" + options.rotateText + "deg)";
- style.webkitTransform = rotate;
- style.msTransform = rotate;
- style.MozTransform = rotate;
- style.OTransform = rotate;
- style.transform = rotate;
- //calculating bounding box of the rotated element
- var sine = Math.abs(Math.sin(options.rotateText * Math.PI / 180));
- var cosine = Math.abs(Math.cos(options.rotateText * Math.PI / 180));
- box.width = element.offsetWidth * cosine + element.offsetHeight * sine;
- box.height = element.offsetWidth * sine + element.offsetHeight * cosine;
- }
-
- var parentWidth = (parentInnerWidth - parentPadding.left - parentPadding.right);
- var parentHeight = (parentInnerHeight - parentPadding.top - parentPadding.bottom);
- var widthFactor = parentWidth / box.width;
- var heightFactor = parentHeight / box.height;
- var lineHeight;
-
- if (options.limitingDimension.toLowerCase() === "width") {
- lineHeight = Math.floor(widthFactor * fontSize);
- } else if (options.limitingDimension.toLowerCase() === "height") {
- lineHeight = Math.floor(heightFactor * fontSize);
- } else if (widthFactor < heightFactor)
- lineHeight = Math.floor(widthFactor * fontSize);
- else if (widthFactor >= heightFactor)
- lineHeight = Math.floor(heightFactor * fontSize);
-
- var fontSize = lineHeight * options.fontSizeFactor;
- if (fontSize < options.minimumFontSize) {
- parentStyle.display = "flex";
- parentStyle.alignItems = "center";
- style.textAlign = "center";
- style.visibility = "";
- style.fontSize = options.minimumFontSize + "px";
- style.lineHeight = "";
- style.overflow = "hidden";
- style.textOverflow = "ellipsis";
- style.top = "";
- style.left = "";
- style.margin = "";
- return element;
- }
- if (options.maximumFontSize && fontSize > options.maximumFontSize) {
- fontSize = options.maximumFontSize;
- lineHeight = fontSize / options.fontSizeFactor;
- }
-
- style.fontSize = Math.floor(fontSize) + "px";
- style.lineHeight = Math.ceil(lineHeight) + "px";
- style.marginBottom = "0px";
- style.marginRight = "0px";
-
- // if (options.limitingDimension.toLowerCase() === "height") {
- // //this option needs the font-size to be set already so computedStyle.getPropertyValue("width") returns the right size
- // //this +4 is to compensate the rounding erros that can occur due to the calls to Math.floor in the centering code
- // parentStyle.width = (parseInt(computedStyle.getPropertyValue("width")) + 4) + "px";
- // }
-
- //Calculate the inner width and height
- var innerDimensions = _calculateInnerDimensions(computedStyle);
- var innerWidth = innerDimensions["width"];
- var innerHeight = innerDimensions["height"];
-
- switch (options.verticalAlign.toLowerCase()) {
- case "top":
- style.top = "0%";
- break;
- case "bottom":
- style.top = "100%";
- style.marginTop = Math.floor(-innerHeight) + "px";
- break;
- default:
- style.marginTop = Math.ceil((-innerHeight / 2)) + "px";
- break;
- }
-
- switch (options.horizontalAlign.toLowerCase()) {
- case "left":
- style.left = "0%";
- break;
- case "right":
- style.left = "100%";
- style.marginLeft = Math.floor(-innerWidth) + "px";
- break;
- default:
- style.marginLeft = Math.ceil((-innerWidth / 2)) + "px";
- break;
- }
-
- //shows the element after the work is done
- style.visibility = "visible";
-
- return element;
-}
diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
index f80ff5f94..d33d12603 100644
--- a/src/client/views/nodes/LabelBox.tsx
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -1,21 +1,17 @@
-import { action, computed, makeObservable, observable } from 'mobx';
+import { Property } from 'csstype';
+import { action, computed, makeObservable, trace } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
-import { Doc, DocListCast, Field, FieldType } from '../../../fields/Doc';
-import { List } from '../../../fields/List';
-import { listSpec } from '../../../fields/Schema';
-import { BoolCast, Cast, NumCast, StrCast } from '../../../fields/Types';
+import * as textfit from 'textfit';
+import { Field, FieldType } from '../../../fields/Doc';
+import { BoolCast, NumCast, StrCast } from '../../../fields/Types';
import { DocumentType } from '../../documents/DocumentTypes';
import { Docs } from '../../documents/Documents';
import { DragManager } from '../../util/DragManager';
-import { undoBatch } from '../../util/UndoManager';
-import { ContextMenu } from '../ContextMenu';
-import { ContextMenuProps } from '../ContextMenuItem';
import { ViewBoxBaseComponent } from '../DocComponent';
import { PinDocView, PinProps } from '../PinFuncs';
import { StyleProp } from '../StyleProp';
import { FieldView, FieldViewProps } from './FieldView';
-import BigText from './LabelBigText';
import './LabelBox.scss';
@observer
@@ -23,28 +19,15 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps>() {
public static LayoutString(fieldKey: string) {
return FieldView.LayoutString(LabelBox, fieldKey);
}
- public static LayoutStringWithTitle(fieldStr: string, label?: string) {
- return !label ? LabelBox.LayoutString(fieldStr) : `<LabelBox fieldKey={'${fieldStr}'} label={'${label}'} {...props} />`; // e.g., "<ImageBox {...props} fieldKey={"data} />"
- }
private dropDisposer?: DragManager.DragDropDisposer;
- private _timeout: any;
+ private _timeout: NodeJS.Timeout | undefined;
+ _divRef: HTMLDivElement | null = null;
constructor(props: FieldViewProps) {
super(props);
makeObservable(this);
}
- componentDidMount() {
- this._props.setContentViewBox?.(this);
- }
- componentWillUnMount() {
- this._timeout && clearTimeout(this._timeout);
- }
-
- @computed get Title() {
- return Field.toString(this.dataDoc[this.fieldKey] as FieldType) || StrCast(this.Document.title);
- }
-
protected createDropTarget = (ele: HTMLDivElement) => {
this.dropDisposer?.();
if (ele) {
@@ -52,44 +35,27 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
};
- get paramsDoc() {
- return Doc.AreProtosEqual(this.layoutDoc, this.dataDoc) ? this.dataDoc : this.layoutDoc;
+ @computed get Title() {
+ return Field.toString(this.dataDoc[this.fieldKey] as FieldType) || StrCast(this.Document.title);
}
- specificContextMenu = (): void => {
- const funcs: ContextMenuProps[] = [];
- !Doc.noviceMode &&
- funcs.push({
- description: 'Clear Script Params',
- event: () => {
- const params = Cast(this.paramsDoc['onClick-paramFieldKeys'], listSpec('string'), []);
- params?.forEach(p => {
- this.paramsDoc[p] = undefined;
- });
- },
- icon: 'trash',
- });
- funcs.length && ContextMenu.Instance.addItem({ description: 'OnClick...', noexpand: true, subitems: funcs, icon: 'mouse-pointer' });
- };
+ @computed get backgroundColor() {
+ return this._props.styleProvider?.(this.Document, this._props, StyleProp.BackgroundColor) as string;
+ }
- @undoBatch
- drop = (e: Event, de: DragManager.DropEvent) => {
- const { docDragData } = de.complete;
- const params = Cast(this.paramsDoc['onClick-paramFieldKeys'], listSpec('string'), []);
- const missingParams = params?.filter(p => !this.paramsDoc[p]);
- if (docDragData && missingParams?.includes((e.target as any).textContent)) {
- this.paramsDoc[(e.target as any).textContent] = new List<Doc>(docDragData.droppedDocuments.map((d, i) => (d.onDragStart ? docDragData.draggedDocuments[i] : d)));
- e.stopPropagation();
- return true;
- }
+ componentDidMount() {
+ this._props.setContentViewBox?.(this);
+ }
+ componentWillUnMount() {
+ this._timeout && clearTimeout(this._timeout);
+ }
+
+ specificContextMenu = (): void => {};
+
+ drop = (/* e: Event, de: DragManager.DropEvent */) => {
return false;
};
- @observable _mouseOver = false;
- @computed get hoverColor() {
- return this._mouseOver ? StrCast(this.layoutDoc._hoverBackgroundColor) : this._props.styleProvider?.(this.Document, this._props, StyleProp.BackgroundColor);
- }
-
getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => {
if (!pinProps) return this.Document;
const anchor = Docs.Create.ConfigDocument({ title: StrCast(this.Document.title), annotationOn: this.Document });
@@ -104,101 +70,92 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps>() {
};
fitTextToBox = (
- r: any
- ):
- | NodeJS.Timeout
- | {
- rotateText: null;
- fontSizeFactor: number;
- minimumFontSize: number;
- maximumFontSize: number;
- limitingDimension: string;
- horizontalAlign: string;
- verticalAlign: string;
- textAlign: string;
- singleLine: boolean;
- whiteSpace: string;
- } => {
- const singleLine = BoolCast(this.layoutDoc._singleLine, true);
- const params = {
- rotateText: null,
- fontSizeFactor: 1,
- minimumFontSize: NumCast(this.layoutDoc._label_minFontSize, 8),
- maximumFontSize: NumCast(this.layoutDoc._label_maxFontSize, 1000),
- limitingDimension: 'both',
- horizontalAlign: 'center',
- verticalAlign: 'center',
- textAlign: 'center',
- singleLine,
- whiteSpace: singleLine ? 'nowrap' : 'pre-wrap',
+ r: HTMLElement | null | undefined
+ ): {
+ minFontSize: number;
+ maxFontSize: number;
+ multiLine: boolean;
+ alignHoriz: boolean;
+ alignVert: boolean;
+ detectMultiLine: boolean;
+ } => {
+ this._timeout && clearTimeout(this._timeout);
+ const textfitParams = {
+ minFontSize: NumCast(this.layoutDoc._label_minFontSize, 1),
+ maxFontSize: NumCast(this.layoutDoc._label_maxFontSize, 100),
+ multiLine: BoolCast(this.layoutDoc._singleLine, true) ? false : true,
+ alignHoriz: true,
+ alignVert: true,
+ detectMultiLine: true,
};
- this._timeout = undefined;
- if (!r) return params;
- if (!r.offsetHeight || !r.offsetWidth) {
- this._timeout = setTimeout(() => this.fitTextToBox(r));
- return this._timeout;
+ if (r) {
+ if (!r.offsetHeight || !r.offsetWidth) {
+ console.log("CAN'T FIT TO EMPTY BOX");
+ this._timeout && clearTimeout(this._timeout);
+ this._timeout = setTimeout(() => this.fitTextToBox(r));
+ return textfitParams;
+ }
+ textfit(r, textfitParams);
}
- const parent = r.parentNode;
- const parentStyle = parent.style;
- parentStyle.display = '';
- parentStyle.alignItems = '';
- r.setAttribute('style', '');
- r.style.width = singleLine ? '' : '100%';
-
- r.style.textOverflow = 'ellipsis';
- r.style.overflow = 'hidden';
- BigText(r, params);
- return params;
+ return textfitParams;
};
- // (!missingParams || !missingParams.length ? "" : "(" + missingParams.map(m => m + ":").join(" ") + ")")
render() {
- const boxParams = this.fitTextToBox(null); // this causes mobx to trigger re-render when data changes
- const params = Cast(this.paramsDoc['onClick-paramFieldKeys'], listSpec('string'), []);
- const missingParams = params?.filter(p => !this.paramsDoc[p]);
- params?.map(p => DocListCast(this.paramsDoc[p])); // bcz: really hacky form of prefetching ...
- const label = this.Title;
+ trace();
+ const boxParams = this.fitTextToBox(undefined); // this causes mobx to trigger re-render when data changes
+ const label = this.Title.startsWith('#') ? null : this.Title;
return (
- <div
- className="labelBox-outerDiv"
- onMouseLeave={action(() => {
- this._mouseOver = false;
- })}
- // eslint-disable-next-line jsx-a11y/mouse-events-have-key-events
- onMouseOver={action(() => {
- this._mouseOver = true;
- })}
- ref={this.createDropTarget}
- onContextMenu={this.specificContextMenu}
- style={{ boxShadow: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BoxShadow) }}>
+ <div key={label?.length} className="labelBox-outerDiv" ref={this.createDropTarget} onContextMenu={this.specificContextMenu} style={{ boxShadow: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BoxShadow) as string }}>
<div
className="labelBox-mainButton"
style={{
- backgroundColor: this.hoverColor,
- fontSize: StrCast(this.layoutDoc._text_fontSize),
+ backgroundColor: this.backgroundColor,
+ // fontSize: StrCast(this.layoutDoc._text_fontSize),
color: StrCast(this.layoutDoc._color),
fontFamily: StrCast(this.layoutDoc._text_fontFamily) || 'inherit',
letterSpacing: StrCast(this.layoutDoc.letterSpacing),
- textTransform: StrCast(this.layoutDoc.textTransform) as any,
+ textTransform: StrCast(this.layoutDoc.textTransform) as Property.TextTransform,
paddingLeft: NumCast(this.layoutDoc._xPadding),
paddingRight: NumCast(this.layoutDoc._xPadding),
paddingTop: NumCast(this.layoutDoc._yPadding),
paddingBottom: NumCast(this.layoutDoc._yPadding),
width: this._props.PanelWidth(),
height: this._props.PanelHeight(),
- whiteSpace: 'singleLine' in boxParams && boxParams.singleLine ? 'pre' : 'pre-wrap',
+ whiteSpace: 'multiLine' in boxParams && boxParams.multiLine ? 'pre-wrap' : 'pre',
}}>
- <span style={{ width: 'singleLine' in boxParams ? '' : '100%' }} ref={action((r: any) => this.fitTextToBox(r))}>
- {label.startsWith('#') ? null : label.replace(/([^a-zA-Z])/g, '$1\u200b')}
- </span>
- </div>
- <div className="labelBox-fieldKeyParams">
- {!missingParams?.length
- ? null
- : missingParams.map(m => (
- <div key={m} className="labelBox-missingParam">
- {m}
- </div>
- ))}
+ <div
+ style={{
+ width: this._props.PanelWidth() - 2 * NumCast(this.layoutDoc._xPadding),
+ height: this._props.PanelHeight() - 2 * NumCast(this.layoutDoc._yPadding),
+ outline: 'unset !important',
+ }}
+ onKeyDown={action(e => {
+ e.stopPropagation();
+ })}
+ onKeyUp={action(e => {
+ e.stopPropagation();
+ if (e.key === 'Enter') {
+ this.dataDoc[this.fieldKey] = this._divRef?.innerText ?? '';
+ setTimeout(() => this._props.select(false));
+ }
+ })}
+ onBlur={() => {
+ this.dataDoc[this.fieldKey] = this._divRef?.innerText ?? '';
+ }}
+ contentEditable={this._props.onClickScript?.() ? false : true}
+ ref={r => {
+ this._divRef = r;
+ this.fitTextToBox(r);
+ if (this._props.isSelected() && this._divRef) {
+ const range = document.createRange();
+ range.setStart(this._divRef, this._divRef.childNodes.length);
+ range.setEnd(this._divRef, this._divRef.childNodes.length);
+ const sel = window.getSelection();
+ sel?.removeAllRanges();
+ sel?.addRange(range);
+ }
+ }}>
+ {label}
+ </div>
</div>
</div>
);
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 7a89b143b..8db68ddfe 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -655,9 +655,11 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
);
else {
if (!PDFBox.pdfpromise.get(href)) PDFBox.pdfpromise.set(href, Pdfjs.getDocument(href).promise);
- PDFBox.pdfpromise.get(href)?.then((pdf: any) => {
- PDFBox.pdfcache.set(href, (this._pdf = pdf));
- });
+ PDFBox.pdfpromise.get(href)?.then(
+ action((pdf: any) => {
+ PDFBox.pdfcache.set(href, (this._pdf = pdf));
+ })
+ );
}
}
return pdfView ?? this.renderTitleBox;
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 8835ea5e7..da947face 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -45,6 +45,7 @@ import { LinkInfo } from './LinkDocPreview';
import { OpenWhere } from './OpenWhere';
import './WebBox.scss';
+// eslint-disable-next-line @typescript-eslint/no-var-requires
const { CreateImage } = require('./WebBoxRenderer');
@observer
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 9f2a9b8e1..5b435e44a 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -87,9 +87,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
public static LiveTextUndo: UndoManager.Batch | undefined; // undo batch when typing a new text note into a collection
static _globalHighlightsCache: string = '';
static _globalHighlights = new ObservableSet<string>(['Audio Tags', 'Text from Others', 'Todo Items', 'Important Items', 'Disagree Items', 'Ignore Items']);
- static _highlightStyleSheet: any = addStyleSheet();
- static _bulletStyleSheet: any = addStyleSheet();
- static _userStyleSheet: any = addStyleSheet();
+ static _highlightStyleSheet = addStyleSheet();
+ static _bulletStyleSheet = addStyleSheet();
+ static _userStyleSheet = addStyleSheet();
static _hadSelection: boolean = false;
private _selectionHTML: string | undefined;
private _sidebarRef = React.createRef<SidebarAnnos>();
@@ -384,7 +384,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
}
}
} else {
- const jsonstring = Cast(dataDoc[this.fieldKey], RichTextField)?.Data!;
+ const jsonstring = Cast(dataDoc[this.fieldKey], RichTextField)?.Data;
if (jsonstring) {
const json = JSON.parse(jsonstring);
json.selection = state.toJSON().selection;
@@ -1925,11 +1925,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
setHeight={this.setSidebarHeight}
/>
) : (
- <div onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => DocumentView.SelectView(this.DocumentView?.()!, false), true)}>
+ <div onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => DocumentView.SelectView(this.DocumentView?.(), false), true)}>
<ComponentTag
// eslint-disable-next-line react/jsx-props-no-spreading
{...this._props}
- ref={this._sidebarTagRef as any}
+ ref={this._sidebarTagRef}
setContentView={emptyFunction}
NativeWidth={returnZero}
NativeHeight={returnZero}
diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx
index 7dd4047c1..3bd42873c 100644
--- a/src/client/views/pdf/Annotation.tsx
+++ b/src/client/views/pdf/Annotation.tsx
@@ -111,6 +111,7 @@ export class Annotation extends ObservableReactComponent<IAnnotationProps> {
outline = () => (this.linkHighlighted ? 'solid 1px lightBlue' : undefined);
background = () => (this._props.annoDoc[Highlight] ? 'orange' : StrCast(this._props.annoDoc.backgroundColor));
render() {
+ const forceRenderHack = [this.background(), this.outline(), this.opacity()]; // forces a re-render when these change -- because RegionAnnotation doesn't do this internally..
return (
<div style={{ display: this._props.annoDoc.textCopied && !Doc.GetBrushHighlightStatus(this._props.annoDoc) ? 'none' : undefined }}>
{StrListCast(this._props.annoDoc.text_inlineAnnotations)
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 6c1617c38..fa5e5cedb 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -24,18 +24,16 @@ import { FieldViewProps } from '../nodes/FieldView';
import { FocusViewOptions } from '../nodes/FocusViewOptions';
import { LinkInfo } from '../nodes/LinkDocPreview';
import { PDFBox } from '../nodes/PDFBox';
-import { ComparisonBox } from '../nodes/ComparisonBox';
import { ObservableReactComponent } from '../ObservableReactComponent';
import { StyleProp } from '../StyleProp';
import { AnchorMenu } from './AnchorMenu';
import { Annotation } from './Annotation';
import { GPTPopup } from './GPTPopup/GPTPopup';
-import { Docs } from '../../documents/Documents';
import './PDFViewer.scss';
// pdfjsLib.GlobalWorkerOptions.workerSrc = `/assets/pdf.worker.js`;
// The workerSrc property shall be specified.
-Pdfjs.GlobalWorkerOptions.workerSrc = 'https://unpkg.com/pdfjs-dist@4.2.67/build/pdf.worker.mjs';
+Pdfjs.GlobalWorkerOptions.workerSrc = 'https://unpkg.com/pdfjs-dist@4.4.168/build/pdf.worker.mjs';
interface IViewerProps extends FieldViewProps {
pdfBox: PDFBox;
@@ -58,7 +56,7 @@ interface IViewerProps extends FieldViewProps {
*/
@observer
export class PDFViewer extends ObservableReactComponent<IViewerProps> {
- static _annotationStyle: any = addStyleSheet();
+ static _annotationStyle = addStyleSheet();
constructor(props: IViewerProps) {
super(props);
@@ -526,7 +524,8 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> {
if (doc instanceof Doc && property === StyleProp.PointerEvents) {
if (this.inlineTextAnnotations.includes(doc) || this._props.isContentActive() === false) return 'none';
const isInk = doc.layout_isSvg && !props?.LayoutTemplateString;
- return isInk ? 'visiblePainted' : 'all';
+ if (isInk) return 'visiblePainted';
+ //return isInk ? 'visiblePainted' : 'all';
}
return this._props.styleProvider?.(doc, props, property);
};
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 1b3d963e8..2792f3aba 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -1,3 +1,5 @@
+/* eslint-disable @typescript-eslint/no-explicit-any */
+/* eslint-disable @typescript-eslint/no-namespace */
/* eslint-disable default-param-last */
/* eslint-disable no-use-before-define */
import { action, computed, makeObservable, observable, ObservableMap, ObservableSet, runInAction } from 'mobx';
@@ -174,53 +176,6 @@ export function updateCachedAcls(doc: Doc) {
return undefined;
}
-export function ActiveInkPen(): Doc { return Doc.UserDoc(); } // prettier-ignore
-export function ActiveInkColor(): string { return StrCast(ActiveInkPen()?.activeInkColor, 'black'); } // prettier-ignore
-export function ActiveFillColor(): string { return StrCast(ActiveInkPen()?.activeFillColor, ''); } // prettier-ignore
-export function ActiveIsInkMask(): boolean { return BoolCast(ActiveInkPen()?.activeIsInkMask, false); } // prettier-ignore
-export function ActiveInkHideTextLabels(): boolean { return BoolCast(ActiveInkPen().activeInkHideTextLabels, false); } // prettier-ignore
-export function ActiveArrowStart(): string { return StrCast(ActiveInkPen()?.activeArrowStart, ''); } // prettier-ignore
-export function ActiveArrowEnd(): string { return StrCast(ActiveInkPen()?.activeArrowEnd, ''); } // prettier-ignore
-export function ActiveArrowScale(): number { return NumCast(ActiveInkPen()?.activeArrowScale, 1); } // prettier-ignore
-export function ActiveDash(): string { return StrCast(ActiveInkPen()?.activeDash, '0'); } // prettier-ignore
-export function ActiveInkWidth(): number { return Number(ActiveInkPen()?.activeInkWidth); } // prettier-ignore
-export function ActiveInkBezierApprox(): string { return StrCast(ActiveInkPen()?.activeInkBezier); } // prettier-ignore
-export function ActiveEraserWidth(): number { return Number(ActiveInkPen()?.eraserWidth); } // prettier-ignore
-
-export function SetActiveInkWidth(width: string): void {
- !isNaN(parseInt(width)) && ActiveInkPen() && (ActiveInkPen().activeInkWidth = width);
-}
-export function SetActiveBezierApprox(bezier: string): void {
- ActiveInkPen() && (ActiveInkPen().activeInkBezier = isNaN(parseInt(bezier)) ? '' : bezier);
-}
-export function SetActiveInkColor(value: string) {
- ActiveInkPen() && (ActiveInkPen().activeInkColor = value);
-}
-export function SetActiveIsInkMask(value: boolean) {
- ActiveInkPen() && (ActiveInkPen().activeIsInkMask = value);
-}
-export function SetActiveInkHideTextLabels(value: boolean) {
- ActiveInkPen() && (ActiveInkPen().activeInkHideTextLabels = value);
-}
-export function SetActiveFillColor(value: string) {
- ActiveInkPen() && (ActiveInkPen().activeFillColor = value);
-}
-export function SetActiveArrowStart(value: string) {
- ActiveInkPen() && (ActiveInkPen().activeArrowStart = value);
-}
-export function SetActiveArrowEnd(value: string) {
- ActiveInkPen() && (ActiveInkPen().activeArrowEnd = value);
-}
-export function SetActiveArrowScale(value: number) {
- ActiveInkPen() && (ActiveInkPen().activeArrowScale = value);
-}
-export function SetActiveDash(dash: string): void {
- !isNaN(parseInt(dash)) && ActiveInkPen() && (ActiveInkPen().activeDash = dash);
-}
-export function SetEraserWidth(width: number): void {
- ActiveInkPen() && (ActiveInkPen().eraserWidth = width);
-}
-
@scriptingGlobal
@Deserializable('Doc', updateCachedAcls, ['id'])
export class Doc extends RefField {