From 22649d15932f719e0b57166158a3660941a7ef72 Mon Sep 17 00:00:00 2001 From: geireann <60007097+geireann@users.noreply.github.com> Date: Wed, 17 Jun 2020 18:38:20 +0800 Subject: pdf view updates --- src/client/views/pdf/PDFViewer.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/client/views/pdf') diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index e39e96607..8b4792ccc 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -679,7 +679,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent; } @computed get pdfViewerDiv() { - return
; + return
; } @computed get contentScaling() { return this.props.ContentScaling(); } @computed get standinViews() { @@ -701,8 +701,8 @@ export class PDFViewer extends ViewBoxAnnotatableComponent 1000) ? NumCast(this.props.Document._nativeWidth) : `${100 / this.contentScaling}%`, + height: !this.props.Document._fitWidth && (window.innerWidth > 1000) ? NumCast(this.props.Document._nativeHeight) : `${100 / this.contentScaling}%`, transform: `scale(${this.props.ContentScaling()})` }} > {this.pdfViewerDiv} -- cgit v1.2.3-70-g09d2 From 57d4c562b6f0ef39dcd68f2985a56c4a683fcf49 Mon Sep 17 00:00:00 2001 From: geireann <60007097+geireann@users.noreply.github.com> Date: Thu, 18 Jun 2020 04:38:08 +0800 Subject: pdf changes + radial menu + create new workspaces (bug with ink) --- src/client/views/GestureOverlay.tsx | 8 --- .../views/collections/CollectionStackingView.tsx | 2 +- .../collectionFreeForm/InkOptionsMenu.tsx | 4 +- src/client/views/nodes/DocumentView.tsx | 12 ++-- src/client/views/nodes/PDFBox.scss | 2 +- src/client/views/nodes/PDFBox.tsx | 7 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 2 +- src/client/views/pdf/PDFViewer.tsx | 4 +- src/mobile/ImageUpload.tsx | 6 +- src/mobile/MobileInterface.tsx | 80 +++++++++++++++++++--- src/server/ApiManagers/PDFManager.ts | 3 +- 11 files changed, 94 insertions(+), 36 deletions(-) (limited to 'src/client/views/pdf') diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index e51e2d4e1..1c305ebeb 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -575,14 +575,6 @@ export default class GestureOverlay extends Touchable { const points = this._points.map(p => ({ X: p.X - B.left, Y: p.Y - B.top })); //push first points to so interactionUtil knows pointer is up this._points.push({ X: this._points[0].X, Y: this._points[0].Y }); - if (MobileInterface.Instance && MobileInterface.Instance.drawingInk) { - DocServer.Mobile.dispatchGesturePoints({ - points: this._points, - bounds: B, - color: ActiveInkColor(), - width: ActiveInkWidth() - }); - } const initialPoint = this._points[0.]; const xInGlass = initialPoint.X > (this._thumbX ?? Number.MAX_SAFE_INTEGER) && initialPoint.X < (this._thumbX ?? Number.MAX_SAFE_INTEGER) + (this.height); diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 797aabf18..9f1b5d63c 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -476,7 +476,7 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument) transformOrigin: "top left", }} onScroll={action(e => { - if (!this.props.isSelected() && this.props.renderDepth && window.innerWidth > 1000) e.currentTarget.scrollTop = this._scroll; + if (!this.props.isSelected() && this.props.renderDepth && window.screen.width > 600) e.currentTarget.scrollTop = this._scroll; else this._scroll = e.currentTarget.scrollTop; })} onDrop={this.onExternalDrop.bind(this)} diff --git a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx index 647847b68..676dc10f4 100644 --- a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx +++ b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx @@ -130,13 +130,13 @@ export default class InkOptionsMenu extends AntimodeMenu { ]; const mobileButtons = [ - this.shapeButtons, + ...this.shapeButtons, this.bezierButton, this.widthPicker, this.colorPicker, ]; - return (window.innerWidth < 1000 ? this.getElement(mobileButtons) : this.getElement(buttons)); + return (window.screen.width < 600 ? this.getElement(mobileButtons) : this.getElement(buttons)); } } Scripting.addGlobal(function activatePen(penBtn: any) { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 75627607b..e027b6a0f 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -31,7 +31,7 @@ import { SelectionManager } from "../../util/SelectionManager"; import SharingManager from '../../util/SharingManager'; import { Transform } from "../../util/Transform"; import { undoBatch, UndoManager } from "../../util/UndoManager"; -import { CollectionDockingView } from "../collections/CollectionDockingView"; +import { CollectionDockingView, DockedFrameRenderer } from "../collections/CollectionDockingView"; import { CollectionView, CollectionViewType } from '../collections/CollectionView'; import { ContextMenu } from "../ContextMenu"; import { ContextMenuProps } from '../ContextMenuItem'; @@ -43,6 +43,7 @@ import "./DocumentView.scss"; import { LinkAnchorBox } from './LinkAnchorBox'; import { RadialMenu } from './RadialMenu'; import React = require("react"); +import { MobileInterface } from '../../../mobile/MobileInterface'; library.add(fa.faEdit, fa.faTrash, fa.faShare, fa.faDownload, fa.faExpandArrowsAlt, fa.faCompressArrowsAlt, fa.faLayerGroup, fa.faExternalLinkAlt, fa.faAlignCenter, fa.faCaretSquareRight, fa.faSquare, fa.faConciergeBell, fa.faWindowRestore, fa.faFolder, fa.faMapPin, fa.faLink, fa.faFingerprint, fa.faCrosshairs, fa.faDesktop, fa.faUnlock, fa.faLock, fa.faLaptopCode, fa.faMale, @@ -181,10 +182,11 @@ export class DocumentView extends DocComponent(Docu const pt = me.touchEvent.touches[me.touchEvent.touches.length - 1]; RadialMenu.Instance.openMenu(pt.pageX - 15, pt.pageY - 15); - RadialMenu.Instance.addItem({ description: "Open Fields", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "onRight"), icon: "map-pin", selected: -1 }); - RadialMenu.Instance.addItem({ description: "Delete this document", event: () => { this.props.ContainingCollectionView?.removeDocument(this.props.Document), RadialMenu.Instance.closeMenu(); }, icon: "layer-group", selected: -1 }); - RadialMenu.Instance.addItem({ description: "Open in a new tab", event: () => this.props.addDocTab(this.props.Document, "onRight"), icon: "trash", selected: -1 }); - RadialMenu.Instance.addItem({ description: "Pin to Presentation", event: () => this.props.pinToPres(this.props.Document), icon: "folder", selected: -1 }); + // RadialMenu.Instance.addItem({ description: "Open Fields", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "onRight"), icon: "map-pin", selected: -1 }); + RadialMenu.Instance.addItem({ description: "Delete", event: () => { this.props.ContainingCollectionView?.removeDocument(this.props.Document), RadialMenu.Instance.closeMenu(); }, icon: "external-link-square-alt", selected: -1 }); + // RadialMenu.Instance.addItem({ description: "Open in a new tab", event: () => this.props.addDocTab(this.props.Document, "onRight"), icon: "trash", selected: -1 }); + RadialMenu.Instance.addItem({ description: "Pin", event: () => DockedFrameRenderer.PinDoc(this.props.Document), icon: "map-pin", selected: -1 }); + RadialMenu.Instance.addItem({ description: "Open", event: () => MobileInterface.Instance.handleClick(this.props.Document), icon: "trash", selected: -1 }); SelectionManager.DeselectAll(); } diff --git a/src/client/views/nodes/PDFBox.scss b/src/client/views/nodes/PDFBox.scss index 474587159..1a31d2916 100644 --- a/src/client/views/nodes/PDFBox.scss +++ b/src/client/views/nodes/PDFBox.scss @@ -224,7 +224,7 @@ } } -@media only screen and (max-width: 1000px) { +@media only screen and (max-width: 600px) { .pdfBox .pdfBox-ui .pdfBox-settingsCont .pdfBox-settingsButton, .pdfBox-interactive .pdfBox-ui .pdfBox-settingsCont .pdfBox-settingsButton { diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 78b7faeee..4b4348d3c 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -215,13 +215,14 @@ export class PDFBox extends ViewBoxAnnotatableComponent 1000)); + console.log("fitWidth ?: " + !(this.props.Document._fitWidth) && (window.screen.width > 600)); console.log("_nativeHeight: " + this.Document._nativeHeight); console.log("%: " + `${100 / this.contentScaling}%`); const classname = "pdfBox" + (this.active() ? "-interactive" : ""); return
1000) ? this.Document._nativeHeight || 0 : `${100 / this.contentScaling}%`, //Adjusted for mobile (!window.innerWidth < 1000) + //height adjusted for mobile (window.screen.width > 600) + height: !this.props.Document._fitWidth && (window.screen.width > 600) ? this.Document._nativeHeight || 0 : `${100 / this.contentScaling}%`, transform: `scale(${this.contentScaling})` }} >
@@ -233,7 +234,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent this._isChildActive; @computed get renderPdfView() { const pdfUrl = Cast(this.dataDoc[this.props.fieldKey], PdfField); - return
1000) ? NumCast(this.Document._height) * this.props.PanelWidth() / NumCast(this.Document._width) : undefined }}> + return
600) ? NumCast(this.Document._height) * this.props.PanelWidth() / NumCast(this.Document._width) : undefined }}> { - if (window.innerWidth < 1000) null; + if (window.screen.width < 600) null; else if (this._editorView && (this._editorView as any).docView) { const mark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight); const activeMark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight, { selected: true }); diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 9cdbea2da..57b7bceca 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -709,8 +709,8 @@ export class PDFViewer extends ViewBoxAnnotatableComponent 1000) ? NumCast(this.props.Document._nativeWidth) : `${100 / this.contentScaling}%`, - height: !this.props.Document._fitWidth && (window.innerWidth > 1000) ? NumCast(this.props.Document._nativeHeight) : `${100 / this.contentScaling}%`, + width: !this.props.Document._fitWidth && (window.screen.width > 600) ? NumCast(this.props.Document._nativeWidth) : `${100 / this.contentScaling}%`, + height: !this.props.Document._fitWidth && (window.screen.width > 600) ? NumCast(this.props.Document._nativeHeight) : `${100 / this.contentScaling}%`, transform: `scale(${this.props.ContentScaling()})` }} > {this.pdfViewerDiv} diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx index d8b1913ee..b66f0461d 100644 --- a/src/mobile/ImageUpload.tsx +++ b/src/mobile/ImageUpload.tsx @@ -65,8 +65,11 @@ export class Uploader extends React.Component { } const path = Utils.prepend(result.accessPaths.agnostic.client); let doc = null; + console.log("type: " + file.type); if (file.type === "video/mp4") { doc = Docs.Create.VideoDocument(path, { _nativeWidth: 200, _width: 200, title: name }); + } else if (file.type === "application/pdf") { + doc = Docs.Create.PdfDocument(path, { _width: 200, title: name }); } else { doc = Docs.Create.ImageDocument(path, { _nativeWidth: 200, _width: 200, title: name }); } @@ -175,7 +178,7 @@ export class Uploader extends React.Component { private get uploadInterface() { return (
- +
@@ -217,4 +220,3 @@ export class Uploader extends React.Component { } -// DocServer.init(window.location.protocol, window.location.hostname, 4321, "image upload"); diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index 5acdc1dea..644535179 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -1,7 +1,7 @@ import * as React from "react"; import { library } from '@fortawesome/fontawesome-svg-core'; import { - faTasks, faMobile, faThLarge, faWindowClose, faEdit, faTrashAlt, faPalette, faAngleRight, faBell, faTrash, faCamera, faExpand, faCaretDown, faCaretLeft, faCaretRight, faCaretSquareDown, faCaretSquareRight, faArrowsAltH, faPlus, faMinus, + faTasks, faExternalLinkSquareAlt, faMobile, faThLarge, faWindowClose, faEdit, faTrashAlt, faPalette, faAngleRight, faBell, faTrash, faCamera, faExpand, faCaretDown, faCaretLeft, faCaretRight, faCaretSquareDown, faCaretSquareRight, faArrowsAltH, faPlus, faMinus, faTerminal, faToggleOn, faFile as fileSolid, faExternalLinkAlt, faLocationArrow, faSearch, faFileDownload, faStop, faCalculator, faWindowMaximize, faAddressCard, faQuestionCircle, faArrowLeft, faArrowRight, faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt, faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter, @@ -17,7 +17,7 @@ import { FieldValue, Cast } from '../fields/Types'; import { CurrentUserUtils } from '../client/util/CurrentUserUtils'; import { emptyPath, emptyFunction, returnFalse, returnOne, returnTrue, returnZero, Utils } from '../Utils'; import { DocServer } from '../client/DocServer'; -import { Docs } from '../client/documents/Documents'; +import { Docs, DocumentOptions } from '../client/documents/Documents'; import { Scripting } from '../client/util/Scripting'; import { DocumentView } from '../client/views/nodes/DocumentView'; import { Transform } from '../client/util/Transform'; @@ -36,8 +36,11 @@ import GestureOverlay from "../client/views/GestureOverlay"; import { ScriptField } from "../fields/ScriptField"; import InkOptionsMenu from "../client/views/collections/collectionFreeForm/InkOptionsMenu"; import { RadialMenu } from "../client/views/nodes/RadialMenu"; +import { UndoManager } from "../client/util/UndoManager"; +import { MainView } from "../client/views/MainView"; +import { List } from "../fields/List"; -library.add(faTasks, faMobile, faThLarge, faWindowClose, faEdit, faTrashAlt, faPalette, faAngleRight, faBell, faTrash, faCamera, faExpand, faCaretDown, faCaretLeft, faCaretRight, faCaretSquareDown, faCaretSquareRight, faArrowsAltH, faPlus, faMinus, +library.add(faTasks, faExternalLinkSquareAlt, faMobile, faThLarge, faWindowClose, faEdit, faTrashAlt, faPalette, faAngleRight, faBell, faTrash, faCamera, faExpand, faCaretDown, faCaretLeft, faCaretRight, faCaretSquareDown, faCaretSquareRight, faArrowsAltH, faPlus, faMinus, faTerminal, faToggleOn, fileSolid, faExternalLinkAlt, faLocationArrow, faSearch, faFileDownload, faStop, faCalculator, faWindowMaximize, faAddressCard, faQuestionCircle, faArrowLeft, faArrowRight, faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt, faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter, @@ -149,7 +152,7 @@ export class MobileInterface extends React.Component { * Return 'Home", which implies returning to 'Home' buttons */ returnHome = () => { - if (this._homeMenu === false || this.sidebarActive === true) { + if (this._homeMenu || this.sidebarActive) { this._homeMenu = true; this._parents = []; this._activeDoc = this._homeDoc; @@ -220,7 +223,7 @@ export class MobileInterface extends React.Component { */ handleClick = async (doc: Doc) => { const children = DocListCast(doc.data); - if (doc.type !== "collection") { + if (doc.type !== "collection" && this.sidebarActive) { this._parents.push(this._activeDoc); this._activeDoc = doc; this.switchCurrentView((userDoc: Doc) => doc); @@ -333,7 +336,7 @@ export class MobileInterface extends React.Component { // Renders the contents of the menu and sidebar renderDefaultContent = () => { - if (this._homeMenu === true) { + if (this._homeMenu) { return (
@@ -351,7 +354,7 @@ export class MobileInterface extends React.Component {
ScriptField.MakeScript("createNewWorkspace()")}>Create New Workspace + onClick={() => MainView.Instance?.createNewWorkspace()}>Create New Workspace
@@ -403,7 +406,10 @@ export class MobileInterface extends React.Component { {buttons}
ScriptField.MakeScript("createNewWorkspace()")}>Create New Workspace + style={{ opacity: 0.7 }} + onClick={() => this.createNewWorkspace()}> + +
Create New Workspace
} @@ -413,6 +419,32 @@ export class MobileInterface extends React.Component { ); } + /** + * Handles the Create New Workspace button in the menu + */ + @action + createNewWorkspace = async (id?: string) => { + const workspaces = Cast(this.userDoc.myWorkspaces, Doc) as Doc; + const workspaceCount = DocListCast(workspaces.data).length + 1; + const freeformOptions: DocumentOptions = { + x: 0, + y: 400, + title: "Collection " + workspaceCount, + _LODdisable: true + }; + const freeformDoc = CurrentUserUtils.GuestTarget || Docs.Create.FreeformDocument([], freeformOptions); + const workspaceDoc = Docs.Create.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600, path: [Doc.UserDoc().myCatalog as Doc] }], { title: `Workspace ${workspaceCount}` }, id, "row"); + + const toggleTheme = ScriptField.MakeScript(`self.darkScheme = !self.darkScheme`); + const toggleComic = ScriptField.MakeScript(`toggleComicMode()`); + const cloneWorkspace = ScriptField.MakeScript(`cloneWorkspace()`); + workspaceDoc.contextMenuScripts = new List([toggleTheme!, toggleComic!, cloneWorkspace!]); + workspaceDoc.contextMenuLabels = new List(["Toggle Theme Colors", "Toggle Comic Mode", "New Workspace Layout"]); + + Doc.AddDocToList(workspaces, "data", workspaceDoc); + // bcz: strangely, we need a timeout to prevent exceptions/issues initializing GoldenLayout (the rendering engine for Main Container) + } + stop = (e: React.MouseEvent) => { e.stopPropagation(); } @@ -431,7 +463,7 @@ export class MobileInterface extends React.Component { } } - // Button for switching between pan and ink mode + // Button for switching between pen and ink mode @action onSwitchInking = () => { const button = document.getElementById("inkButton") as HTMLElement; @@ -465,6 +497,16 @@ export class MobileInterface extends React.Component { if (this._activeDoc._viewType === "docking") { return ( <> + {/*
{ + UndoManager.Undo(); + e.stopPropagation(); + }}> + +
*/}
+ {/*
{ + UndoManager.Redo(); + e.stopPropagation(); + }}> + +
*/} ); } } @@ -645,6 +697,12 @@ export class MobileInterface extends React.Component { ); } + displayRadialMenu = () => { + if (this._activeDoc.type === "collection" && this._activeDoc !== this._homeDoc) { + return ; + } + } + onDragOver = (e: React.DragEvent) => { e.preventDefault(); e.stopPropagation(); @@ -669,12 +727,14 @@ export class MobileInterface extends React.Component { {this.displayWorkspaces()} {this.renderDefaultContent()} - + {this.displayRadialMenu()}
); } } + + Scripting.addGlobal(function switchMobileView(doc: (userDoc: Doc) => Doc, renderView?: () => JSX.Element, onSwitch?: () => void) { return MobileInterface.Instance.switchCurrentView(doc, renderView, onSwitch); }); Scripting.addGlobal(function openMobilePresentation() { return MobileInterface.Instance.setupDefaultPresentation(); }); Scripting.addGlobal(function toggleMobileSidebar() { return MobileInterface.Instance.toggleSidebar(); }); diff --git a/src/server/ApiManagers/PDFManager.ts b/src/server/ApiManagers/PDFManager.ts index d2a9e9cce..b0b5a484a 100644 --- a/src/server/ApiManagers/PDFManager.ts +++ b/src/server/ApiManagers/PDFManager.ts @@ -55,7 +55,8 @@ async function CreateThumbnail(coreFilename: string, pageNum: number, res: expre const documentProxy = await Pdfjs.getDocument(sourcePath).promise; const factory = new NodeCanvasFactory(); const page = await documentProxy.getPage(pageNum); - const viewport = page.getViewport(1 as any); + const scale = 1; + const viewport = page.getViewport(scale as any); const { canvas, context } = factory.create(viewport.width, viewport.height); const renderContext = { canvasContext: context, -- cgit v1.2.3-70-g09d2 From 6f0357e17c0dfe201fe60e841ab89e4714d86d16 Mon Sep 17 00:00:00 2001 From: geireann <60007097+geireann@users.noreply.github.com> Date: Thu, 2 Jul 2020 12:00:41 +0800 Subject: fixing kluge with scrolling --- src/client/views/collections/CollectionStackingView.tsx | 2 +- src/client/views/pdf/PDFViewer.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/client/views/pdf') diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 0af5c21be..9d8790dda 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -476,7 +476,7 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument) transformOrigin: "top left", }} onScroll={action(e => { - if (!this.props.isSelected() && this.props.renderDepth && window.screen.width > 600) e.currentTarget.scrollTop = this._scroll; + if (!this.props.isSelected() && this.props.renderDepth) e.currentTarget.scrollTop = this._scroll; else this._scroll = e.currentTarget.scrollTop; })} onDrop={this.onExternalDrop.bind(this)} diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index b03dfe217..cd6aa4e29 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -695,7 +695,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent; } @computed get pdfViewerDiv() { - return
; + return
; } @computed get contentScaling() { return this.props.ContentScaling(); } @computed get standinViews() { -- cgit v1.2.3-70-g09d2 From 3fdee81100954e66f54c73661cb11967993ff467 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 15 Jul 2020 15:24:53 -0400 Subject: fixed tooltips to share a csss style. added tooltips for richtext. --- src/client/documents/Documents.ts | 2 +- src/client/views/DocumentButtonBar.tsx | 10 ++--- src/client/views/DocumentDecorations.tsx | 15 +++---- src/client/views/MainView.scss | 4 ++ .../views/collections/CollectionLinearView.tsx | 20 +++++---- src/client/views/collections/CollectionMenu.tsx | 13 +++--- src/client/views/collections/CollectionView.tsx | 3 +- .../CollectionFreeFormLinkView.tsx | 12 +++--- src/client/views/linking/LinkEditor.tsx | 14 +++---- src/client/views/linking/LinkMenuItem.tsx | 19 +++------ src/client/views/nodes/DocumentLinksButton.tsx | 5 +-- src/client/views/nodes/DocumentView.tsx | 25 +++-------- .../formattedText/FormattedTextBoxComment.tsx | 4 +- .../views/nodes/formattedText/RichTextMenu.tsx | 49 +++++++++++++--------- src/client/views/pdf/PDFViewer.tsx | 2 +- 15 files changed, 94 insertions(+), 103 deletions(-) (limited to 'src/client/views/pdf') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 1fd533b62..b57f4c6c7 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -915,7 +915,7 @@ export namespace DocUtils { const linkDoc = Docs.Create.LinkDocument(source, target, { linkRelationship, layoutKey: "layout_linkView", description }, id); linkDoc.linkDisplay = true; - linkDoc.hideAnhors = true; + linkDoc.hidden = true; linkDoc.layout_linkView = Cast(Cast(Doc.UserDoc()["template-button-link"], Doc, null).dragFactory, Doc, null); Doc.GetProto(linkDoc).title = ComputedField.MakeFunction('self.anchor1?.title +" (" + (self.linkRelationship||"to") +") " + self.anchor2?.title'); diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 05538a28e..45f4c7393 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -118,7 +118,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV const targetDoc = this.view0?.props.Document; const published = targetDoc && Doc.GetProto(targetDoc)[GoogleRef] !== undefined; const animation = this.isAnimatingPulse ? "shadow-pulse 1s linear infinite" : "none"; - return !targetDoc ? (null) :
{`${published ? "Push" : "Publish"} to Google Docs`}
}> + return !targetDoc ? (null) :
{`${published ? "Push" : "Publish"} to Google Docs`}
}>
(DocumentV })(); return !targetDoc || !dataDoc || !dataDoc[GoogleRef] ? (null) :
{title}
}> + title={<>
{title}
}>
{ @@ -197,7 +197,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV get pinButton() { const targetDoc = this.view0?.props.Document; const isPinned = targetDoc && Doc.isDocPinned(targetDoc); - return !targetDoc ? (null) :
{Doc.isDocPinned(targetDoc) ? "Unpin from presentation" : "Pin to presentation"}
}> + return !targetDoc ? (null) :
{Doc.isDocPinned(targetDoc) ? "Unpin from presentation" : "Pin to presentation"}
}>
DockedFrameRenderer.PinDoc(targetDoc, isPinned)}> @@ -209,7 +209,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV @computed get metadataButton() { const view0 = this.view0; - return !view0 ? (null) :
Show metadata panel
}> + return !view0 ? (null) :
Show metadata panel
}>
dv).map(dv => dv!.props.Document)} suggestWithFunction /> /* tfs: @bcz This might need to be the data document? */}> @@ -258,7 +258,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV Array.from(Object.values(Templates.TemplateList)).map(template => templates.set(template, views.reduce((checked, doc) => checked || doc?.props.Document["_show" + template.Name] ? true : false, false as boolean))); return !view0 ? (null) : -
Tap: Customize layout. Drag: Create alias
}> +
Tap: Customize layout. Drag: Create alias
}>
this._aliasDown = true)} onClose={action(() => this._aliasDown = false)} content={!this._aliasDown ? (null) : v).map(v => v as DocumentView)} templates={templates} />}> diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 2fd017f7b..376b1d46b 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -81,6 +81,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> return SelectionManager.SelectedDocuments().reduce((bounds, documentView) => { if (documentView.props.renderDepth === 0 || documentView.props.treeViewDoc || + !documentView.ContentDiv || Doc.AreProtosEqual(documentView.props.Document, Doc.UserDoc())) { return bounds; } @@ -88,7 +89,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> var [sptX, sptY] = transform.transformPoint(0, 0); let [bptX, bptY] = transform.transformPoint(documentView.props.PanelWidth(), documentView.props.PanelHeight()); if (documentView.props.Document.type === DocumentType.LINK) { - const docuBox = documentView.ContentDiv!.getElementsByClassName("linkAnchorBox-cont"); + const docuBox = documentView.ContentDiv.getElementsByClassName("linkAnchorBox-cont"); if (docuBox.length) { const rect = docuBox[0].getBoundingClientRect(); sptX = rect.left; @@ -544,11 +545,11 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> } const minimal = bounds.r - bounds.x < 100 ? true : false; const maximizeIcon = minimal ? ( -
Show context menu
} placement="top"> +
Show context menu
} placement="top">
) : ( -
Iconify
} placement="top"> +
Iconify
} placement="top">
{/* Currently, this is set to be enabled if there is no ink selected. It might be interesting to think about minimizing ink if it's useful? -syip2*/} @@ -572,7 +573,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
} : <> - {minimal ? (null) :
Show context menu
} placement="top">
+ {minimal ? (null) :
Show context menu
} placement="top">
}
@@ -611,11 +612,11 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> {maximizeIcon} {titleArea} {SelectionManager.SelectedDocuments().length !== 1 || seldoc.Document.type === DocumentType.INK ? (null) : -
{`${seldoc.finalLayoutKey.includes("icon") ? "De" : ""}Iconify Document`}
} placement="top"> +
{`${seldoc.finalLayoutKey.includes("icon") ? "De" : ""}Iconify Document`}
} placement="top">
{"_"}
} -
Open Document In Tab
} placement="top">
+
Open Document In Tab
} placement="top">
{SelectionManager.SelectedDocuments().length === 1 ? DocumentDecorations.DocumentIcon(StrCast(seldoc.props.Document.layout, "...")) : "..."}
e.preventDefault()}>
{seldoc.props.renderDepth <= 1 || !seldoc.props.ContainingCollectionView ? (null) : -
tap to select containing document
} placement="top"> +
tap to select containing document
} placement="top">
e.preventDefault()}> diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss index 5b142ffda..e1ddbc533 100644 --- a/src/client/views/MainView.scss +++ b/src/client/views/MainView.scss @@ -1,6 +1,10 @@ @import "globalCssVariables"; @import "nodeModuleOverrides"; +.dash-tooltip { + font-size: 11px; + padding: 2px; +} .mainView-tabButtons { position: relative; diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx index 319cca70f..407524353 100644 --- a/src/client/views/collections/CollectionLinearView.tsx +++ b/src/client/views/collections/CollectionLinearView.tsx @@ -124,7 +124,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) { return
-
{BoolCast(this.props.Document.linearViewIsExpanded) ? "Close menu" : "Open menu"}
} placement="top"> +
{BoolCast(this.props.Document.linearViewIsExpanded) ? "Close menu" : "Open menu"}
} placement="top"> {menuOpener}
e.stopPropagation()} > - Creating link from: {DocumentLinksButton.StartLink.title} + Creating link from: {DocumentLinksButton.StartLink.title} + -
{LinkDescriptionPopup.showDescriptions ? "Turn off description pop-up" : - "Turn on description pop-up"}
} placement="top"> - Labels: {LinkDescriptionPopup.showDescriptions ? LinkDescriptionPopup.showDescriptions : "ON"} +
{LinkDescriptionPopup.showDescriptions ? "Turn off description pop-up" : + "Turn on description pop-up"}
} placement="top"> + + Labels: {LinkDescriptionPopup.showDescriptions ? LinkDescriptionPopup.showDescriptions : "ON"}
-
Exit link clicking mode
} placement="top"> - Clear +
Exit link clicking mode
} placement="top"> + + Clear +
{/* : , - - ]); + const button = ; + + return this.getElement(!this.SelectedCollection ? [button] : + [, + button]); } } diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index c1a6b5b0d..c1da23470 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -142,6 +142,7 @@ export class CollectionView extends Touchable d instanceof Doc); - first && (first.hidden = true); doc.displayTimecode = undefined; } doc.context = this.props.Document; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index dea936113..0933d525a 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -29,13 +29,13 @@ export class CollectionFreeFormLinkView extends React.Component [this.props.A.props.ScreenToLocalTransform(), this.props.B.props.ScreenToLocalTransform(), this.props.A.isSelected() || Doc.IsBrushed(this.props.A.props.Document), this.props.A.isSelected() || Doc.IsBrushed(this.props.A.props.Document)], action(() => { - if (SnappingManager.GetIsDragging()) return; + if (SnappingManager.GetIsDragging() || !this.props.A.ContentDiv || !this.props.B.ContentDiv) return; setTimeout(action(() => this._opacity = 1), 0); // since the render code depends on querying the Dom through getBoudndingClientRect, we need to delay triggering render() setTimeout(action(() => (!this.props.LinkDocs.length || !this.props.LinkDocs[0].linkDisplay) && (this._opacity = 0.05)), 750); // this will unhighlight the link line. - const acont = this.props.A.props.Document.type === DocumentType.LINK ? this.props.A.ContentDiv!.getElementsByClassName("linkAnchorBox-cont") : []; - const bcont = this.props.B.props.Document.type === DocumentType.LINK ? this.props.B.ContentDiv!.getElementsByClassName("linkAnchorBox-cont") : []; - const adiv = (acont.length ? acont[0] : this.props.A.ContentDiv!); - const bdiv = (bcont.length ? bcont[0] : this.props.B.ContentDiv!); + const acont = this.props.A.props.Document.type === DocumentType.LINK ? this.props.A.ContentDiv.getElementsByClassName("linkAnchorBox-cont") : []; + const bcont = this.props.B.props.Document.type === DocumentType.LINK ? this.props.B.ContentDiv.getElementsByClassName("linkAnchorBox-cont") : []; + const adiv = (acont.length ? acont[0] : this.props.A.ContentDiv); + const bdiv = (bcont.length ? bcont[0] : this.props.B.ContentDiv); const a = adiv.getBoundingClientRect(); const b = bdiv.getBoundingClientRect(); const abounds = adiv.parentElement!.getBoundingClientRect(); @@ -103,7 +103,7 @@ export class CollectionFreeFormLinkView extends React.Component { @observable description = StrCast(LinkManager.currentLink?.description); @observable openDropdown: boolean = false; - @observable followBehavior = this.props.linkDoc.follow ? this.props.linkDoc.follow : "Default"; @observable showInfo: boolean = false; @computed get infoIcon() { if (this.showInfo) { return "chevron-up"; } return "chevron-down"; } @observable private buttonColor: string = "black"; @@ -364,8 +363,7 @@ export class LinkEditor extends React.Component { @action changeFollowBehavior = (follow: string) => { this.openDropdown = false; - this.followBehavior = follow; - this.props.linkDoc.follow = follow; + Doc.GetProto(this.props.linkDoc).followLinkLocation = follow; } @computed @@ -376,7 +374,7 @@ export class LinkEditor extends React.Component {
- {this.followBehavior} + {StrCast(this.props.linkDoc.followLinkLocation, "Default")} @@ -388,11 +386,11 @@ export class LinkEditor extends React.Component { Default
this.changeFollowBehavior("Always open in right tab")}> + onPointerDown={() => this.changeFollowBehavior("onRight")}> Always open in right tab
this.changeFollowBehavior("Always open in new tab")}> + onPointerDown={() => this.changeFollowBehavior("inTab")}> Always open in new tab
@@ -416,7 +414,7 @@ export class LinkEditor extends React.Component { return !destination ? (null) : (
-
Return to link menu
} placement="top"> +
Return to link menu
} placement="top"> */} -
Show more link information
} placement="top"> +
Show more link information
} placement="top">
diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx index 6782f625b..0e847632b 100644 --- a/src/client/views/linking/LinkMenuItem.tsx +++ b/src/client/views/linking/LinkMenuItem.tsx @@ -16,7 +16,6 @@ import { DocumentView } from '../nodes/DocumentView'; import { DocumentLinksButton } from '../nodes/DocumentLinksButton'; import { LinkDocPreview } from '../nodes/LinkDocPreview'; import { Tooltip } from '@material-ui/core'; -import { RichTextField } from '../../../fields/RichTextField'; import { DocumentType } from '../../documents/DocumentTypes'; library.add(faEye, faEdit, faTimes, faArrowRight, faChevronDown, faChevronUp, faPencilAlt, faEyeSlash); @@ -157,14 +156,8 @@ export class LinkMenuItem extends React.Component { DocumentLinksButton.EditLink = undefined; LinkDocPreview.LinkInfo = undefined; - if (this.props.linkDoc.follow) { - if (this.props.linkDoc.follow === "Default") { - DocumentManager.Instance.FollowLink(this.props.linkDoc, this.props.sourceDoc, doc => this.props.addDocTab(doc, "onRight"), false); - } else if (this.props.linkDoc.follow === "Always open in right tab") { - this.props.addDocTab(this.props.destinationDoc, "onRight"); - } else if (this.props.linkDoc.follow === "Always open in new tab") { - this.props.addDocTab(this.props.destinationDoc, "inTab"); - } + if (this.props.linkDoc.followLinkLocation && this.props.linkDoc.followLinkLocation !== "Default") { + this.props.addDocTab(this.props.destinationDoc, StrCast(this.props.linkDoc.followLinkLocation)); } else { DocumentManager.Instance.FollowLink(this.props.linkDoc, this.props.sourceDoc, doc => this.props.addDocTab(doc, "onRight"), false); } @@ -221,8 +214,6 @@ export class LinkMenuItem extends React.Component { StrCast(this.props.linkDoc.storedText).substr(0, 18) : this.props.linkDoc.storedText : undefined : undefined; - const showTitle = this.props.linkDoc.hidden ? "Show link" : "Hide link"; - return (
@@ -255,16 +246,16 @@ export class LinkMenuItem extends React.Component { {canExpand ?
this.toggleShowMore(e)}>
: <>} -
{showTitle}
}> +
{this.props.linkDoc.hidden ? "Show link" : "Hide link"}
}>
-
Edit Link
}> +
Edit Link
}>
-
Delete Link
}> +
Delete Link
}>
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx index 01c068966..bbef48e44 100644 --- a/src/client/views/nodes/DocumentLinksButton.tsx +++ b/src/client/views/nodes/DocumentLinksButton.tsx @@ -134,7 +134,6 @@ export class DocumentLinksButton extends React.Component { if (linkDoc) { @@ -213,10 +212,10 @@ export class DocumentLinksButton extends React.Component
{title}
}> +
{title}
}> {linkButton}
: !!!DocumentLinksButton.EditLink ? -
{title}
}> +
{title}
}> {linkButton}
: linkButton; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index a6771443a..c0a8b3a59 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -589,16 +589,12 @@ export class DocumentView extends DocComponent(Docu @undoBatch toggleLinkButtonBehavior = (): void => { + this.Document.ignoreClick = false; if (this.Document.isLinkButton || this.onClickHandler || this.Document.ignoreClick) { this.Document.isLinkButton = false; - const first = DocListCast(this.Document.links).find(d => d instanceof Doc); - first && (first.hidden = false); - this.Document.ignoreClick = false; this.Document.onClick = this.layoutDoc.onClick = undefined; } else { this.Document.isLinkButton = true; - const first = DocListCast(this.Document.links).find(d => d instanceof Doc); - first && (first.hidden = true); this.Document.followLinkZoom = false; this.Document.followLinkLocation = undefined; } @@ -606,14 +602,9 @@ export class DocumentView extends DocComponent(Docu @undoBatch toggleFollowInPlace = (): void => { + this.Document.ignoreClick = false; + this.Document.isLinkButton = !this.Document.isLinkButton; if (this.Document.isLinkButton) { - this.Document.isLinkButton = false; - const first = DocListCast(this.Document.links).find(d => d instanceof Doc); - first && (first.hidden = false); - } else { - this.Document.isLinkButton = true; - const first = DocListCast(this.Document.links).find(d => d instanceof Doc); - first && (first.hidden = true); this.Document.followLinkZoom = true; this.Document.followLinkLocation = "inPlace"; } @@ -621,15 +612,10 @@ export class DocumentView extends DocComponent(Docu @undoBatch toggleFollowOnRight = (): void => { + this.Document.ignoreClick = false; + this.Document.isLinkButton = !this.Document.isLinkButton; if (this.Document.isLinkButton) { - this.Document.isLinkButton = false; - const first = DocListCast(this.Document.links).find(d => d instanceof Doc); - first && (first.hidden = false); - } else { - this.Document.isLinkButton = true; this.Document.followLinkZoom = false; - const first = DocListCast(this.Document.links).find(d => d instanceof Doc); - first && (first.hidden = true); this.Document.followLinkLocation = "onRight"; } } @@ -643,7 +629,6 @@ export class DocumentView extends DocComponent(Docu } const makeLink = action((linkDoc: Doc) => { LinkManager.currentLink = linkDoc; - linkDoc.hidden = true; LinkCreatedBox.popupX = de.x; LinkCreatedBox.popupY = de.y - 33; diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx index c98b5eac1..3687d5513 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx @@ -270,14 +270,14 @@ export class FormattedTextBoxComment {
-
Delete Link
} placement="top"> +
Delete Link
} placement="top">
this._deleteRef = r}>
-
Follow Link
} placement="top"> +
Follow Link
} placement="top">
this._followRef = r}> - - + {title}
} key={title} placement="bottom"> + +
); } @@ -388,7 +391,9 @@ export default class RichTextMenu extends AntimodeMenu { } }); } - return ; + return {key}
} placement="bottom"> + + ; } createNodesDropdown(activeMap: string, options: { node: NodeType | any | null, title: string, label: string, command: (node: NodeType | any) => void, hidden?: boolean, style?: {} }[], key: string, setter: (val: string) => {}): JSX.Element { @@ -412,7 +417,10 @@ export default class RichTextMenu extends AntimodeMenu { } }); } - return ; + + return {key}
} placement="bottom"> + + ; } changeFontSize = (mark: Mark, view: EditorView) => { @@ -595,10 +603,11 @@ export default class RichTextMenu extends AntimodeMenu { label = "No marks are currently stored"; } - const button = -
} placement="bottom"> + ; + +
; const dropdownContent =
@@ -667,11 +676,12 @@ export default class RichTextMenu extends AntimodeMenu { self.TextView.EditorView!.focus(); } - const button = -
} placement="bottom"> + ; + +
; const dropdownContent =
@@ -720,11 +730,12 @@ export default class RichTextMenu extends AntimodeMenu { UndoManager.RunInBatch(() => self.view && self.insertHighlight(self.activeHighlightColor, self.view.state, self.view.dispatch), "rt highlighter"); } - const button = -
} placement="bottom"> + ; + +
; const dropdownContent =
@@ -763,7 +774,9 @@ export default class RichTextMenu extends AntimodeMenu { const link = this.currentLink ? this.currentLink : ""; - const button = ; + const button = set hyperlink
} placement="bottom"> +
+ ; const dropdownContent =
@@ -774,9 +787,7 @@ export default class RichTextMenu extends AntimodeMenu {
; - return ( - - ); + return ; } async getTextLinkTargetTitle() { @@ -935,7 +946,7 @@ export default class RichTextMenu extends AntimodeMenu { {[this.createMarksDropdown(this.activeFontSize, this.fontSizeOptions, "font size", action((val: string) => this.activeFontSize = val)), this.createMarksDropdown(this.activeFontFamily, this.fontFamilyOptions, "font family", action((val: string) => this.activeFontFamily = val)),
, - this.createNodesDropdown(this.activeListType, this.listTypeOptions, "nodes", action((val: string) => this.activeListType = val)), + this.createNodesDropdown(this.activeListType, this.listTypeOptions, "list type", action((val: string) => this.activeListType = val)), this.createButton("sort-amount-down", "Summarize", undefined, this.insertSummarizer), this.createButton("quote-left", "Blockquote", undefined, this.insertBlockquote), this.createButton("minus", "Horizontal Rule", undefined, this.insertHorizontalRule), diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 4e5fdbfbb..56212a773 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -637,7 +637,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent { - if (this.active()) { + if (this.active(true)) { e.stopPropagation(); if (e.ctrlKey) { const curScale = Number(this._pdfViewer.currentScaleValue); -- cgit v1.2.3-70-g09d2 From 60819bced2eb67282b77e25c77939dd45d01e7d8 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 17 Jul 2020 00:06:59 -0400 Subject: fixed pdf runtime errors. fixed link lines to redraw durin animations. --- .../CollectionFreeFormLinkView.tsx | 26 +++++++++++++++------- src/client/views/nodes/PDFBox.tsx | 2 +- src/client/views/pdf/PDFViewer.tsx | 4 ++-- 3 files changed, 21 insertions(+), 11 deletions(-) (limited to 'src/client/views/pdf') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index 0933d525a..6d44ac967 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -5,12 +5,10 @@ import { DocumentView } from "../../nodes/DocumentView"; import "./CollectionFreeFormLinkView.scss"; import React = require("react"); import { DocumentType } from "../../../documents/DocumentTypes"; -import { observable, action, reaction, IReactionDisposer } from "mobx"; +import { observable, action, reaction, IReactionDisposer, trace, computed } from "mobx"; import { StrCast, Cast, NumCast } from "../../../../fields/Types"; import { Id } from "../../../../fields/FieldSymbols"; import { SnappingManager } from "../../../util/SnappingManager"; -import { OverlayView } from "../../OverlayView"; -import { LinkEditor } from "../../linking/LinkEditor"; export interface CollectionFreeFormLinkViewProps { A: DocumentView; @@ -21,14 +19,20 @@ export interface CollectionFreeFormLinkViewProps { @observer export class CollectionFreeFormLinkView extends React.Component { @observable _opacity: number = 0; + @observable _start = 0; _anchorDisposer: IReactionDisposer | undefined; - + _timeout: NodeJS.Timeout | undefined; componentWillUnmount() { this._anchorDisposer?.(); } + @action + timeout = () => (Date.now() < this._start++ + 1000) && setTimeout(this.timeout, 25); componentDidMount() { this._anchorDisposer = reaction(() => [this.props.A.props.ScreenToLocalTransform(), this.props.B.props.ScreenToLocalTransform(), this.props.A.isSelected() || Doc.IsBrushed(this.props.A.props.Document), this.props.A.isSelected() || Doc.IsBrushed(this.props.A.props.Document)], action(() => { + this._start = Date.now(); + this._timeout && clearTimeout(this._timeout); + this._timeout = setTimeout(this.timeout, 25); if (SnappingManager.GetIsDragging() || !this.props.A.ContentDiv || !this.props.B.ContentDiv) return; setTimeout(action(() => this._opacity = 1), 0); // since the render code depends on querying the Dom through getBoudndingClientRect, we need to delay triggering render() setTimeout(action(() => (!this.props.LinkDocs.length || !this.props.LinkDocs[0].linkDisplay) && (this._opacity = 0.05)), 750); // this will unhighlight the link line. @@ -101,9 +105,11 @@ export class CollectionFreeFormLinkView extends React.Component - diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 1c5825a8f..323da1233 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -268,7 +268,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent { this._pdf = pdf; console.log("promise"); })); + promise.then(action(pdf => this._pdf = pdf)); } } diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 56212a773..30c51d9ca 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -262,7 +262,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent this._showCover = this._showWaiting = false)); - const pdfLinkService = new PDFJSViewer.PDFLinkService(); + const pdfLinkService = new PDFJSViewer.PDFLinkService({ eventBus }); const pdfFindController = new PDFJSViewer.PDFFindController({ linkService: pdfLinkService, eventBus }); this._pdfViewer = new PDFJSViewer.PDFViewer({ container: this._mainCont.current, @@ -392,7 +392,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent { if (clear) { - this._pdfViewer.findController.executeCommand('reset', {}); + this._pdfViewer.findController.executeCommand('reset', { query: "" }); } else if (!searchString) { fwd ? this.nextAnnotation() : this.prevAnnotation(); } else if (this._pdfViewer.pageViewsReady) { -- cgit v1.2.3-70-g09d2 From 4cc4f636fdf020e001c78a58b771032f94396fa1 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 20 Jul 2020 17:19:23 -0400 Subject: fixed active flag for pdfs --- src/client/views/pdf/PDFMenu.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client/views/pdf') diff --git a/src/client/views/pdf/PDFMenu.tsx b/src/client/views/pdf/PDFMenu.tsx index 00c56d73e..6592c488b 100644 --- a/src/client/views/pdf/PDFMenu.tsx +++ b/src/client/views/pdf/PDFMenu.tsx @@ -47,7 +47,7 @@ export default class PDFMenu extends AntimodeMenu { public AddTag: (key: string, value: string) => boolean = returnFalse; public PinToPres: () => void = unimplementedFunction; public Marquee: { left: number; top: number; width: number; height: number; } | undefined; - public get Active() { return this._opacity ? true : false; } + public get Active() { return this._left > 0; } constructor(props: Readonly<{}>) { super(props); -- cgit v1.2.3-70-g09d2 From 49fcb0f6613344fb62db618c0b466c6155c20eb0 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik 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/pdf') 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 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/pdf') 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 From 622ba99eff99f9af2e03c3a5f8a47e9ce95cdf7e Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 27 Jul 2020 23:46:22 -0400 Subject: removed pdf menu pin button. tried to improve performance by computin links in document view. --- src/client/views/DocumentButtonBar.tsx | 4 ++-- src/client/views/DocumentDecorations.tsx | 2 +- src/client/views/nodes/DocumentLinksButton.tsx | 24 +++++++++++++----------- src/client/views/nodes/DocumentView.tsx | 15 +++++++++------ src/client/views/pdf/PDFMenu.tsx | 7 ------- src/fields/documentSchemas.ts | 1 + 6 files changed, 26 insertions(+), 27 deletions(-) (limited to 'src/client/views/pdf') diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index c99034d81..6b85616c2 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -276,10 +276,10 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV const considerPush = isText && this.considerGoogleDocsPush; return
- +
{DocumentLinksButton.StartLink ?
- +
: null}
{this.templateButton} diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 9a4df926c..4257ec3c9 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -88,7 +88,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> const transform = (documentView.props.ScreenToLocalTransform().scale(documentView.props.ContentScaling())).inverse(); var [sptX, sptY] = transform.transformPoint(0, 0); let [bptX, bptY] = transform.transformPoint(documentView.props.PanelWidth(), documentView.props.PanelHeight()); - if (documentView.props.Document.type === DocumentType.LINK) { + if (StrCast(Doc.Layout(documentView.props.Document).layout).includes("LinkAnchorBox")) { const docuBox = documentView.ContentDiv.getElementsByClassName("linkAnchorBox-cont"); if (docuBox.length) { const rect = docuBox[0].getBoundingClientRect(); diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx index c9d23ff3a..ddfa77967 100644 --- a/src/client/views/nodes/DocumentLinksButton.tsx +++ b/src/client/views/nodes/DocumentLinksButton.tsx @@ -1,19 +1,19 @@ +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { Tooltip } from "@material-ui/core"; import { action, computed, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; -import { Doc, DocListCast } from "../../../fields/Doc"; -import { emptyFunction, setupMoveUpEvents, returnFalse } from "../../../Utils"; +import { Doc } from "../../../fields/Doc"; +import { TraceMobx } from "../../../fields/util"; +import { emptyFunction, returnFalse, setupMoveUpEvents } from "../../../Utils"; +import { DocUtils } from "../../documents/Documents"; import { DragManager } from "../../util/DragManager"; -import { UndoManager, undoBatch } from "../../util/UndoManager"; +import { LinkManager } from "../../util/LinkManager"; +import { undoBatch, UndoManager } from "../../util/UndoManager"; import './DocumentLinksButton.scss'; import { DocumentView } from "./DocumentView"; -import React = require("react"); -import { DocUtils } from "../../documents/Documents"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { LinkDocPreview } from "./LinkDocPreview"; -import { TaskCompletionBox } from "./TaskCompletedBox"; import { LinkDescriptionPopup } from "./LinkDescriptionPopup"; -import { LinkManager } from "../../util/LinkManager"; -import { Tooltip } from "@material-ui/core"; +import { TaskCompletionBox } from "./TaskCompletedBox"; +import React = require("react"); const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -24,6 +24,7 @@ interface DocumentLinksButtonProps { AlwaysOn?: boolean; InMenu?: boolean; StartLink?: boolean; + links: Doc[]; } @observer export class DocumentLinksButton extends React.Component { @@ -158,7 +159,8 @@ export class DocumentLinksButton extends React.Component(Docu const alias = Doc.MakeAlias(this.props.Document); DocUtils.makeCustomViewClicked(alias, undefined, "onClick"); this.props.addDocTab(alias, "onRight"); - } else if (this.props.Document.links && this.Document.isLinkButton && !e.shiftKey && !e.ctrlKey) { - DocListCast(this.props.Document.links).length && this.followLinkClick(e.altKey, e.ctrlKey, e.shiftKey); + } else if (this.allLinks && this.Document.isLinkButton && !e.shiftKey && !e.ctrlKey) { + this.allLinks.length && this.followLinkClick(e.altKey, e.ctrlKey, e.shiftKey); } else { if ((this.layoutDoc.onDragStart || (this.props.Document.rootDocument)) && !(e.ctrlKey || e.button > 0)) { // onDragStart implies a button doc that we don't want to select when clicking. RootDocument & isTEmplaetForField implies we're clicking on part of a template instance and we want to select the whole template, not the part stopPropagate = false; // don't stop propagation for field templates -- want the selection to propagate up to the root document of the template @@ -683,7 +683,7 @@ export class DocumentView extends DocComponent(Docu @undoBatch @action makeIntoPortal = async () => { - const portalLink = DocListCast(this.Document.links).find(d => d.anchor1 === this.props.Document); + const portalLink = this.allLinks.find(d => d.anchor1 === this.props.Document); if (!portalLink) { const portal = Docs.Create.FreeformDocument([], { _width: NumCast(this.layoutDoc._width) + 10, _height: NumCast(this.layoutDoc._height), title: StrCast(this.props.Document.title) + ".portal" }); DocUtils.MakeLink({ doc: this.props.Document }, { doc: portal }, "portal to"); @@ -1038,6 +1038,7 @@ export class DocumentView extends DocComponent(Docu return this.isSelected(outsideReaction) || (this.props.Document.rootDocument && this.props.rootSelected?.(outsideReaction)) || false; } childScaling = () => (this.layoutDoc._fitWidth ? this.props.PanelWidth() / this.nativeWidth : this.props.ContentScaling()); + @computed.struct get linkOffset() { return [-15, 0]; } @computed get contents() { TraceMobx(); return (
@@ -1081,7 +1082,7 @@ export class DocumentView extends DocComponent(Docu {this.layoutDoc.hideAllLinks ? (null) : this.allAnchors} {/* {this.allAnchors} */} {this.props.forcedBackgroundColor?.(this.Document) === "transparent" || this.layoutDoc.isLinkButton || this.layoutDoc.hideLinkButton || this.props.dontRegisterView ? (null) : - } + }
); } @@ -1104,13 +1105,15 @@ export class DocumentView extends DocComponent(Docu anchorPanelWidth = () => this.props.PanelWidth() || 1; anchorPanelHeight = () => this.props.PanelHeight() || 1; - @computed get allAnchors() { + @computed.struct get directLinks() { return LinkManager.Instance.getAllDirectLinks(this.Document); } + @computed.struct get allLinks() { return DocListCast(this.Document.links); } + @computed.struct get allAnchors() { TraceMobx(); if (this.props.LayoutTemplateString?.includes("LinkAnchorBox")) return null; return (this.props.treeViewDoc && this.props.LayoutTemplateString) || // render nothing for: tree view anchor dots this.layoutDoc.presBox || // presentationbox nodes this.props.dontRegisterView ? (null) : // view that are not registered - DocUtils.FilterDocs(LinkManager.Instance.getAllDirectLinks(this.Document), this.props.docFilters(), []).filter(d => !d.hidden && this.isNonTemporalLink).map((d, i) => + DocUtils.FilterDocs(this.directLinks, this.props.docFilters(), []).filter(d => !d.hidden && this.isNonTemporalLink).map((d, i) => { - this.Pinned = !this.Pinned; - !this.Pinned && (this.Highlighting = false); - }); - @action highlightClicked = (e: React.MouseEvent) => { if (!this.Highlight(this.highlightColor) && this.Pinned) { @@ -161,8 +156,6 @@ export default class PDFMenu extends AntimodeMenu { this.highlighter, , - , ] : [ , diff --git a/src/fields/documentSchemas.ts b/src/fields/documentSchemas.ts index ddffb56c3..8cf8f47b7 100644 --- a/src/fields/documentSchemas.ts +++ b/src/fields/documentSchemas.ts @@ -90,6 +90,7 @@ export const documentSchema = createSchema({ followLinkLocation: "string",// flag for where to place content when following a click interaction (e.g., onRight, inPlace, inTab, ) hideLinkButton: "boolean", // whether the blue link counter button should be hidden hideAllLinks: "boolean", // whether all individual blue anchor dots should be hidden + linkDisplay: "boolean", // whether a link connection should be shown between link anchor endpoints. isInPlaceContainer: "boolean",// whether the marked object will display addDocTab() calls that target "inPlace" destinations isLinkButton: "boolean", // whether document functions as a link follow button to follow the first link on the document when clicked isBackground: "boolean", // whether document is a background element and ignores input events (can only select with marquee) -- cgit v1.2.3-70-g09d2