diff options
25 files changed, 160 insertions, 180 deletions
diff --git a/src/client/util/Import & Export/DirectoryImportBox.tsx b/src/client/util/Import & Export/DirectoryImportBox.tsx index 63e74da5f..f0880f193 100644 --- a/src/client/util/Import & Export/DirectoryImportBox.tsx +++ b/src/client/util/Import & Export/DirectoryImportBox.tsx @@ -114,8 +114,7 @@ export default class DirectoryImportBox extends React.Component<FieldViewProps> runInAction(() => this.phase = `Internal: uploading ${this.quota - this.completed} files to Dash...`); - const batched = BatchedArray.from(validated, { batchSize: 15 }); - const uploads = await batched.batchedMapAsync<ImageUploadResponse>(async (batch, collector) => { + const uploads = await BatchedArray.from(validated, { batchSize: 15 }).batchedMapAsync<ImageUploadResponse>(async (batch, collector) => { const formData = new FormData(); batch.forEach(file => { diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index 961a5a016..286a77f81 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -84,6 +84,8 @@ export function DocAnnotatableComponent<P extends DocAnnotatableProps, T>(schema whenActiveChanged = action((isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive)); active = () => ((InkingControl.Instance.selectedTool === InkTool.None && !this.props.Document.isBackground) && (this.props.Document.forceActive || this.props.isSelected() || this._isChildActive || this.props.renderDepth === 0) ? true : false) + annotationsActive = () => (InkingControl.Instance.selectedTool !== InkTool.None || + (this.props.Document.forceActive || this.props.isSelected() || this._isChildActive || this.props.renderDepth === 0) ? true : false) } return Component; }
\ No newline at end of file diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 1412316f9..c7ee413c9 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -8,13 +8,12 @@ import { RichTextField } from '../../new_fields/RichTextField'; import { NumCast, StrCast } from "../../new_fields/Types"; import { emptyFunction } from "../../Utils"; import { Pulls, Pushes } from '../apis/google_docs/GoogleApiClientUtils'; -import { DragLinksAsDocuments, DragManager } from "../util/DragManager"; +import { DragManager } from "../util/DragManager"; import { LinkManager } from '../util/LinkManager'; import { UndoManager } from "../util/UndoManager"; import './DocumentButtonBar.scss'; import './collections/ParentDocumentSelector.scss'; import { LinkMenu } from "./linking/LinkMenu"; -import { MetadataEntryMenu } from './MetadataEntryMenu'; import { FormattedTextBox, GoogleRef } from "./nodes/FormattedTextBox"; import { TemplateMenu } from "./TemplateMenu"; import { Template, Templates } from "./Templates"; @@ -43,7 +42,6 @@ const fetch: IconProp = "sync-alt"; @observer export class DocumentButtonBar extends React.Component<{ views: DocumentView[], stack?: any }, {}> { private _linkButton = React.createRef<HTMLDivElement>(); - private _linkerButton = React.createRef<HTMLDivElement>(); private _aliasButton = React.createRef<HTMLDivElement>(); private _tooltipoff = React.createRef<HTMLDivElement>(); private _textDoc?: Doc; @@ -109,14 +107,6 @@ export class DocumentButtonBar extends React.Component<{ views: DocumentView[], document.addEventListener("pointerup", this.onLinkerButtonUp); } - onAliasButtonDown = (e: React.PointerEvent): void => { - e.stopPropagation(); - e.preventDefault(); - document.removeEventListener("pointermove", this.onAliasButtonMoved); - document.addEventListener("pointermove", this.onAliasButtonMoved); - document.removeEventListener("pointerup", this.onAliasButtonUp); - document.addEventListener("pointerup", this.onAliasButtonUp); - } onLinkerButtonUp = (e: PointerEvent): void => { document.removeEventListener("pointermove", this.onLinkerButtonMoved); @@ -124,22 +114,17 @@ export class DocumentButtonBar extends React.Component<{ views: DocumentView[], e.stopPropagation(); } - onAliasButtonUp = (e: PointerEvent): void => { - document.removeEventListener("pointermove", this.onAliasButtonMoved); - document.removeEventListener("pointerup", this.onAliasButtonUp); - e.stopPropagation(); - } @action onLinkerButtonMoved = (e: PointerEvent): void => { - if (this._linkerButton.current !== null) { + if (this._linkButton.current !== null) { document.removeEventListener("pointermove", this.onLinkerButtonMoved); - document.removeEventListener("pointerup", this.onLinkerButtonUp); + document.removeEventListener("pointerup", this.onLinkButtonUp); let docView = this.props.views[0]; let container = docView.props.ContainingCollectionDoc ? docView.props.ContainingCollectionDoc.proto : undefined; let dragData = new DragManager.LinkDragData(docView.props.Document, container ? [container] : []); let linkDrag = UndoManager.StartBatch("Drag Link"); - DragManager.StartLinkDrag(this._linkerButton.current, dragData, e.pageX, e.pageY, { + DragManager.StartLinkDrag(this._linkButton.current, dragData, e.pageX, e.pageY, { handlers: { dragComplete: () => { let tooltipmenu = FormattedTextBox.ToolTipTextMenu; @@ -163,62 +148,22 @@ export class DocumentButtonBar extends React.Component<{ views: DocumentView[], e.stopPropagation(); } - @action - onAliasButtonMoved = (e: PointerEvent): void => { - if (this._aliasButton.current !== null) { - document.removeEventListener("pointermove", this.onAliasButtonMoved); - document.removeEventListener("pointerup", this.onAliasButtonUp); - - let dragDocView = this.props.views[0]; - let dragData = new DragManager.DocumentDragData([dragDocView.props.Document]); - const [left, top] = dragDocView.props.ScreenToLocalTransform().scale(dragDocView.props.ContentScaling()).inverse().transformPoint(0, 0); - dragData.offset = dragDocView.props.ScreenToLocalTransform().scale(dragDocView.props.ContentScaling()).transformDirection(e.clientX - left, e.clientY - top); - dragData.embedDoc = true; - dragData.dropAction = "alias"; - DragManager.StartDocumentDrag([dragDocView.ContentDiv!], dragData, e.x, e.y, { - offsetX: dragData.offset[0], - offsetY: dragData.offset[1], - handlers: { - dragComplete: action(emptyFunction), - }, - hideSource: false - }); - } - e.stopPropagation(); - } onLinkButtonDown = (e: React.PointerEvent): void => { e.stopPropagation(); e.preventDefault(); - document.removeEventListener("pointermove", this.onLinkButtonMoved); - document.addEventListener("pointermove", this.onLinkButtonMoved); + document.removeEventListener("pointermove", this.onLinkerButtonMoved); + document.addEventListener("pointermove", this.onLinkerButtonMoved); document.removeEventListener("pointerup", this.onLinkButtonUp); document.addEventListener("pointerup", this.onLinkButtonUp); } onLinkButtonUp = (e: PointerEvent): void => { - document.removeEventListener("pointermove", this.onLinkButtonMoved); + document.removeEventListener("pointermove", this.onLinkerButtonMoved); document.removeEventListener("pointerup", this.onLinkButtonUp); e.stopPropagation(); } - onLinkButtonMoved = async (e: PointerEvent) => { - if (this._linkButton.current !== null && (e.movementX > 1 || e.movementY > 1)) { - document.removeEventListener("pointermove", this.onLinkButtonMoved); - document.removeEventListener("pointerup", this.onLinkButtonUp); - DragLinksAsDocuments(this._linkButton.current, e.x, e.y, this.props.views[0].props.Document); - } - e.stopPropagation(); - } - - aliasDragger = () => { - return (<div className="linkButtonWrapper"> - <div title="Drag Alias" className="linkButton-linker" ref={this._aliasButton} onPointerDown={this.onAliasButtonDown}> - <FontAwesomeIcon className="documentdecorations-icon" icon="image" size="sm" /> - </div> - </div>); - } - private get targetDoc() { return this.props.views[0].props.Document; } @@ -317,30 +262,18 @@ export class DocumentButtonBar extends React.Component<{ views: DocumentView[], } } - get metadataMenu() { - return ( - <div className="linkButtonWrapper"> - <Flyout anchorPoint={anchorPoints.TOP_LEFT} - content={<MetadataEntryMenu docs={() => this.props.views.map(dv => dv.props.Document)} suggestWithFunction />}>{/* tfs: @bcz This might need to be the data document? */} - <div className="docDecs-tagButton" title="Add fields"><FontAwesomeIcon className="documentdecorations-icon" icon="tag" size="sm" /></div> - </Flyout> - </div> - ); - } - render() { let linkButton = null; if (this.props.views.length > 0) { let selFirst = this.props.views[0]; let linkCount = LinkManager.Instance.getAllRelatedLinks(selFirst.props.Document).length; - linkButton = (<Flyout - anchorPoint={anchorPoints.RIGHT_TOP} - content={<LinkMenu docView={selFirst} - addDocTab={selFirst.props.addDocTab} - changeFlyout={emptyFunction} />}> - <div className={"linkButton-" + (linkCount ? "nonempty" : "empty")} onPointerDown={this.onLinkButtonDown} >{linkCount}</div> - </Flyout >); + linkButton = <Flyout anchorPoint={anchorPoints.RIGHT_TOP} + content={<LinkMenu docView={selFirst} addDocTab={selFirst.props.addDocTab} changeFlyout={emptyFunction} />}> + <div className={"linkButton-" + (linkCount ? "nonempty" : "empty")} onPointerDown={this.onLinkButtonDown} > + {linkCount ? linkCount : <FontAwesomeIcon className="documentdecorations-icon" icon="link" size="sm" />} + </div> + </Flyout >; } let templates: Map<Template, boolean> = new Map(); @@ -349,21 +282,14 @@ export class DocumentButtonBar extends React.Component<{ views: DocumentView[], return (<div className="documentButtonBar"> <div className="linkButtonWrapper"> - <div title="View Links" className="linkFlyout" ref={this._linkButton}> {linkButton} </div> - </div> - <div className="linkButtonWrapper"> - <div title="Drag Link" className="linkButton-linker" ref={this._linkerButton} onPointerDown={this.onLinkerButtonDown}> - <FontAwesomeIcon className="documentdecorations-icon" icon="link" size="sm" /> - </div> + <div title="Drag(create link) Tap(view links)" className="linkFlyout" ref={this._linkButton}> {linkButton} </div> </div> <div className="linkButtonWrapper"> <TemplateMenu docs={this.props.views} templates={templates} /> </div> - {this.metadataMenu} - {this.aliasDragger()} {this.considerGoogleDocsPush()} {this.considerGoogleDocsPull()} - <ParentDocSelector Document={this.props.views[0].props.Document} addDocTab={(doc, data, where) => { + <ParentDocSelector Views={this.props.views} Document={this.props.views[0].props.Document} addDocTab={(doc, data, where) => { where === "onRight" ? CollectionDockingView.AddRightSplit(doc, data) : this.props.stack ? CollectionDockingView.Instance.AddTab(this.props.stack, doc, data) : this.props.views[0].props.addDocTab(doc, data, "onRight"); return true; }} /> diff --git a/src/client/views/InkSelectDecorations.tsx b/src/client/views/InkSelectDecorations.tsx index 95ccc1777..d40df9b75 100644 --- a/src/client/views/InkSelectDecorations.tsx +++ b/src/client/views/InkSelectDecorations.tsx @@ -3,7 +3,7 @@ import { Touchable } from "./Touchable"; import { PointData } from "../../new_fields/InkField"; import { observer } from "mobx-react"; import { computed, observable, action, runInAction } from "mobx"; -import "./InkSelectDecorations.scss" +import "./InkSelectDecorations.scss"; @observer export default class InkSelectDecorations extends Touchable { @@ -46,14 +46,10 @@ export default class InkSelectDecorations extends Touchable { render() { let bounds = this.Bounds; - return ( - <div style={{ - top: bounds.y, left: bounds.x, - height: bounds.b - bounds.y, - width: bounds.r - bounds.x - }}> - - </div> - ) + return <div style={{ + top: bounds.y, left: bounds.x, + height: bounds.b - bounds.y, + width: bounds.r - bounds.x + }} />; } }
\ No newline at end of file diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 411b0d3a0..74211cc90 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -1,18 +1,14 @@ +import { computed } from "mobx"; import { observer } from "mobx-react"; -import { observable, trace, runInAction, computed } from "mobx"; -import { InkingControl } from "./InkingControl"; -import React = require("react"); -import { InkTool, InkField, InkData } from "../../new_fields/InkField"; -import "./InkingStroke.scss"; -import { AudioBox } from "./nodes/AudioBox"; -import { Doc, FieldResult } from "../../new_fields/Doc"; -import { createSchema, makeInterface, listSpec } from "../../new_fields/Schema"; import { documentSchema } from "../../new_fields/documentSchemas"; +import { InkData, InkField, InkTool } from "../../new_fields/InkField"; +import { makeInterface } from "../../new_fields/Schema"; +import { Cast } from "../../new_fields/Types"; import { DocExtendableComponent } from "./DocComponent"; -import { FieldViewProps, FieldView } from "./nodes/FieldView"; -import { Transform } from "../util/Transform"; -import { Cast, FieldValue } from "../../new_fields/Types"; -import { List } from "../../new_fields/List"; +import { InkingControl } from "./InkingControl"; +import "./InkingStroke.scss"; +import { FieldView, FieldViewProps } from "./nodes/FieldView"; +import React = require("react"); type InkDocument = makeInterface<[typeof documentSchema]>; const InkDocument = makeInterface(documentSchema); @@ -40,7 +36,7 @@ export class InkingStroke extends DocExtendableComponent<FieldViewProps, InkDocu render() { // let pathData = this.parseData(this.props.line); - let data: InkData = Cast(this.Document.data, InkField) ?.inkData ?? []; + let data: InkData = Cast(this.Document.data, InkField)?.inkData ?? []; let xs = data.map(p => p.x); let ys = data.map(p => p.y); let left = Math.min(...xs); diff --git a/src/client/views/Main.scss b/src/client/views/Main.scss index 9cbe6e144..465527468 100644 --- a/src/client/views/Main.scss +++ b/src/client/views/Main.scss @@ -27,7 +27,7 @@ div { pointer-events: none; border-radius: inherit; position: inherit; - background: inherit; + // background: inherit; } p { diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index 96265385e..1df5f49c4 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -10,6 +10,7 @@ import { Template, Templates } from "./Templates"; import React = require("react"); import { Doc } from "../../new_fields/Doc"; import { StrCast } from "../../new_fields/Types"; +import { emptyFunction } from "../../Utils"; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -46,10 +47,13 @@ export interface TemplateMenuProps { templates: Map<Template, boolean>; } + @observer export class TemplateMenu extends React.Component<TemplateMenuProps> { @observable private _hidden: boolean = true; - dragRef = React.createRef<HTMLUListElement>(); + private _downx = 0; + private _downy = 0; + private _dragRef = React.createRef<HTMLUListElement>(); toggleCustom = (e: React.ChangeEvent<HTMLInputElement>): void => { this.props.docs.map(dv => dv.setCustomView(e.target.checked)); @@ -122,6 +126,43 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> { layout.chromeStatus = (layout.chromeStatus !== "disabled" ? "disabled" : "enabled"); }); } + onAliasButtonUp = (e: PointerEvent): void => { + document.removeEventListener("pointermove", this.onAliasButtonMoved); + document.removeEventListener("pointerup", this.onAliasButtonUp); + e.stopPropagation(); + } + + onAliasButtonDown = (e: React.PointerEvent): void => { + this._downx = e.clientX; + this._downy = e.clientY; + e.stopPropagation(); + e.preventDefault(); + document.removeEventListener("pointermove", this.onAliasButtonMoved); + document.addEventListener("pointermove", this.onAliasButtonMoved); + document.removeEventListener("pointerup", this.onAliasButtonUp); + document.addEventListener("pointerup", this.onAliasButtonUp); + } + onAliasButtonMoved = (e: PointerEvent): void => { + if (this._dragRef.current !== null && (Math.abs(e.clientX - this._downx) > 4 || Math.abs(e.clientY - this._downy) > 4)) { + document.removeEventListener("pointermove", this.onAliasButtonMoved); + document.removeEventListener("pointerup", this.onAliasButtonUp); + + let dragDocView = this.props.docs[0]; + let dragData = new DragManager.DocumentDragData([dragDocView.props.Document]); + const [left, top] = dragDocView.props.ScreenToLocalTransform().inverse().transformPoint(0, 0); + dragData.embedDoc = true; + dragData.dropAction = "alias"; + DragManager.StartDocumentDrag([dragDocView.ContentDiv!], dragData, left, top, { + offsetX: dragData.offset[0], + offsetY: dragData.offset[1], + handlers: { + dragComplete: action(emptyFunction), + }, + hideSource: false + }); + } + e.stopPropagation(); + } render() { let layout = Doc.Layout(this.props.docs[0].Document); @@ -132,9 +173,9 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> { templateMenu.push(<OtherToggle key={"custom"} name={"Custom"} checked={StrCast(this.props.docs[0].Document.layoutKey, "layout") !== "layout"} toggle={this.toggleCustom} />); templateMenu.push(<OtherToggle key={"chrome"} name={"Chrome"} checked={layout.chromeStatus !== "disabled"} toggle={this.toggleChrome} />); return ( - <div className="templating-menu" > - <div title="Template Options" className="templating-button" onClick={() => this.toggleTemplateActivity()}>+</div> - <ul id="template-list" ref={this.dragRef} style={{ display: this._hidden ? "none" : "block" }}> + <div className="templating-menu" onPointerDown={this.onAliasButtonDown}> + <div title="Drag:(create alias). Tap:(modify layout)." className="templating-button" onClick={() => this.toggleTemplateActivity()}>+</div> + <ul id="template-list" ref={this._dragRef} style={{ display: this._hidden ? "none" : "block" }}> {templateMenu} {<button onClick={this.clearTemplates}>Restore Defaults</button>} </ul> diff --git a/src/client/views/collections/CollectionStaffView.tsx b/src/client/views/collections/CollectionStaffView.tsx index eea05ea61..40e860b12 100644 --- a/src/client/views/collections/CollectionStaffView.tsx +++ b/src/client/views/collections/CollectionStaffView.tsx @@ -1,6 +1,6 @@ import { CollectionSubView } from "./CollectionSubView"; import { Transform } from "../../util/Transform"; -import React = require("react") +import React = require("react"); import { computed, action, IReactionDisposer, reaction, runInAction, observable } from "mobx"; import { Doc, HeightSym } from "../../../new_fields/Doc"; import { NumCast } from "../../../new_fields/Types"; @@ -36,7 +36,7 @@ export class CollectionStaffView extends CollectionSubView(doc => doc) { for (let i = 0; i < this._staves; i++) { let rows = []; for (let j = 0; j < 5; j++) { - rows.push(<div key={`staff-${i}-${j}`} className="collectionStaffView-line"></div>) + rows.push(<div key={`staff-${i}-${j}`} className="collectionStaffView-line"></div>); } staves.push(<div key={`staff-${i}`} className="collectionStaffView-staff"> {rows} @@ -51,11 +51,9 @@ export class CollectionStaffView extends CollectionSubView(doc => doc) { } render() { - return ( - <div className="collectionStaffView" ref={this._mainCont}> - {this.staves} - {this.addStaffButton} - </div> - ) + return <div className="collectionStaffView" ref={this._mainCont}> + {this.staves} + {this.addStaffButton} + </div>; } }
\ No newline at end of file diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 8f1278670..347fa7d0d 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -168,7 +168,7 @@ export class CollectionView extends Touchable<FieldViewProps> { case CollectionViewType.Schema: return (<CollectionSchemaView key="collview" {...props} />); case CollectionViewType.Docking: return (<CollectionDockingView key="collview" {...props} />); case CollectionViewType.Tree: return (<CollectionTreeView key="collview" {...props} />); - case CollectionViewType.Staff: return (<CollectionStaffView chromeCollapsed={true} key="collview" {...props} ChromeHeight={this.chromeHeight} CollectionView={this} />) + case CollectionViewType.Staff: return (<CollectionStaffView chromeCollapsed={true} key="collview" {...props} ChromeHeight={this.chromeHeight} CollectionView={this} />); case CollectionViewType.Linear: { return (<CollectionLinearView key="collview" {...props} />); } case CollectionViewType.Stacking: { this.props.Document.singleColumn = true; return (<CollectionStackingView key="collview" {...props} />); } case CollectionViewType.Masonry: { this.props.Document.singleColumn = false; return (<CollectionStackingView key="collview" {...props} />); } @@ -229,7 +229,7 @@ export class CollectionView extends Touchable<FieldViewProps> { let more = ContextMenu.Instance.findByDescription("More..."); let moreItems = more && "subitems" in more ? more.subitems : []; moreItems.push({ description: "Export Image Hierarchy", icon: "columns", event: () => ImageUtils.ExportHierarchyToFileSystem(this.props.Document) }); - !more && ContextMenu.Instance.addItem({ description: "More...", subitems: moreItems, icon: "hand-point-right" }) + !more && ContextMenu.Instance.addItem({ description: "More...", subitems: moreItems, icon: "hand-point-right" }); } } diff --git a/src/client/views/collections/ParentDocumentSelector.scss b/src/client/views/collections/ParentDocumentSelector.scss index c186d15f8..aa25a900c 100644 --- a/src/client/views/collections/ParentDocumentSelector.scss +++ b/src/client/views/collections/ParentDocumentSelector.scss @@ -23,6 +23,12 @@ .parentDocumentSelector-button { pointer-events: all; } +.parentDocumentSelector-metadata { + pointer-events: auto; + padding-right: 5px; + width: 25px; + display: inline-block; +} .buttonSelector { position: absolute; display: inline-block; diff --git a/src/client/views/collections/ParentDocumentSelector.tsx b/src/client/views/collections/ParentDocumentSelector.tsx index 8b6fa330c..ba83630a4 100644 --- a/src/client/views/collections/ParentDocumentSelector.tsx +++ b/src/client/views/collections/ParentDocumentSelector.tsx @@ -13,10 +13,14 @@ import { DocumentManager } from "../../util/DocumentManager"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faEdit } from "@fortawesome/free-solid-svg-icons"; import { library } from "@fortawesome/fontawesome-svg-core"; +import { MetadataEntryMenu } from "../MetadataEntryMenu"; +const higflyout = require("@hig/flyout"); +export const { anchorPoints } = higflyout; +export const Flyout = higflyout.default; library.add(faEdit); -type SelectorProps = { Document: Doc, Stack?: any, addDocTab(doc: Doc, dataDoc: Doc | undefined, location: string): void }; +type SelectorProps = { Document: Doc, Views: DocumentView[], Stack?: any, addDocTab(doc: Doc, dataDoc: Doc | undefined, location: string): void }; @observer export class SelectorContextMenu extends React.Component<SelectorProps> { @observable private _docs: { col: Doc, target: Doc }[] = []; @@ -53,16 +57,23 @@ export class SelectorContextMenu extends React.Component<SelectorProps> { this.props.addDocTab(col, undefined, "inTab"); // bcz: dataDoc? }; } + get metadataMenu() { + return <div className="parentDocumentSelector-metadata"> + <Flyout anchorPoint={anchorPoints.TOP_LEFT} + content={<MetadataEntryMenu docs={() => this.props.Views.map(dv => dv.props.Document)} suggestWithFunction />}>{/* tfs: @bcz This might need to be the data document? */} + <div className="docDecs-tagButton" title="Add fields"><FontAwesomeIcon className="documentdecorations-icon" icon="tag" size="sm" /></div> + </Flyout> + </div>; + } render() { - return ( - <> - <p key="contexts">Contexts:</p> - {this._docs.map(doc => <p key={doc.col[Id] + doc.target[Id]}><a onClick={this.getOnClick(doc)}>{doc.col.title}</a></p>)} - {this._otherDocs.length ? <hr key="hr" /> : null} - {this._otherDocs.map(doc => <p key="p"><a onClick={this.getOnClick(doc)}>{doc.col.title}</a></p>)} - </> - ); + return <div > + <div key="metadata">Metadata: {this.metadataMenu}</div> + <p key="contexts">Contexts:</p> + {this._docs.map(doc => <p key={doc.col[Id] + doc.target[Id]}><a onClick={this.getOnClick(doc)}>{doc.col.title}</a></p>)} + {this._otherDocs.length ? <hr key="hr" /> : null} + {this._otherDocs.map(doc => <p key="p"><a onClick={this.getOnClick(doc)}>{doc.col.title}</a></p>)} + </div>; } } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss index db36c4391..d2731703f 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss @@ -45,7 +45,6 @@ // linear-gradient(to bottom, $light-color-secondary 1px, transparent 1px); // background-size: 30px 30px; // } - opacity: 0.99; border: 0px solid $light-color-secondary; border-radius: inherit; box-sizing: border-box; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 59858df8d..210a5132a 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -4,43 +4,41 @@ import { faBraille, faChalkboard, faCompass, faCompressArrowsAlt, faExpandArrows import { action, computed, observable, trace } from "mobx"; import { observer } from "mobx-react"; import { Doc, DocListCast, HeightSym, Opt, WidthSym } from "../../../../new_fields/Doc"; +import { documentSchema, positionSchema } from "../../../../new_fields/documentSchemas"; import { Id } from "../../../../new_fields/FieldSymbols"; -import { InkField, PointData, InkTool } from "../../../../new_fields/InkField"; +import { InkTool } from "../../../../new_fields/InkField"; import { createSchema, makeInterface } from "../../../../new_fields/Schema"; import { ScriptField } from "../../../../new_fields/ScriptField"; import { BoolCast, Cast, DateCast, NumCast, StrCast } from "../../../../new_fields/Types"; import { CurrentUserUtils } from "../../../../server/authentication/models/current_user_utils"; import { aggregateBounds, emptyFunction, intersectRect, returnOne, Utils } from "../../../../Utils"; -import { CognitiveServices } from "../../../cognitive_services/CognitiveServices"; import { DocServer } from "../../../DocServer"; import { Docs } from "../../../documents/Documents"; import { DocumentType } from "../../../documents/DocumentTypes"; import { DocumentManager } from "../../../util/DocumentManager"; import { DragManager } from "../../../util/DragManager"; import { HistoryUtil } from "../../../util/History"; +import { InteractionUtils } from "../../../util/InteractionUtils"; import { SelectionManager } from "../../../util/SelectionManager"; import { Transform } from "../../../util/Transform"; import { undoBatch, UndoManager } from "../../../util/UndoManager"; import { COLLECTION_BORDER_WIDTH } from "../../../views/globalCssVariables.scss"; import { ContextMenu } from "../../ContextMenu"; import { ContextMenuProps } from "../../ContextMenuItem"; -import { InkingCanvas } from "../../InkingCanvas"; +import { InkingControl } from "../../InkingControl"; +import { CreatePolyline } from "../../InkingStroke"; import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView"; import { DocumentViewProps } from "../../nodes/DocumentView"; import { FormattedTextBox } from "../../nodes/FormattedTextBox"; import { pageSchema } from "../../nodes/ImageBox"; +import PDFMenu from "../../pdf/PDFMenu"; import { CollectionSubView } from "../CollectionSubView"; import { computePivotLayout, ViewDefResult } from "./CollectionFreeFormLayoutEngines"; import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCursors"; import "./CollectionFreeFormView.scss"; +import MarqueeOptionsMenu from "./MarqueeOptionsMenu"; import { MarqueeView } from "./MarqueeView"; import React = require("react"); -import { InteractionUtils } from "../../../util/InteractionUtils"; -import MarqueeOptionsMenu from "./MarqueeOptionsMenu"; -import PDFMenu from "../../pdf/PDFMenu"; -import { documentSchema, positionSchema } from "../../../../new_fields/documentSchemas"; -import { InkingControl } from "../../InkingControl"; -import { InkingStroke, CreatePolyline } from "../../InkingStroke"; library.add(faEye as any, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt, faCompass, faUpload, faBraille, faChalkboard, faFileUpload); @@ -273,7 +271,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { onPointerDown = (e: React.PointerEvent): void => { if (e.nativeEvent.cancelBubble) return; this._hitCluster = this.props.Document.useClusters ? this.pickCluster(this.getTransform().transformPoint(e.clientX, e.clientY)) !== -1 : false; - if (e.button === 0 && !e.shiftKey && !e.altKey && !e.ctrlKey && (!this.isAnnotationOverlay || this.zoomScaling() !== 1) && this.props.active()) { + if (e.button === 0 && !e.shiftKey && !e.altKey && !e.ctrlKey && this.props.active()) { document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); document.addEventListener("pointermove", this.onPointerMove); @@ -344,14 +342,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { return [[range[0][0] > x ? x : range[0][0], range[0][1] < xe ? xe : range[0][1]], [range[1][0] > y ? y : range[1][0], range[1][1] < ye ? ye : range[1][1]]]; }, [[minx, maxx], [miny, maxy]]); - let ink = this.extensionDoc && Cast(this.extensionDoc.ink, InkField); - if (ink && ink.inkData) { - // ink.inkData.forEach((value: PointData, key: string) => { - // let bounds = InkingCanvas.StrokeRect(value); - // ranges[0] = [Math.min(ranges[0][0], bounds.left), Math.max(ranges[0][1], bounds.right)]; - // ranges[1] = [Math.min(ranges[1][0], bounds.top), Math.max(ranges[1][1], bounds.bottom)]; - // }); - } let cscale = this.props.ContainingCollectionDoc ? NumCast(this.props.ContainingCollectionDoc.scale) : 1; let panelDim = this.props.ScreenToLocalTransform().transformDirection(this.props.PanelWidth() / this.zoomScaling() * cscale, @@ -757,11 +747,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } analyzeStrokes = async () => { - const extensionDoc = this.extensionDoc; - let data = extensionDoc && Cast(extensionDoc.ink, InkField); - if (data && extensionDoc) { - CognitiveServices.Inking.Appliers.ConcatenateHandwriting(extensionDoc, ["inkAnalysis", "handwriting"], data.inkData); - } + // CognitiveServices.Inking.Appliers.ConcatenateHandwriting(this.dataDoc, ["inkAnalysis", "handwriting"], data.inkData); } onContextMenu = (e: React.MouseEvent) => { @@ -852,8 +838,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { children = () => { let eles: JSX.Element[] = []; - this.currentStroke && (eles.push(this.currentStroke)); this.extensionDoc && (eles.push(...this.childViews())); + this.currentStroke && (eles.push(this.currentStroke)); eles.push(<CollectionFreeFormRemoteCursors {...this.props} key="remoteCursors" />); return eles; } diff --git a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx index 91fcad4be..28ddc19d7 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx @@ -1,4 +1,4 @@ -import React = require("react") +import React = require("react"); import AntimodeMenu from "../../AntimodeMenu"; import { observer } from "mobx-react"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; @@ -40,7 +40,7 @@ export default class MarqueeOptionsMenu extends AntimodeMenu { onPointerDown={this.delete}> <FontAwesomeIcon icon="trash-alt" size="lg" /> </button>, - ] + ]; return this.getElement(buttons); } }
\ No newline at end of file diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 5083b45f1..338cf6202 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -537,7 +537,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu return (showTitle ? 25 : 0) + 1; } - @computed get finalLayoutKey() { return this.props.layoutKey || "layout" } + @computed get finalLayoutKey() { return this.props.layoutKey || "layout"; } childScaling = () => (this.layoutDoc.fitWidth ? this.props.PanelWidth() / this.nativeWidth : this.props.ContentScaling()); @computed get contents() { // trace(); @@ -645,7 +645,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu const ruleRounding = this.props.ruleProvider ? StrCast(this.props.ruleProvider["ruleRounding_" + this.Document.heading]) : undefined; const colorSet = this.setsLayoutProp("backgroundColor"); const clusterCol = this.props.ContainingCollectionDoc && this.props.ContainingCollectionDoc.clusterOverridesDefaultBackground; - const backgroundColor = this.Document.isBackground || (clusterCol && !colorSet) ? + const backgroundColor = (clusterCol && !colorSet) ? this.props.backgroundColor(this.Document) || StrCast(this.layoutDoc.backgroundColor) : ruleColor && !colorSet ? ruleColor : StrCast(this.layoutDoc.backgroundColor) || this.props.backgroundColor(this.Document); @@ -672,7 +672,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu background: this.layoutDoc.type === DocumentType.FONTICON || this.layoutDoc.viewType === CollectionViewType.Linear ? undefined : backgroundColor, width: animwidth, height: animheight, - //transform: `scale(${this.layoutDoc.fitWidth ? 1 : this.props.ContentScaling()})`, opacity: this.Document.opacity }} > {this.innards} diff --git a/src/client/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss index b9f1e9940..269a3ca68 100644 --- a/src/client/views/nodes/FormattedTextBox.scss +++ b/src/client/views/nodes/FormattedTextBox.scss @@ -45,10 +45,18 @@ position: relative; overflow: auto; display: inline-block; - padding: 10px 10px; width: 100%; height: 100%; } +.formattedTextBox-sidebar,.formattedTextBox-sidebar-inking { + border-left: solid 1px black; + height: 100%; + display: inline-block; +} + +.formattedTextBox-sidebar-inking { + pointer-events: all; +} .formattedTextBox-inner-rounded { height: 70%; diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index ef54a387c..0e5fae4af 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -46,6 +46,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { documentSchema } from '../../../new_fields/documentSchemas'; import { AudioBox } from './AudioBox'; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; +import { InkTool } from '../../../new_fields/InkField'; library.add(faEdit); library.add(faSmile, faTextHeight, faUpload); @@ -1049,7 +1050,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & <div className={`formattedTextBox-outer`} style={{ width: `calc(100% - ${this.sidebarWidthPercent})`, }}> <div className={`formattedTextBox-inner${rounded}`} style={{ whiteSpace: "pre-wrap", pointerEvents: ((this.Document.isButton || this.props.onClick) && !this.props.isSelected()) ? "none" : undefined }} ref={this.createDropTarget} /> </div> - {this.sidebarWidthPercent === "0%" ? (null) : <div style={{ borderLeft: "solid 1px black", width: `${this.sidebarWidthPercent}`, height: "100%", display: "inline-block" }}> + {this.sidebarWidthPercent === "0%" ? (null) : <div className={"formattedTextBox-sidebar" + (InkingControl.Instance.selectedTool !== InkTool.None ? "-inking" : "")} style={{ width: `${this.sidebarWidthPercent}` }}> <CollectionFreeFormView {...this.props} PanelHeight={() => this.props.PanelHeight()} PanelWidth={() => this.sidebarWidth} @@ -1058,7 +1059,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & focus={this.props.focus} isSelected={this.props.isSelected} select={emptyFunction} - active={this.active} + active={this.annotationsActive} ContentScaling={returnOne} whenActiveChanged={this.whenActiveChanged} removeDocument={this.removeDocument} diff --git a/src/client/views/nodes/ImageBox.scss b/src/client/views/nodes/ImageBox.scss index 57c024bbf..dcecbdc6e 100644 --- a/src/client/views/nodes/ImageBox.scss +++ b/src/client/views/nodes/ImageBox.scss @@ -11,6 +11,7 @@ } .imageBox-container { + pointer-events: all; border-radius: inherit; width:100%; height:100%; diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 7a9ebc00a..86dc4fccc 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -342,7 +342,7 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum focus={this.props.focus} isSelected={this.props.isSelected} select={emptyFunction} - active={this.active} + active={this.annotationsActive} ContentScaling={returnOne} whenActiveChanged={this.whenActiveChanged} removeDocument={this.removeDocument} diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 3685df91f..4c826f835 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -344,7 +344,7 @@ export class VideoBox extends DocAnnotatableComponent<FieldViewProps, VideoDocum isSelected={this.props.isSelected} isAnnotationOverlay={true} select={emptyFunction} - active={this.active} + active={this.annotationsActive} ContentScaling={returnOne} whenActiveChanged={this.whenActiveChanged} removeDocument={this.removeDocument} diff --git a/src/client/views/pdf/PDFViewer.scss b/src/client/views/pdf/PDFViewer.scss index 6f9dbb78d..ac018aa0e 100644 --- a/src/client/views/pdf/PDFViewer.scss +++ b/src/client/views/pdf/PDFViewer.scss @@ -54,7 +54,7 @@ opacity: 0.1; } - .pdfViewer-overlay { + .pdfViewer-overlay, .pdfViewer-overlay-inking { transform-origin: left top; position: absolute; top: 0px; @@ -63,6 +63,11 @@ width:100%; pointer-events: none; } + .pdfViewer-overlay-inking { + .collectionfreeformview-container { + pointer-events: all; + } + } .pdfViewer-annotationLayer { position: absolute; transform-origin: left top; diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index de9eeaf97..c56422076 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -27,6 +27,8 @@ import { DocAnnotatableComponent } from "../DocComponent"; import { DocumentType } from "../../documents/DocumentTypes"; import { documentSchema } from "../../../new_fields/documentSchemas"; import { DocumentDecorations } from "../DocumentDecorations"; +import { InkingControl } from "../InkingControl"; +import { InkTool } from "../../../new_fields/InkField"; const PDFJSViewer = require("pdfjs-dist/web/pdf_viewer"); const pdfjsLib = require("pdfjs-dist"); @@ -628,7 +630,7 @@ export class PDFViewer extends DocAnnotatableComponent<IViewerProps, PdfDocument panelWidth = () => (this.Document.scrollHeight || this.Document.nativeHeight || 0); panelHeight = () => this._pageSizes.length && this._pageSizes[0] ? this._pageSizes[0].width : (this.Document.nativeWidth || 0); @computed get overlayLayer() { - return <div className="pdfViewer-overlay" id="overlay" style={{ transform: `scale(${this._zoomed})` }}> + return <div className={`pdfViewer-overlay${InkingControl.Instance.selectedTool !== InkTool.None ? "-inking" : ""}`} id="overlay" style={{ transform: `scale(${this._zoomed})` }}> <CollectionFreeFormView {...this.props} annotationsKey={this.annotationsKey} setPreviewCursor={this.setPreviewCursor} @@ -639,7 +641,7 @@ export class PDFViewer extends DocAnnotatableComponent<IViewerProps, PdfDocument isSelected={this.props.isSelected} isAnnotationOverlay={true} select={emptyFunction} - active={this.active} + active={this.annotationsActive} ContentScaling={this.contentZoom} whenActiveChanged={this.whenActiveChanged} removeDocument={this.removeDocument} @@ -652,7 +654,7 @@ export class PDFViewer extends DocAnnotatableComponent<IViewerProps, PdfDocument ContainingCollectionDoc={this.props.ContainingCollectionView?.props.Document} chromeCollapsed={true}> </CollectionFreeFormView> - </div> + </div>; } @computed get pdfViewerDiv() { return <div className={"pdfViewer-text" + ((!DocumentDecorations.Instance.Interacting && (this.props.isSelected() || this.props.isChildActive())) ? "-selected" : "")} ref={this._viewer} />; diff --git a/src/server/ApiManagers/GooglePhotosManager.ts b/src/server/ApiManagers/GooglePhotosManager.ts index 1138dede1..c7af69375 100644 --- a/src/server/ApiManagers/GooglePhotosManager.ts +++ b/src/server/ApiManagers/GooglePhotosManager.ts @@ -31,6 +31,9 @@ interface NewMediaItem { } const prefix = "google_photos_"; +/** + * This manager handles the creation of routes for google photos functionality. + */ export default class GooglePhotosManager extends ApiManager { protected initialize(register: Registration): void { diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 20f6cc8c7..052aa54a6 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -11,9 +11,10 @@ import { listSpec } from "../../../new_fields/Schema"; import { ScriptField, ComputedField } from "../../../new_fields/ScriptField"; import { Cast, PromiseValue } from "../../../new_fields/Types"; import { Utils } from "../../../Utils"; -import { InkingControl } from "../../../client/views/InkingControl"; -import { DragManager } from "../../../client/util/DragManager"; +import { ButtonBox } from "../../../client/views/nodes/ButtonBox"; import { nullAudio } from "../../../new_fields/URLField"; +import { DragManager } from "../../../client/util/DragManager"; +import { InkingControl } from "../../../client/views/InkingControl"; export class CurrentUserUtils { private static curr_id: string; diff --git a/src/server/index.ts b/src/server/index.ts index ad9c5886c..01ebf0ac1 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -43,7 +43,7 @@ async function preliminaryFunctions() { // divide the public directory based on type await Promise.all(Object.keys(Partitions).map(partition => DashUploadUtils.createIfNotExists(filesDirectory + partition))); // connect to the database - await log_execution("attempting to initialize database connection", "connected", Database.tryInitializeConnection); + await Database.tryInitializeConnection(); } /** |