From 3bcc0e3a8ce4ab67dff4b3d62191c346764aa351 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 23 Jul 2020 11:56:05 -0400 Subject: got rid of lots of console.logs(). fixed fonticon box to show a 'label' if defined otherwise 'title'. if neither, then it shows no tooltip. --- src/client/views/nodes/WebBox.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client/views/nodes/WebBox.tsx') diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 05355caba..39bb7c01d 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -189,7 +189,7 @@ export class WebBox extends ViewBoxAnnotatableComponent([]); } catch (e) { - console.log("Error in URL :" + this._url); + console.log("WebBox URL error:" + this._url); } } -- cgit v1.2.3-70-g09d2 From afdb653478692083bfe4a1318413ae68da7b4ec2 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 26 Jul 2020 17:23:21 -0400 Subject: added UseCors menu option for WebBox. fixed webbox css so that link button is in riht place. --- src/client/views/nodes/WebBox.scss | 219 +++++++++++++++++++------------------ src/client/views/nodes/WebBox.tsx | 106 +++++++++--------- 2 files changed, 166 insertions(+), 159 deletions(-) (limited to 'src/client/views/nodes/WebBox.tsx') diff --git a/src/client/views/nodes/WebBox.scss b/src/client/views/nodes/WebBox.scss index 4623444b9..4b2f3cc1a 100644 --- a/src/client/views/nodes/WebBox.scss +++ b/src/client/views/nodes/WebBox.scss @@ -1,135 +1,140 @@ @import "../globalCssVariables.scss"; -.webBox-container, .webBox-container-dragging { - transform-origin: top left; - width: 100%; - height: 100%; - - .webBox-htmlSpan { - position: absolute; - top: 0; - left: 0; - } - .webBox-cont { - pointer-events: none; - } - .webBox-cont, .webBox-cont-interactive { - padding: 0vw; - position: absolute; - top: 0; - left: 0; +.webBox { + height:100%; + position: relative; + display: flex; + .webBox-container, .webBox-container-dragging { + transform-origin: top left; width: 100%; height: 100%; - transform-origin: top left; - overflow: auto; - .webBox-iframe { + + .webBox-htmlSpan { + position: absolute; + top: 0; + left: 0; + } + .webBox-cont { + pointer-events: none; + } + .webBox-cont, .webBox-cont-interactive { + padding: 0vw; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + transform-origin: top left; + overflow: auto; + .webBox-iframe { + width: 100%; + height: 100%; + position: absolute; + top:0; + } + } + .webBox-cont-interactive { + span { + user-select: text !important; + } + } + .webBox-outerContent { width: 100%; height: 100%; position: absolute; - top:0; + top: 0; + left: 0; + overflow: auto; + .webBox-innerContent { + width:100%; + } } - } - .webBox-cont-interactive { - span { - user-select: text !important; + div.webBox-outerContent::-webkit-scrollbar-thumb { + display:none; } } - .webBox-outerContent { + + + .webBox-overlay { width: 100%; height: 100%; position: absolute; - top: 0; - left: 0; - overflow: auto; - .webBox-innerContent { - width:100%; - } - } - div.webBox-outerContent::-webkit-scrollbar-thumb { - display:none; } -} - - -.webBox-overlay { - width: 100%; - height: 100%; - position: absolute; -} -.webBox-buttons { - margin-left: 44; - background:lightGray; - width: 100%; -} -.webBox-freeze { - display: flex; - align-items: center; - justify-content: center; - margin-right: 5px; - width: 30px; -} - -.webBox-urlEditor { - position: relative; - opacity: 0.9; - z-index: 9001; - transition: top .5s; - - .urlEditor { - display: grid; - grid-template-columns: 1fr auto; - padding-bottom: 10px; - overflow: hidden; - - .editorBase { - display: flex; - - .editor-collapse { - transition: all .5s, opacity 0.3s; - position: absolute; - width: 40px; - transform-origin: top left; - } + .webBox-buttons { + margin-left: 44; + background:lightGray; + width: 100%; + } + .webBox-freeze { + display: flex; + align-items: center; + justify-content: center; + margin-right: 5px; + width: 30px; + } - .switchToText { - color: $main-accent; + .webBox-urlEditor { + position: relative; + opacity: 0.9; + z-index: 9001; + transition: top .5s; + + .urlEditor { + display: grid; + grid-template-columns: 1fr auto; + padding-bottom: 10px; + overflow: hidden; + + .editorBase { + display: flex; + + .editor-collapse { + transition: all .5s, opacity 0.3s; + position: absolute; + width: 40px; + transform-origin: top left; + } + + .switchToText { + color: $main-accent; + } + + .switchToText:hover { + color: $dark-color; + } } - .switchToText:hover { - color: $dark-color; + button:hover { + transform: scale(1); } } + } - button:hover { - transform: scale(1); - } + .webpage-urlInput { + padding: 12px 10px 11px 10px; + border: 0px; + color: grey; + letter-spacing: 2px; + outline-color: black; + background: rgb(238, 238, 238); + width: 100%; + margin-right: 10px; + height: 100%; } -} - -.webpage-urlInput { - padding: 12px 10px 11px 10px; - border: 0px; - color: grey; - letter-spacing: 2px; - outline-color: black; - background: rgb(238, 238, 238); - width: 100%; - margin-right: 10px; - height: 100%; -} - -.touch-iframe-overlay { - width: 100%; - height: 100%; - position: absolute; - - .indicator { + + .touch-iframe-overlay { + width: 100%; + height: 100%; position: absolute; - &.active { - background-color: rgba(0, 0, 0, 0.1); + .indicator { + position: absolute; + + &.active { + background-color: rgba(0, 0, 0, 0.1); + } } } } \ No newline at end of file diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 39bb7c01d..5ae23f982 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -399,7 +399,7 @@ export class WebBox extends ViewBoxAnnotatableComponent { const cm = ContextMenu.Instance; const funcs: ContextMenuProps[] = []; - funcs.push({ description: (!this.layoutDoc._nativeWidth || !this.layoutDoc._nativeHeight ? "Freeze" : "Unfreeze") + " Aspect", event: this.toggleNativeDimensions, icon: "snowflake" }); + funcs.push({ description: (this.layoutDoc.UseCors ? "Don't Use" : "Use") + " Cors", event: () => this.layoutDoc.UseCors = !this.layoutDoc.UseCors, icon: "snowflake" }); cm.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" }); } @@ -446,58 +446,60 @@ export class WebBox extends ViewBoxAnnotatableComponent this.props.ScreenToLocalTransform().translate(NumCast(this.layoutDoc._scrollLeft), NumCast(this.layoutDoc._scrollTop)); render() { - return (
- - {this.content} -
e.stopPropagation()} - onScroll={e => { - const iframe = this._iframeRef?.current?.contentDocument; - const outerFrame = this._outerRef.current; - if (iframe && outerFrame) { - if (iframe.children[0].scrollTop !== outerFrame.scrollTop) { - iframe.children[0].scrollTop = outerFrame.scrollTop; + return (
+
+ + {this.content} +
e.stopPropagation()} + onScroll={e => { + const iframe = this._iframeRef?.current?.contentDocument; + const outerFrame = this._outerRef.current; + if (iframe && outerFrame) { + if (iframe.children[0].scrollTop !== outerFrame.scrollTop) { + iframe.children[0].scrollTop = outerFrame.scrollTop; + } + if (iframe.children[0].scrollLeft !== outerFrame.scrollLeft) { + iframe.children[0].scrollLeft = outerFrame.scrollLeft; + } } - if (iframe.children[0].scrollLeft !== outerFrame.scrollLeft) { - iframe.children[0].scrollLeft = outerFrame.scrollLeft; - } - } - //this._outerRef.current!.scrollTop !== this._scrollTop && (this._outerRef.current!.scrollTop = this._scrollTop) - }}> -
- - + //this._outerRef.current!.scrollTop !== this._scrollTop && (this._outerRef.current!.scrollTop = this._scrollTop) + }}> +
+ + +
-
-
); +
+
); } } \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 139d58d68f022c308664ef9e0ba19df851801afb Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 26 Jul 2020 17:48:36 -0400 Subject: from last --- src/client/views/nodes/WebBox.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/client/views/nodes/WebBox.tsx') diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 5ae23f982..52e8b92a1 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -446,12 +446,12 @@ export class WebBox extends ViewBoxAnnotatableComponent this.props.ScreenToLocalTransform().translate(NumCast(this.layoutDoc._scrollLeft), NumCast(this.layoutDoc._scrollTop)); render() { - return (
+ return (
-- cgit v1.2.3-70-g09d2 From a904a5fd2d33fd4783a45b3411c9309cc25ad0fd Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 26 Jul 2020 18:07:54 -0400 Subject: from last --- src/client/views/nodes/WebBox.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client/views/nodes/WebBox.tsx') diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 52e8b92a1..724044295 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -446,7 +446,7 @@ export class WebBox extends ViewBoxAnnotatableComponent this.props.ScreenToLocalTransform().translate(NumCast(this.layoutDoc._scrollLeft), NumCast(this.layoutDoc._scrollTop)); render() { - return (
+ return (
Date: Mon, 27 Jul 2020 00:32:50 -0400 Subject: extended pdfviewer interactions to WebBox's. --- src/client/views/DocComponent.tsx | 2 +- src/client/views/nodes/WebBox.scss | 21 ++- src/client/views/nodes/WebBox.tsx | 262 ++++++++++++++++++++++++++++++++++--- src/client/views/pdf/PDFViewer.tsx | 8 +- 4 files changed, 265 insertions(+), 28 deletions(-) (limited to 'src/client/views/nodes/WebBox.tsx') diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index cfabae8a1..9fd406407 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -122,7 +122,7 @@ export function ViewBoxAnnotatableComponent

doc.annotationOn = undefined); + docs.map(doc => doc.isPushpin = doc.annotationOn = undefined); const targetDataDoc = this.dataDoc; const value = DocListCast(targetDataDoc[this.annotationKey]); const toRemove = value.filter(v => docs.includes(v)); diff --git a/src/client/views/nodes/WebBox.scss b/src/client/views/nodes/WebBox.scss index 4b2f3cc1a..f5c8745e7 100644 --- a/src/client/views/nodes/WebBox.scss +++ b/src/client/views/nodes/WebBox.scss @@ -5,6 +5,24 @@ height:100%; position: relative; display: flex; + + .pdfViewerDash-dragAnnotationBox { + position:absolute; + background-color: transparent; + opacity: 0.1; + } + .webBox-annotationLayer { + position: absolute; + transform-origin: left top; + top: 0; + width: 100%; + pointer-events: none; + mix-blend-mode: multiply; // bcz: makes text fuzzy! + } + .webBox-annotationBox { + position: absolute; + background-color: rgba(245, 230, 95, 0.616); + } .webBox-container, .webBox-container-dragging { transform-origin: top left; width: 100%; @@ -46,9 +64,6 @@ top: 0; left: 0; overflow: auto; - .webBox-innerContent { - width:100%; - } } div.webBox-outerContent::-webkit-scrollbar-thumb { display:none; diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 724044295..bc30b15e6 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -1,46 +1,62 @@ -import { library } from "@fortawesome/fontawesome-svg-core"; -import { faStickyNote, faPen, faMousePointer } from '@fortawesome/free-solid-svg-icons'; -import { action, computed, observable, trace, IReactionDisposer, reaction, runInAction } from "mobx"; +import { faMousePointer, faPen, faStickyNote } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; -import { Doc, FieldResult, DocListCast } from "../../../fields/Doc"; +import { Dictionary } from "typescript-collections"; +import * as WebRequest from 'web-request'; +import { Doc, DocListCast, Opt } from "../../../fields/Doc"; import { documentSchema } from "../../../fields/documentSchemas"; +import { Id } from "../../../fields/FieldSymbols"; import { HtmlField } from "../../../fields/HtmlField"; import { InkTool } from "../../../fields/InkField"; -import { makeInterface, listSpec } from "../../../fields/Schema"; -import { Cast, NumCast, BoolCast, StrCast } from "../../../fields/Types"; +import { List } from "../../../fields/List"; +import { listSpec, makeInterface } from "../../../fields/Schema"; +import { Cast, NumCast, StrCast } from "../../../fields/Types"; import { WebField } from "../../../fields/URLField"; -import { Utils, returnOne, emptyFunction, returnZero } from "../../../Utils"; -import { Docs } from "../../documents/Documents"; +import { TraceMobx } from "../../../fields/util"; +import { addStyleSheet, clearStyleSheetRules, emptyFunction, returnOne, returnZero, Utils } from "../../../Utils"; +import { Docs, DocUtils } from "../../documents/Documents"; import { DragManager } from "../../util/DragManager"; import { ImageUtils } from "../../util/Import & Export/ImageUtils"; +import { undoBatch } from "../../util/UndoManager"; +import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; +import { ContextMenu } from "../ContextMenu"; +import { ContextMenuProps } from "../ContextMenuItem"; import { ViewBoxAnnotatableComponent } from "../DocComponent"; import { DocumentDecorations } from "../DocumentDecorations"; +import Annotation from "../pdf/Annotation"; +import PDFMenu from "../pdf/PDFMenu"; +import { PdfViewerMarquee } from "../pdf/PDFViewer"; import { FieldView, FieldViewProps } from './FieldView'; import "./WebBox.scss"; +import "../pdf/PDFViewer.scss"; import React = require("react"); -import * as WebRequest from 'web-request'; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; -import { ContextMenu } from "../ContextMenu"; -import { ContextMenuProps } from "../ContextMenuItem"; -import { undoBatch } from "../../util/UndoManager"; -import { List } from "../../../fields/List"; const htmlToText = require("html-to-text"); -library.add(faStickyNote); - type WebDocument = makeInterface<[typeof documentSchema]>; const WebDocument = makeInterface(documentSchema); @observer export class WebBox extends ViewBoxAnnotatableComponent(WebDocument) { + private _annotationLayer: React.RefObject = React.createRef(); + static _annotationStyle: any = addStyleSheet(); + private _mainCont: React.RefObject = React.createRef(); + private _startX: number = 0; + private _startY: number = 0; + @observable private _marqueeX: number = 0; + @observable private _marqueeY: number = 0; + @observable private _marqueeWidth: number = 0; + @observable private _marqueeHeight: number = 0; + @observable private _marqueeing: boolean = false; public static LayoutString(fieldKey: string) { return FieldView.LayoutString(WebBox, fieldKey); } get _collapsed() { return StrCast(this.layoutDoc._chromeStatus) !== "enabled"; } set _collapsed(value) { this.layoutDoc._chromeStatus = !value ? "enabled" : "disabled"; } @observable private _url: string = "hello"; @observable private _pressX: number = 0; @observable private _pressY: number = 0; + @observable private _savedAnnotations: Dictionary = new Dictionary(); + private _selectionReactionDisposer?: IReactionDisposer; private _keyInput = React.createRef(); private _longPressSecondsHack?: NodeJS.Timeout; private _outerRef = React.createRef(); @@ -75,6 +91,7 @@ export class WebBox extends ViewBoxAnnotatableComponent void) => this._setPreviewCursor = func; iframedown = (e: PointerEvent) => { this._setPreviewCursor?.(e.screenX, e.screenY, false); @@ -89,6 +106,17 @@ export class WebBox extends ViewBoxAnnotatableComponent this._url = urlField?.url.toString() || ""); + + this._selectionReactionDisposer = reaction(() => this.props.isSelected(), + selected => { + if (!selected) { + this._savedAnnotations.values().forEach(v => v.forEach(a => a.remove())); + this._savedAnnotations.keys().forEach(k => this._savedAnnotations.setValue(k, [])); + PDFMenu.Instance.fadeOut(true); + } + }, + { fireImmediately: true }); + document.addEventListener("pointerup", this.onLongPressUp); document.addEventListener("pointermove", this.onLongPressMove); const field = Cast(this.rootDoc[this.props.fieldKey], WebField); @@ -112,6 +140,7 @@ export class WebBox extends ViewBoxAnnotatableComponent { this._collapsed = !this._collapsed; } + + _ignore = 0; onPreWheel = (e: React.WheelEvent) => { this._ignore = e.timeStamp; @@ -284,6 +316,7 @@ export class WebBox extends ViewBoxAnnotatableComponent { if (this._ignore !== e.timeStamp) { e.stopPropagation(); @@ -430,6 +463,7 @@ export class WebBox extends ViewBoxAnnotatableComponent

{view}
; @@ -444,9 +478,188 @@ export class WebBox extends ViewBoxAnnotatableComponent); } + + + + @computed get allAnnotations() { return DocListCast(this.dataDoc[this.props.fieldKey + "-annotations"]); } + @computed get nonDocAnnotations() { return this.allAnnotations.filter(a => a.annotations); } + + @undoBatch + @action + makeAnnotationDocument = (color: string): Opt => { + if (this._savedAnnotations.size() === 0) return undefined; + const anno = this._savedAnnotations.values()[0][0]; + const annoDoc = Docs.Create.FreeformDocument([], { backgroundColor: color, annotationOn: this.props.Document, title: "Annotation on " + this.Document.title }); + if (anno.style.left) annoDoc.x = parseInt(anno.style.left); + if (anno.style.top) annoDoc.y = NumCast(this.layoutDoc._scrollTop) + parseInt(anno.style.top); + if (anno.style.height) annoDoc._height = parseInt(anno.style.height); + if (anno.style.width) annoDoc._width = parseInt(anno.style.width); + anno.remove(); + this._savedAnnotations.clear(); + return annoDoc; + } + @computed get annotationLayer() { + TraceMobx(); + return
+ {this.nonDocAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y)).map(anno => + ) + } +
; + } + @action + createAnnotation = (div: HTMLDivElement, page: number) => { + if (this._annotationLayer.current) { + if (div.style.top) { + div.style.top = (parseInt(div.style.top)).toString(); + } + this._annotationLayer.current.append(div); + div.style.backgroundColor = "#ACCEF7"; + div.style.opacity = "0.5"; + const savedPage = this._savedAnnotations.getValue(page); + if (savedPage) { + savedPage.push(div); + this._savedAnnotations.setValue(page, savedPage); + } + else { + this._savedAnnotations.setValue(page, [div]); + } + } + } + + @action + highlight = (color: string) => { + // creates annotation documents for current highlights + const annotationDoc = this.makeAnnotationDocument(color); + annotationDoc && Doc.AddDocToList(this.props.Document, this.annotationKey, annotationDoc); + return annotationDoc; + } + /** + * This is temporary for creating annotations from highlights. It will + * start a drag event and create or put the necessary info into the drag event. + */ + @action + startDrag = async (e: PointerEvent, ele: HTMLElement) => { + e.preventDefault(); + e.stopPropagation(); + + const clipDoc = Doc.MakeAlias(this.dataDoc); + clipDoc._fitWidth = true; + clipDoc._width = this.marqueeWidth(); + clipDoc._height = this.marqueeHeight(); + clipDoc._scrollTop = this.marqueeY(); + const targetDoc = Docs.Create.TextDocument("", { _width: 200, _height: 200, title: "Note linked to " + this.props.Document.title }); + Doc.GetProto(targetDoc).data = new List([clipDoc]); + clipDoc.rootDocument = targetDoc; + targetDoc.layoutKey = "layout"; + const annotationDoc = this.highlight("rgba(146, 245, 95, 0.467)"); // yellowish highlight color when dragging out a text selection + if (annotationDoc) { + DragManager.StartPdfAnnoDrag([ele], new DragManager.PdfAnnoDragData(this.props.Document, annotationDoc, targetDoc), e.pageX, e.pageY, { + dragComplete: e => { + if (!e.aborted && e.annoDragData && !e.annoDragData.linkedToDoc) { + DocUtils.MakeLink({ doc: annotationDoc }, { doc: e.annoDragData.dropDocument }, "Annotation"); + annotationDoc.isLinkButton = true; + e.annoDragData.dropDocument.isPushpin = true; + e.annoDragData.dropDocument.isLinkButton = true; + } + } + }); + } + } + @action + onMarqueeDown = (e: React.PointerEvent) => { + this._marqueeing = false; + if (!e.altKey && e.button === 0 && this.active(true)) { + // clear out old marquees and initialize menu for new selection + PDFMenu.Instance.StartDrag = this.startDrag; + PDFMenu.Instance.Highlight = this.highlight; + PDFMenu.Instance.Status = "pdf"; + PDFMenu.Instance.fadeOut(true); + this._savedAnnotations.values().forEach(v => v.forEach(a => a.remove())); + this._savedAnnotations.keys().forEach(k => this._savedAnnotations.setValue(k, [])); + if ((e.target as any)?.parentElement.className === "textLayer") { + // start selecting text if mouse down on textLayer spans + } + else if (this._mainCont.current) { + // set marquee x and y positions to the spatially transformed position + const boundingRect = this._mainCont.current.getBoundingClientRect(); + this._startX = (e.clientX - boundingRect.left) / boundingRect.width * (this.Document._nativeWidth || 1); + this._startY = (e.clientY - boundingRect.top) / boundingRect.height * (this.Document._nativeHeight || 1); + this._marqueeHeight = this._marqueeWidth = 0; + this._marqueeing = true; + } + document.removeEventListener("pointermove", this.onSelectMove); + document.addEventListener("pointermove", this.onSelectMove); + document.removeEventListener("pointerup", this.onSelectEnd); + document.addEventListener("pointerup", this.onSelectEnd); + } + } + @action + onSelectMove = (e: PointerEvent): void => { + if (this._marqueeing && this._mainCont.current) { + // transform positions and find the width and height to set the marquee to + const boundingRect = this._mainCont.current.getBoundingClientRect(); + const curX = (e.clientX - boundingRect.left) / boundingRect.width * (this.Document._nativeWidth || 1); + const curY = (e.clientY - boundingRect.top) / boundingRect.height * (this.Document._nativeHeight || 1); + this._marqueeWidth = curX - this._startX; + this._marqueeHeight = curY - this._startY; + this._marqueeX = Math.min(this._startX, this._startX + this._marqueeWidth); + this._marqueeY = Math.min(this._startY, this._startY + this._marqueeHeight); + this._marqueeWidth = Math.abs(this._marqueeWidth); + this._marqueeHeight = Math.abs(this._marqueeHeight); + e.stopPropagation(); + e.preventDefault(); + } + else if (e.target && (e.target as any).parentElement === this._mainCont.current) { + e.stopPropagation(); + } + } + + @action + onSelectEnd = (e: PointerEvent): void => { + clearStyleSheetRules(WebBox._annotationStyle); + this._savedAnnotations.clear(); + if (this._marqueeWidth > 10 || this._marqueeHeight > 10) { + const marquees = this._mainCont.current!.getElementsByClassName("pdfViewerDash-dragAnnotationBox"); + if (marquees?.length) { // copy the marquee and convert it to a permanent annotation. + const style = (marquees[0] as HTMLDivElement).style; + const copy = document.createElement("div"); + copy.style.left = style.left; + copy.style.top = style.top; + copy.style.width = style.width; + copy.style.height = style.height; + copy.style.border = style.border; + copy.style.opacity = style.opacity; + (copy as any).marqueeing = true; + copy.className = "webBox-annotationBox"; + this.createAnnotation(copy, 0); + } + + if (!e.ctrlKey) { + PDFMenu.Instance.Marquee = { left: this._marqueeX, top: this._marqueeY, width: this._marqueeWidth, height: this._marqueeHeight }; + } + PDFMenu.Instance.jumpTo(e.clientX, e.clientY); + } + //this._marqueeing = false; + + if (PDFMenu.Instance.Highlighting) {// when highlighter has been toggled when menu is pinned, we auto-highlight immediately on mouse up + this.highlight("rgba(245, 230, 95, 0.616)"); // yellowish highlight color for highlighted text (should match PDFMenu's highlight color) + } + else { + PDFMenu.Instance.StartDrag = this.startDrag; + PDFMenu.Instance.Highlight = this.highlight; + } + document.removeEventListener("pointermove", this.onSelectMove); + document.removeEventListener("pointerup", this.onSelectEnd); + } + + marqueeWidth = () => this._marqueeWidth; + marqueeHeight = () => this._marqueeHeight; + marqueeX = () => this._marqueeX; + marqueeY = () => this._marqueeY; + marqueeing = () => this._marqueeing; scrollXf = () => this.props.ScreenToLocalTransform().translate(NumCast(this.layoutDoc._scrollLeft), NumCast(this.layoutDoc._scrollTop)); render() { - return (
+ return (
{this.content}
e.stopPropagation()} + onPointerDown={this.onMarqueeDown} onScroll={e => { const iframe = this._iframeRef?.current?.contentDocument; const outerFrame = this._outerRef.current; @@ -473,7 +690,10 @@ export class WebBox extends ViewBoxAnnotatableComponent -
+
+ {this.annotationLayer} +
); } diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 30c51d9ca..5ed842ab7 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -521,7 +521,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent 10 || this._marqueeHeight > 10) { const marquees = this._mainCont.current!.getElementsByClassName("pdfViewerDash-dragAnnotationBox"); - if (marquees && marquees.length) { // copy the marquee and convert it to a permanent annotation. + if (marquees?.length) { // copy the marquee and convert it to a permanent annotation. const style = (marquees[0] as HTMLDivElement).style; const copy = document.createElement("div"); copy.style.left = style.left; @@ -544,7 +544,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent boolean; width: () => number; height: () => number; @@ -735,7 +735,7 @@ interface PdfViewerMarqueeProps { } @observer -class PdfViewerMarquee extends React.Component { +export class PdfViewerMarquee extends React.Component { render() { return !this.props.isMarqueeing() ? (null) :
Date: Mon, 27 Jul 2020 08:25:39 -0400 Subject: added vertical resie of fixedaspect when _fitWidth is on. fixin webBox css to not clip contents. --- src/client/views/DocumentDecorations.tsx | 7 ++++--- src/client/views/nodes/WebBox.scss | 3 ++- src/client/views/nodes/WebBox.tsx | 10 ++++++---- 3 files changed, 12 insertions(+), 8 deletions(-) (limited to 'src/client/views/nodes/WebBox.tsx') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 8d63537e7..9a4df926c 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -374,7 +374,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> move[1] = thisPt.thisY - this._snapY; this._snapX = thisPt.thisX; this._snapY = thisPt.thisY; - + let dragBottom = false; let dX = 0, dY = 0, dW = 0, dH = 0; const unfreeze = () => SelectionManager.SelectedDocuments().forEach(action((element: DocumentView) => @@ -412,6 +412,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> case "documentDecorations-bottomResizer": unfreeze(); dH = move[1]; + dragBottom = true; break; case "documentDecorations-leftResizer": unfreeze(); @@ -438,7 +439,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> if (nwidth / nheight !== width / height) { height = nheight / nwidth * width; } - if (!e.ctrlKey) { + if (!e.ctrlKey && (!dragBottom || !element.layoutDoc._fitWidth)) { // ctrl key enables modification of the nativeWidth or nativeHeight durin the interaction if (Math.abs(dW) > Math.abs(dH)) dH = dW * nheight / nwidth; else dW = dH * nwidth / nheight; } @@ -473,7 +474,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> else if (!fixedAspect || !e.ctrlKey) doc._height = actualdH; } else { - if (!fixedAspect || e.ctrlKey) { + if (!fixedAspect || e.ctrlKey || (dragBottom && element.layoutDoc._fitWidth)) { doc._nativeHeight = actualdH / (doc._height || 1) * (doc._nativeHeight || 0); } doc._height = actualdH; diff --git a/src/client/views/nodes/WebBox.scss b/src/client/views/nodes/WebBox.scss index f5c8745e7..62657780d 100644 --- a/src/client/views/nodes/WebBox.scss +++ b/src/client/views/nodes/WebBox.scss @@ -23,10 +23,11 @@ position: absolute; background-color: rgba(245, 230, 95, 0.616); } - .webBox-container, .webBox-container-dragging { + .webBox-container { transform-origin: top left; width: 100%; height: 100%; + overflow-x:hidden; .webBox-htmlSpan { position: absolute; diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index bc30b15e6..fe48dfc6c 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -659,12 +659,14 @@ export class WebBox extends ViewBoxAnnotatableComponent this._marqueeing; scrollXf = () => this.props.ScreenToLocalTransform().translate(NumCast(this.layoutDoc._scrollLeft), NumCast(this.layoutDoc._scrollTop)); render() { + const noScalin = this.props.ContentScaling() < 1; return (
@@ -672,7 +674,7 @@ export class WebBox extends ViewBoxAnnotatableComponent e.stopPropagation()} -- cgit v1.2.3-70-g09d2 From 777c4ff1c11d2532dc1be4243b548debd5d004ea Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 27 Jul 2020 09:00:56 -0400 Subject: fixed drain of webbox to keep annotations sychronized. fixed css for when web box is small. --- src/client/views/nodes/WebBox.scss | 1 - src/client/views/nodes/WebBox.tsx | 46 +++++++++++++++++++++----------------- 2 files changed, 25 insertions(+), 22 deletions(-) (limited to 'src/client/views/nodes/WebBox.tsx') diff --git a/src/client/views/nodes/WebBox.scss b/src/client/views/nodes/WebBox.scss index 62657780d..875142169 100644 --- a/src/client/views/nodes/WebBox.scss +++ b/src/client/views/nodes/WebBox.scss @@ -27,7 +27,6 @@ transform-origin: top left; width: 100%; height: 100%; - overflow-x:hidden; .webBox-htmlSpan { position: absolute; diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index fe48dfc6c..7e3e662a4 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -57,13 +57,14 @@ export class WebBox extends ViewBoxAnnotatableComponent = new Dictionary(); private _selectionReactionDisposer?: IReactionDisposer; + private _scrollReactionDisposer?: IReactionDisposer; + private _moveReactionDisposer?: IReactionDisposer; private _keyInput = React.createRef(); private _longPressSecondsHack?: NodeJS.Timeout; private _outerRef = React.createRef(); private _iframeRef = React.createRef(); private _iframeIndicatorRef = React.createRef(); private _iframeDragRef = React.createRef(); - private _reactionDisposer?: IReactionDisposer; private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean) => void); iframeLoaded = action((e: any) => { @@ -76,22 +77,24 @@ export class WebBox extends ViewBoxAnnotatableComponent ({ y: this.layoutDoc._scrollY, x: this.layoutDoc._scrollX }), - ({ x, y }) => { - if (y !== undefined) { - this._outerRef.current!.scrollTop = y; - this.layoutDoc._scrollY = undefined; - } - if (x !== undefined) { - this._outerRef.current!.scrollLeft = x; - this.layoutDoc.scrollX = undefined; - } - }, + this._scrollReactionDisposer?.(); + this._scrollReactionDisposer = reaction(() => ({ y: this.layoutDoc._scrollY, x: this.layoutDoc._scrollX }), + ({ x, y }) => this.updateScroll(x, y), { fireImmediately: true } ); }); + updateScroll = (x: Opt, y: Opt) => { + if (y !== undefined) { + this._outerRef.current!.scrollTop = y; + this.layoutDoc._scrollY = undefined; + } + if (x !== undefined) { + this._outerRef.current!.scrollLeft = x; + this.layoutDoc.scrollX = undefined; + } + } + setPreviewCursor = (func?: (x: number, y: number, drag: boolean) => void) => this._setPreviewCursor = func; iframedown = (e: PointerEvent) => { this._setPreviewCursor?.(e.screenX, e.screenY, false); @@ -106,6 +109,8 @@ export class WebBox extends ViewBoxAnnotatableComponent this._url = urlField?.url.toString() || ""); + this._moveReactionDisposer = reaction(() => this.layoutDoc.x || this.layoutDoc.y, + () => this.updateScroll(this.layoutDoc._scrollLeft, this.layoutDoc._scrollTop)); this._selectionReactionDisposer = reaction(() => this.props.isSelected(), selected => { @@ -140,8 +145,9 @@ export class WebBox extends ViewBoxAnnotatableComponent this._marqueeWidth; marqueeHeight = () => this._marqueeHeight; marqueeX = () => this._marqueeX; @@ -659,14 +664,13 @@ export class WebBox extends ViewBoxAnnotatableComponent this._marqueeing; scrollXf = () => this.props.ScreenToLocalTransform().translate(NumCast(this.layoutDoc._scrollLeft), NumCast(this.layoutDoc._scrollTop)); render() { - const noScalin = this.props.ContentScaling() < 1; return (
@@ -674,7 +678,7 @@ export class WebBox extends ViewBoxAnnotatableComponent e.stopPropagation()} -- cgit v1.2.3-70-g09d2 From 56832abc50045b5154c97155dd5e7aa25ae5de29 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 27 Jul 2020 20:50:38 -0400 Subject: fixed scrollin to web annotations --- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 13 +++++++++++++ src/client/views/nodes/WebBox.tsx | 21 +++++++++++++++------ src/client/views/pdf/PDFViewer.tsx | 4 ++-- 4 files changed, 31 insertions(+), 9 deletions(-) (limited to 'src/client/views/nodes/WebBox.tsx') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index daa6e7440..792f3af5f 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -892,7 +892,7 @@ export class CollectionFreeFormView extends CollectionSubView(Docu } } + @undoBatch + togglePushpin = () => { + this.Document.ignoreClick = false; + if (this.Document.isLinkButton || this.Document.isPushpin || this.onClickHandler || this.Document.ignoreClick) { + this.Document.isPushpin = this.Document.isLinkButton = false; + this.Document.onClick = this.layoutDoc.onClick = undefined; + } else { + this.Document.isPushpin = this.Document.isLinkButton = true; + this.Document.followLinkZoom = false; + this.Document.followLinkLocation = undefined; + } + } @undoBatch toggleLinkButtonBehavior = (): void => { @@ -776,6 +788,7 @@ export class DocumentView extends DocComponent(Docu onClicks.push({ description: this.Document.isLinkButton ? "Remove Follow Behavior" : "Follow Link in Place", event: this.toggleFollowInPlace, icon: "concierge-bell" }); onClicks.push({ description: this.Document.isLinkButton ? "Remove Follow Behavior" : "Follow Link on Right", event: this.toggleFollowOnRight, icon: "concierge-bell" }); onClicks.push({ description: this.Document.isLinkButton || this.onClickHandler ? "Remove Click Behavior" : "Follow Link", event: this.toggleLinkButtonBehavior, icon: "concierge-bell" }); + onClicks.push({ description: (this.Document.isPushpin ? "Remove" : "Make") + " Pushpin", event: this.togglePushpin, icon: "snowflake" }); onClicks.push({ description: "Edit onClick Script", event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this.props.Document, undefined, "onClick"), "edit onClick"), icon: "edit" }); !existingOnClick && cm.addItem({ description: "OnClick...", noexpand: true, addDivider: true, subitems: onClicks, icon: "hand-point-right" }); diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 7e3e662a4..d30f1499e 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -14,7 +14,7 @@ import { listSpec, makeInterface } from "../../../fields/Schema"; import { Cast, NumCast, StrCast } from "../../../fields/Types"; import { WebField } from "../../../fields/URLField"; import { TraceMobx } from "../../../fields/util"; -import { addStyleSheet, clearStyleSheetRules, emptyFunction, returnOne, returnZero, Utils } from "../../../Utils"; +import { addStyleSheet, clearStyleSheetRules, emptyFunction, returnOne, returnZero, Utils, returnTrue } from "../../../Utils"; import { Docs, DocUtils } from "../../documents/Documents"; import { DragManager } from "../../util/DragManager"; import { ImageUtils } from "../../util/Import & Export/ImageUtils"; @@ -553,7 +553,7 @@ export class WebBox extends ViewBoxAnnotatableComponent([clipDoc]); clipDoc.rootDocument = targetDoc; targetDoc.layoutKey = "layout"; @@ -564,8 +564,6 @@ export class WebBox extends ViewBoxAnnotatableComponent this._marqueeX; marqueeY = () => this._marqueeY; marqueeing = () => this._marqueeing; + visibleHeiht = () => { + if (this._mainCont.current) { + const boundingRect = this._mainCont.current.getBoundingClientRect(); + const scalin = (this.Document._nativeWidth || 0) / boundingRect.width; + return Math.min(boundingRect.height * scalin, this.props.PanelHeight() * scalin); + } + return this.props.PanelHeight(); + } scrollXf = () => this.props.ScreenToLocalTransform().translate(NumCast(this.layoutDoc._scrollLeft), NumCast(this.layoutDoc._scrollTop)); render() { return (
@@ -706,6 +714,7 @@ export class WebBox extends ViewBoxAnnotatableComponent { if (scrollToAnnotation) { - const offset = this.visibleHeight() / 2 * 96 / 72; + const offset = this.visibleHeight() / 2; this._mainCont.current && smoothScroll(500, this._mainCont.current, NumCast(scrollToAnnotation.y) - offset); Doc.linkFollowHighlight(scrollToAnnotation); } @@ -705,7 +705,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent this._marqueeX; marqueeY = () => this._marqueeY; marqueeing = () => this._marqueeing; - visibleHeight = () => this.props.PanelHeight() / this.props.ContentScaling() * 72 / 96; + visibleHeight = () => this.props.PanelHeight() / this.props.ContentScaling(); contentZoom = () => this._zoomed; render() { TraceMobx(); -- cgit v1.2.3-70-g09d2