From a63ab5802551887f62265d420b7c5e925b5cd7d6 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 5 Sep 2023 01:26:54 -0400
Subject: added ui for specifying wehther to play a/v when following links, and
 cleaned up ui/etc for pres trails.  fixed a bunch of colors in pres
 properties.  fixed a/v anchors to be configs when not adding them to the doc,
 otherwise labels.

---
 src/client/views/collections/CollectionStackedTimeline.tsx | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

(limited to 'src/client/views/collections/CollectionStackedTimeline.tsx')

diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index d2be70577..0a5a80936 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -32,7 +32,7 @@ import './CollectionStackedTimeline.scss';
 export type CollectionStackedTimelineProps = {
     Play: () => void;
     Pause: () => void;
-    playLink: (linkDoc: Doc) => void;
+    playLink: (linkDoc: Doc, options: DocFocusOptions) => void;
     playFrom: (seekTimeInSeconds: number, endTime?: number) => void;
     playing: () => boolean;
     setTime: (time: number) => void;
@@ -677,7 +677,7 @@ interface StackedTimelineAnchorProps {
     height: number;
     toTimeline: (screen_delta: number, width: number) => number;
     styleProvider?: (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string) => any;
-    playLink: (linkDoc: Doc) => void;
+    playLink: (linkDoc: Doc, options: DocFocusOptions) => void;
     setTime: (time: number) => void;
     startTag: string;
     endTag: string;
@@ -793,7 +793,7 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
     renderInner = computedFn(function (this: StackedTimelineAnchor, mark: Doc, script: undefined | (() => ScriptField), doublescript: undefined | (() => ScriptField), screenXf: () => Transform, width: () => number, height: () => number) {
         const anchor = observable({ view: undefined as any });
         const focusFunc = (doc: Doc, options: DocFocusOptions): number | undefined => {
-            this.props.playLink(mark);
+            this.props.playLink(mark, options);
             return undefined;
         };
         return {
-- 
cgit v1.2.3-70-g09d2


From 7bc82b283bc7aa11a163c95607a6e192439bd601 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 8 Sep 2023 10:10:09 -0400
Subject: added cancel trim and revert buttons to audiobox

---
 src/client/documents/Documents.ts                  |  4 +-
 src/client/views/SidebarAnnos.tsx                  |  1 -
 src/client/views/collections/CollectionMenu.tsx    |  3 +-
 .../collections/CollectionStackedTimeline.tsx      |  4 ++
 src/client/views/nodes/AudioBox.tsx                | 56 ++++++++++++++++++----
 src/client/views/nodes/ScreenshotBox.tsx           |  3 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |  9 ++--
 7 files changed, 63 insertions(+), 17 deletions(-)

(limited to 'src/client/views/collections/CollectionStackedTimeline.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index e413d4389..90c090f29 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -32,7 +32,7 @@ import { ContextMenu } from '../views/ContextMenu';
 import { ContextMenuProps } from '../views/ContextMenuItem';
 import { DFLT_IMAGE_NATIVE_DIM } from '../views/global/globalCssVariables.scss';
 import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, ActiveIsInkMask, InkingStroke } from '../views/InkingStroke';
-import { AudioBox } from '../views/nodes/AudioBox';
+import { AudioBox, media_state } from '../views/nodes/AudioBox';
 import { ColorBox } from '../views/nodes/ColorBox';
 import { ComparisonBox } from '../views/nodes/ComparisonBox';
 import { DataVizBox } from '../views/nodes/DataVizBox/DataVizBox';
@@ -269,7 +269,7 @@ export class DocumentOptions {
     _label_maxFontSize?: NUMt = new NumInfo('maximum font size for labelBoxes', false);
     stroke_width?: NUMt = new NumInfo('width of an ink stroke', false);
     icon_label?: STRt = new StrInfo('label to use for a fontIcon doc (otherwise, the title is used)', false);
-    mediaState?: STRt = new StrInfo('status of audio/video media document: "pendingRecording", "recording", "paused", "playing"', false);
+    mediaState?: STRt = new StrInfo(`status of audio/video media document: ${media_state.PendingRecording}, ${media_state.Recording}, ${media_state.Paused}, ${media_state.Playing}`, false);
     recording?: BOOLt = new BoolInfo('whether WebCam is recording or not');
     autoPlayAnchors?: BOOLt = new BoolInfo('whether to play audio/video when an anchor is clicked in a stackedTimeline.');
     dontPlayLinkOnSelect?: BOOLt = new BoolInfo('whether an audio/video should start playing when a link is followed to it.');
diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx
index f3452c780..ff347d65f 100644
--- a/src/client/views/SidebarAnnos.tsx
+++ b/src/client/views/SidebarAnnos.tsx
@@ -79,7 +79,6 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
             _layout_autoHeight: true,
             _text_fontSize: StrCast(Doc.UserDoc().fontSize),
             _text_fontFamily: StrCast(Doc.UserDoc().fontFamily),
-            target: 'HELLO' as any,
         });
         FormattedTextBox.SelectOnLoad = target[Id];
         FormattedTextBox.DontSelectInitialText = true;
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 5c9dd2058..78ab0797b 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -41,6 +41,7 @@ import { COLLECTION_BORDER_WIDTH } from './CollectionView';
 import { TabDocView } from './TabDocView';
 import { CollectionFreeFormView } from './collectionFreeForm';
 import { CollectionLinearView } from './collectionLinear';
+import { media_state } from '../nodes/AudioBox';
 
 interface CollectionMenuProps {
     panelHeight: () => number;
@@ -579,7 +580,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewMenu
     @undoBatch
     @action
     startRecording = () => {
-        const doc = Docs.Create.ScreenshotDocument({ title: 'screen recording', _layout_fitWidth: true, _width: 400, _height: 200, mediaState: 'pendingRecording' });
+        const doc = Docs.Create.ScreenshotDocument({ title: 'screen recording', _layout_fitWidth: true, _width: 400, _height: 200, mediaState: media_state.PendingRecording });
         CollectionDockingView.AddSplit(doc, OpenWhereMod.right);
     };
 
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index 0a5a80936..ad3160a08 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -161,6 +161,10 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
         this.layoutDoc.clipEnd = this.trimEnd;
         this._trimming = TrimScope.None;
     }
+    @action
+    public CancelTrimming() {
+        this._trimming = TrimScope.None;
+    }
 
     @action
     public setZoom(zoom: number) {
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 50b2432d2..8d80f1364 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -1,9 +1,10 @@
 import React = require('react');
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { Tooltip } from '@material-ui/core';
 import { action, computed, IReactionDisposer, observable, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import { DateField } from '../../../fields/DateField';
-import { Doc, DocListCast } from '../../../fields/Doc';
+import { Doc } from '../../../fields/Doc';
 import { ComputedField } from '../../../fields/ScriptField';
 import { Cast, DateCast, NumCast } from '../../../fields/Types';
 import { AudioField, nullAudio } from '../../../fields/URLField';
@@ -18,9 +19,9 @@ import { ContextMenu } from '../ContextMenu';
 import { ContextMenuProps } from '../ContextMenuItem';
 import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent';
 import './AudioBox.scss';
+import { DocFocusOptions } from './DocumentView';
 import { FieldView, FieldViewProps } from './FieldView';
 import { PinProps, PresBox } from './trails';
-import { DocFocusOptions } from './DocumentView';
 
 /**
  * AudioBox
@@ -67,7 +68,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
     _stream: MediaStream | undefined; // passed to MediaRecorder, records device input audio
     _play: any = null; // timeout for playback
 
-    @observable _stackedTimeline: any; // CollectionStackedTimeline ref
+    @observable _stackedTimeline: CollectionStackedTimeline | null | undefined; // CollectionStackedTimeline ref
     @observable _finished: boolean = false; // has playback reached end of clip
     @observable _volume: number = 1;
     @observable _muted: boolean = false;
@@ -476,9 +477,35 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         this.timeline?.StartTrimming(scope);
     };
 
+    // for trim button, double click displays full clip, single displays curr trim bounds
+    onResetPointerDown = (e: React.PointerEvent) => {
+        e.stopPropagation();
+        this.timeline &&
+            setupMoveUpEvents(
+                this,
+                e,
+                returnFalse,
+                returnFalse,
+                action(e => {
+                    if (this.timeline?.IsTrimming !== TrimScope.None) {
+                        this.timeline?.CancelTrimming();
+                    } else {
+                        this.beginEndtime = this.timeline?.trimEnd;
+                        this.beginStarttime = this.timeline?.trimStart;
+                        this.startTrim(TrimScope.All);
+                    }
+                })
+            );
+    };
+
+    beginEndtime: number | undefined;
+    beginStarttime: number | undefined;
+
     // for trim button, double click displays full clip, single displays curr trim bounds
     onClipPointerDown = (e: React.PointerEvent) => {
         e.stopPropagation();
+        this.beginEndtime = this.timeline?.trimEnd;
+        this.beginStarttime = this.timeline?.trimStart;
         this.timeline &&
             setupMoveUpEvents(
                 this,
@@ -529,7 +556,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                 r,
                 (e, de) => {
                     const [xp, yp] = this.props.ScreenToLocalTransform().transformPoint(de.x, de.y);
-                    de.complete.docDragData && this.timeline.internalDocDrop(e, de, de.complete.docDragData, xp);
+                    de.complete.docDragData && this.timeline?.internalDocDrop(e, de, de.complete.docDragData, xp);
                 },
                 this.layoutDoc,
                 undefined
@@ -591,9 +618,22 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                         </div>
 
                         {!this.miniPlayer && (
-                            <div className="audiobox-button" title={this.timeline?.IsTrimming !== TrimScope.None ? 'finish' : 'trim'} onPointerDown={this.onClipPointerDown}>
-                                <FontAwesomeIcon icon={this.timeline?.IsTrimming !== TrimScope.None ? 'check' : 'cut'} size={'1x'} />
-                            </div>
+                            <>
+                                <Tooltip title={<>trim audio</>}>
+                                    <div className="audiobox-button" onPointerDown={this.onClipPointerDown}>
+                                        <FontAwesomeIcon icon={this.timeline?.IsTrimming !== TrimScope.None ? 'check' : 'cut'} size={'1x'} />
+                                    </div>
+                                </Tooltip>
+                                {this.timeline?.IsTrimming == TrimScope.None && !NumCast(this.layoutDoc.clipStart) && NumCast(this.layoutDoc.clipEnd) === this.rawDuration ? (
+                                    <></>
+                                ) : (
+                                    <Tooltip title={<>{this.timeline?.IsTrimming !== TrimScope.None ? 'Cancel trimming' : 'Edit original timeline'}</>}>
+                                        <div className="audiobox-button" onPointerDown={this.onResetPointerDown}>
+                                            <FontAwesomeIcon icon={this.timeline?.IsTrimming !== TrimScope.None ? 'cancel' : 'arrows-left-right'} size={'1x'} />
+                                        </div>
+                                    </Tooltip>
+                                )}
+                            </>
                         )}
                     </div>
                     <div className="controls-right">
@@ -658,7 +698,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
     @computed get renderTimeline() {
         return (
             <CollectionStackedTimeline
-                ref={action((r: any) => (this._stackedTimeline = r))}
+                ref={action((r: CollectionStackedTimeline | null) => (this._stackedTimeline = r))}
                 {...this.props}
                 CollectionFreeFormDocumentView={undefined}
                 dataFieldKey={this.fieldKey}
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index 26ad8b7bb..ebb8a3374 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -27,6 +27,7 @@ import { FormattedTextBox } from './formattedText/FormattedTextBox';
 import './ScreenshotBox.scss';
 import { VideoBox } from './VideoBox';
 import { TrackMovements } from '../../util/TrackMovements';
+import { media_state } from './AudioBox';
 
 declare class MediaRecorder {
     constructor(e: any, options?: any); // whatever MediaRecorder has
@@ -181,7 +182,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
                 ref={r => {
                     this._videoRef = r;
                     setTimeout(() => {
-                        if (this.rootDoc.mediaState === 'pendingRecording' && this._videoRef) {
+                        if (this.rootDoc.mediaState === media_state.PendingRecording && this._videoRef) {
                             this.toggleRecording();
                         }
                     }, 100);
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 58b824159..6fdde4b6b 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -71,6 +71,7 @@ import { schema } from './schema_rts';
 import { SummaryView } from './SummaryView';
 import applyDevTools = require('prosemirror-dev-tools');
 import React = require('react');
+import { media_state } from '../AudioBox';
 const translateGoogleApi = require('translate-google-api');
 export const GoogleRef = 'googleDocId';
 type PullHandler = (exportState: Opt<GoogleApiClientUtils.Docs.ImportResult>, dataDoc: Doc) => void;
@@ -154,10 +155,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         return this.titleHeight + NumCast(this.layoutDoc._layout_autoHeightMargins);
     }
     @computed get _recordingDictation() {
-        return this.dataDoc?.mediaState === 'recording';
+        return this.dataDoc?.mediaState === media_state.Recording;
     }
     set _recordingDictation(value) {
-        !this.dataDoc[`${this.fieldKey}_recordingSource`] && (this.dataDoc.mediaState = value ? 'recording' : undefined);
+        !this.dataDoc[`${this.fieldKey}_recordingSource`] && (this.dataDoc.mediaState = value ? media_state.Recording : undefined);
     }
     @computed get config() {
         this._keymap = buildKeymap(schema, this.props);
@@ -271,7 +272,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                 if (target) {
                     anchor.followLinkAudio = true;
                     let stopFunc: any;
-                    Doc.GetProto(target).mediaState = 'recording';
+                    Doc.GetProto(target).mediaState = media_state.Recording;
                     Doc.GetProto(target).audioAnnoState = 'recording';
                     DocumentViewInternal.recordAudioAnnotation(Doc.GetProto(target), Doc.LayoutFieldKey(target), stop => (stopFunc = stop));
                     let reactionDisposer = reaction(
@@ -389,7 +390,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         let link;
         LinkManager.Links(this.dataDoc).forEach((l, i) => {
             const anchor = (l.link_anchor_1 as Doc).annotationOn ? (l.link_anchor_1 as Doc) : (l.link_anchor_2 as Doc).annotationOn ? (l.link_anchor_2 as Doc) : undefined;
-            if (anchor && (anchor.annotationOn as Doc).mediaState === 'recording') {
+            if (anchor && (anchor.annotationOn as Doc).mediaState === media_state.Recording) {
                 linkTime = NumCast(anchor._timecodeToShow /* audioStart */);
                 linkAnchor = anchor;
                 link = l;
-- 
cgit v1.2.3-70-g09d2


From 0df1fc3fd85c1dea84dcaec5a934fc08f0da6832 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 4 Oct 2023 07:46:05 -0400
Subject: several fixes for webclips, linking to pdf/web, fonticon dropdowns.
 removed sliderbox. reduce uses of scriptContext

fixed web clipping annotations to be in correct spot and not to crash because of using a url that it doesn't have.
fixed pdf/web links to not use anchor from other end of link. because of sharing of GetAnchor global.
added a backup when presbox overwrites a doc's data field.
removed sliderBox.
fixed fontIcon dropdowns to not call click script twice.
removed scriptContext where it wasn't needed which is everywhere except TreeViews.
---
 src/client/documents/DocumentTypes.ts              |   3 +-
 src/client/documents/Documents.ts                  |   8 --
 src/client/util/CurrentUserUtils.ts                |   2 +-
 src/client/views/MainView.tsx                      |   2 -
 src/client/views/StyleProvider.tsx                 |   2 -
 .../views/collections/CollectionNoteTakingView.tsx |   1 -
 .../collections/CollectionStackedTimeline.tsx      |  37 +++-----
 .../views/collections/CollectionStackingView.tsx   |   1 -
 .../collectionSchema/CollectionSchemaView.tsx      |   1 -
 src/client/views/nodes/DocumentContentsView.tsx    |   2 -
 src/client/views/nodes/FontIconBox/FontIconBox.tsx |   1 -
 src/client/views/nodes/PDFBox.tsx                  |   2 +-
 src/client/views/nodes/SliderBox.scss              |  19 ----
 src/client/views/nodes/SliderBox.tsx               | 103 ---------------------
 src/client/views/nodes/WebBox.scss                 |   1 -
 src/client/views/nodes/WebBox.tsx                  |  80 +++++++++++-----
 src/client/views/nodes/trails/PresBox.tsx          |   7 +-
 src/client/views/pdf/PDFViewer.tsx                 |   5 +-
 18 files changed, 82 insertions(+), 195 deletions(-)
 delete mode 100644 src/client/views/nodes/SliderBox.scss
 delete mode 100644 src/client/views/nodes/SliderBox.tsx

(limited to 'src/client/views/collections/CollectionStackedTimeline.tsx')

diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts
index f8d129e79..87010f770 100644
--- a/src/client/documents/DocumentTypes.ts
+++ b/src/client/documents/DocumentTypes.ts
@@ -30,14 +30,13 @@ export enum DocumentType {
     // special purpose wrappers that either take no data or are compositions of lower level types
     LINK = 'link',
     IMPORT = 'import',
-    SLIDER = 'slider',
     PRES = 'presentation',
     PRESELEMENT = 'preselement',
     COLOR = 'color',
     YOUTUBE = 'youtube',
     COMPARISON = 'comparison',
     GROUP = 'group',
-    PUSHPIN = "pushpin",
+    PUSHPIN = 'pushpin',
 
     SCRIPTDB = 'scriptdb', // database of scripts
     GROUPDB = 'groupdb', // database of groups
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index f7ceef4f4..a79a62b57 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -54,7 +54,6 @@ import { PhysicsSimulationBox } from '../views/nodes/PhysicsBox/PhysicsSimulatio
 import { RecordingBox } from '../views/nodes/RecordingBox/RecordingBox';
 import { ScreenshotBox } from '../views/nodes/ScreenshotBox';
 import { ScriptingBox } from '../views/nodes/ScriptingBox';
-import { SliderBox } from '../views/nodes/SliderBox';
 import { TaskCompletionBox } from '../views/nodes/TaskCompletedBox';
 import { PresBox } from '../views/nodes/trails/PresBox';
 import { PresElementBox } from '../views/nodes/trails/PresElementBox';
@@ -628,13 +627,6 @@ export namespace Docs {
                     options: {},
                 },
             ],
-            [
-                DocumentType.SLIDER,
-                {
-                    layout: { view: SliderBox, dataField: defaultDataKey },
-                    options: {},
-                },
-            ],
             [
                 DocumentType.PRES,
                 {
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 2ea5972ee..cc8f72ddf 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -820,7 +820,7 @@ export class CurrentUserUtils {
     // When the user views one of these documents, it will be added to the sharing documents 'viewed' list field
     // The sharing document also stores the user's color value which helps distinguish shared documents from personal documents
     static setupSharedDocs(doc: Doc, sharingDocumentId: string) {
-        const dblClkScript = "{scriptContext.openLevel(documentView); addDocToList(scriptContext.props.treeView.props.Document, 'viewed', documentView.rootDoc);}";
+        const dblClkScript = "{scriptContext.openLevel(documentView); addDocToList(documentView.props.treeViewDoc, 'viewed', documentView.rootDoc);}";
         
         const sharedScripts = {  treeView_ChildDoubleClick: dblClkScript,  }
         const sharedDocOpts:DocumentOptions = {
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index d6f5d63fe..0a3389fc2 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -728,7 +728,6 @@ export class MainView extends React.Component {
                         PanelHeight={this.leftMenuFlyoutHeight}
                         renderDepth={0}
                         isContentActive={returnTrue}
-                        scriptContext={CollectionDockingView.Instance?.props.Document}
                         focus={emptyFunction}
                         whenChildContentsActiveChanged={emptyFunction}
                         bringToFront={emptyFunction}
@@ -766,7 +765,6 @@ export class MainView extends React.Component {
                     childFilters={returnEmptyFilter}
                     childFiltersByRanges={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
-                    scriptContext={this}
                 />
             </div>
         );
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index d7537bffb..8417a6f5b 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -21,7 +21,6 @@ import { InkingStroke } from './InkingStroke';
 import { DocumentView, DocumentViewProps } from './nodes/DocumentView';
 import { FieldViewProps } from './nodes/FieldView';
 import { KeyValueBox } from './nodes/KeyValueBox';
-import { SliderBox } from './nodes/SliderBox';
 import './StyleProvider.scss';
 import React = require('react');
 import { PropertiesView } from './PropertiesView';
@@ -215,7 +214,6 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                 case DocumentType.SCREENSHOT:
                 case DocumentType.VID:         docColor = docColor || (Colors.LIGHT_GRAY); break;
                 case DocumentType.COL:
-                    if (StrCast(Doc.LayoutField(doc)).includes(SliderBox.name)) break;
                     docColor = docColor || (Doc.IsSystem(doc)
                             ? SettingsManager.userBackgroundColor
                             : doc.annotationOn
diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx
index a69049b59..c7ad80f11 100644
--- a/src/client/views/collections/CollectionNoteTakingView.tsx
+++ b/src/client/views/collections/CollectionNoteTakingView.tsx
@@ -269,7 +269,6 @@ export class CollectionNoteTakingView extends CollectionSubView() {
                 whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
                 addDocTab={this.props.addDocTab}
                 bringToFront={returnFalse}
-                scriptContext={this.props.scriptContext}
                 pinToPres={this.props.pinToPres}
             />
         );
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index ad3160a08..c4650647c 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -58,9 +58,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
     @observable static SelectingRegion: CollectionStackedTimeline | undefined = undefined;
     @observable public static CurrentlyPlaying: DocumentView[];
 
-    static RangeScript: ScriptField;
     static LabelScript: ScriptField;
-    static RangePlayScript: ScriptField;
     static LabelPlayScript: ScriptField;
 
     private _timeline: HTMLDivElement | null = null; // ref to actual timeline div
@@ -114,25 +112,6 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
         return this._zoomFactor;
     }
 
-    constructor(props: any) {
-        super(props);
-        // onClick play scripts
-        CollectionStackedTimeline.RangeScript =
-            CollectionStackedTimeline.RangeScript ||
-            ScriptField.MakeFunction(`scriptContext.clickAnchor(this, clientX)`, {
-                self: Doc.name,
-                scriptContext: 'any',
-                clientX: 'number',
-            })!;
-        CollectionStackedTimeline.RangePlayScript =
-            CollectionStackedTimeline.RangePlayScript ||
-            ScriptField.MakeFunction(`scriptContext.playOnClick(this, clientX)`, {
-                self: Doc.name,
-                scriptContext: 'any',
-                clientX: 'number',
-            })!;
-    }
-
     componentDidMount() {
         document.addEventListener('keydown', this.keyEvents, true);
     }
@@ -179,8 +158,19 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
         return Math.max(this.clipStart, Math.min(this.clipEnd, (screen_delta / width) * this.clipDuration + this.clipStart));
     };
 
-    rangeClickScript = () => CollectionStackedTimeline.RangeScript;
-    rangePlayScript = () => CollectionStackedTimeline.RangePlayScript;
+    @computed get rangeClick() {
+        // prettier-ignore
+        return ScriptField.MakeFunction('stackedTimeline.clickAnchor(this, clientX)',
+            { stackedTimeline: 'any', clientX: 'number' }, { stackedTimeline: this as any }
+        )!;
+    }
+    @computed get rangePlay() {
+        // prettier-ignore
+        return ScriptField.MakeFunction('stackedTimeline.playOnClick(this, clientX)', 
+            { stackedTimeline: 'any', clientX: 'number' }, { stackedTimeline: this as any })!;
+    }
+    rangeClickScript = () => this.rangeClick;
+    rangePlayScript = () => this.rangePlay;
 
     // handles key events for for creating key anchors, scrubbing, exiting trim
     @action
@@ -835,7 +825,6 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
                     hideResizeHandles={true}
                     bringToFront={emptyFunction}
                     contextMenuItems={this.contextMenuItems}
-                    scriptContext={this.props.stackedTimeline}
                 />
             ),
         };
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 36f8bc101..c43a9d2b8 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -361,7 +361,6 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
                 whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
                 addDocTab={this.props.addDocTab}
                 bringToFront={returnFalse}
-                scriptContext={this.props.scriptContext}
                 pinToPres={this.props.pinToPres}
             />
         );
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index d2b61167e..f73c037f4 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -972,7 +972,6 @@ class CollectionSchemaViewDocs extends React.Component<CollectionSchemaViewDocsP
                                 hideDocumentButtonBar={true}
                                 hideLinkAnchors={true}
                                 layout_fitWidth={returnTrue}
-                                scriptContext={this}
                             />
                         </div>
                     );
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/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/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..d4ba7a48f 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -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) {
@@ -750,7 +788,7 @@ 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={r => r && (this._scrollHeight = Number(getComputedStyle(r).height.replace('px', '')))} 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 +813,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);
     };
 
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}
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 2a191477b..23dc084ad 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -82,9 +82,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
     private _ignoreScroll = false;
     private _initialScroll: { loc: Opt<number>; easeFunc: 'linear' | 'ease' | undefined } | undefined;
     private _forcedScroll = true;
-    get _getAnchor() {
-        return AnchorMenu.Instance?.GetAnchor;
-    }
+    _getAnchor: (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => Opt<Doc> = () => undefined;
 
     selectionText = () => this._selectionText;
     selectionContent = () => this._selectionContent;
@@ -400,6 +398,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
 
     @action
     finishMarquee = (x?: number, y?: number) => {
+        this._getAnchor = AnchorMenu.Instance?.GetAnchor;
         this.isAnnotating = false;
         this._marqueeing = undefined;
         this._textSelecting = true;
-- 
cgit v1.2.3-70-g09d2

