aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/WebBox.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/nodes/WebBox.tsx')
-rw-r--r--src/client/views/nodes/WebBox.tsx279
1 files changed, 168 insertions, 111 deletions
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index c740644d4..28af6bfa1 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -15,7 +15,6 @@ import { TraceMobx } from "../../../fields/util";
import { emptyFunction, getWordAtPoint, OmitKeys, returnFalse, returnOne, setupMoveUpEvents, smoothScroll, Utils } from "../../../Utils";
import { Docs } from "../../documents/Documents";
import { CurrentUserUtils } from "../../util/CurrentUserUtils";
-import { KeyCodes } from "../../util/KeyCodes";
import { ScriptingGlobals } from "../../util/ScriptingGlobals";
import { SnappingManager } from "../../util/SnappingManager";
import { undoBatch } from "../../util/UndoManager";
@@ -41,7 +40,6 @@ import React = require("react");
const { CreateImage } = require("./WebBoxRenderer");
const _global = (window /* browser */ || global /* node */) as any;
const htmlToText = require("html-to-text");
-
@observer
export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps>() {
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(WebBox, fieldKey); }
@@ -53,7 +51,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
private _disposers: { [name: string]: IReactionDisposer } = {};
private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef();
private _keyInput = React.createRef<HTMLInputElement>();
- private _initialScroll: Opt<number>;
+ private _initialScroll: Opt<number> = NumCast(this.layoutDoc.thumbScrollTop, NumCast(this.layoutDoc.scrollTop));
+ private _getAnchor: (savedAnnotations?: ObservableMap<number, HTMLDivElement[]>) => Opt<Doc> = () => undefined;
private _sidebarRef = React.createRef<SidebarAnnos>();
private _searchRef = React.createRef<HTMLInputElement>();
private _searchString = "";
@@ -69,19 +68,22 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
@observable private _iframeClick: HTMLIFrameElement | undefined = undefined;
@observable private _iframe: HTMLIFrameElement | null = null;
@observable private _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>();
- @observable private _scrollHeight = NumCast(this.layoutDoc.scrollHeight, 1500);
+ @observable private _scrollHeight = NumCast(this.layoutDoc.scrollHeight);
@computed get _url() { return this.webField?.toString() || ""; }
@computed get _urlHash() { return this._url ? WebBox.urlHash(this._url) + "" : ""; }
- @computed get scrollHeight() { return this._scrollHeight; }
+ @computed get scrollHeight() { return Math.max(this.layoutDoc[HeightSym](), this._scrollHeight); }
@computed get allAnnotations() { return DocListCast(this.dataDoc[this.annotationKey]); }
@computed get inlineTextAnnotations() { return this.allAnnotations.filter(a => a.textInlineAnnotations); }
@computed get webField() { return Cast(this.dataDoc[this.props.fieldKey], WebField)?.url; }
- @computed get webThumb() { return ImageCast(this.layoutDoc["thumb-frozen"], ImageCast(this.layoutDoc.thumb))?.url; }
+ @computed get webThumb() {
+ return this.props.thumbShown?.() &&
+ ImageCast(this.layoutDoc["thumb-frozen"],
+ ImageCast(this.layoutDoc.thumbScrollTop === this.layoutDoc._scrollTop && this.layoutDoc.thumbNativeWidth === NumCast(this.layoutDoc.nativeWidth) &&
+ this.layoutDoc.thumbNativeHeight === NumCast(this.layoutDoc.nativeHeight) ? this.layoutDoc.thumb : undefined))?.url;
+ }
constructor(props: any) {
super(props);
- Doc.SetNativeWidth(this.dataDoc, Doc.NativeWidth(this.dataDoc) || 850);
- Doc.SetNativeHeight(this.dataDoc, Doc.NativeHeight(this.dataDoc) || this.Document[HeightSym]() / this.Document[WidthSym]() * 850);
runInAction(() => this._webUrl = this._url); // setting the weburl will change the src parameter of the embedded iframe and force a navigation to it.
}
@@ -103,6 +105,52 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
}
return true;
}
+ @action
+ setScrollPos = (pos: number) => {
+ if (!this._outerRef.current || this._outerRef.current.scrollHeight < pos) {
+ if (this._webPageHasBeenRendered) setTimeout(() => this.setScrollPos(pos), 250);
+ } else {
+ this._outerRef.current.scrollTop = pos;
+ this._initialScroll = undefined;
+ }
+ }
+
+ lockout = false;
+ updateThumb = async () => {
+ const imageBitmap = ImageCast(this.layoutDoc["thumb-frozen"])?.url.href;
+ const scrollTop = NumCast(this.layoutDoc._scrollTop);
+ const nativeWidth = NumCast(this.layoutDoc.nativeWidth);
+ const nativeHeight = nativeWidth * this.props.PanelHeight() / this.props.PanelWidth();
+ if (!this.lockout && this._iframe && !imageBitmap && (scrollTop !== this.layoutDoc.thumbScrollTop || nativeWidth !== this.layoutDoc.thumbNativeWidth || nativeHeight !== this.layoutDoc.thumbNativeHeight)) {
+ var htmlString = this._iframe.contentDocument && new XMLSerializer().serializeToString(this._iframe.contentDocument);
+ if (!htmlString) {
+ htmlString = await (await fetch(Utils.CorsProxy(this.webField!.href))).text();
+ }
+ this.layoutDoc.thumb = undefined;
+ this.lockout = true; // lock to prevent multiple thumb updates.
+ CreateImage(
+ this._webUrl.endsWith("/") ? this._webUrl.substring(0, this._webUrl.length - 1) : this._webUrl,
+ this._iframe.contentDocument?.styleSheets ?? [],
+ htmlString,
+ nativeWidth,
+ nativeHeight,
+ scrollTop
+ ).then
+ ((data_url: any) => {
+ VideoBox.convertDataUri(data_url, this.layoutDoc[Id] + "-icon" + (new Date()).getTime(), true, this.layoutDoc[Id] + "-icon").then(
+ returnedfilename => setTimeout(action(() => {
+ this.lockout = false;
+ this.layoutDoc.thumb = new ImageField(returnedfilename);
+ this.layoutDoc.thumbScrollTop = scrollTop;
+ this.layoutDoc.thumbNativeWidth = nativeWidth;
+ this.layoutDoc.thumbNativeHeight = nativeHeight;
+ }), 500));
+ })
+ .catch(function (error: any) {
+ console.error('oops, something went wrong!', error);
+ });
+ }
+ }
async componentDidMount() {
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)
@@ -112,54 +160,22 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
this.dataDoc[this.fieldKey + "-annotations"] = ComputedField.MakeFunction(`copyField(this["${this.fieldKey}-"+urlHash(this["${this.fieldKey}"]?.url?.toString())+"-annotations"`);
this.dataDoc[this.fieldKey + "-sidebar"] = ComputedField.MakeFunction(`copyField(this["${this.fieldKey}-"+urlHash(this["${this.fieldKey}"]?.url?.toString())+"-sidebar"`);
});
- reaction(() => this.props.isSelected(),
+ reaction(() => this.props.isSelected() || this.isAnyChildContentActive() || Doc.isBrushedHighlightedDegree(this.props.Document),
async (selected) => {
if (selected) {
this._webPageHasBeenRendered = true;
- setTimeout(action(() => {
- this._scrollHeight = Math.max(this.scrollHeight, this._iframe?.contentDocument?.body.scrollHeight || 0);
- if (this._initialScroll !== undefined && this._outerRef.current) {
- setTimeout(() => {
- this._outerRef.current!.scrollTop = this._initialScroll!;
- this._initialScroll = undefined;
- });
- }
- }));
- } else if (!this.props.isContentActive() &&
- !this.props.docViewPath().lastElement()?.docView?._pendingDoubleClick && /// don't create a thumbnail when double-clicking to enter lightbox because thumbnail will be empty
+ } else if ((!this.props.isContentActive() || SnappingManager.GetIsDragging()) && // update thumnail when unselected AND (no child annotation is active OR we've started dragging the document in which case no additional deselect will occur so this is the only chance to update the thumbnail)
+ !this.props.docViewPath().lastElement()?.docView?._pendingDoubleClick && // don't create a thumbnail when double-clicking to enter lightbox because thumbnail will be empty
LightboxView.LightboxDoc !== this.rootDoc) { // don't create a thumbnail if entering Lightbox from maximize either, since thumb will be empty.
- const imageBitmap = ImageCast(this.layoutDoc["thumb-frozen"])?.url.href;
- if (this._iframe && !imageBitmap) {
- var htmlString = this._iframe.contentDocument && new XMLSerializer().serializeToString(this._iframe.contentDocument);
- if (!htmlString) {
- htmlString = await (await fetch(Utils.CorsProxy(this.webField!.href))).text();
- }
- this.layoutDoc.thumb = undefined;
- const nativeWidth = NumCast(this.layoutDoc.nativeWidth);
- CreateImage(
- this._webUrl.endsWith("/") ? this._webUrl.substring(0, this._webUrl.length - 1) : this._webUrl,
- this._iframe.contentDocument?.styleSheets ?? [],
- htmlString,
- nativeWidth,
- nativeWidth * this.props.PanelHeight() / this.props.PanelWidth(),
- NumCast(this.layoutDoc._scrollTop)
- ).then
- ((dataUrl: any) => {
- VideoBox.convertDataUri(dataUrl, this.layoutDoc[Id] + "-thumb" + (new Date()).getTime(), true).then(
- returnedfilename => setTimeout(action(() => this.layoutDoc.thumb = new ImageField(returnedfilename)), 500));
- })
- .catch(function (error: any) {
- console.error('oops, something went wrong!', error);
- });
- }
+ this.updateThumb();
}
- });
+ }, { fireImmediately: this.props.isSelected() || this.isAnyChildContentActive() || (Doc.isBrushedHighlightedDegree(this.props.Document) ? true : false) });
this._disposers.autoHeight = reaction(() => this.layoutDoc._autoHeight,
autoHeight => {
if (autoHeight) {
this.layoutDoc._nativeHeight = NumCast(this.props.Document[this.props.fieldKey + "-nativeHeight"]);
- this.props.setHeight(NumCast(this.props.Document[this.props.fieldKey + "-nativeHeight"]) * (this.props.scaling?.() || 1));
+ this.props.setHeight?.(NumCast(this.props.Document[this.props.fieldKey + "-nativeHeight"]) * (this.props.scaling?.() || 1));
}
});
@@ -181,31 +197,26 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
}
}
- var quickScroll = true;
this._disposers.scrollReaction = reaction(() => NumCast(this.layoutDoc._scrollTop),
(scrollTop) => {
- if (quickScroll) this._initialScroll = scrollTop;
- else {
- const viewTrans = StrCast(this.Document._viewTransition);
- const durationMiliStr = viewTrans.match(/([0-9]*)ms/);
- const durationSecStr = viewTrans.match(/([0-9.]*)s/);
- const duration = durationMiliStr ? Number(durationMiliStr[1]) : durationSecStr ? Number(durationSecStr[1]) * 1000 : 0;
- this.goTo(scrollTop, duration);
- }
+ const viewTrans = StrCast(this.Document._viewTransition);
+ const durationMiliStr = viewTrans.match(/([0-9]*)ms/);
+ const durationSecStr = viewTrans.match(/([0-9.]*)s/);
+ const duration = durationMiliStr ? Number(durationMiliStr[1]) : durationSecStr ? Number(durationSecStr[1]) * 1000 : 0;
+ this.goTo(scrollTop, duration);
},
{ fireImmediately: true }
);
- quickScroll = false;
}
- componentWillUnmount() {
+ @action componentWillUnmount() {
Object.values(this._disposers).forEach(disposer => disposer?.());
- this._iframe?.removeEventListener('wheel', this.iframeWheel, true);
- this._iframe?.contentDocument?.removeEventListener("pointerup", this.iframeUp);
+ // this._iframe?.removeEventListener('wheel', this.iframeWheel, true);
+ // this._iframe?.contentDocument?.removeEventListener("pointerup", this.iframeUp);
}
@action
- createTextAnnotation = (sel: Selection, selRange: Range) => {
- if (this._mainCont.current) {
+ createTextAnnotation = (sel: Selection, selRange: Range | undefined) => {
+ if (this._mainCont.current && selRange) {
const clientRects = selRange.getClientRects();
for (let i = 0; i < clientRects.length; i++) {
const rect = clientRects.item(i);
@@ -226,6 +237,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
// clear selection
if (sel.empty) sel.empty();// Chrome
else if (sel.removeAllRanges) sel.removeAllRanges(); // Firefox
+ return this._savedAnnotations;
}
menuControls = () => this.urlEditor; // controls to be added to the top bar when a document of this type is selected
@@ -238,21 +250,22 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
if (this._sidebarRef?.current?.makeDocUnfiltered(doc)) return 1;
if (doc !== this.rootDoc && this._outerRef.current) {
const windowHeight = this.props.PanelHeight() / (this.props.scaling?.() || 1);
- const scrollTo = Utils.scrollIntoView(NumCast(doc.y), doc[HeightSym](), NumCast(this.layoutDoc._scrollTop), windowHeight, windowHeight * .1);
- if (scrollTo !== undefined) {
+ const scrollTo = Utils.scrollIntoView(NumCast(doc.y), doc[HeightSym](), NumCast(this.layoutDoc._scrollTop), windowHeight, windowHeight * .1,
+ Math.max(NumCast(doc.y) + doc[HeightSym](), this.getScrollHeight()));
+ if (scrollTo !== undefined && this._initialScroll === undefined) {
const focusSpeed = smooth ? 500 : 0;
- this._initialScroll !== undefined && (this._initialScroll = scrollTo);
this.goTo(scrollTo, focusSpeed);
return focusSpeed;
+ } else if (!this._webPageHasBeenRendered || !this.getScrollHeight() || this._initialScroll !== undefined) {
+ this._initialScroll = scrollTo;
}
}
- this._initialScroll = NumCast(this.layoutDoc._scrollTop);
- return 0;
+ return undefined;
}
getAnchor = () => {
const anchor =
- AnchorMenu.Instance?.GetAnchor(this._savedAnnotations) ??
+ this._getAnchor(this._savedAnnotations) ??
Docs.Create.WebanchorDocument(this._url, {
title: StrCast(this.rootDoc.title + " " + this.layoutDoc._scrollTop),
y: NumCast(this.layoutDoc._scrollTop),
@@ -262,15 +275,19 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
return anchor;
}
+ _textAnnotationCreator: (() => ObservableMap<number, HTMLDivElement[]>) | undefined;
+ savedAnnotationsCreator: (() => ObservableMap<number, HTMLDivElement[]>) = () => this._textAnnotationCreator?.() || this._savedAnnotations;
+
@action
iframeUp = (e: PointerEvent) => {
+ this._textAnnotationCreator = undefined;
this.props.docViewPath().lastElement()?.docView?.cleanupPointerEvents(); // pointerup events aren't generated on containing document view, so we have to invoke it here.
if (this._iframe?.contentWindow && this._iframe.contentDocument && !this._iframe.contentWindow.getSelection()?.isCollapsed) {
const mainContBounds = Utils.GetScreenTransform(this._mainCont.current!);
const scale = (this.props.scaling?.() || 1) * mainContBounds.scale;
const sel = this._iframe.contentWindow.getSelection();
if (sel) {
- this.createTextAnnotation(sel, sel.getRangeAt(0));
+ 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._scrollTop) * scale);
}
@@ -278,6 +295,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
}
@action
iframeDown = (e: PointerEvent) => {
+ const sel = this._iframe?.contentWindow?.getSelection?.();
const mainContBounds = Utils.GetScreenTransform(this._mainCont.current!);
const scale = (this.props.scaling?.() || 1) * mainContBounds.scale;
const word = getWordAtPoint(e.target, e.clientX, e.clientY);
@@ -315,6 +333,9 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
@action
iframeLoaded = (e: any) => {
const iframe = this._iframe;
+ if (this._initialScroll !== undefined) {
+ this.setScrollPos(this._initialScroll);
+ }
let requrlraw = decodeURIComponent(iframe?.contentWindow?.location.href.replace(Utils.prepend("") + "/corsProxy/", "") ?? this._url.toString());
if (requrlraw !== this._url.toString()) {
if (requrlraw.match(/q=.*&/)?.length && this._url.toString().match(/q=.*&/)?.length) {
@@ -333,8 +354,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
if (iframe?.contentDocument) {
iframe.contentDocument.addEventListener("pointerup", this.iframeUp);
iframe.contentDocument.addEventListener("pointerdown", this.iframeDown);
- this._scrollHeight = Math.max(this.scrollHeight, iframe?.contentDocument.body.scrollHeight);
- setTimeout(action(() => this._scrollHeight = Math.max(this.scrollHeight, iframe?.contentDocument?.body.scrollHeight || 0)), 5000);
+ this._scrollHeight = Math.max(this._scrollHeight, iframe?.contentDocument.body.scrollHeight);
+ setTimeout(action(() => this._scrollHeight = Math.max(this._scrollHeight, iframe?.contentDocument?.body.scrollHeight || 0)), 5000);
iframe.setAttribute("enable-annotation", "true");
iframe.contentDocument.addEventListener("click", undoBatch(action((e: MouseEvent) => {
let href = "";
@@ -365,29 +386,32 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
@action
setDashScrollTop = (scrollTop: number, timeout: number = 250) => {
- const iframeHeight = Math.max(1000, this._scrollHeight - this.panelHeight());
- timeout = scrollTop > iframeHeight ? 0 : timeout;
+ const iframeHeight = Math.max(scrollTop, this._scrollHeight - this.panelHeight());
this._scrollTimer && clearTimeout(this._scrollTimer);
this._scrollTimer = setTimeout(action(() => {
this._scrollTimer = undefined;
- if (!LinkDocPreview.LinkInfo && this._outerRef.current &&
+ const newScrollTop = scrollTop > iframeHeight ? iframeHeight : scrollTop;
+ if (!LinkDocPreview.LinkInfo && this._outerRef.current && newScrollTop !== this.layoutDoc.thumbScrollTop &&
(!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this.props.docViewPath()))) {
- this.layoutDoc._scrollTop = this._outerRef.current.scrollTop = scrollTop > iframeHeight ? iframeHeight : scrollTop;
- }
+ this.layoutDoc.thumb = undefined;
+ this.layoutDoc.thumbScrollTop = undefined;
+ this.layoutDoc.thumbNativeWidth = undefined;
+ this.layoutDoc.thumbNativeHeight = undefined;
+ this.layoutDoc.scrollTop = this._outerRef.current.scrollTop = newScrollTop;
+ } else if (this._outerRef.current) this._outerRef.current.scrollTop = newScrollTop;
}), timeout);
}
goTo = (scrollTop: number, duration: number) => {
if (this._outerRef.current) {
- const iframeHeight = Math.max(1000, this._scrollHeight - this.panelHeight());
- scrollTop = scrollTop > iframeHeight + 50 ? iframeHeight : scrollTop;
+ const iframeHeight = Math.max(scrollTop, this._scrollHeight - this.panelHeight());
if (duration) {
smoothScroll(duration, [this._outerRef.current], scrollTop);
this.setDashScrollTop(scrollTop, duration);
} else {
this.setDashScrollTop(scrollTop);
}
- }
+ } else this._initialScroll = scrollTop;
}
forward = (checkAvailable?: boolean) => {
@@ -447,6 +471,12 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
if (url && !preview) {
this.dataDoc[this.fieldKey + "-history"] = new List<string>([...(history || []), url]);
this.layoutDoc._scrollTop = 0;
+ if (this._webPageHasBeenRendered) {
+ this.layoutDoc.thumb = undefined;
+ this.layoutDoc.thumbScrollTop = undefined;
+ this.layoutDoc.thumbNativeWidth = undefined;
+ this.layoutDoc.thumbNativeHeight = undefined;
+ }
future && (future.length = 0);
}
if (!preview) {
@@ -538,9 +568,13 @@ 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();
+ if (sel?.empty) sel.empty();// Chrome
+ else if (sel?.removeAllRanges) sel.removeAllRanges(); // Firefox
if (x !== undefined && y !== undefined) {
this._setPreviewCursor?.(x, y, false, false);
ContextMenu.Instance.closeMenu();
@@ -554,10 +588,11 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
@computed get urlContent() {
if (this._hackHide || (this.webThumb && (!this._webPageHasBeenRendered && LightboxView.LightboxDoc !== this.rootDoc))) return (null);
+ this.props.thumbShown?.();
const field = this.dataDoc[this.props.fieldKey];
let view;
if (field instanceof HtmlField) {
- view = <span className="webBox-htmlSpan" dangerouslySetInnerHTML={{ __html: field.html }} />;
+ view = <span className="webBox-htmlSpan" contentEditable onPointerDown={e => e.stopPropagation()} dangerouslySetInnerHTML={{ __html: field.html }} />;
} else if (field instanceof WebField) {
const url = this.layoutDoc.useCors ? Utils.CorsProxy(this._webUrl) : this._webUrl;
view = <iframe className="webBox-iframe" enable-annotation={"true"}
@@ -571,7 +606,13 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
style={{ pointerEvents: this._scrollTimer ? "none" : undefined }} // if we allow pointer events when scrolling is on, then reversing direction does not work smoothly
ref={action((r: HTMLIFrameElement | null) => this._iframe = r)} src={"https://crossorigin.me/https://cs.brown.edu"} />;
}
- setTimeout(action(() => this._webPageHasBeenRendered = true));
+ setTimeout(action(() => {
+ this._scrollHeight = Math.max(this._scrollHeight, this._iframe && this._iframe.contentDocument && this._iframe.contentDocument.body ? this._iframe.contentDocument.body.scrollHeight : 0);
+ if (this._initialScroll === undefined && !this._webPageHasBeenRendered) {
+ this.setScrollPos(NumCast(this.layoutDoc.thumbScrollTop, NumCast(this.layoutDoc.scrollTop)));
+ }
+ this._webPageHasBeenRendered = true;
+ }));
return view;
}
@@ -605,7 +646,13 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
@observable _previewNativeWidth: Opt<number> = undefined;
@observable _previewWidth: Opt<number> = undefined;
toggleSidebar = action((preview: boolean = false) => {
- const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + "-nativeWidth"]);
+ var nativeWidth = NumCast(this.layoutDoc[this.fieldKey + "-nativeWidth"]);
+ if (!nativeWidth) {
+ const defaultNativeWidth = this.dataDoc[this.fieldKey] instanceof WebField ? 850 : this.Document[WidthSym]();
+ Doc.SetNativeWidth(this.dataDoc, Doc.NativeWidth(this.dataDoc) || defaultNativeWidth);
+ Doc.SetNativeHeight(this.dataDoc, Doc.NativeHeight(this.dataDoc) || this.Document[HeightSym]() / this.Document[WidthSym]() * defaultNativeWidth);
+ nativeWidth = NumCast(this.layoutDoc[this.fieldKey + "-nativeWidth"]);
+ }
const sideratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? WebBox.openSidebarWidth : 0) + nativeWidth) / nativeWidth;
const pdfratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? WebBox.openSidebarWidth + WebBox.sidebarResizerWidth : 0) + nativeWidth) / nativeWidth;
const curNativeWidth = NumCast(this.layoutDoc.nativeWidth, nativeWidth);
@@ -615,19 +662,23 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
this._showSidebar = true;
}
else {
- this.layoutDoc.nativeWidth = nativeWidth * pdfratio;
+ this.layoutDoc._showSidebar = !this.layoutDoc._showSidebar;
this.layoutDoc._width = this.layoutDoc[WidthSym]() * nativeWidth * pdfratio / curNativeWidth;
- this.layoutDoc._showSidebar = nativeWidth !== this.layoutDoc._nativeWidth;
+ if (!this.layoutDoc._showSidebar && !(this.dataDoc[this.fieldKey] instanceof WebField)) {
+ this.layoutDoc.nativeWidth = this.dataDoc[this.fieldKey + "-nativeWidth"] = undefined;
+ } else {
+ this.layoutDoc.nativeWidth = nativeWidth * pdfratio;
+ }
}
});
sidebarWidth = () => !this.SidebarShown ? 0 :
- this._previewWidth ? WebBox.openSidebarWidth :
- (NumCast(this.layoutDoc.nativeWidth) - Doc.NativeWidth(this.dataDoc)) * this.props.PanelWidth() /
- NumCast(this.layoutDoc.nativeWidth)
+ WebBox.sidebarResizerWidth + (this._previewWidth ? WebBox.openSidebarWidth :
+ (NumCast(this.layoutDoc.nativeWidth) - Doc.NativeWidth(this.dataDoc)) * this.props.PanelWidth() / NumCast(this.layoutDoc.nativeWidth))
@computed get content() {
- const interactive = !this.props.docViewPath().lastElement()?.docView?._pendingDoubleClick && this.props.isContentActive() && this.props.pointerEvents !== "none" && CurrentUserUtils.SelectedTool === InkTool.None && !DocumentDecorations.Instance?.Interacting;
+ const interactive = !this.props.docViewPath().lastElement()?.docView?._pendingDoubleClick && this.props.isContentActive() && this.props.pointerEvents?.() !== "none" && CurrentUserUtils.SelectedTool === InkTool.None && !DocumentDecorations.Instance?.Interacting;
return <div className={"webBox-cont" + (interactive ? "-interactive" : "")}
+ onKeyDown={e => e.stopPropagation()}
style={{ width: !this.layoutDoc.forceReflow ? NumCast(this.layoutDoc[this.fieldKey + "-nativeWidth"]) || `100%` : "100%", }}>
{this.urlContent}
</div>;
@@ -635,10 +686,9 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
@computed get annotationLayer() {
TraceMobx();
- const pe = this.pointerEvents();
return <div className="webBox-annotationLayer" style={{ height: Doc.NativeHeight(this.Document) || undefined }} ref={this._annotationLayer}>
{this.inlineTextAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y)).map(anno =>
- <Annotation {...this.props} fieldKey={this.annotationKey} pointerEvents={pe} showInfo={this.showInfo} dataDoc={this.dataDoc} anno={anno} key={`${anno[Id]}-annotation`} />)}
+ <Annotation {...this.props} fieldKey={this.annotationKey} pointerEvents={this.pointerEvents} showInfo={this.showInfo} dataDoc={this.dataDoc} anno={anno} key={`${anno[Id]}-annotation`} />)}
</div>;
}
@@ -650,7 +700,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
<div className="webBox-overlayCont" onPointerDown={(e) => e.stopPropagation()} style={{ left: `${this._searching ? 0 : 100}%` }}>
<button className="webBox-overlayButton" title={"search"} />
<input className="webBox-searchBar" placeholder="Search" ref={this._searchRef} onChange={this.searchStringChanged}
- onKeyDown={e => e.keyCode === KeyCodes.ENTER && this.search(this._searchString, e.shiftKey)} />
+ onKeyDown={e => { e.key === "Enter" && this.search(this._searchString, e.shiftKey); e.stopPropagation(); }} />
<button className="webBox-search" title="Search" onClick={e => this.search(this._searchString, e.shiftKey)}>
<FontAwesomeIcon icon="search" size="sm" />
</button>
@@ -667,7 +717,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
searchStringChanged = (e: React.ChangeEvent<HTMLInputElement>) => this._searchString = e.currentTarget.value;
showInfo = action((anno: Opt<Doc>) => this._overlayAnnoInfo = anno);
setPreviewCursor = (func?: (x: number, y: number, drag: boolean, hide: boolean) => void) => this._setPreviewCursor = func;
- panelWidth = () => this.props.PanelWidth() / (this.props.scaling?.() || 1) - this.sidebarWidth(); // (this.Document.scrollHeight || Doc.NativeHeight(this.Document) || 0);
+ panelWidth = () => this.props.PanelWidth() / (this.props.scaling?.() || 1) - this.sidebarWidth() + WebBox.sidebarResizerWidth; // (this.Document.scrollHeight || Doc.NativeHeight(this.Document) || 0);
panelHeight = () => this.props.PanelHeight() / (this.props.scaling?.() || 1); // () => this._pageSizes.length && this._pageSizes[0] ? this._pageSizes[0].width : Doc.NativeWidth(this.Document);
scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._scrollTop));
anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick;
@@ -680,9 +730,10 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
}
return this.props.styleProvider?.(doc, props, property);
}
- pointerEvents = () => !this._draggingSidebar && this.props.isContentActive() && this.props.pointerEvents !== "none" && !MarqueeOptionsMenu.Instance.isShown() ? "all" : SnappingManager.GetIsDragging() ? undefined : "none";
+ pointerEvents = () => !this._draggingSidebar && this.props.isContentActive() && this.props.pointerEvents?.() !== "none" && !MarqueeOptionsMenu.Instance.isShown() ? "all" : SnappingManager.GetIsDragging() ? undefined : "none";
+ annotationPointerEvents = () => this._isAnnotating || SnappingManager.GetIsDragging() ? "all" : "none";
render() {
- const pointerEvents = this.props.layerProvider?.(this.layoutDoc) === false ? "none" : this.props.pointerEvents ? this.props.pointerEvents as any : undefined;
+ const pointerEvents = this.layoutDoc._lockedPosition ? "none" : this.props.pointerEvents?.() as any;
const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1;
const scale = previewScale * (this.props.scaling?.() || 1);
const renderAnnotations = (docFilters?: () => string[]) =>
@@ -708,14 +759,13 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
addDocument={this.sidebarAddDocument}
styleProvider={this.childStyleProvider}
childPointerEvents={this.props.isContentActive() ? "all" : undefined}
- pointerEvents={this._isAnnotating || SnappingManager.GetIsDragging() ? "all" : "none"} />;
+ pointerEvents={this.annotationPointerEvents} />;
return (
<div className="webBox" ref={this._mainCont}
style={{ pointerEvents: this.pointerEvents(), display: this.props.thumbShown?.() ? "none" : undefined }} >
- <div className="webBox-background" onPointerDown={e => this.sidebarBtnDown(e, false)} />
+ <div className="webBox-background" style={{ backgroundColor: this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor) }} />
<div className="webBox-container" style={{
- position: "absolute",
- width: `calc(${100 / scale}% - ${(this.sidebarWidth() + WebBox.sidebarResizerWidth) / scale * (this._previewWidth ? scale : 1)}px)`,
+ width: `calc(${100 / scale}% - ${!this.SidebarShown ? 0 : (this.sidebarWidth() - WebBox.sidebarResizerWidth) / scale * (this._previewWidth ? scale : 1)}px)`,
transform: `scale(${scale})`,
pointerEvents
}} onContextMenu={this.specificContextMenu}>
@@ -728,7 +778,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
onScroll={e => this.setDashScrollTop(this._outerRef.current?.scrollTop || 0)}
onPointerDown={this.onMarqueeDown}
>
- <div className={"webBox-innerContent"} style={{ height: NumCast(this.scrollHeight, 50), pointerEvents }}>
+ <div className={"webBox-innerContent"} style={{ height: this._webPageHasBeenRendered ? NumCast(this.scrollHeight, 50) : "100%", pointerEvents }}>
{this.content}
<div style={{ mixBlendMode: "multiply" }}>
{renderAnnotations(this.transparentFilter)}
@@ -739,19 +789,26 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
</div>
</div>
{!this._marqueeing || !this._mainCont.current || !this._annotationLayer.current ? (null) :
- <MarqueeAnnotator rootDoc={this.rootDoc}
- iframe={this.isFirefox() ? this.iframeClick : undefined}
- iframeScaling={this.isFirefox() ? this.iframeScaling : undefined}
- anchorMenuClick={this.anchorMenuClick}
- scrollTop={0}
- down={this._marqueeing} scaling={returnOne}
- addDocument={this.addDocumentWrapper}
- docView={this.props.docViewPath().lastElement()}
- finishMarquee={this.finishMarquee}
- savedAnnotations={this._savedAnnotations}
- annotationLayer={this._annotationLayer.current}
- mainCont={this._mainCont.current} />}
+ <div style={{ transformOrigin: "top left", transform: `scale(${1 / scale})` }}>
+ <MarqueeAnnotator rootDoc={this.rootDoc}
+ iframe={this.isFirefox() ? this.iframeClick : undefined}
+ iframeScaling={this.isFirefox() ? this.iframeScaling : undefined}
+ anchorMenuClick={this.anchorMenuClick}
+ scrollTop={0}
+ down={this._marqueeing} scaling={returnOne}
+ addDocument={this.addDocumentWrapper}
+ docView={this.props.docViewPath().lastElement()}
+ finishMarquee={this.finishMarquee}
+ savedAnnotations={this.savedAnnotationsCreator}
+ annotationLayer={this._annotationLayer.current}
+ mainCont={this._mainCont.current} /> </div>}
</div >
+ <div className="webBox-sideResizer" style={{
+ display: this.SidebarShown ? undefined : "none",
+ width: WebBox.sidebarResizerWidth,
+ left: `calc(100% - ${this.sidebarWidth() - WebBox.sidebarResizerWidth}px)`
+ }}
+ onPointerDown={e => this.sidebarBtnDown(e, false)} />
<SidebarAnnos ref={this._sidebarRef}
{...this.props}
whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
@@ -760,7 +817,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
layoutDoc={this.layoutDoc}
dataDoc={this.dataDoc}
setHeight={emptyFunction}
- nativeWidth={this._previewNativeWidth ?? NumCast(this.layoutDoc._nativeWidth)}
+ nativeWidth={this._previewNativeWidth ?? NumCast(this.layoutDoc._nativeWidth) - WebBox.sidebarResizerWidth / (this.props.scaling?.() || 1)}
showSidebar={this.SidebarShown}
sidebarAddDocument={this.sidebarAddDocument}
moveDocument={this.moveDocument}