aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/nodes')
-rw-r--r--src/client/views/nodes/DocumentContentsView.tsx2
-rw-r--r--src/client/views/nodes/DocumentView.tsx20
-rw-r--r--src/client/views/nodes/FieldView.tsx1
-rw-r--r--src/client/views/nodes/FontIconBox/FontIconBox.tsx1
-rw-r--r--src/client/views/nodes/MapBox/MapAnchorMenu.tsx62
-rw-r--r--src/client/views/nodes/MapBox/MapBox.tsx38
-rw-r--r--src/client/views/nodes/PDFBox.tsx2
-rw-r--r--src/client/views/nodes/SliderBox.scss19
-rw-r--r--src/client/views/nodes/SliderBox.tsx103
-rw-r--r--src/client/views/nodes/WebBox.scss1
-rw-r--r--src/client/views/nodes/WebBox.tsx98
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx10
-rw-r--r--src/client/views/nodes/trails/PresBox.tsx7
13 files changed, 155 insertions, 209 deletions
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 8ac9d6804..e1de2fa76 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -41,7 +41,6 @@ import { PhysicsSimulationBox } from './PhysicsBox/PhysicsSimulationBox';
import { RecordingBox } from './RecordingBox';
import { ScreenshotBox } from './ScreenshotBox';
import { ScriptingBox } from './ScriptingBox';
-import { SliderBox } from './SliderBox';
import { PresBox } from './trails/PresBox';
import { VideoBox } from './VideoBox';
import { WebBox } from './WebBox';
@@ -240,7 +239,6 @@ export class DocumentContentsView extends React.Component<
FontIconBox,
LabelBox,
EquationBox,
- SliderBox,
FieldView,
CollectionFreeFormView,
CollectionDockingView,
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index ef96e64be..e4fc6c4a2 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -394,18 +394,15 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
dragData.treeViewDoc = this.props.treeViewDoc;
dragData.removeDocument = this.props.removeDocument;
dragData.moveDocument = this.props.moveDocument;
+ dragData.draggedViews = [this.props.DocumentView()];
dragData.canEmbed = this.rootDoc.dragAction ?? this.props.dragAction ? true : false;
- const ffview = this.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView;
- ffview && runInAction(() => (ffview.ChildDrag = this.props.DocumentView()));
DragManager.StartDocumentDrag(
selected.map(dv => dv.docView!._mainCont.current!),
dragData,
x,
y,
- { hideSource: hideSource || (!dropAction && !this.layoutDoc.onDragStart && !this.props.dontHideOnDrag) },
- () => setTimeout(action(() => ffview && (ffview.ChildDrag = undefined)))
+ { hideSource: hideSource || (!dropAction && !this.layoutDoc.onDragStart && !this.props.dontHideOnDrag) }
); // this needs to happen after the drop event is processed.
- ffview?.setupDragLines(false);
}
}
@@ -495,11 +492,10 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
}
const sendToBack = e.altKey;
this._singleClickFunc =
- clickFunc ??
- (() =>
- sendToBack
- ? this.props.DocumentView().props.CollectionFreeFormDocumentView?.().props.bringToFront(this.rootDoc, true)
- : this._componentView?.select?.(e.ctrlKey || e.metaKey, e.shiftKey) ?? this.props.select(e.ctrlKey || e.metaKey || e.shiftKey));
+ // prettier-ignore
+ clickFunc ?? (() => (sendToBack ? this.props.DocumentView().props.bringToFront(this.rootDoc, true) :
+ this._componentView?.select?.(e.ctrlKey || e.metaKey, e.shiftKey) ??
+ this.props.select(e.ctrlKey || e.metaKey || e.shiftKey)));
const waitFordblclick = this.props.waitForDoubleClickToClick?.() ?? this.Document.waitForDoubleClickToClick;
if ((clickFunc && waitFordblclick !== 'never') || waitFordblclick === 'always') {
this._doubleClickTimeout && clearTimeout(this._doubleClickTimeout);
@@ -1099,7 +1095,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
captionStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string) => this.props?.styleProvider?.(doc, props, property + ':caption');
@computed get innards() {
TraceMobx();
- const ffscale = () => this.props.DocumentView().props.CollectionFreeFormDocumentView?.().props.ScreenToLocalTransform().Scale || 1;
const showTitle = this.layout_showTitle?.split(':')[0];
const showTitleHover = this.layout_showTitle?.includes(':hover');
const captionView = !this.layout_showCaption ? null : (
@@ -1107,8 +1102,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
className="documentView-captionWrapper"
style={{
pointerEvents: this.rootDoc.ignoreClick ? 'none' : this.isContentActive() || this.props.isDocumentActive?.() ? 'all' : undefined,
- minWidth: 50 * ffscale(),
- maxHeight: `max(100%, ${20 * ffscale()}px)`,
background: StrCast(this.layoutDoc._backgroundColor, 'rgba(0,0,0,0.2)'),
color: lightOrDark(StrCast(this.layoutDoc._backgroundColor, 'black')),
}}>
@@ -1117,7 +1110,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
yPadding={10}
xPadding={10}
fieldKey={this.layout_showCaption}
- fontSize={12 * Math.max(1, (2 * ffscale()) / 3)}
styleProvider={this.captionStyleProvider}
dontRegisterView={true}
noSidebar={true}
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 4ebf22ddf..f014f842e 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -34,7 +34,6 @@ export interface FieldViewProps extends DocumentViewSharedProps {
backgroundColor?: string;
treeViewDoc?: Doc;
color?: string;
- fontSize?: number;
height?: number;
width?: number;
noSidebar?: boolean;
diff --git a/src/client/views/nodes/FontIconBox/FontIconBox.tsx b/src/client/views/nodes/FontIconBox/FontIconBox.tsx
index 14a3d16ef..d2e1293da 100644
--- a/src/client/views/nodes/FontIconBox/FontIconBox.tsx
+++ b/src/client/views/nodes/FontIconBox/FontIconBox.tsx
@@ -240,7 +240,6 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
text: typeof value === 'string' ? value.charAt(0).toUpperCase() + value.slice(1) : StrCast(DocCast(value)?.title),
val: value,
style: getStyle(value),
- onClick: undoable(() => script.script.run({ this: this.layoutDoc, self: this.rootDoc, value }), value),
// shortcut: '#',
}));
diff --git a/src/client/views/nodes/MapBox/MapAnchorMenu.tsx b/src/client/views/nodes/MapBox/MapAnchorMenu.tsx
index f0827936b..7af4d9b59 100644
--- a/src/client/views/nodes/MapBox/MapAnchorMenu.tsx
+++ b/src/client/views/nodes/MapBox/MapAnchorMenu.tsx
@@ -1,41 +1,32 @@
import React = require('react');
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, IReactionDisposer, observable, ObservableMap, reaction } from 'mobx';
+import { IReactionDisposer, ObservableMap, reaction } from 'mobx';
import { observer } from 'mobx-react';
-import { ColorState } from 'react-color';
import { Doc, Opt } from '../../../../fields/Doc';
-import { returnFalse, setupMoveUpEvents, unimplementedFunction, Utils } from '../../../../Utils';
+import { returnFalse, setupMoveUpEvents, unimplementedFunction } from '../../../../Utils';
import { SelectionManager } from '../../../util/SelectionManager';
import { AntimodeMenu, AntimodeMenuProps } from '../../AntimodeMenu';
-import { LinkPopup } from '../../linking/LinkPopup';
-import { gptAPICall, GPTCallType } from '../../../apis/gpt/GPT';
// import { GPTPopup, GPTPopupMode } from './../../GPTPopup/GPTPopup';
-import { EditorView } from 'prosemirror-view';
-import './MapAnchorMenu.scss';
-import { ColorPicker, Group, IconButton, Popup, Size, Toggle, ToggleType, Type } from 'browndash-components';
-import { StrCast } from '../../../../fields/Types';
-import { DocumentType } from '../../../documents/DocumentTypes';
+import { IconButton } from 'browndash-components';
import { SettingsManager } from '../../../util/SettingsManager';
+import './MapAnchorMenu.scss';
@observer
export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
static Instance: MapAnchorMenu;
private _disposer: IReactionDisposer | undefined;
- private _disposer2: IReactionDisposer | undefined;
- private _commentCont = React.createRef<HTMLButtonElement>();
+ private _commentRef = React.createRef<HTMLDivElement>();
public onMakeAnchor: () => Opt<Doc> = () => undefined; // Method to get anchor from text search
public Center: () => void = unimplementedFunction;
- // public OnClick: (e: PointerEvent) => void = unimplementedFunction;
+ public OnClick: (e: PointerEvent) => void = unimplementedFunction;
// public OnAudio: (e: PointerEvent) => void = unimplementedFunction;
- // public StartDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction;
- // public StartCropDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction;
+ public StartDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction;
public Highlight: (color: string, isTargetToggler: boolean, savedAnnotations?: ObservableMap<number, HTMLDivElement[]>, addAsAnnotation?: boolean) => Opt<Doc> = (color: string, isTargetToggler: boolean) => undefined;
public GetAnchor: (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => Opt<Doc> = (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => undefined;
public Delete: () => void = unimplementedFunction;
- public LinkNote: () => void = unimplementedFunction;
// public MakeTargetToggle: () => void = unimplementedFunction;
// public ShowTargetTrail: () => void = unimplementedFunction;
public IsTargetToggler: () => boolean = returnFalse;
@@ -52,23 +43,12 @@ export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
componentWillUnmount() {
this._disposer?.();
- this._disposer2?.();
}
componentDidMount() {
- this._disposer2 = reaction(
- () => this._opacity,
- opacity => {
- if (!opacity) {
- }
- },
- { fireImmediately: true }
- );
this._disposer = reaction(
() => SelectionManager.Views().slice(),
- selected => {
- MapAnchorMenu.Instance.fadeOut(true);
- }
+ selected => MapAnchorMenu.Instance.fadeOut(true)
);
}
// audioDown = (e: React.PointerEvent) => {
@@ -87,6 +67,18 @@ export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
// e => this.OnCrop?.(e)
// );
// };
+ notePointerDown = (e: React.PointerEvent) => {
+ setupMoveUpEvents(
+ this,
+ e,
+ (e: PointerEvent) => {
+ this.StartDrag(e, this._commentRef.current!);
+ return true;
+ },
+ returnFalse,
+ e => this.OnClick(e)
+ );
+ };
static top = React.createRef<HTMLDivElement>();
// public get Top(){
@@ -105,12 +97,14 @@ export class MapAnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
/>
}
{
- <IconButton
- tooltip="Link Note to Pin" //
- onPointerDown={this.LinkNote}
- icon={<FontAwesomeIcon icon="sticky-note" />}
- color={SettingsManager.userColor}
- />
+ <div ref={this._commentRef}>
+ <IconButton
+ tooltip="Link Note to Pin" //
+ onPointerDown={this.notePointerDown}
+ icon={<FontAwesomeIcon icon="sticky-note" />}
+ color={SettingsManager.userColor}
+ />
+ </div>
}
{
<IconButton
diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx
index d7469e530..65c138975 100644
--- a/src/client/views/nodes/MapBox/MapBox.tsx
+++ b/src/client/views/nodes/MapBox/MapBox.tsx
@@ -6,6 +6,7 @@ import { observer } from 'mobx-react';
import * as React from 'react';
import { Doc, DocListCast, Field, Opt } from '../../../../fields/Doc';
import { DocCss, Highlight, Width } from '../../../../fields/DocSymbols';
+import { Id } from '../../../../fields/FieldSymbols';
import { InkTool } from '../../../../fields/InkField';
import { DocCast, NumCast, StrCast } from '../../../../fields/Types';
import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnOne, setupMoveUpEvents, Utils } from '../../../../Utils';
@@ -24,6 +25,7 @@ import { MarqueeAnnotator } from '../../MarqueeAnnotator';
import { SidebarAnnos } from '../../SidebarAnnos';
import { DocumentView } from '../DocumentView';
import { FieldView, FieldViewProps } from '../FieldView';
+import { FormattedTextBox } from '../formattedText/FormattedTextBox';
import { PinProps, PresBox } from '../trails';
import { MapAnchorMenu } from './MapAnchorMenu';
import './MapBox.scss';
@@ -215,6 +217,37 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
this.layoutDoc._width = this.layoutDoc._layout_showSidebar ? NumCast(this.layoutDoc._width) * 1.2 : Math.max(20, NumCast(this.layoutDoc._width) - prevWidth);
};
+ startAnchorDrag = (e: PointerEvent, ele: HTMLElement) => {
+ e.preventDefault();
+ e.stopPropagation();
+
+ const sourceAnchorCreator = action(() => {
+ const note = this.getAnchor(true);
+ if (note && this.selectedPin) {
+ note.latitude = this.selectedPin.latitude;
+ note.longitude = this.selectedPin.longitude;
+ note.map = this.selectedPin.map;
+ }
+ return note as Doc;
+ });
+
+ const targetCreator = (annotationOn: Doc | undefined) => {
+ const target = DocUtils.GetNewTextDoc('Note linked to ' + this.rootDoc.title, 0, 0, 100, 100, undefined, annotationOn, undefined, 'yellow');
+ FormattedTextBox.SelectOnLoad = target[Id];
+ return target;
+ };
+ const docView = this.props.DocumentView?.();
+ docView &&
+ DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(docView, sourceAnchorCreator, targetCreator), e.pageX, e.pageY, {
+ dragComplete: e => {
+ if (!e.aborted && e.annoDragData && e.annoDragData.linkSourceDoc && e.annoDragData.dropDocument && e.linkDocument) {
+ e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.props.Document;
+ e.annoDragData.linkSourceDoc.followLinkZoom = false;
+ }
+ },
+ });
+ };
+
createNoteAnnotation = () => {
const createFunc = undoable(
action(() => {
@@ -388,7 +421,8 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
MapAnchorMenu.Instance.Delete = this.deleteSelectedPin;
MapAnchorMenu.Instance.Center = this.centerOnSelectedPin;
- MapAnchorMenu.Instance.LinkNote = this.createNoteAnnotation;
+ MapAnchorMenu.Instance.OnClick = this.createNoteAnnotation;
+ MapAnchorMenu.Instance.StartDrag = this.startAnchorDrag;
const point = this._bingMap.current.tryLocationToPixel(new this.MicrosoftMaps.Location(this.selectedPin.latitude, this.selectedPin.longitude));
const x = point.x + (this.props.PanelWidth() - this.sidebarWidth()) / 2;
@@ -516,7 +550,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
// Removes filter
Doc.setDocFilter(this.rootDoc, 'latitude', this.selectedPin.latitude, 'remove');
Doc.setDocFilter(this.rootDoc, 'longitude', this.selectedPin.longitude, 'remove');
- Doc.setDocFilter(this.rootDoc, '-linkedTo', `mapPin=${Field.toString(DocCast(this.selectedPin.mapPin))}`, 'remove');
+ Doc.setDocFilter(this.rootDoc, '-linkedTo', `mapPin=${Field.toScriptString(DocCast(this.selectedPin))}`, 'remove');
this.removePushpin(this.selectedPin);
}
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 73a5be90a..cf44649a2 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -242,7 +242,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
title: StrCast(this.rootDoc.title + '@' + NumCast(this.layoutDoc._layout_scrollTop)?.toFixed(0)),
annotationOn: this.rootDoc,
});
- const visibleAnchor = this._pdfViewer?._getAnchor(this._pdfViewer.savedAnnotations(), true);
+ const visibleAnchor = this._pdfViewer?._getAnchor?.(this._pdfViewer.savedAnnotations(), true);
const anchor = visibleAnchor ?? docAnchor();
PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), scrollable: true, pannable: true } }, this.rootDoc);
anchor.text = ele?.textContent ?? '';
diff --git a/src/client/views/nodes/SliderBox.scss b/src/client/views/nodes/SliderBox.scss
deleted file mode 100644
index 4206a368d..000000000
--- a/src/client/views/nodes/SliderBox.scss
+++ /dev/null
@@ -1,19 +0,0 @@
-.sliderBox-outerDiv {
- width: calc(100% - 14px); // 14px accounts for handles that are at the max value of the slider that would extend outside the box
- height: 100%;
- border-radius: inherit;
- display: flex;
- flex-direction: column;
- position: relative;
- .slider-tracks {
- top: 7px;
- position: relative;
- }
- .slider-ticks {
- position: relative;
- }
- .slider-handles {
- top: 7px;
- position: relative;
- }
-} \ No newline at end of file
diff --git a/src/client/views/nodes/SliderBox.tsx b/src/client/views/nodes/SliderBox.tsx
deleted file mode 100644
index 430b20eb5..000000000
--- a/src/client/views/nodes/SliderBox.tsx
+++ /dev/null
@@ -1,103 +0,0 @@
-import { runInAction } from 'mobx';
-import { observer } from 'mobx-react';
-import * as React from 'react';
-import { Handles, Rail, Slider, Ticks, Tracks } from 'react-compound-slider';
-import { NumCast, ScriptCast, StrCast } from '../../../fields/Types';
-import { ContextMenu } from '../ContextMenu';
-import { ContextMenuProps } from '../ContextMenuItem';
-import { ViewBoxBaseComponent } from '../DocComponent';
-import { ScriptBox } from '../ScriptBox';
-import { StyleProp } from '../StyleProvider';
-import { FieldView, FieldViewProps } from './FieldView';
-import { Handle, Tick, TooltipRail, Track } from './SliderBox-components';
-import './SliderBox.scss';
-
-@observer
-export class SliderBox extends ViewBoxBaseComponent<FieldViewProps>() {
- public static LayoutString(fieldKey: string) {
- return FieldView.LayoutString(SliderBox, fieldKey);
- }
-
- get minThumbKey() {
- return this.fieldKey + '-minThumb';
- }
- get maxThumbKey() {
- return this.fieldKey + '-maxThumb';
- }
- get minKey() {
- return this.fieldKey + '-min';
- }
- get maxKey() {
- return this.fieldKey + '-max';
- }
- specificContextMenu = (e: React.MouseEvent): void => {
- const funcs: ContextMenuProps[] = [];
- funcs.push({ description: 'Edit Thumb Change Script', icon: 'edit', event: (obj: any) => ScriptBox.EditButtonScript('On Thumb Change ...', this.props.Document, 'onThumbChange', obj.x, obj.y) });
- ContextMenu.Instance.addItem({ description: 'Options...', subitems: funcs, icon: 'asterisk' });
- };
- onChange = (values: readonly number[]) =>
- runInAction(() => {
- this.dataDoc[this.minThumbKey] = values[0];
- this.dataDoc[this.maxThumbKey] = values[1];
- ScriptCast(this.layoutDoc.onThumbChanged, null)?.script.run({
- self: this.rootDoc,
- scriptContext: this.props.scriptContext,
- range: values,
- this: this.layoutDoc,
- });
- });
-
- render() {
- const domain = [NumCast(this.layoutDoc[this.minKey]), NumCast(this.layoutDoc[this.maxKey])];
- const defaultValues = [NumCast(this.dataDoc[this.minThumbKey]), NumCast(this.dataDoc[this.maxThumbKey])];
- return domain[1] <= domain[0] ? null : (
- <div className="sliderBox-outerDiv" onContextMenu={this.specificContextMenu} onPointerDown={e => e.stopPropagation()} style={{ boxShadow: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BoxShadow) }}>
- <div
- className="sliderBox-mainButton"
- onContextMenu={this.specificContextMenu}
- style={{
- background: StrCast(this.layoutDoc.backgroundColor),
- color: StrCast(this.layoutDoc.color, 'black'),
- fontSize: StrCast(this.layoutDoc._text_fontSize),
- letterSpacing: StrCast(this.layoutDoc.letterSpacing),
- }}>
- <Slider mode={2} step={Math.min(1, 0.1 * (domain[1] - domain[0]))} domain={domain} rootStyle={{ position: 'relative', width: '100%' }} onChange={this.onChange} values={defaultValues}>
- <Rail>{railProps => <TooltipRail {...railProps} />}</Rail>
- <Handles>
- {({ handles, activeHandleID, getHandleProps }) => (
- <div className="slider-handles">
- {handles.map((handle, i) => {
- const value = i === 0 ? defaultValues[0] : defaultValues[1];
- return (
- <div title={String(value)}>
- <Handle key={handle.id} handle={handle} domain={domain} isActive={handle.id === activeHandleID} getHandleProps={getHandleProps} />
- </div>
- );
- })}
- </div>
- )}
- </Handles>
- <Tracks left={false} right={false}>
- {({ tracks, getTrackProps }) => (
- <div className="slider-tracks">
- {tracks.map(({ id, source, target }) => (
- <Track key={id} source={source} target={target} disabled={false} getTrackProps={getTrackProps} />
- ))}
- </div>
- )}
- </Tracks>
- <Ticks count={5}>
- {({ ticks }) => (
- <div className="slider-ticks">
- {ticks.map(tick => (
- <Tick key={tick.id} tick={tick} count={ticks.length} format={(val: number) => val.toString()} />
- ))}
- </div>
- )}
- </Ticks>
- </Slider>
- </div>
- </div>
- );
- }
-}
diff --git a/src/client/views/nodes/WebBox.scss b/src/client/views/nodes/WebBox.scss
index 75847c100..511c91da0 100644
--- a/src/client/views/nodes/WebBox.scss
+++ b/src/client/views/nodes/WebBox.scss
@@ -176,7 +176,6 @@
width: 100%;
height: 100%;
transform-origin: top left;
- overflow: auto;
.webBox-iframe {
width: 100%;
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 27c19105f..af20ff061 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -13,7 +13,7 @@ import { listSpec } from '../../../fields/Schema';
import { Cast, ImageCast, NumCast, StrCast, WebCast } from '../../../fields/Types';
import { ImageField, WebField } from '../../../fields/URLField';
import { TraceMobx } from '../../../fields/util';
-import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, getWordAtPoint, returnFalse, returnOne, returnZero, setupMoveUpEvents, smoothScroll, Utils } from '../../../Utils';
+import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, getWordAtPoint, lightOrDark, returnFalse, returnOne, returnZero, setupMoveUpEvents, smoothScroll, Utils } from '../../../Utils';
import { Docs, DocUtils } from '../../documents/Documents';
import { DocumentManager } from '../../util/DocumentManager';
import { DragManager } from '../../util/DragManager';
@@ -62,10 +62,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
private _searchRef = React.createRef<HTMLInputElement>();
private _searchString = '';
private _scrollTimer: any;
+ private _getAnchor: (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => Opt<Doc> = () => undefined;
- private get _getAnchor() {
- return AnchorMenu.Instance?.GetAnchor;
- }
@observable private _webUrl = ''; // url of the src parameter of the embedded iframe but not necessarily the rendered page - eg, when following a link, the rendered page changes but we don't want the src parameter to also change as that would cause an unnecessary re-render.
@observable private _hackHide = false; // apparently changing the value of the 'sandbox' prop doesn't necessarily apply it to the active iframe. so thisforces the ifrmae to be rebuilt when allowScripts is toggled
@observable private _searching: boolean = false;
@@ -186,13 +184,15 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
this.props.setContentView?.(this); // this tells the DocumentView that this WebBox is the "content" of the document. this allows the DocumentView to call WebBox relevant methods to configure the UI (eg, show back/forward buttons)
runInAction(() => {
- this._annotationKeySuffix = () => this._urlHash + '_annotations';
- const reqdFuncs: { [key: string]: string } = {};
+ this._annotationKeySuffix = () => (this._urlHash ? this._urlHash + '_' : '') + 'annotations';
// bcz: need to make sure that doc.data_annotations points to the currently active web page's annotations (this could/should be when the doc is created)
- reqdFuncs[this.fieldKey + '_annotations'] = `copyField(this["${this.fieldKey}_"+urlHash(this["${this.fieldKey}"]?.url?.toString())+"_annotations"])`;
- reqdFuncs[this.fieldKey + '_annotations-setter'] = `this["${this.fieldKey}_"+urlHash(this["${this.fieldKey}"]?.url?.toString())+"_annotations"] = value`;
- reqdFuncs[this.fieldKey + '_sidebar'] = `copyField(this["${this.fieldKey}_"+urlHash(this["${this.fieldKey}"]?.url?.toString())+"_sidebar"])`;
- DocUtils.AssignScripts(this.dataDoc, {}, reqdFuncs);
+ if (this._url) {
+ const reqdFuncs: { [key: string]: string } = {};
+ reqdFuncs[this.fieldKey + '_annotations'] = `copyField(this["${this.fieldKey}_"+urlHash(this["${this.fieldKey}"]?.url?.toString())+"annotations"])`;
+ reqdFuncs[this.fieldKey + '_annotations-setter'] = `this["${this.fieldKey}_"+urlHash(this["${this.fieldKey}"]?.url?.toString())+"annotations"] = value`;
+ reqdFuncs[this.fieldKey + '_sidebar'] = `copyField(this["${this.fieldKey}_"+urlHash(this["${this.fieldKey}"]?.url?.toString())+"sidebar"])`;
+ DocUtils.AssignScripts(this.dataDoc, {}, reqdFuncs);
+ }
});
this._disposers.urlchange = reaction(
() => WebCast(this.rootDoc.data),
@@ -264,14 +264,16 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
const clientRects = selRange.getClientRects();
for (let i = 0; i < clientRects.length; i++) {
const rect = clientRects.item(i);
+ const mainrect = this._url ? { translateX: 0, translateY: 0, scale: 1 } : Utils.GetScreenTransform(this._mainCont.current);
if (rect && rect.width !== this._mainCont.current.clientWidth) {
const annoBox = document.createElement('div');
annoBox.className = 'marqueeAnnotator-annotationBox';
+ const scale = this._url ? 1 : this.props.ScreenToLocalTransform().Scale;
// transforms the positions from screen onto the pdf div
- annoBox.style.top = (rect.top + this._mainCont.current.scrollTop).toString();
- annoBox.style.left = rect.left.toString();
- annoBox.style.width = rect.width.toString();
- annoBox.style.height = rect.height.toString();
+ annoBox.style.top = ((rect.top - mainrect.translateY) * scale + (this._url ? this._mainCont.current.scrollTop : NumCast(this.layoutDoc.layout_scrollTop))).toString();
+ annoBox.style.left = ((rect.left - mainrect.translateX) * scale).toString();
+ annoBox.style.width = (rect.width * scale).toString();
+ annoBox.style.height = (rect.height * scale).toString();
this._annotationLayer.current && MarqueeAnnotator.previewNewAnnotation(this._savedAnnotations, this._annotationLayer.current, annoBox, 1);
}
}
@@ -340,7 +342,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
});
PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), scrollable: pinProps?.pinData ? true : false, pannable: true } }, this.rootDoc);
anchor.text = ele?.textContent ?? '';
- anchor.text_html = ele?.innerHTML;
+ anchor.text_html = ele?.innerHTML ?? this._selectionText;
addAsAnnotation && this.addDocumentWrapper(anchor);
return anchor;
};
@@ -362,12 +364,49 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
this._textAnnotationCreator = () => this.createTextAnnotation(sel, !sel.isCollapsed ? sel.getRangeAt(0) : undefined);
AnchorMenu.Instance.jumpTo(e.clientX * scale + mainContBounds.translateX, e.clientY * scale + mainContBounds.translateY - NumCast(this.layoutDoc._layout_scrollTop) * scale);
// Changing which document to add the annotation to (the currently selected WebBox)
- GPTPopup.Instance.setSidebarId(`${this.props.fieldKey}_${this._urlHash}_sidebar`);
+ GPTPopup.Instance.setSidebarId(`${this.props.fieldKey}_${this._urlHash ? this._urlHash + '_' : ''}sidebar`);
GPTPopup.Instance.addDoc = this.sidebarAddDocument;
}
}
};
@action
+ webClipDown = (e: React.PointerEvent) => {
+ const mainContBounds = Utils.GetScreenTransform(this._mainCont.current!);
+ const scale = (this.props.NativeDimScaling?.() || 1) * mainContBounds.scale;
+ const word = getWordAtPoint(e.target, e.clientX, e.clientY);
+ this._setPreviewCursor?.(e.clientX, e.clientY, false, true, this.rootDoc);
+ MarqueeAnnotator.clearAnnotations(this._savedAnnotations);
+ e.button !== 2 && (this._marqueeing = [e.clientX, e.clientY]);
+ if (word || (e.target as any)?.className?.includes('rangeslider') || (e.target as any)?.onclick || (e.target as any)?.parentNode?.onclick) {
+ e.stopPropagation();
+ setTimeout(
+ action(() => (this._marqueeing = undefined)),
+ 100
+ ); // bcz: hack .. anchor menu is setup within MarqueeAnnotator so we need to at least create the marqueeAnnotator even though we aren't using it.
+ } else {
+ this._isAnnotating = true;
+ this.props.select(false);
+ e.stopPropagation();
+ e.preventDefault();
+ }
+ document.addEventListener('pointerup', this.webClipUp);
+ };
+ webClipUp = (e: PointerEvent) => {
+ document.removeEventListener('pointerup', this.webClipUp);
+ this._getAnchor = AnchorMenu.Instance?.GetAnchor; // need to save AnchorMenu's getAnchor since a subsequent selection on another doc will overwrite this value
+ const sel = window.getSelection();
+ if (sel && !sel.isCollapsed) {
+ const selRange = sel.getRangeAt(0);
+ this._selectionText = sel.toString();
+ AnchorMenu.Instance.setSelectedText(sel.toString());
+ this._textAnnotationCreator = () => this.createTextAnnotation(sel, selRange);
+ AnchorMenu.Instance.jumpTo(e.clientX, e.clientY);
+ // Changing which document to add the annotation to (the currently selected WebBox)
+ GPTPopup.Instance.setSidebarId(`${this.props.fieldKey}_${this._urlHash ? this._urlHash + '_' : ''}sidebar`);
+ GPTPopup.Instance.addDoc = this.sidebarAddDocument;
+ }
+ };
+ @action
iframeDown = (e: PointerEvent) => {
const mainContBounds = Utils.GetScreenTransform(this._mainCont.current!);
const scale = (this.props.NativeDimScaling?.() || 1) * mainContBounds.scale;
@@ -396,9 +435,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
ContextMenu.Instance.setIgnoreEvents(true);
}
};
- isFirefox = () => {
- return 'InstallTrigger' in window; // navigator.userAgent.indexOf("Chrome") !== -1;
- };
+ isFirefox = () => 'InstallTrigger' in window; // navigator.userAgent.indexOf("Chrome") !== -1;
iframeClick = () => this._iframeClick;
iframeScaling = () => 1 / this.props.ScreenToLocalTransform().Scale;
@@ -722,10 +759,11 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
}
};
@action finishMarquee = (x?: number, y?: number, e?: PointerEvent) => {
+ this._getAnchor = AnchorMenu.Instance?.GetAnchor;
this._marqueeing = undefined;
this._isAnnotating = false;
this._iframeClick = undefined;
- const sel = this._iframe?.contentDocument?.getSelection();
+ const sel = this._url ? this._iframe?.contentDocument?.getSelection() : window.document.getSelection();
if (sel?.empty) sel.empty(); // Chrome
else if (sel?.removeAllRanges) sel.removeAllRanges(); // Firefox
if (x !== undefined && y !== undefined) {
@@ -739,6 +777,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
}
};
+ @observable lighttext = false;
+
@computed get urlContent() {
setTimeout(
action(() => {
@@ -750,7 +790,20 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
);
const field = this.rootDoc[this.props.fieldKey];
if (field instanceof HtmlField) {
- return <span className="webBox-htmlSpan" contentEditable onPointerDown={e => e.stopPropagation()} dangerouslySetInnerHTML={{ __html: field.html }} />;
+ return (
+ <span
+ className="webBox-htmlSpan"
+ ref={action((r: any) => {
+ if (r) {
+ this._scrollHeight = Number(getComputedStyle(r).height.replace('px', ''));
+ this.lighttext = Array.from(r.children).some((c: any) => c instanceof HTMLElement && lightOrDark(getComputedStyle(c).color) !== Colors.WHITE);
+ }
+ })}
+ contentEditable
+ onPointerDown={this.webClipDown}
+ dangerouslySetInnerHTML={{ __html: field.html }}
+ />
+ );
}
if (field instanceof WebField) {
const url = this.layoutDoc[this.fieldKey + '_useCors'] ? Utils.CorsProxy(this._webUrl) : this._webUrl;
@@ -775,7 +828,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
}
addDocumentWrapper = (doc: Doc | Doc[], annotationKey?: string) => {
- (doc instanceof Doc ? [doc] : doc).forEach(doc => (doc.config_data = new WebField(this._url)));
+ this._url && (doc instanceof Doc ? [doc] : doc).forEach(doc => (doc.config_data = new WebField(this._url)));
return this.addDocument(doc, annotationKey);
};
@@ -900,6 +953,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
style={{
transform: `scale(${this.zoomScaling()}) translate(${-NumCast(this.layoutDoc.freeform_panX)}px, ${-NumCast(this.layoutDoc.freeform_panY)}px)`,
height: Doc.NativeHeight(this.Document) || undefined,
+ mixBlendMode: this._url || !this.lighttext ? 'multiply' : 'hard-light',
}}
ref={this._annotationLayer}>
{this.inlineTextAnnotations
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 6a92d09d9..90ebf5206 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -78,9 +78,7 @@ const translate = setCORS('http://cors-anywhere.herokuapp.com/');
export const GoogleRef = 'googleDocId';
type PullHandler = (exportState: Opt<GoogleApiClientUtils.Docs.ImportResult>, dataDoc: Doc) => void;
-export interface FormattedTextBoxProps {
- allowScroll?: boolean;
-}
+export interface FormattedTextBoxProps {}
@observer
export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps & FormattedTextBoxProps>() {
public static LayoutString(fieldStr: string) {
@@ -562,7 +560,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
drop = (e: Event, de: DragManager.DropEvent) => {
if (de.complete.annoDragData) {
de.complete.annoDragData.dropDocCreator = () => this.getAnchor(true);
- e.stopPropagation();
return true;
}
const dragData = de.complete.docDragData;
@@ -2067,10 +2064,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
}
// if scrollTop is 0, then don't let wheel trigger scroll on any container (which it would since onScroll won't be triggered on this)
- if (this.props.isContentActive() && !this.props.allowScroll) {
+ if (this.props.isContentActive()) {
// prevent default if selected || child is active but this doc isn't scrollable
if (
- (this._scrollRef.current?.scrollHeight ?? 0) <= Math.ceil(Number(this.layoutDoc._height)) && //
+ (this._scrollRef.current?.scrollHeight ?? 0) <= Math.ceil(this.props.PanelHeight()) && //
(this.props.isSelected() || this.isAnyChildContentActive())
) {
e.preventDefault();
@@ -2131,7 +2128,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
ref={this._ref}
style={{
cursor: this.props.isContentActive() ? 'text' : undefined,
- overflow: this.layout_autoHeight && this.props.CollectionFreeFormDocumentView?.() ? 'hidden' : undefined, //x this breaks viewing an layout_autoHeight doc in its own tab, or in the lightbox
height: this.props.height || (this.layout_autoHeight && this.props.renderDepth && !this.props.suppressSetHeight ? 'max-content' : undefined),
pointerEvents: Doc.ActiveTool === InkTool.None && !this.props.onBrowseClick?.() ? undefined : 'none',
}}
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 2a3b232bd..383b400c8 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -465,7 +465,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
const fkey = Doc.LayoutFieldKey(bestTarget);
const setData = bestTargetView?.ComponentView?.setData;
if (setData) setData(activeItem.config_data);
- else Doc.GetProto(bestTarget)[fkey] = activeItem.config_data instanceof ObjectField ? activeItem.config_data[Copy]() : activeItem.config_data;
+ else {
+ const current = Doc.GetProto(bestTarget)[fkey];
+ Doc.GetProto(bestTarget)[fkey + '_' + Date.now()] = current instanceof ObjectField ? current[Copy]() : current;
+ Doc.GetProto(bestTarget)[fkey] = activeItem.config_data instanceof ObjectField ? activeItem.config_data[Copy]() : activeItem.config_data;
+ }
bestTarget[fkey + '_usePath'] = activeItem.config_usePath;
setTimeout(() => (bestTarget._dataTransition = undefined), transTime + 10);
}
@@ -2650,7 +2654,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
removeDocument={returnFalse}
dontRegisterView={true}
focus={this.focusElement}
- scriptContext={this}
ScreenToLocalTransform={this.getTransform}
AddToMap={this.AddToMap}
RemFromMap={this.RemFromMap}