From e8e713173e93eaa9fc2d2865d5efabdcca51b1f3 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 14 Oct 2019 19:00:40 -0400 Subject: fixed some minor layout issues with flyout and masonry views --- src/client/views/MainView.scss | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src/client/views/MainView.scss') diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss index e61494e71..21b135c49 100644 --- a/src/client/views/MainView.scss +++ b/src/client/views/MainView.scss @@ -33,7 +33,6 @@ position: absolute; width:100%; height:100%; - border: black 1px solid; .documentView-node-topmost { background: lightgrey; } @@ -63,8 +62,8 @@ .mainView-expandFlyoutButton { position: absolute; - top: 30px; - right: 30px; + top: 5px; + right: 5px; cursor: pointer; } -- cgit v1.2.3-70-g09d2 From aad42660123c227cbe2152fbbbc159f6a38fca17 Mon Sep 17 00:00:00 2001 From: Stanley Yip Date: Tue, 15 Oct 2019 16:29:08 -0400 Subject: library flyout changes --- src/client/views/MainView.scss | 24 +++++++++++++++--------- src/client/views/MainView.tsx | 24 +++++++++++++----------- 2 files changed, 28 insertions(+), 20 deletions(-) (limited to 'src/client/views/MainView.scss') diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss index e61494e71..851818099 100644 --- a/src/client/views/MainView.scss +++ b/src/client/views/MainView.scss @@ -4,8 +4,9 @@ .mainView-tabButtons { position: relative; - width:100%; + width: 100%; } + // add nodes menu. Note that the + button is actually an input label, not an actual button. .mainView-docButtons { position: absolute; @@ -22,22 +23,26 @@ overflow: auto; z-index: 1; } + .mainView-mainContent { - width:100%; - height:100%; - position:absolute; + width: 100%; + height: 100%; + position: absolute; } -.mainView-flyoutContainer{ - display:flex; + +.mainView-flyoutContainer { + display: flex; flex-direction: column; position: absolute; - width:100%; - height:100%; + width: 100%; + height: 100%; border: black 1px solid; + .documentView-node-topmost { background: lightgrey; } } + .mainView-mainDiv { width: 100%; height: 100%; @@ -63,7 +68,7 @@ .mainView-expandFlyoutButton { position: absolute; - top: 30px; + top: 100px; right: 30px; cursor: pointer; } @@ -76,6 +81,7 @@ border-radius: 5px; position: absolute; z-index: 1; + touch-action: none; } .mainView-workspace { diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index b329717c4..dd4e07165 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -287,13 +287,15 @@ export class MainView extends React.Component { } onPointerDown = (e: React.PointerEvent) => { - this._flyoutSizeOnDown = e.clientX; - document.removeEventListener("pointermove", this.onPointerMove); - document.removeEventListener("pointerup", this.onPointerUp); - document.addEventListener("pointermove", this.onPointerMove); - document.addEventListener("pointerup", this.onPointerUp); - e.stopPropagation(); - e.preventDefault(); + if (this._flyoutTranslate) { + this._flyoutSizeOnDown = e.clientX; + document.removeEventListener("pointermove", this.onPointerMove); + document.removeEventListener("pointerup", this.onPointerUp); + document.addEventListener("pointermove", this.onPointerMove); + document.addEventListener("pointerup", this.onPointerUp); + e.stopPropagation(); + e.preventDefault(); + } } @action @@ -412,10 +414,10 @@ export class MainView extends React.Component { style={{ cursor: "ew-resize", left: `${(this.flyoutWidth * (this._flyoutTranslate ? 1 : 0)) - 10}px`, backgroundColor: `${StrCast(sidebar.backgroundColor, "lightGray")}` }} onPointerDown={this.onPointerDown} onPointerOver={this.pointerOverDragger}>
Date: Tue, 15 Oct 2019 17:29:57 -0400 Subject: good enough for stanley to start texting i think --- src/client/views/DocComponent.tsx | 7 +-- src/client/views/Main.scss | 2 +- src/client/views/MainView.scss | 11 ---- .../views/collections/CollectionDockingView.scss | 69 ++++++++++++++++++++-- .../views/collections/CollectionDockingView.tsx | 20 ++++--- .../collections/collectionFreeForm/MarqueeView.tsx | 4 +- 6 files changed, 79 insertions(+), 34 deletions(-) (limited to 'src/client/views/MainView.scss') diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index 9d7c06750..94717352e 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -7,18 +7,13 @@ import { listSpec } from '../../new_fields/Schema'; import { InkingControl } from './InkingControl'; import { InkTool } from '../../new_fields/InkField'; -<<<<<<< HEAD -export function DocComponent

(schemaCtor: (doc: Doc) => T) { - class Component extends Touchable

{ -======= /// DocComponents returns a generic base class for React views of document fields that are not interactive interface DocComponentProps { Document: Doc; } export function DocComponent

(schemaCtor: (doc: Doc) => T) { - class Component extends React.Component

{ ->>>>>>> 33811c112c7e479813908ba10f72813954a3e289 + class Component extends Touchable

{ //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then @computed get Document(): T { diff --git a/src/client/views/Main.scss b/src/client/views/Main.scss index 0335e12a5..4a174f8c7 100644 --- a/src/client/views/Main.scss +++ b/src/client/views/Main.scss @@ -36,7 +36,7 @@ p { ::-webkit-scrollbar { -webkit-appearance: none; height: 8px; - width: 8px; + width: 20px; } ::-webkit-scrollbar-thumb { diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss index a6b28f488..25af67161 100644 --- a/src/client/views/MainView.scss +++ b/src/client/views/MainView.scss @@ -34,15 +34,9 @@ display: flex; flex-direction: column; position: absolute; -<<<<<<< HEAD width: 100%; height: 100%; - border: black 1px solid; -======= - width:100%; - height:100%; ->>>>>>> 33811c112c7e479813908ba10f72813954a3e289 .documentView-node-topmost { background: lightgrey; } @@ -73,13 +67,8 @@ .mainView-expandFlyoutButton { position: absolute; -<<<<<<< HEAD top: 100px; right: 30px; -======= - top: 5px; - right: 5px; ->>>>>>> 33811c112c7e479813908ba10f72813954a3e289 cursor: pointer; } diff --git a/src/client/views/collections/CollectionDockingView.scss b/src/client/views/collections/CollectionDockingView.scss index 6f5abd05b..b4ab8d550 100644 --- a/src/client/views/collections/CollectionDockingView.scss +++ b/src/client/views/collections/CollectionDockingView.scss @@ -1,12 +1,13 @@ @import "../../views/globalCssVariables.scss"; -.lm_active .messageCounter{ - color:white; +.lm_active .messageCounter { + color: white; background: #999999; } + .messageCounter { - width:18px; - height:20px; + width: 18px; + height: 20px; text-align: center; border-radius: 20px; margin-left: 5px; @@ -18,22 +19,29 @@ .collectiondockingview-container { width: 100%; - height:100%; + height: 100%; border-style: solid; border-width: $COLLECTION_BORDER_WIDTH; position: absolute; top: 0; left: 0; overflow: hidden; + + .collectionDockingView-dragAsDocument { + touch-action: none; + } + .lm_controls>li { opacity: 0.6; transform: scale(1.2); } + .lm_maximised .lm_controls .lm_maximise { opacity: 1; transform: scale(0.8); background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAKElEQVR4nGP8////fwYCgImQAgYGBgYWKM2IR81/okwajIpgvsMbVgAwgQYRVakEKQAAAABJRU5ErkJggg==) !important; } + .flexlayout__layout { left: 0; top: 0; @@ -42,17 +50,21 @@ position: absolute; overflow: hidden; } + .flexlayout__splitter { background-color: black; } + .flexlayout__splitter:hover { background-color: #333; } + .flexlayout__splitter_drag { border-radius: 5px; background-color: #444; z-index: 1000; } + .flexlayout__outline_rect { position: absolute; cursor: move; @@ -62,6 +74,7 @@ z-index: 1000; box-sizing: border-box; } + .flexlayout__outline_rect_edge { cursor: move; border: 2px solid #b7d1b5; @@ -70,12 +83,14 @@ z-index: 1000; box-sizing: border-box; } + .flexlayout__edge_rect { position: absolute; z-index: 1000; box-shadow: inset 0 0 5px rgba(0, 0, 0, .2); background-color: lightgray; } + .flexlayout__drag_rect { position: absolute; cursor: move; @@ -94,11 +109,13 @@ padding: 10px; word-wrap: break-word; } + .flexlayout__tabset { overflow: hidden; background-color: #222; box-sizing: border-box; } + .flexlayout__tab { overflow: auto; position: absolute; @@ -106,6 +123,7 @@ background-color: #222; color: black; } + .flexlayout__tab_button { cursor: pointer; padding: 2px 8px 3px 8px; @@ -117,28 +135,35 @@ vertical-align: top; box-sizing: border-box; } + .flexlayout__tab_button--selected { color: #ddd; background-color: #222; } + .flexlayout__tab_button--unselected { color: gray; } + .flexlayout__tab_button_leading { display: inline-block; } + .flexlayout__tab_button_content { display: inline-block; } + .flexlayout__tab_button_textbox { float: left; border: none; color: lightgreen; background-color: #222; } + .flexlayout__tab_button_textbox:focus { outline: none; } + .flexlayout__tab_button_trailing { display: inline-block; margin-left: 5px; @@ -146,10 +171,12 @@ width: 8px; height: 8px; } + .flexlayout__tab_button:hover .flexlayout__tab_button_trailing, .flexlayout__tab_button--selected .flexlayout__tab_button_trailing { background: transparent url("../../../../node_modules/flexlayout-react/images/close_white.png") no-repeat center; } + .flexlayout__tab_button_overflow { float: left; width: 20px; @@ -162,6 +189,7 @@ font-family: Arial, sans-serif; background: transparent url("../../../../node_modules/flexlayout-react/images/more.png") no-repeat left; } + .flexlayout__tabset_header { position: absolute; left: 0; @@ -172,6 +200,7 @@ /*box-shadow: inset 0px 0px 3px 0px rgba(136, 136, 136, 0.54);*/ box-sizing: border-box; } + .flexlayout__tab_header_inner { position: absolute; left: 0; @@ -179,6 +208,7 @@ bottom: 0; width: 10000px; } + .flexlayout__tab_header_outer { background-color: black; position: absolute; @@ -188,12 +218,15 @@ /*height: 100px;*/ overflow: hidden; } + .flexlayout__tabset-selected { background-image: linear-gradient(#111, #444); } + .flexlayout__tabset-maximized { background-image: linear-gradient(#666, #333); } + .flexlayout__tab_toolbar { position: absolute; display: flex; @@ -203,6 +236,7 @@ bottom: 0; right: 0; } + .flexlayout__tab_toolbar_button-min { width: 20px; height: 20px; @@ -210,6 +244,7 @@ outline-width: 0; background: transparent url("../../../../node_modules/flexlayout-react/images/maximize.png") no-repeat center; } + .flexlayout__tab_toolbar_button-max { width: 20px; height: 20px; @@ -217,14 +252,18 @@ outline-width: 0; background: transparent url("../../../../node_modules/flexlayout-react/images/restore.png") no-repeat center; } + .flexlayout__popup_menu {} + .flexlayout__popup_menu_item { padding: 2px 10px 2px 10px; color: #ddd; } + .flexlayout__popup_menu_item:hover { background-color: #444444; } + .flexlayout__popup_menu_container { box-shadow: inset 0 0 5px rgba(0, 0, 0, .15); border: 1px solid #555; @@ -233,33 +272,39 @@ position: absolute; z-index: 1000; } + .flexlayout__border_top { background-color: black; border-bottom: 1px solid #ddd; box-sizing: border-box; overflow: hidden; } + .flexlayout__border_bottom { background-color: black; border-top: 1px solid #333; box-sizing: border-box; overflow: hidden; } + .flexlayout__border_left { background-color: black; border-right: 1px solid #333; box-sizing: border-box; overflow: hidden; } + .flexlayout__border_right { background-color: black; border-left: 1px solid #333; box-sizing: border-box; overflow: hidden; } + .flexlayout__border_inner_bottom { display: flex; } + .flexlayout__border_inner_left { position: absolute; white-space: nowrap; @@ -267,6 +312,7 @@ transform-origin: top right; transform: rotate(-90deg); } + .flexlayout__border_inner_right { position: absolute; white-space: nowrap; @@ -274,6 +320,7 @@ transform-origin: top left; transform: rotate(90deg); } + .flexlayout__border_button { background-color: #222; color: white; @@ -285,29 +332,36 @@ vertical-align: top; box-sizing: border-box; } + .flexlayout__border_button--selected { color: #ddd; background-color: #222; } + .flexlayout__border_button--unselected { color: gray; } + .flexlayout__border_button_leading { float: left; display: inline; } + .flexlayout__border_button_content { display: inline-block; } + .flexlayout__border_button_textbox { float: left; border: none; color: green; background-color: #ddd; } + .flexlayout__border_button_textbox:focus { outline: none; } + .flexlayout__border_button_trailing { display: inline-block; margin-left: 5px; @@ -315,10 +369,12 @@ width: 8px; height: 8px; } + .flexlayout__border_button:hover .flexlayout__border_button_trailing, .flexlayout__border_button--selected .flexlayout__border_button_trailing { background: transparent url("../../../../node_modules/flexlayout-react/images/close_white.png") no-repeat center; } + .flexlayout__border_toolbar_left { position: absolute; display: flex; @@ -328,6 +384,7 @@ left: 0; right: 0; } + .flexlayout__border_toolbar_right { position: absolute; display: flex; @@ -337,6 +394,7 @@ left: 0; right: 0; } + .flexlayout__border_toolbar_top { position: absolute; display: flex; @@ -346,6 +404,7 @@ bottom: 0; right: 0; } + .flexlayout__border_toolbar_bottom { position: absolute; display: flex; diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 1f78c8c97..5e00fda36 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -426,15 +426,17 @@ export class CollectionDockingView extends React.Component { - e.preventDefault(); - e.stopPropagation(); - DragManager.StartDocumentDrag([dragSpan], new DragManager.DocumentDragData([doc]), e.clientX, e.clientY, { - handlers: { dragComplete: emptyFunction }, - hideSource: false - }); - }}>, dragSpan); + ReactDOM.render( { + e.preventDefault(); + e.stopPropagation(); + DragManager.StartDocumentDrag([dragSpan], new DragManager.DocumentDragData([doc]), e.clientX, e.clientY, { + handlers: { dragComplete: emptyFunction }, + hideSource: false + }); + }}>, dragSpan); ReactDOM.render(, gearSpan); // ReactDOM.render( { // where === "onRight" ? CollectionDockingView.AddRightSplit(doc, dataDoc) : CollectionDockingView.Instance.AddTab(stack, doc, dataDoc); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index e9f4c40a6..07db6354f 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -198,7 +198,7 @@ export class MarqueeView extends React.Component } this.props.selectDocuments(mselect.length ? mselect : [this.props.container.props.Document]); } - if (!this._commandExecuted) { + if (!this._commandExecuted && (Math.abs(this.Bounds.height * this.Bounds.width) > 100)) { MarqueeOptionsMenu.Instance.createCollection = this.collection; MarqueeOptionsMenu.Instance.delete = this.delete; MarqueeOptionsMenu.Instance.summarize = this.summary; @@ -213,7 +213,7 @@ export class MarqueeView extends React.Component MarqueeOptionsMenu.Instance.fadeOut(true); document.removeEventListener("pointerdown", hideMarquee); } - document.addEventListener("pointerdown", hideMarquee) + document.addEventListener("pointerdown", hideMarquee); if (e.altKey) { e.preventDefault(); -- cgit v1.2.3-70-g09d2 From d7150995d62c498ab8435de986b90d98bdca020c Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 12 Nov 2019 15:07:03 -0500 Subject: a bunch of cleanup and bug fixes to text links and doculink buttons --- src/client/documents/Documents.ts | 5 +- src/client/util/LinkManager.ts | 2 - src/client/util/RichTextSchema.tsx | 4 +- src/client/util/TooltipTextMenu.tsx | 23 +++--- src/client/views/DocumentDecorations.tsx | 10 ++- src/client/views/GlobalKeyHandler.ts | 2 +- src/client/views/Main.tsx | 24 ------- src/client/views/MainView.scss | 2 +- src/client/views/MainView.tsx | 8 +-- src/client/views/linking/LinkMenuItem.tsx | 1 - src/client/views/nodes/FormattedTextBox.tsx | 9 ++- src/client/views/nodes/FormattedTextBoxComment.tsx | 83 ++++++++++++---------- src/client/views/nodes/PDFBox.scss | 2 + src/client/views/nodes/PDFBox.tsx | 76 +++++++++++--------- src/client/views/pdf/Annotation.tsx | 6 +- src/client/views/pdf/PDFViewer.tsx | 14 +--- src/new_fields/Doc.ts | 2 +- .../authentication/models/current_user_utils.ts | 1 - 18 files changed, 127 insertions(+), 147 deletions(-) (limited to 'src/client/views/MainView.scss') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index d1fcabc4a..ba9f87025 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -257,6 +257,9 @@ export namespace Docs { return PrototypeMap.get(type)!; } + /** + * A collection of all links in the database. Ideally, this would be a search, but for now all links are cached here. + */ export function MainLinkDocument() { return Prototypes.get(DocumentType.LINKDOC); } @@ -703,6 +706,7 @@ export namespace DocUtils { linkDocProto.title = title === "" ? source.doc.title + " to " + target.doc.title : title; linkDocProto.linkDescription = description; + linkDocProto.isPrototype = true; linkDocProto.anchor1 = source.doc; linkDocProto.anchor2 = target.doc; @@ -714,7 +718,6 @@ export namespace DocUtils { linkDocProto.anchor2Timecode = target.doc.currentTimecode; linkDocProto.layoutKey1 = DocuLinkBox.LayoutString("anchor1"); linkDocProto.layoutKey2 = DocuLinkBox.LayoutString("anchor2"); - linkDocProto.borderRounding = "20"; linkDocProto.width = linkDocProto.height = 0; linkDocProto.isBackground = true; linkDocProto.isButton = true; diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts index ee2f2dadc..eedc4967d 100644 --- a/src/client/util/LinkManager.ts +++ b/src/client/util/LinkManager.ts @@ -34,8 +34,6 @@ export class LinkManager { // the linkmanagerdoc stores a list of docs representing all linkdocs in 'allLinks' and a list of strings representing all group types in 'allGroupTypes' // lists of strings representing the metadata keys for each group type is stored under a key that is the same as the group type public get LinkManagerDoc(): Doc | undefined { - // return FieldValue(Cast(CurrentUserUtils.UserDocument.linkManagerDoc, Doc)); - return Docs.Prototypes.MainLinkDocument(); } diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index a5e0ca720..76b8aeaa1 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -305,8 +305,8 @@ export const marks: { [index: string]: MarkSpec } = { }], toDOM(node: any) { return node.attrs.docref && node.attrs.title ? - ["div", ["span", `"`], ["span", 0], ["span", `"`], ["br"], ["a", { ...node.attrs, class: "prosemirror-attribution" }, node.attrs.title], ["br"]] : - ["a", { ...node.attrs }, 0]; + ["div", ["span", `"`], ["span", 0], ["span", `"`], ["br"], ["a", { ...node.attrs, class: "prosemirror-attribution", title: `${node.attrs.title}` }, node.attrs.title], ["br"]] : + ["a", { ...node.attrs, title: `${node.attrs.title}` }, 0]; } }, diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 9ce7acec8..38471a955 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -17,7 +17,7 @@ import { DragManager } from "./DragManager"; import { LinkManager } from "./LinkManager"; import { schema } from "./RichTextSchema"; import "./TooltipTextMenu.scss"; -import { Cast, NumCast } from '../../new_fields/Types'; +import { Cast, NumCast, StrCast } from '../../new_fields/Types'; import { updateBullets } from './ProsemirrorExampleTransfer'; import { DocumentDecorations } from '../views/DocumentDecorations'; const { toggleMark, setBlockType } = require("prosemirror-commands"); @@ -284,7 +284,7 @@ export class TooltipTextMenu { if (proto && docView) { proto.sourceContext = docView.props.ContainingCollectionDoc; } - let text = this.makeLink(linkDoc, ctrlKey ? "onRight" : "inTab"); + let text = this.makeLink(linkDoc, StrCast(linkDoc.anchor2.title), ctrlKey ? "onRight" : "inTab"); if (linkDoc instanceof Doc && linkDoc.anchor2 instanceof Doc) { proto.title = text === "" ? proto.title : text + " to " + linkDoc.anchor2.title; // TODODO open to more descriptive descriptions of following in text link } @@ -374,25 +374,20 @@ export class TooltipTextMenu { // let link = state.schema.mark(state.schema.marks.link, { href: target, location: location }); // } - makeLink = (targetDoc: Doc, location: string): string => { - let target = Utils.prepend("/doc/" + targetDoc[Id]); + makeLink = (targetDoc: Doc, title: string, location: string): string => { + let link = this.view.state.schema.marks.link.create({ href: Utils.prepend("/doc/" + targetDoc[Id]), title: title, location: location }); + this.view.dispatch(this.view.state.tr.removeMark(this.view.state.selection.from, this.view.state.selection.to, this.view.state.schema.marks.link). + addMark(this.view.state.selection.from, this.view.state.selection.to, link)); let node = this.view.state.selection.$from.nodeAfter; - let link = this.view.state.schema.mark(this.view.state.schema.marks.link, { href: target, location: location, guid: targetDoc[Id] }); - this.view.dispatch(this.view.state.tr.removeMark(this.view.state.selection.from, this.view.state.selection.to, this.view.state.schema.marks.link)); - this.view.dispatch(this.view.state.tr.addMark(this.view.state.selection.from, this.view.state.selection.to, link)); - node = this.view.state.selection.$from.nodeAfter; - link = node && node.marks.find(m => m.type.name === "link"); - if (node) { - if (node.text) { - return node.text; - } + if (node && node.text) { + return node.text; } return ""; } deleteLink = () => { let node = this.view.state.selection.$from.nodeAfter; - let link = node && node.marks.find(m => m.type.name === "link"); + let link = node && node.marks.find(m => m.type === this.view.state.schema.marks.link); let href = link!.attrs.href; if (href) { if (href.indexOf(Utils.prepend("/doc/")) === 0) { diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 0336440d5..55c211d1d 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -24,6 +24,7 @@ import { DocumentView } from "./nodes/DocumentView"; import { FieldView } from "./nodes/FieldView"; import { IconBox } from "./nodes/IconBox"; import React = require("react"); +import { DocumentType } from '../documents/DocumentTypes'; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -112,7 +113,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> } else { if (SelectionManager.SelectedDocuments().length > 0) { - SelectionManager.SelectedDocuments()[0].props.Document.customTitle = true; + SelectionManager.SelectedDocuments()[0].props.Document.customTitle = !this._title.startsWith("-"); let field = SelectionManager.SelectedDocuments()[0].props.Document[this._fieldKey]; if (typeof field === "number") { SelectionManager.SelectedDocuments().forEach(d => { @@ -174,6 +175,13 @@ 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) { + let rect = documentView.ContentDiv!.getElementsByClassName("docuLinkBox-cont")[0].getBoundingClientRect(); + sptX = rect.left; + sptY = rect.top; + bptX = rect.right; + bptY = rect.bottom; + } return { x: Math.min(sptX, bounds.x), y: Math.min(sptY, bounds.y), r: Math.max(bptX, bounds.r), b: Math.max(bptY, bounds.b) diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index 9ca9fc163..8f397e331 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -165,7 +165,7 @@ export default class KeyManager { } } break; - case "c": + case "t": PromiseValue(Cast(CurrentUserUtils.UserDocument.Create, Doc)).then(pv => pv && (pv.onClick as ScriptField).script.run({ this: pv })); if (MainView.Instance.flyoutWidth === 240) { MainView.Instance.flyoutWidth = 0; diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index a91a2b69e..b21eb9c8f 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -3,34 +3,11 @@ import { Docs } from "../documents/Documents"; import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils"; import * as ReactDOM from 'react-dom'; import * as React from 'react'; -import { Cast } from "../../new_fields/Types"; -import { Doc, DocListCastAsync } from "../../new_fields/Doc"; -import { List } from "../../new_fields/List"; import { DocServer } from "../DocServer"; import { AssignAllExtensions } from "../../extensions/General/Extensions"; AssignAllExtensions(); -let swapDocs = async () => { - let oldDoc = await Cast(CurrentUserUtils.UserDocument.linkManagerDoc, Doc); - // Docs.Prototypes.MainLinkDocument().allLinks = new List(); - if (oldDoc) { - let links = await DocListCastAsync(oldDoc.allLinks); - // if (links && DocListCast(links)) { - if (links && links.length) { - let data = await DocListCastAsync(Docs.Prototypes.MainLinkDocument().allLinks); - if (data) { - data.push(...links.filter(i => data!.indexOf(i) === -1)); - Docs.Prototypes.MainLinkDocument().allLinks = new List(data.filter((i, idx) => data!.indexOf(i) === idx)); - } - else { - Docs.Prototypes.MainLinkDocument().allLinks = new List(links); - } - } - CurrentUserUtils.UserDocument.linkManagerDoc = undefined; - } -}; - (async () => { const info = await CurrentUserUtils.loadCurrentUser(); DocServer.init(window.location.protocol, window.location.hostname, 4321, info.email); @@ -38,7 +15,6 @@ let swapDocs = async () => { if (info.id !== "__guest__") { // a guest will not have an id registered await CurrentUserUtils.loadUserDocument(info); - await swapDocs(); } document.getElementById('root')!.addEventListener('wheel', event => { if (event.ctrlKey) { diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss index 21b135c49..a858a73c7 100644 --- a/src/client/views/MainView.scss +++ b/src/client/views/MainView.scss @@ -13,7 +13,7 @@ left: 250px; } -.mainView-container { +#mainView-container { width: 100%; height: 100%; position: absolute; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 773da05df..83dbb433b 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -37,7 +37,6 @@ import { OverlayView } from './OverlayView'; import PDFMenu from './pdf/PDFMenu'; import { PreviewCursor } from './PreviewCursor'; import { Scripting } from '../util/Scripting'; -import { LinkManager } from '../util/LinkManager'; import { AudioBox } from './nodes/AudioBox'; @observer @@ -197,11 +196,6 @@ export class MainView extends React.Component { var dockingLayout = { content: [{ type: 'row', content: [CollectionDockingView.makeDocumentConfig(freeformDoc, freeformDoc, 600)] }] }; let mainDoc = Docs.Create.DockDocument([freeformDoc], JSON.stringify(dockingLayout), {}, id); if (this.userDoc && ((workspaces = Cast(this.userDoc.workspaces, Doc)) instanceof Doc)) { - if (!this.userDoc.linkManagerDoc) { - let linkManagerDoc = new Doc(); - linkManagerDoc.allLinks = new List([]); - this.userDoc.linkManagerDoc = linkManagerDoc; - } Doc.AddDocToList(workspaces, "data", mainDoc); mainDoc.title = `Workspace ${DocListCast(workspaces.data).length}`; } @@ -504,7 +498,7 @@ export class MainView extends React.Component { } render() { - return (

+ return (
diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx index a6ee9c2c6..238660de3 100644 --- a/src/client/views/linking/LinkMenuItem.tsx +++ b/src/client/views/linking/LinkMenuItem.tsx @@ -8,7 +8,6 @@ import { Cast, StrCast } from '../../../new_fields/Types'; import { DragLinkAsDocument } from '../../util/DragManager'; import { LinkManager } from '../../util/LinkManager'; import { ContextMenu } from '../ContextMenu'; -import { MainView } from '../MainView'; import { LinkFollowBox } from './LinkFollowBox'; import './LinkMenu.scss'; import React = require("react"); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index abf26826c..a0f8523a2 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -842,6 +842,7 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F this._editorView && this._editorView.destroy(); } onPointerDown = (e: React.PointerEvent): void => { + FormattedTextBoxComment.textBox = this; let pos = this._editorView!.posAtCoords({ left: e.clientX, top: e.clientY }); pos && (this._nodeClicked = this._editorView!.state.doc.nodeAt(pos.pos)); if (this.props.onClick && e.button === 0) { @@ -1018,11 +1019,13 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F } render() { + trace(); let rounded = StrCast(this.layoutDoc.borderRounding) === "100%" ? "-rounded" : ""; - let interactive: "all" | "none" = InkingControl.Instance.selectedTool || this.layoutDoc.isBackground - ? "none" : "all"; + let interactive = InkingControl.Instance.selectedTool || this.layoutDoc.isBackground; if (this.props.isSelected()) { FormattedTextBox._toolTipTextMenu!.updateFromDash(this._editorView!, undefined, this.props); + } else if (FormattedTextBoxComment.textBox === this) { + FormattedTextBoxComment.Hide(); } return (
{ let keep = e.target && (e.target as any).type === "checkbox" ? true : false; @@ -91,62 +93,67 @@ export class FormattedTextBoxComment { let state = view.state; // Don't do anything if the document/selection didn't change if (lastState && lastState.doc.eq(state.doc) && - lastState.selection.eq(state.selection)) return; + lastState.selection.eq(state.selection)) { + return; + } - if (!FormattedTextBoxComment.textBox || !FormattedTextBoxComment.textBox.props || !FormattedTextBoxComment.textBox.props.isSelected()) return; + const textBox = FormattedTextBoxComment.textBox; + if (!textBox || !textBox.props) { + return; + } let set = "none"; - if (FormattedTextBoxComment.textBox && state.selection.$from) { - let nbef = findStartOfMark(state.selection.$from, view, findOtherUserMark); + let nbef = 0; + // this section checks to see if the insertion point is over text entered by a different user. If so, it sets ths comment text to indicate the user and the modification date + if (state.selection.$from) { + nbef = findStartOfMark(state.selection.$from, view, findOtherUserMark); let naft = findEndOfMark(state.selection.$from, view, findOtherUserMark); - const spos = state.selection.$from.pos - nbef; - const epos = state.selection.$from.pos + naft; - let child = state.selection.$from.nodeBefore; - let mark = child && findOtherUserMark(child.marks); let noselection = view.state.selection.$from === view.state.selection.$to; + let child: any = null; + state.doc.nodesBetween(state.selection.from, state.selection.to, (node: any, pos: number, parent: any) => !child && node.marks.length && (child = node)); + let mark = child && findOtherUserMark(child.marks); if (mark && child && (nbef || naft) && (!mark.attrs.opened || noselection)) { - FormattedTextBoxComment.SetState(this, mark.attrs.opened, spos, epos, mark); + FormattedTextBoxComment.SetState(FormattedTextBoxComment.textBox, mark.attrs.opened, state.selection.$from.pos - nbef, state.selection.$from.pos + naft, mark); } - if (mark && child && nbef && naft) { - FormattedTextBoxComment.tooltipText.textContent = mark.attrs.userid + " " + mark.attrs.modified; - // These are in screen coordinates - // let start = view.coordsAtPos(state.selection.from), end = view.coordsAtPos(state.selection.to); - let start = view.coordsAtPos(state.selection.from - nbef), end = view.coordsAtPos(state.selection.from - nbef); - // The box in which the tooltip is positioned, to use as base - let box = (document.getElementById("main-div") as any).getBoundingClientRect(); - // Find a center-ish x position from the selection endpoints (when - // crossing lines, end may be more to the left) - let left = Math.max((start.left + end.left) / 2, start.left + 3); - FormattedTextBoxComment.tooltip.style.left = (left - box.left) + "px"; - FormattedTextBoxComment.tooltip.style.bottom = (box.bottom - start.top) + "px"; + if (mark && child && ((nbef && naft) || !noselection)) { + FormattedTextBoxComment.tooltipText.textContent = mark.attrs.userid + " date=" + (new Date(mark.attrs.modified * 5000)).toDateString(); set = ""; } } + // this checks if the selection is a hyperlink. If so, it displays the target doc's text for internal links, and the url of the target for external links. if (set === "none" && state.selection.$from) { - FormattedTextBoxComment.textBox = undefined; - let nbef = findStartOfMark(state.selection.$from, view, findLinkMark); + nbef = findStartOfMark(state.selection.$from, view, findLinkMark); let naft = findEndOfMark(state.selection.$from, view, findLinkMark); - let child = state.selection.$from.nodeBefore; + let child: any = null; + state.doc.nodesBetween(state.selection.from, state.selection.to, (node: any, pos: number, parent: any) => !child && node.marks.length && (child = node)); let mark = child && findLinkMark(child.marks); if (mark && child && nbef && naft) { - FormattedTextBoxComment.tooltipText.textContent = "link : " + (mark.attrs.title || mark.attrs.href); + FormattedTextBoxComment.tooltipText.textContent = "external => " + mark.attrs.href; if (mark.attrs.href.indexOf(Utils.prepend("/doc/")) === 0) { let docTarget = mark.attrs.href.replace(Utils.prepend("/doc/"), "").split("?")[0]; - docTarget && DocServer.GetRefField(docTarget).then(linkDoc => - (linkDoc as Doc) && (FormattedTextBoxComment.tooltipText.textContent = "link :" + StrCast((linkDoc as Doc).title))); + docTarget && DocServer.GetRefField(docTarget).then(linkDoc => { + if (linkDoc instanceof Doc) { + let target = FieldValue(Doc.AreProtosEqual(FieldValue(Cast(linkDoc.anchor1, Doc)), textBox.props.Document) ? Cast(linkDoc.anchor2, Doc) : Cast(linkDoc.anchor1, Doc)); + let ext = (target && Doc.fieldExtensionDoc(target, "data")) || target; // try guessing that the target doc's data is in the 'data' field. probably need an 'overviewLayout' and then just display the target Document .... + let text = ext && StrCast(ext.text); + ext && (FormattedTextBoxComment.tooltipText.textContent = "=> " + (text || StrCast(ext.title))); + } + }); } - // These are in screen coordinates - // let start = view.coordsAtPos(state.selection.from), end = view.coordsAtPos(state.selection.to); - let start = view.coordsAtPos(state.selection.from - nbef), end = view.coordsAtPos(state.selection.from - nbef); - // The box in which the tooltip is positioned, to use as base - let box = (document.getElementById("main-div") as any).getBoundingClientRect(); - // Find a center-ish x position from the selection endpoints (when - // crossing lines, end may be more to the left) - let left = Math.max((start.left + end.left) / 2, start.left + 3); - FormattedTextBoxComment.tooltip.style.left = (left - box.left) + "px"; - FormattedTextBoxComment.tooltip.style.bottom = (box.bottom - start.top) + "px"; set = ""; } } + if (set !== "none") { + // These are in screen coordinates + // let start = view.coordsAtPos(state.selection.from), end = view.coordsAtPos(state.selection.to); + let start = view.coordsAtPos(state.selection.from - nbef), end = view.coordsAtPos(state.selection.from - nbef); + // The box in which the tooltip is positioned, to use as base + let box = (document.getElementById("mainView-container") as any).getBoundingClientRect(); + // Find a center-ish x position from the selection endpoints (when + // crossing lines, end may be more to the left) + let left = Math.max((start.left + end.left) / 2, start.left + 3); + FormattedTextBoxComment.tooltip.style.left = (left - box.left) + "px"; + FormattedTextBoxComment.tooltip.style.bottom = (box.bottom - start.top) + "px"; + } FormattedTextBoxComment.tooltip && (FormattedTextBoxComment.tooltip.style.display = set); } diff --git a/src/client/views/nodes/PDFBox.scss b/src/client/views/nodes/PDFBox.scss index 963205206..2d92c9581 100644 --- a/src/client/views/nodes/PDFBox.scss +++ b/src/client/views/nodes/PDFBox.scss @@ -48,6 +48,7 @@ } .pdfViewer-text { .textLayer { + will-change: transform; span { user-select: none; } @@ -59,6 +60,7 @@ pointer-events: all; .pdfViewer-text { .textLayer { + will-change: transform; span { user-select: text; } diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 3baa6eb09..8e0515f8a 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -1,5 +1,5 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, observable, runInAction, reaction, IReactionDisposer, trace } from 'mobx'; +import { action, observable, runInAction, reaction, IReactionDisposer, trace, untracked, computed } from 'mobx'; import { observer } from "mobx-react"; import * as Pdfjs from "pdfjs-dist"; import "pdfjs-dist/web/pdf_viewer.css"; @@ -32,7 +32,7 @@ export class PDFBox extends DocAnnotatableComponent private _valueValue: string = ""; private _scriptValue: string = ""; private _searchString: string = ""; - private _initialScale: number | undefined; // the initial scale of the PDF when first rendered which determines whether the document will be live on startup or not. Getting bigger after startup won't make it automatically be live. + private _initialScale: number = 0; // the initial scale of the PDF when first rendered which determines whether the document will be live on startup or not. Getting bigger after startup won't make it automatically be live. private _everActive = false; // has this box ever had its contents activated -- if so, stop drawing the overlay title private _pdfViewer: PDFViewer | undefined; private _searchRef = React.createRef(); @@ -46,6 +46,11 @@ export class PDFBox extends DocAnnotatableComponent @observable private _pdf: Opt; @observable private _pageControls = false; + constructor(props: any) { + super(props); + this._initialScale = this.props.ScreenToLocalTransform().Scale; + } + componentWillUnmount() { this._selectReactionDisposer && this._selectReactionDisposer(); } @@ -190,39 +195,46 @@ export class PDFBox extends DocAnnotatableComponent ContextMenu.Instance.addItem({ description: "Pdf Funcs...", subitems: funcs, icon: "asterisk" }); } - render() { + @computed get renderTitleBox() { + let classname = "pdfBox-cont" + (this.active() ? "-interactive" : ""); + return
+
+ {` ${this.props.Document.title}`} +
+
; + } + + @computed get renderPdfView() { trace(); const pdfUrl = Cast(this.dataDoc[this.props.fieldKey], PdfField); let classname = "pdfBox-cont" + (this.active() ? "-interactive" : ""); - let noPdf = !(pdfUrl instanceof PdfField) || !this._pdf; - if (this._initialScale === undefined) this._initialScale = this.props.ScreenToLocalTransform().Scale; + return
{ + let hit = document.elementFromPoint(e.clientX, e.clientY); + if (hit && hit.localName === "span" && this.props.isSelected()) { // drag selecting text stops propagation + e.button === 0 && e.stopPropagation(); + } + }}> + + {this.settingsPanel()} +
; + } + + render() { + const pdfUrl = Cast(this.dataDoc[this.props.fieldKey], PdfField, null); if (this.props.isSelected() || this.props.Document.scrollY !== undefined) this._everActive = true; - return (!this.extensionDoc || noPdf || (!this._everActive && this.props.ScreenToLocalTransform().Scale > 2.5) ? -
-
- {` ${this.props.Document.title}`} -
-
: -
{ - let hit = document.elementFromPoint(e.clientX, e.clientY); - if (hit && hit.localName === "span" && this.props.isSelected()) { // drag selecting text stops propagation - e.button === 0 && e.stopPropagation(); - } - }}> - - {this.settingsPanel()} -
); + return !pdfUrl || !this._pdf || !this.extensionDoc || (!this._everActive && this.props.ScreenToLocalTransform().Scale > 2.5) ? + this.renderTitleBox : this.renderPdfView; } } \ No newline at end of file diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx index 2d8f47666..936af9ab8 100644 --- a/src/client/views/pdf/Annotation.tsx +++ b/src/client/views/pdf/Annotation.tsx @@ -52,11 +52,7 @@ class RegionAnnotation extends React.Component { this._brushDisposer = reaction( () => FieldValue(Cast(this.props.document.group, Doc)) && Doc.isBrushedHighlightedDegree(FieldValue(Cast(this.props.document.group, Doc))!), - (brushed) => { - if (brushed !== undefined) { - runInAction(() => this._brushed = brushed !== 0); - } - } + brushed => brushed !== undefined && runInAction(() => this._brushed = brushed !== 0) ); } diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 060ba8613..0cb671156 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -199,7 +199,7 @@ export class PDFViewer extends DocAnnotatableComponent this.extensionDoc && DocListCast(this.extensionDoc.annotations), - annotations => annotations && annotations.length && this.renderAnnotations(annotations, true), + annotations => annotations && annotations.length && (this._annotations = annotations), { fireImmediately: true }); this._filterReactionDisposer = reaction( @@ -297,18 +297,6 @@ export class PDFViewer extends DocAnnotatableComponent { - if (removeOldAnnotations) { - this._annotations = annotations; - } - else { - this._annotations.push(...annotations); - this._annotations = new Array(...this._annotations); - } - } - @action prevAnnotation = () => { this.Index = Math.max(this.Index - 1, 0); diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 6aad4a6be..3bf1129b5 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -669,8 +669,8 @@ export namespace Doc { return doc; } - export function LinkEndpoint(linkDoc: Doc, anchorDoc: Doc) { return Doc.AreProtosEqual(anchorDoc, Cast(linkDoc.anchor1, Doc) as Doc) ? "layoutKey1" : "layoutKey2"; } + export function LinkEndpoint(linkDoc: Doc, anchorDoc: Doc) { return Doc.AreProtosEqual(anchorDoc, Cast(linkDoc.anchor1, Doc) as Doc) ? "layoutKey1" : "layoutKey2"; } export function linkFollowUnhighlight() { Doc.UnhighlightAll(); document.removeEventListener("pointerdown", linkFollowUnhighlight); diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 56ea5bfe1..833e44bf6 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -15,7 +15,6 @@ import { RouteStore } from "../../RouteStore"; import { InkingControl } from "../../../client/views/InkingControl"; import { DragManager } from "../../../client/util/DragManager"; import { nullAudio } from "../../../new_fields/URLField"; -import { LinkManager } from "../../../client/util/LinkManager"; export class CurrentUserUtils { private static curr_id: string; -- cgit v1.2.3-70-g09d2