diff options
author | bobzel <zzzman@gmail.com> | 2023-10-04 07:46:05 -0400 |
---|---|---|
committer | bobzel <zzzman@gmail.com> | 2023-10-04 07:46:05 -0400 |
commit | 0df1fc3fd85c1dea84dcaec5a934fc08f0da6832 (patch) | |
tree | 4e7b6d7a7c26172ed954ab84bb85816bc7b35f93 /src | |
parent | adc81b8eb374ee7cc729a2383bd8407ee2eb848f (diff) |
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.
Diffstat (limited to 'src')
-rw-r--r-- | src/client/documents/DocumentTypes.ts | 3 | ||||
-rw-r--r-- | src/client/documents/Documents.ts | 8 | ||||
-rw-r--r-- | src/client/util/CurrentUserUtils.ts | 2 | ||||
-rw-r--r-- | src/client/views/MainView.tsx | 2 | ||||
-rw-r--r-- | src/client/views/StyleProvider.tsx | 2 | ||||
-rw-r--r-- | src/client/views/collections/CollectionNoteTakingView.tsx | 1 | ||||
-rw-r--r-- | src/client/views/collections/CollectionStackedTimeline.tsx | 37 | ||||
-rw-r--r-- | src/client/views/collections/CollectionStackingView.tsx | 1 | ||||
-rw-r--r-- | src/client/views/collections/collectionSchema/CollectionSchemaView.tsx | 1 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentContentsView.tsx | 2 | ||||
-rw-r--r-- | src/client/views/nodes/FontIconBox/FontIconBox.tsx | 1 | ||||
-rw-r--r-- | src/client/views/nodes/PDFBox.tsx | 2 | ||||
-rw-r--r-- | src/client/views/nodes/SliderBox.scss | 19 | ||||
-rw-r--r-- | src/client/views/nodes/SliderBox.tsx | 103 | ||||
-rw-r--r-- | src/client/views/nodes/WebBox.scss | 1 | ||||
-rw-r--r-- | src/client/views/nodes/WebBox.tsx | 80 | ||||
-rw-r--r-- | src/client/views/nodes/trails/PresBox.tsx | 7 | ||||
-rw-r--r-- | src/client/views/pdf/PDFViewer.tsx | 5 |
18 files changed, 82 insertions, 195 deletions
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'; @@ -629,13 +628,6 @@ export namespace Docs { }, ], [ - DocumentType.SLIDER, - { - layout: { view: SliderBox, dataField: defaultDataKey }, - options: {}, - }, - ], - [ DocumentType.PRES, { layout: { view: PresBox, dataField: defaultDataKey }, 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; |