aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes
diff options
context:
space:
mode:
authorFawn <fangrui_tong@brown.edu>2019-11-14 23:39:52 -0500
committerFawn <fangrui_tong@brown.edu>2019-11-14 23:39:52 -0500
commitf108bc9f9f1ff9cad2db4b794e3b433768c342a1 (patch)
treea2603e85291d118bbea3370ce823ab833e63281a /src/client/views/nodes
parente3f06e390f98cc5b97d63fc287daff994d5fef6f (diff)
parentc9fbdb9cfd5fcf35f7a599706cb41d4e7e586e19 (diff)
merged with master
Diffstat (limited to 'src/client/views/nodes')
-rw-r--r--src/client/views/nodes/AudioBox.scss28
-rw-r--r--src/client/views/nodes/AudioBox.tsx46
-rw-r--r--src/client/views/nodes/CollectionFreeFormDocumentView.tsx59
-rw-r--r--src/client/views/nodes/ContentFittingDocumentView.scss23
-rw-r--r--src/client/views/nodes/ContentFittingDocumentView.tsx118
-rw-r--r--src/client/views/nodes/DocuLinkBox.tsx10
-rw-r--r--src/client/views/nodes/DocumentView.scss139
-rw-r--r--src/client/views/nodes/DocumentView.tsx173
-rw-r--r--src/client/views/nodes/FontIconBox.tsx2
-rw-r--r--src/client/views/nodes/FormattedTextBox.scss12
-rw-r--r--src/client/views/nodes/FormattedTextBox.tsx159
-rw-r--r--src/client/views/nodes/FormattedTextBoxComment.scss1
-rw-r--r--src/client/views/nodes/FormattedTextBoxComment.tsx172
-rw-r--r--src/client/views/nodes/ImageBox.tsx2
-rw-r--r--src/client/views/nodes/PDFBox.scss3
-rw-r--r--src/client/views/nodes/PDFBox.tsx125
16 files changed, 655 insertions, 417 deletions
diff --git a/src/client/views/nodes/AudioBox.scss b/src/client/views/nodes/AudioBox.scss
index ccbf0d75f..3b19a6dba 100644
--- a/src/client/views/nodes/AudioBox.scss
+++ b/src/client/views/nodes/AudioBox.scss
@@ -44,22 +44,27 @@
width:100%;
height: 80%;
position: relative;
+ padding-right: 5px;
display: flex;
.audiobox-playhead {
position: relative;
margin-top: auto;
margin-bottom: auto;
width: 25px;
+ padding: 2px;
}
.audiobox-timeline {
position:relative;
height:100%;
width:100%;
+ background: white;
+ border: gray solid 1px;
+ border-radius: 3px;
.audiobox-current {
width: 1px;
height:100%;
background-color: red;
- position: absolute;;
+ position: absolute;
}
.audiobox-linker, .audiobox-linker-mini {
position:absolute;
@@ -72,10 +77,11 @@
background-color: transparent;
box-shadow: black 2px 2px 1px;
.docuLinkBox-cont {
- width:15px !important;
- height:15px !important;
- left: calc(100% - 15px) !important;
- top: calc(100% - 15px) !important;
+ position: relative !important;
+ height: 100% !important;
+ width: 100% !important;
+ left:unset !important;
+ top:unset !important;
}
}
.audiobox-linker-mini {
@@ -86,10 +92,11 @@
margin-left: -1;
margin-top: -2;
.docuLinkBox-cont {
- width:8px !important;
- height:8px !important;
- left: calc(100% - 8px) !important;
- top: calc(100% - 8px) !important;
+ position: relative !important;
+ height: 100% !important;
+ width: 100% !important;
+ left:unset !important;
+ top:unset !important;
}
}
.audiobox-linker:hover, .audiobox-linker-mini:hover {
@@ -98,7 +105,8 @@
.audiobox-marker-container, .audiobox-marker-minicontainer {
position:absolute;
width:10px;
- height:100%;
+ height:90%;
+ top:2.5%;
background:gray;
border-radius: 5px;
box-shadow: black 2px 2px 1px;
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index cc1c63d44..86bd23b67 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -12,12 +12,11 @@ import { RouteStore } from "../../../server/RouteStore";
import { runInAction, observable, reaction, IReactionDisposer, computed, action } from "mobx";
import { DateField } from "../../../new_fields/DateField";
import { SelectionManager } from "../../util/SelectionManager";
-import { Doc, DocListCast, WidthSym } from "../../../new_fields/Doc";
+import { Doc, DocListCast } from "../../../new_fields/Doc";
import { ContextMenuProps } from "../ContextMenuItem";
import { ContextMenu } from "../ContextMenu";
import { Id } from "../../../new_fields/FieldSymbols";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { DocumentManager } from "../../util/DocumentManager";
import { DocumentView } from "./DocumentView";
interface Window {
@@ -38,6 +37,7 @@ const AudioDocument = makeInterface(documentSchema, audioSchema);
@observer
export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocument>(AudioDocument) {
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(AudioBox, fieldKey); }
+ public static Enabled = false;
_linkPlayDisposer: IReactionDisposer | undefined;
_reactionDisposer: IReactionDisposer | undefined;
@@ -59,7 +59,7 @@ export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocume
scrollLinkId && DocListCast(this.dataDoc.links).filter(l => l[Id] === scrollLinkId).map(l => {
let la1 = l.anchor1 as Doc;
let linkTime = Doc.AreProtosEqual(la1, this.dataDoc) ? NumCast(l.anchor1Timecode) : NumCast(l.anchor2Timecode);
- setTimeout(() => this.playFrom(linkTime), 250);
+ setTimeout(() => { this.playFrom(linkTime); Doc.linkFollowHighlight(l); }, 250);
});
scrollLinkId && Doc.SetInPlace(this.layoutDoc, "scrollToLinkID", undefined, false);
}, { fireImmediately: true });
@@ -75,11 +75,9 @@ export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocume
}
timecodeChanged = () => {
- const extensionDoc = this.extensionDoc;
const htmlEle = this._ele;
- const start = extensionDoc && DateCast(extensionDoc.recordingStart);
- if (start && htmlEle) {
- htmlEle && htmlEle.duration && htmlEle.duration !== Infinity && runInAction(() => this.dataDoc.duration = htmlEle.duration);
+ if (this._audioState === "recorded" && htmlEle) {
+ htmlEle.duration && htmlEle.duration !== Infinity && runInAction(() => this.dataDoc.duration = htmlEle.duration);
DocListCast(this.dataDoc.links).map(l => {
let la1 = l.anchor1 as Doc;
let linkTime = NumCast(l.anchor2Timecode);
@@ -98,10 +96,10 @@ export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocume
pause = action(() => {
this._ele!.pause();
this._playing = false;
- })
+ });
playFrom = (seekTimeInSeconds: number) => {
- if (this._ele) {
+ if (this._ele && AudioBox.Enabled) {
if (seekTimeInSeconds < 0) {
this.pause();
} else if (seekTimeInSeconds <= this._ele.duration) {
@@ -195,7 +193,8 @@ export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocume
}
setRef = (e: HTMLAudioElement | null) => {
- e && e.addEventListener("timeupdate", action(() => this.Document.currentTimecode = e!.currentTime));
+ e && e.addEventListener("timeupdate", this.timecodeChanged);
+ e && e.addEventListener("ended", this.pause);
this._ele = e;
}
@@ -225,13 +224,13 @@ export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocume
</button> :
<div className="audiobox-controls">
<div className="audiobox-player" onClick={this.onPlay}>
- <FontAwesomeIcon className="audiobox-playhead" icon={this._playing ? "pause" : "play"} size={this.props.PanelHeight() < 36 ? "1x" : "2x"} />
- <div className="audiobox-playhead" onClick={this.onStop}><FontAwesomeIcon className="audiobox-playhead" icon="stop" size={this.props.PanelHeight() < 36 ? "1x" : "2x"} /></div>
+ <div className="audiobox-playhead"> <FontAwesomeIcon style={{ width: "100%" }} icon={this._playing ? "pause" : "play"} size={this.props.PanelHeight() < 36 ? "1x" : "2x"} /></div>
+ <div className="audiobox-playhead" onClick={this.onStop}><FontAwesomeIcon style={{ width: "100%" }} icon="stop" size={this.props.PanelHeight() < 36 ? "1x" : "2x"} /></div>
<div className="audiobox-timeline" onClick={e => e.stopPropagation()}
onPointerDown={e => {
if (e.button === 0 && !e.ctrlKey) {
let rect = (e.target as any).getBoundingClientRect();
- this._ele!.currentTime = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration);
+ this._ele!.currentTime = this.Document.currentTimecode = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration);
this.pause();
e.stopPropagation();
}
@@ -245,16 +244,17 @@ export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocume
la2 = l.anchor1 as Doc;
linkTime = NumCast(l.anchor1Timecode);
}
- return !linkTime ? (null) : <div className={this.props.PanelHeight() < 32 ? "audiobox-marker-minicontainer" : "audiobox-marker-container"} style={{ left: `${linkTime / NumCast(this.dataDoc.duration, 1) * 100}%` }}>
- <div className={this.props.PanelHeight() < 32 ? "audioBox-linker-mini" : "audioBox-linker"} key={"linker" + i}>
- <DocumentView {...this.props} Document={l} layoutKey={Doc.LinkEndpoint(l, la2)}
- parentActive={returnTrue} bringToFront={emptyFunction} zoomToScale={emptyFunction} getScale={returnOne}
- backgroundColor={returnTransparent} />
- </div>
- <div key={i} className="audiobox-marker" onPointerEnter={() => Doc.linkFollowHighlight(la1)}
- onPointerDown={e => { if (e.button === 0 && !e.ctrlKey) { this.playFrom(linkTime); e.stopPropagation(); } }}
- onClick={e => { if (e.button === 0 && !e.ctrlKey) { this.pause(); e.stopPropagation(); } }} />
- </div>;
+ return !linkTime ? (null) :
+ <div className={this.props.PanelHeight() < 32 ? "audiobox-marker-minicontainer" : "audiobox-marker-container"} key={l[Id]} style={{ left: `${linkTime / NumCast(this.dataDoc.duration, 1) * 100}%` }}>
+ <div className={this.props.PanelHeight() < 32 ? "audioBox-linker-mini" : "audioBox-linker"} key={"linker" + i}>
+ <DocumentView {...this.props} Document={l} layoutKey={Doc.LinkEndpoint(l, la2)}
+ parentActive={returnTrue} bringToFront={emptyFunction} zoomToScale={emptyFunction} getScale={returnOne}
+ backgroundColor={returnTransparent} />
+ </div>
+ <div key={i} className="audiobox-marker" onPointerEnter={() => Doc.linkFollowHighlight(la1)}
+ onPointerDown={e => { if (e.button === 0 && !e.ctrlKey) { this.playFrom(linkTime); e.stopPropagation(); } }}
+ onClick={e => { if (e.button === 0 && !e.ctrlKey) { this.pause(); e.stopPropagation(); } }} />
+ </div>;
})}
<div className="audiobox-current" style={{ left: `${NumCast(this.Document.currentTimecode) / NumCast(this.dataDoc.duration, 1) * 100}%` }} />
{this.audio}
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 58cb831f8..a035bdc3d 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -1,10 +1,9 @@
import { random } from "animejs";
-import { computed, IReactionDisposer, observable, reaction } from "mobx";
+import { computed, IReactionDisposer, observable, reaction, trace } from "mobx";
import { observer } from "mobx-react";
import { Doc, HeightSym, WidthSym } from "../../../new_fields/Doc";
import { listSpec } from "../../../new_fields/Schema";
import { Cast, NumCast, StrCast } from "../../../new_fields/Types";
-import { percent2frac } from "../../../Utils";
import { Transform } from "../../util/Transform";
import { DocComponent } from "../DocComponent";
import "./CollectionFreeFormDocumentView.scss";
@@ -71,12 +70,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
let ruleRounding = this.props.ruleProvider ? StrCast(this.props.ruleProvider["ruleRounding_" + this.Document.heading]) : undefined;
let ld = this.layoutDoc[StrCast(this.layoutDoc.layoutKey, "layout")] instanceof Doc ? this.layoutDoc[StrCast(this.layoutDoc.layoutKey, "layout")] as Doc : undefined;
let br = StrCast((ld || this.props.Document).borderRounding);
- br = !br && ruleRounding ? ruleRounding : br;
- if (br.endsWith("%")) {
- let nativeDim = Math.min(NumCast(this.layoutDoc.nativeWidth), NumCast(this.layoutDoc.nativeHeight));
- return percent2frac(br) * (nativeDim ? nativeDim : Math.min(this.props.PanelWidth(), this.props.PanelHeight()));
- }
- return undefined;
+ return !br && ruleRounding ? ruleRounding : br;
}
@computed
@@ -90,30 +84,29 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
finalPanelHeight = () => this.dataProvider ? this.dataProvider.height : this.panelHeight();
render() {
- return (
- <div className="collectionFreeFormDocumentView-container"
- style={{
- boxShadow:
- this.layoutDoc.opacity === 0 ? undefined : // if it's not visible, then no shadow
- this.layoutDoc.z ? `#9c9396 ${StrCast(this.layoutDoc.boxShadow, "10px 10px 0.9vw")}` : // if it's a floating doc, give it a big shadow
- this.clusterColor ? (`${this.clusterColor} ${StrCast(this.layoutDoc.boxShadow, `0vw 0vw ${(this.layoutDoc.isBackground ? 100 : 50) / this.props.ContentScaling()}px`)}`) : // if it's just in a cluster, make the shadown roughly match the cluster border extent
- this.layoutDoc.isBackground ? `1px 1px 1px ${this.clusterColor}` : // if it's a background & has a cluster color, make the shadow spread really big
- StrCast(this.layoutDoc.boxShadow, ""),
- borderRadius: this.borderRounding(),
- transform: this.transform,
- transition: this.Document.isAnimating !== undefined ? ".5s ease-in" : this.props.transition ? this.props.transition : this.dataProvider ? this.dataProvider.transition : StrCast(this.layoutDoc.transition),
- width: this.width,
- height: this.height,
- zIndex: this.Document.zIndex || 0,
- }} >
- <DocumentView {...this.props}
- ContentScaling={this.contentScaling}
- ScreenToLocalTransform={this.getTransform}
- backgroundColor={this.clusterColorFunc}
- PanelWidth={this.finalPanelWidth}
- PanelHeight={this.finalPanelHeight}
- />
- </div>
- );
+ trace();
+ return <div className="collectionFreeFormDocumentView-container"
+ style={{
+ boxShadow:
+ this.layoutDoc.opacity === 0 ? undefined : // if it's not visible, then no shadow
+ this.layoutDoc.z ? `#9c9396 ${StrCast(this.layoutDoc.boxShadow, "10px 10px 0.9vw")}` : // if it's a floating doc, give it a big shadow
+ this.clusterColor ? (`${this.clusterColor} ${StrCast(this.layoutDoc.boxShadow, `0vw 0vw ${(this.layoutDoc.isBackground ? 100 : 50) / this.props.ContentScaling()}px`)}`) : // if it's just in a cluster, make the shadown roughly match the cluster border extent
+ this.layoutDoc.isBackground ? `1px 1px 1px ${this.clusterColor}` : // if it's a background & has a cluster color, make the shadow spread really big
+ StrCast(this.layoutDoc.boxShadow, ""),
+ borderRadius: this.borderRounding(),
+ transform: this.transform,
+ transition: this.Document.isAnimating !== undefined ? ".5s ease-in" : this.props.transition ? this.props.transition : this.dataProvider ? this.dataProvider.transition : StrCast(this.layoutDoc.transition),
+ width: this.width,
+ height: this.height,
+ zIndex: this.Document.zIndex || 0,
+ }} >
+ <DocumentView {...this.props}
+ ContentScaling={this.contentScaling}
+ ScreenToLocalTransform={this.getTransform}
+ backgroundColor={this.clusterColorFunc}
+ PanelWidth={this.finalPanelWidth}
+ PanelHeight={this.finalPanelHeight}
+ />
+ </div>;
}
} \ No newline at end of file
diff --git a/src/client/views/nodes/ContentFittingDocumentView.scss b/src/client/views/nodes/ContentFittingDocumentView.scss
new file mode 100644
index 000000000..796e67269
--- /dev/null
+++ b/src/client/views/nodes/ContentFittingDocumentView.scss
@@ -0,0 +1,23 @@
+@import "../globalCssVariables";
+
+.contentFittingDocumentView {
+ position: relative;
+ height: auto !important;
+
+ .contentFittingDocumentView-previewDoc {
+ position: absolute;
+ display: inline;
+ }
+
+ .contentFittingDocumentView-input {
+ position: absolute;
+ max-width: 150px;
+ width: 100%;
+ bottom: 0px;
+ }
+
+ .documentView-node:first-child {
+ position: relative;
+ background: $light-color;
+ }
+} \ No newline at end of file
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
new file mode 100644
index 000000000..c8255b6fe
--- /dev/null
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -0,0 +1,118 @@
+import React = require("react");
+import { action, computed } from "mobx";
+import { observer } from "mobx-react";
+import "react-table/react-table.css";
+import { Doc } from "../../../new_fields/Doc";
+import { ComputedField, ScriptField } from "../../../new_fields/ScriptField";
+import { NumCast, StrCast } from "../../../new_fields/Types";
+import { emptyFunction, returnEmptyString, returnOne } from "../../../Utils";
+import { DragManager } from "../../util/DragManager";
+import { Transform } from "../../util/Transform";
+import { undoBatch } from "../../util/UndoManager";
+import '../DocumentDecorations.scss';
+import { DocumentView } from "../nodes/DocumentView";
+import "./ContentFittingDocumentView.scss";
+import { CollectionView } from "../collections/CollectionView";
+
+interface ContentFittingDocumentViewProps {
+ Document?: Doc;
+ DataDocument?: Doc;
+ childDocs?: Doc[];
+ renderDepth: number;
+ fitToBox?: boolean;
+ PanelWidth: () => number;
+ PanelHeight: () => number;
+ ruleProvider: Doc | undefined;
+ focus?: (doc: Doc) => void;
+ showOverlays?: (doc: Doc) => { title?: string, caption?: string };
+ CollectionView?: CollectionView;
+ CollectionDoc?: Doc;
+ onClick?: ScriptField;
+ getTransform: () => Transform;
+ addDocument: (document: Doc) => boolean;
+ moveDocument: (document: Doc, target: Doc, addDoc: ((doc: Doc) => boolean)) => boolean;
+ removeDocument: (document: Doc) => boolean;
+ active: () => boolean;
+ whenActiveChanged: (isActive: boolean) => void;
+ addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean;
+ pinToPres: (document: Doc) => void;
+ dontRegisterView?: boolean;
+ setPreviewScript: (script: string) => void;
+ previewScript?: string;
+}
+
+@observer
+export class ContentFittingDocumentView extends React.Component<ContentFittingDocumentViewProps>{
+ private get layoutDoc() { return this.props.Document && Doc.Layout(this.props.Document); }
+ private get nativeWidth() { return NumCast(this.layoutDoc!.nativeWidth, this.props.PanelWidth()); }
+ private get nativeHeight() { return NumCast(this.layoutDoc!.nativeHeight, this.props.PanelHeight()); }
+ private contentScaling = () => {
+ let wscale = this.props.PanelWidth() / (this.nativeWidth ? this.nativeWidth : this.props.PanelWidth());
+ if (wscale * this.nativeHeight > this.props.PanelHeight()) {
+ return this.props.PanelHeight() / (this.nativeHeight ? this.nativeHeight : this.props.PanelHeight());
+ }
+ return wscale;
+ }
+
+ @undoBatch
+ @action
+ drop = (e: Event, de: DragManager.DropEvent) => {
+ if (de.data instanceof DragManager.DocumentDragData) {
+ this.props.childDocs && this.props.childDocs.map(otherdoc => {
+ let target = Doc.GetProto(otherdoc);
+ target.layout = ComputedField.MakeFunction("this.image_data[0]");
+ target.layoutCustom = Doc.MakeDelegate(de.data.draggedDocuments[0]);
+ });
+ e.stopPropagation();
+ }
+ return true;
+ }
+ private PanelWidth = () => this.nativeWidth && (!this.props.Document || !this.props.Document.fitWidth) ? this.nativeWidth * this.contentScaling() : this.props.PanelWidth();
+ private PanelHeight = () => this.nativeHeight && (!this.props.Document || !this.props.Document.fitWidth) ? this.nativeHeight * this.contentScaling() : this.props.PanelHeight();
+ private getTransform = () => this.props.getTransform().translate(-this.centeringOffset, 0).scale(1 / this.contentScaling());
+ private get centeringOffset() { return this.nativeWidth && (!this.props.Document || !this.props.Document.fitWidth) ? (this.props.PanelWidth() - this.nativeWidth * this.contentScaling()) / 2 : 0; }
+
+ @computed get borderRounding() { return StrCast(this.props.Document!.borderRounding); }
+
+ render() {
+ return (<div className="contentFittingDocumentView" style={{ width: this.props.PanelWidth(), height: this.props.PanelHeight() }}>
+ {!this.props.Document || !this.props.PanelWidth ? (null) : (
+ <div className="contentFittingDocumentView-previewDoc"
+ style={{
+ transform: `translate(${this.centeringOffset}px, 0px)`,
+ borderRadius: this.borderRounding,
+ height: this.props.PanelHeight(),
+ width: this.props.PanelWidth()
+ }}>
+ <DocumentView {...this.props}
+ DataDoc={this.props.DataDocument}
+ Document={this.props.Document}
+ fitToBox={this.props.fitToBox}
+ onClick={this.props.onClick}
+ ruleProvider={this.props.ruleProvider}
+ showOverlays={this.props.showOverlays}
+ addDocument={this.props.addDocument}
+ removeDocument={this.props.removeDocument}
+ moveDocument={this.props.moveDocument}
+ whenActiveChanged={this.props.whenActiveChanged}
+ ContainingCollectionView={this.props.CollectionView}
+ ContainingCollectionDoc={this.props.CollectionDoc}
+ addDocTab={this.props.addDocTab}
+ pinToPres={this.props.pinToPres}
+ parentActive={this.props.active}
+ ScreenToLocalTransform={this.getTransform}
+ renderDepth={this.props.renderDepth + 1}
+ ContentScaling={this.contentScaling}
+ PanelWidth={this.PanelWidth}
+ PanelHeight={this.PanelHeight}
+ focus={this.props.focus || emptyFunction}
+ backgroundColor={returnEmptyString}
+ bringToFront={emptyFunction}
+ dontRegisterView={this.props.dontRegisterView}
+ zoomToScale={emptyFunction}
+ getScale={returnOne}
+ />
+ </div>)}
+ </div>);
+ }
+} \ No newline at end of file
diff --git a/src/client/views/nodes/DocuLinkBox.tsx b/src/client/views/nodes/DocuLinkBox.tsx
index f2ab6fcd8..d73407903 100644
--- a/src/client/views/nodes/DocuLinkBox.tsx
+++ b/src/client/views/nodes/DocuLinkBox.tsx
@@ -36,7 +36,7 @@ export class DocuLinkBox extends DocComponent<FieldViewProps, DocLinkSchema>(Doc
(e.button === 0 && !e.ctrlKey) && e.stopPropagation();
}
onPointerMove = action((e: PointerEvent) => {
- let cdiv = this._ref.current!.parentElement;
+ let cdiv = this._ref && this._ref.current && this._ref.current.parentElement;
if (cdiv && (Math.abs(e.clientX - this._downx) > 5 || Math.abs(e.clientY - this._downy) > 5)) {
let bounds = cdiv.getBoundingClientRect();
let pt = Utils.getNearestPointInPerimeter(bounds.left, bounds.top, bounds.width, bounds.height, e.clientX, e.clientY);
@@ -65,15 +65,19 @@ export class DocuLinkBox extends DocComponent<FieldViewProps, DocLinkSchema>(Doc
}
e.stopPropagation();
}
+
render() {
let anchorDoc = Cast(this.props.Document[this.props.fieldKey], Doc);
let hasAnchor = anchorDoc instanceof Doc && anchorDoc.type === DocumentType.PDFANNO;
let y = NumCast(this.props.Document[this.props.fieldKey + "_y"], 100);
let x = NumCast(this.props.Document[this.props.fieldKey + "_x"], 100);
let c = StrCast(this.props.Document.backgroundColor, "lightblue");
- return <div className="docuLinkBox-cont" onPointerDown={this.onPointerDown} onClick={this.onClick} title={StrCast((this.props.Document[this.props.fieldKey === "anchor1" ? "anchor2" : "anchor1"]! as Doc).title)}
+ let anchor = this.props.fieldKey === "anchor1" ? "anchor2" : "anchor1";
+ let timecode = this.props.Document[anchor + "Timecode"];
+ let targetTitle = StrCast((this.props.Document[anchor]! as Doc).title) + (timecode !== undefined ? ":" + timecode : "");
+ return <div className="docuLinkBox-cont" onPointerDown={this.onPointerDown} onClick={this.onClick} title={targetTitle}
ref={this._ref} style={{
- background: c, width: "25px", left: `calc(${x}% - 12.5px)`, top: `calc(${y}% - 12.5px)`,
+ background: c, left: `calc(${x}% - 12.5px)`, top: `calc(${y}% - 12.5px)`,
transform: `scale(${hasAnchor ? 0.333 : 1 / this.props.ContentScaling()})`
}} />;
}
diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss
index a0bf74990..65df86d27 100644
--- a/src/client/views/nodes/DocumentView.scss
+++ b/src/client/views/nodes/DocumentView.scss
@@ -1,89 +1,82 @@
@import "../globalCssVariables";
.documentView-node, .documentView-node-topmost {
- position: inherit;
- top: 0;
- left:0;
- border-radius: inherit;
- transition : outline .3s linear;
- cursor: grab;
-
- // background: $light-color; //overflow: hidden;
- transform-origin: left top;
+ position: inherit;
+ top: 0;
+ left:0;
+ border-radius: inherit;
+ transition : outline .3s linear;
+ cursor: grab;
+
+ // background: $light-color; //overflow: hidden;
+ transform-origin: left top;
- &.minimized {
- width: 30px;
- height: 30px;
- }
+ &.minimized {
+ width: 30px;
+ height: 30px;
+ }
- .top {
- height: 20px;
- cursor: pointer;
- }
+ .top {
+ height: 20px;
+ cursor: pointer;
+ }
- .content {
- padding: 20px 20px;
- height: auto;
- box-sizing: border-box;
- }
+ .content {
+ padding: 20px 20px;
+ height: auto;
+ box-sizing: border-box;
+ }
- .scroll-box {
- overflow-y: scroll;
- height: calc(100% - 20px);
- }
+ .scroll-box {
+ overflow-y: scroll;
+ height: calc(100% - 20px);
+ }
- .documentView-overlays {
- border-radius: inherit;
- position: absolute;
- display: inline-block;
- width: 100%;
- height: 100%;
- pointer-events: none;
- .documentView-textOverlay {
- border-radius: inherit;
- width: 100%;
- display: inline-block;
+ .documentView-docuLinkWrapper {
+ pointer-events: none;
position: absolute;
+ transform-origin: top left;
+ width: 100%;
+ height: 100%;
}
- }
-}
+ .documentView-styleWrapper {
+ position: absolute;
+ display: inline-block;
+ width:100%;
+ height:100%;
+ pointer-events: none;
-.documentView-styleWrapper {
- position: absolute;
- display: inline-block;
- width:100%;
- height:100%;
- pointer-events: none;
+ .documentView-styleContentWrapper {
+ width:100%;
+ display: inline-block;
+ position: absolute;
+ }
+ .documentView-titleWrapper {
+ overflow:hidden;
+ color: white;
+ transform-origin: top left;
+ top: 0;
+ height: 25;
+ background: rgba(0, 0, 0, .4);
+ padding: 4px;
+ text-align: center;
+ text-overflow: ellipsis;
+ white-space: pre;
+ }
- .documentView-styleContentWrapper {
- width:100%;
- display: inline-block;
- position: absolute;
- }
- .documentView-titleWrapper {
- overflow:hidden;
- color: white;
- transform-origin: top left;
- top: 0;
- height: 25;
- background: rgba(0, 0, 0, .4);
- padding: 4px;
- text-align: center;
- text-overflow: ellipsis;
- white-space: pre;
- }
+ .documentView-searchHighlight {
+ position: absolute;
+ background: yellow;
+ bottom: -20px;
+ border-radius: 5px;
+ transform-origin: bottom left;
+ }
- .documentView-searchHighlight {
- position: absolute;
- background: yellow;
- bottom: -20px;
- border-radius: 5px;
- transform-origin: bottom left;
+ .documentView-captionWrapper {
+ position: absolute;
+ bottom: 0;
+ transform-origin: bottom left;
+ }
}
- .documentView-captionWrapper {
- position: absolute;
- bottom: 0;
- transform-origin: bottom left;
- }
} \ No newline at end of file
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index ed93aa83e..7132f181e 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1,6 +1,6 @@
import { library } from '@fortawesome/fontawesome-svg-core';
import * as fa from '@fortawesome/free-solid-svg-icons';
-import { action, computed, runInAction } from "mobx";
+import { action, computed, runInAction, trace } from "mobx";
import { observer } from "mobx-react";
import * as rp from "request-promise";
import { Doc, DocListCast, DocListCastAsync, Opt } from "../../../new_fields/Doc";
@@ -41,30 +41,10 @@ import { DocumentContentsView } from "./DocumentContentsView";
import "./DocumentView.scss";
import { FormattedTextBox } from './FormattedTextBox';
import React = require("react");
-import { link } from 'fs';
-
-library.add(fa.faEdit);
-library.add(fa.faTrash);
-library.add(fa.faShare);
-library.add(fa.faDownload);
-library.add(fa.faExpandArrowsAlt);
-library.add(fa.faCompressArrowsAlt);
-library.add(fa.faLayerGroup);
-library.add(fa.faExternalLinkAlt);
-library.add(fa.faAlignCenter);
-library.add(fa.faCaretSquareRight);
-library.add(fa.faSquare);
-library.add(fa.faConciergeBell);
-library.add(fa.faWindowRestore);
-library.add(fa.faFolder);
-library.add(fa.faMapPin);
-library.add(fa.faLink);
-library.add(fa.faFingerprint);
-library.add(fa.faCrosshairs);
-library.add(fa.faDesktop);
-library.add(fa.faUnlock);
-library.add(fa.faLock);
-library.add(fa.faLaptopCode, fa.faMale, fa.faCopy, fa.faHandPointRight, fa.faCompass, fa.faSnowflake, fa.faMicrophone);
+
+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,
+ fa.faCopy, fa.faHandPointRight, fa.faCompass, fa.faSnowflake, fa.faMicrophone);
export interface DocumentViewProps {
ContainingCollectionView: Opt<CollectionView>;
@@ -94,6 +74,7 @@ export interface DocumentViewProps {
getScale: () => number;
animateBetweenIcon?: (maximize: boolean, target: number[]) => void;
ChromeHeight?: () => number;
+ dontRegisterView?: boolean;
layoutKey?: string;
}
@@ -118,7 +99,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
@action
componentDidMount() {
this._mainCont.current && (this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, { handlers: { drop: this.drop.bind(this) } }));
- DocumentManager.Instance.DocumentViews.push(this);
+
+ !this.props.dontRegisterView && DocumentManager.Instance.DocumentViews.push(this);
}
@action
@@ -131,7 +113,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
componentWillUnmount() {
this._dropDisposer && this._dropDisposer();
Doc.UnBrushDoc(this.props.Document);
- DocumentManager.Instance.DocumentViews.splice(DocumentManager.Instance.DocumentViews.indexOf(this), 1);
+ !this.props.dontRegisterView && DocumentManager.Instance.DocumentViews.splice(DocumentManager.Instance.DocumentViews.indexOf(this), 1);
}
startDragging(x: number, y: number, dropAction: dropActionType, applyAsTemplate?: boolean) {
@@ -156,7 +138,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
(Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD)) {
e.stopPropagation();
let preventDefault = true;
- if (this._doubleTap && this.props.renderDepth && (!this.onClickHandler || !this.onClickHandler.script)) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click
+ if (this._doubleTap && this.props.renderDepth && !this.onClickHandler?.script) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click
let fullScreenAlias = Doc.MakeAlias(this.props.Document);
if (StrCast(fullScreenAlias.layoutKey) !== "layoutCustom" && fullScreenAlias.layoutCustom !== undefined) {
fullScreenAlias.layoutKey = "layoutCustom";
@@ -370,9 +352,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
@undoBatch
@action
setCustomView = (custom: boolean): void => {
- if (this.props.ContainingCollectionView && this.props.ContainingCollectionView.props.DataDoc) {
- Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.ContainingCollectionView.props.DataDoc);
- } else { // bcz: not robust -- for now documents with string layout are native documents, and those with Doc layouts are customized
+ if (this.props.ContainingCollectionView?.props.DataDoc || this.props.ContainingCollectionView?.props.Document.isTemplateDoc) {
+ Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.ContainingCollectionView.props.Document);
+ } else {
custom ? DocumentView.makeCustomViewClicked(this.props.Document, this.props.DataDoc) : DocumentView.makeNativeViewClicked(this.props.Document);
}
}
@@ -390,6 +372,12 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
this.Document.lockedPosition = this.Document.lockedPosition ? undefined : true;
}
+ @undoBatch
+ @action
+ toggleLockTransform = (): void => {
+ this.Document.lockedTransform = this.Document.lockedTransform ? undefined : true;
+ }
+
listen = async () => {
Doc.GetProto(this.props.Document).transcript = await DictationManager.Controls.listen({
continuous: { indefinite: true },
@@ -462,6 +450,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
layoutItems.push({ description: `${this.Document.autoHeight ? "Variable Height" : "Auto Height"}`, event: () => this.layoutDoc.autoHeight = !this.layoutDoc.autoHeight, icon: "plus" });
layoutItems.push({ description: this.Document.ignoreAspect || !this.Document.nativeWidth || !this.Document.nativeHeight ? "Freeze" : "Unfreeze", event: this.freezeNativeDimensions, icon: "snowflake" });
layoutItems.push({ description: this.Document.lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.Document.lockedPosition) ? "unlock" : "lock" });
+ layoutItems.push({ description: this.Document.lockedTransform ? "Unlock Transform" : "Lock Transform", event: this.toggleLockTransform, icon: BoolCast(this.Document.lockedTransform) ? "unlock" : "lock" });
layoutItems.push({ description: "Center View", event: () => this.props.focus(this.props.Document, false), icon: "crosshairs" });
layoutItems.push({ description: "Zoom to Document", event: () => this.props.focus(this.props.Document, true), icon: "search" });
if (this.Document.type !== DocumentType.COL && this.Document.type !== DocumentType.TEMPLATE) {
@@ -597,26 +586,11 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
return anchor.type === DocumentType.AUDIO && NumCast(ept) ? false : true;
}
- render() {
- if (!this.props.Document) return (null);
- const animDims = this.Document.animateToDimensions ? Array.from(this.Document.animateToDimensions) : undefined;
- const ruleColor = this.props.ruleProvider ? StrCast(this.props.ruleProvider["ruleColor_" + this.Document.heading]) : undefined;
- 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) ?
- this.props.backgroundColor(this.Document) || StrCast(this.layoutDoc.backgroundColor) :
- ruleColor && !colorSet ? ruleColor : StrCast(this.layoutDoc.backgroundColor) || this.props.backgroundColor(this.Document);
-
- const nativeWidth = this.layoutDoc.fitWidth ? this.props.PanelWidth() - 2 : this.nativeWidth > 0 && !this.layoutDoc.ignoreAspect ? `${this.nativeWidth}px` : "100%";
- const nativeHeight = this.layoutDoc.fitWidth ? this.props.PanelHeight() - 2 : this.Document.ignoreAspect ? this.props.PanelHeight() / this.props.ContentScaling() : this.nativeHeight > 0 ? `${this.nativeHeight}px` : "100%";
+ @computed get innards() {
const showOverlays = this.props.showOverlays ? this.props.showOverlays(this.Document) : undefined;
const showTitle = showOverlays && "title" in showOverlays ? showOverlays.title : this.getLayoutPropStr("showTitle");
const showCaption = showOverlays && "caption" in showOverlays ? showOverlays.caption : this.getLayoutPropStr("showCaption");
const showTextTitle = showTitle && StrCast(this.Document.layout).indexOf("FormattedTextBox") !== -1 ? showTitle : undefined;
- const fullDegree = Doc.isBrushedHighlightedDegree(this.props.Document);
- const borderRounding = this.getLayoutPropStr("borderRounding") || ruleRounding;
- const localScale = this.props.ScreenToLocalTransform().Scale * fullDegree;
const searchHighlight = (!this.Document.searchFields ? (null) :
<div className="documentView-searchHighlight" style={{ width: `${100 * this.props.ContentScaling()}%`, transform: `scale(${1 / this.props.ContentScaling()})` }}>
{this.Document.searchFields}
@@ -631,10 +605,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
</div>);
const titleView = (!showTitle ? (null) :
<div className="documentView-titleWrapper" style={{
+ width: `${100 * this.props.ContentScaling()}%`, transform: `scale(${1 / this.props.ContentScaling()})`,
position: showTextTitle ? "relative" : "absolute",
pointerEvents: SelectionManager.GetIsDragging() ? "none" : "all",
- width: `${100 * this.props.ContentScaling()}%`,
- transform: `scale(${1 / this.props.ContentScaling()})`
}}>
<EditableView
contents={this.Document[showTitle]}
@@ -643,54 +616,72 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
SetValue={(value: string) => (Doc.GetProto(this.Document)[showTitle] = value) ? true : true}
/>
</div>);
+ return <>
+ {this.Document.links && DocListCast(this.Document.links).filter((d) => !DocListCast(this.layoutDoc.hiddenLinks).some(hidden => Doc.AreProtosEqual(hidden, d))).filter(this.isNonTemporalLink).map((d, i) =>
+ <div className="documentView-docuLinkWrapper" key={`${d[Id]}`} style={{ transform: `scale(${this.layoutDoc.fitWidth ? 1 : 1 / this.props.ContentScaling()})` }}>
+ <DocumentView {...this.props} Document={d} layoutKey={this.linkEndpoint(d)} backgroundColor={returnTransparent} removeDocument={undoBatch(doc => Doc.AddDocToList(this.layoutDoc, "hiddenLinks", doc))} />
+ </div>)}
+ {!showTitle && !showCaption ?
+ this.Document.searchFields ?
+ (<div className="documentView-searchWrapper">
+ {this.contents}
+ {searchHighlight}
+ </div>)
+ :
+ this.contents
+ :
+ <div className="documentView-styleWrapper" >
+ <div className="documentView-styleContentWrapper" style={{ height: showTextTitle ? "calc(100% - 29px)" : "100%", top: showTextTitle ? "29px" : undefined }}>
+ {this.contents}
+ </div>
+ {titleView}
+ {captionView}
+ {searchHighlight}
+ </div>
+ }
+ </>;
+ }
+ render() {
+ if (!this.props.Document) return (null);
+ trace();
+ const animDims = this.Document.animateToDimensions ? Array.from(this.Document.animateToDimensions) : undefined;
+ const ruleColor = this.props.ruleProvider ? StrCast(this.props.ruleProvider["ruleColor_" + this.Document.heading]) : undefined;
+ 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) ?
+ this.props.backgroundColor(this.Document) || StrCast(this.layoutDoc.backgroundColor) :
+ ruleColor && !colorSet ? ruleColor : StrCast(this.layoutDoc.backgroundColor) || this.props.backgroundColor(this.Document);
+
+ const nativeWidth = this.layoutDoc.fitWidth ? this.props.PanelWidth() - 2 : this.nativeWidth > 0 && !this.layoutDoc.ignoreAspect ? `${this.nativeWidth}px` : "100%";
+ const nativeHeight = this.layoutDoc.fitWidth ? this.props.PanelHeight() - 2 : this.Document.ignoreAspect ? this.props.PanelHeight() / this.props.ContentScaling() : this.nativeHeight > 0 ? `${this.nativeHeight}px` : "100%";
+ const fullDegree = Doc.isBrushedHighlightedDegree(this.props.Document);
+ const borderRounding = this.getLayoutPropStr("borderRounding") || ruleRounding;
+ const localScale = this.props.ScreenToLocalTransform().Scale * fullDegree;
+
let animheight = animDims ? animDims[1] : nativeHeight;
let animwidth = animDims ? animDims[0] : nativeWidth;
const highlightColors = ["transparent", "maroon", "maroon", "yellow", "magenta", "cyan", "orange"];
const highlightStyles = ["solid", "dashed", "solid", "solid", "solid", "solid", "solid", "solid"];
let highlighting = fullDegree && this.layoutDoc.type !== DocumentType.FONTICON && this.layoutDoc.viewType !== CollectionViewType.Linear;
- return (
- <div className={`documentView-node${this.topMost ? "-topmost" : ""}`}
- ref={this._mainCont}
- style={{
- transition: this.Document.isAnimating !== undefined ? ".5s linear" : StrCast(this.Document.transition),
- pointerEvents: this.Document.isBackground && !this.isSelected() ? "none" : "all",
- color: StrCast(this.Document.color),
- outline: highlighting && !borderRounding ? `${highlightColors[fullDegree]} ${highlightStyles[fullDegree]} ${localScale}px` : "solid 0px",
- border: highlighting && borderRounding ? `${highlightStyles[fullDegree]} ${highlightColors[fullDegree]} ${localScale}px` : undefined,
- 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
- }}
- onDrop={this.onDrop} onContextMenu={this.onContextMenu} onPointerDown={this.onPointerDown} onClick={this.onClick}
- onPointerEnter={() => Doc.BrushDoc(this.props.Document)} onPointerLeave={() => Doc.UnBrushDoc(this.props.Document)}
- >
- {this.Document.links && DocListCast(this.Document.links).filter(this.isNonTemporalLink).map((d, i) =>
- <div style={{ pointerEvents: "none", position: "absolute", transformOrigin: "top left", width: "100%", height: "100%", transform: `scale(${this.layoutDoc.fitWidth ? 1 : 1 / this.props.ContentScaling()})` }}>
- <DocumentView {...this.props} backgroundColor={returnTransparent} Document={d} layoutKey={this.linkEndpoint(d)} />
- </div>)}
- {!showTitle && !showCaption ?
- this.Document.searchFields ?
- (<div className="documentView-searchWrapper">
- {this.contents}
- {searchHighlight}
- </div>)
- :
- this.contents
- :
- <div className="documentView-styleWrapper" >
- <div className="documentView-styleContentWrapper" style={{ height: showTextTitle ? "calc(100% - 29px)" : "100%", top: showTextTitle ? "29px" : undefined }}>
- {this.contents}
- </div>
- {titleView}
- {captionView}
- {searchHighlight}
- </div>
- }
- </div>
- );
+ return <div className={`documentView-node${this.topMost ? "-topmost" : ""}`} ref={this._mainCont}
+ onDrop={this.onDrop} onContextMenu={this.onContextMenu} onPointerDown={this.onPointerDown} onClick={this.onClick}
+ onPointerEnter={() => Doc.BrushDoc(this.props.Document)} onPointerLeave={e => Doc.UnBrushDoc(this.props.Document)}
+ style={{
+ transition: this.Document.isAnimating !== undefined ? ".5s linear" : StrCast(this.Document.transition),
+ pointerEvents: this.Document.isBackground && !this.isSelected() ? "none" : "all",
+ color: StrCast(this.Document.color),
+ outline: highlighting && !borderRounding ? `${highlightColors[fullDegree]} ${highlightStyles[fullDegree]} ${localScale}px` : "solid 0px",
+ border: highlighting && borderRounding ? `${highlightStyles[fullDegree]} ${highlightColors[fullDegree]} ${localScale}px` : undefined,
+ 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}
+ </div>;
}
}
diff --git a/src/client/views/nodes/FontIconBox.tsx b/src/client/views/nodes/FontIconBox.tsx
index ae9273639..83ecc4657 100644
--- a/src/client/views/nodes/FontIconBox.tsx
+++ b/src/client/views/nodes/FontIconBox.tsx
@@ -25,7 +25,7 @@ export class FontIconBox extends DocComponent<FieldViewProps, FontIconDocument>(
this._backgroundReaction = reaction(() => this.props.Document.backgroundColor,
() => {
if (this._ref && this._ref.current) {
- let col = Utils.fromRGBAstr(getComputedStyle(this._ref.current).backgroundColor!);
+ let col = Utils.fromRGBAstr(getComputedStyle(this._ref.current).backgroundColor);
let colsum = (col.r + col.g + col.b);
if (colsum / col.a > 600 || col.a < 0.25) runInAction(() => this._foregroundColor = "black");
else if (colsum / col.a <= 600 || col.a >= .25) runInAction(() => this._foregroundColor = "white");
diff --git a/src/client/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss
index 7ae2767e7..b497b12b4 100644
--- a/src/client/views/nodes/FormattedTextBox.scss
+++ b/src/client/views/nodes/FormattedTextBox.scss
@@ -36,6 +36,18 @@
}
}
+.collectionfreeformview-container {
+ position: relative;
+}
+.formattedTextBox-outer {
+ position: relative;
+ overflow: auto;
+ display: inline-block;
+ padding: 10px 10px;
+ width: 100%;
+ height: 100%;
+}
+
.formattedTextBox-inner-rounded {
height: 70%;
width: 85%;
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 566b698bd..b7df3fb0e 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -18,7 +18,7 @@ import { RichTextField } from "../../../new_fields/RichTextField";
import { RichTextUtils } from '../../../new_fields/RichTextUtils';
import { createSchema, makeInterface } from "../../../new_fields/Schema";
import { Cast, DateCast, NumCast, StrCast } from "../../../new_fields/Types";
-import { numberRange, Utils, addStyleSheet, addStyleSheetRule, clearStyleSheetRules } from '../../../Utils';
+import { numberRange, Utils, addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, returnOne } from '../../../Utils';
import { GoogleApiClientUtils, Pulls, Pushes } from '../../apis/google_docs/GoogleApiClientUtils';
import { DocServer } from "../../DocServer";
import { Docs, DocUtils } from '../../documents/Documents';
@@ -33,7 +33,7 @@ import { SelectionManager } from "../../util/SelectionManager";
import { TooltipLinkingMenu } from "../../util/TooltipLinkingMenu";
import { TooltipTextMenu } from "../../util/TooltipTextMenu";
import { undoBatch, UndoManager } from "../../util/UndoManager";
-import { DocExtendableComponent } from "../DocComponent";
+import { DocAnnotatableComponent } from "../DocComponent";
import { DocumentButtonBar } from '../DocumentButtonBar';
import { DocumentDecorations } from '../DocumentDecorations';
import { InkingControl } from "../InkingControl";
@@ -46,6 +46,7 @@ import { ContextMenu } from '../ContextMenu';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { documentSchema } from '../../../new_fields/documentSchemas';
import { AudioBox } from './AudioBox';
+import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView';
library.add(faEdit);
library.add(faSmile, faTextHeight, faUpload);
@@ -70,7 +71,7 @@ const RichTextDocument = makeInterface(richTextSchema, documentSchema);
type PullHandler = (exportState: Opt<GoogleApiClientUtils.Docs.ImportResult>, dataDoc: Doc) => void;
@observer
-export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & FormattedTextBoxProps), RichTextDocument>(RichTextDocument) {
+export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & FormattedTextBoxProps), RichTextDocument>(RichTextDocument) {
public static LayoutString(fieldStr: string) { return FieldView.LayoutString(FormattedTextBox, fieldStr); }
public static blankState = () => EditorState.create(FormattedTextBox.Instance.config);
public static Instance: FormattedTextBox;
@@ -85,7 +86,6 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F
private _searchReactionDisposer?: Lambda;
private _scrollToRegionReactionDisposer: Opt<IReactionDisposer>;
private _reactionDisposer: Opt<IReactionDisposer>;
- private _textReactionDisposer: Opt<IReactionDisposer>;
private _heightReactionDisposer: Opt<IReactionDisposer>;
private _rulesReactionDisposer: Opt<IReactionDisposer>;
private _proxyReactionDisposer: Opt<IReactionDisposer>;
@@ -93,8 +93,8 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F
private _pushReactionDisposer: Opt<IReactionDisposer>;
private dropDisposer?: DragManager.DragDropDisposer;
- @observable private _fontSize = 13;
- @observable private _fontFamily = "Arial";
+ @observable private _ruleFontSize = 0;
+ @observable private _ruleFontFamily = "Arial";
@observable private _fontAlign = "";
@observable private _entered = false;
public static SelectOnLoad = "";
@@ -187,16 +187,12 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F
}
const state = this._editorView.state.apply(tx);
this._editorView.updateState(state);
- if (state.selection.empty && FormattedTextBox._toolTipTextMenu && tx.storedMarks) {
- FormattedTextBox._toolTipTextMenu.mark_key_pressed(tx.storedMarks);
- }
let tsel = this._editorView.state.selection.$from;
- tsel.marks().filter(m => m.type === this._editorView!.state.schema.marks.user_mark).map(m => AudioBox.SetScrubTime(Math.max(0, m.attrs.modified * 5000 - 5000)));
+ tsel.marks().filter(m => m.type === this._editorView!.state.schema.marks.user_mark).map(m => AudioBox.SetScrubTime(Math.max(0, m.attrs.modified * 5000 - 1000)));
this._applyingChange = true;
- this.extensionDoc && (this.extensionDoc.text = state.doc.textBetween(0, state.doc.content.size, "\n\n"));
this.extensionDoc && (this.extensionDoc.lastModified = new DateField(new Date(Date.now())));
- this.dataDoc[this.props.fieldKey] = new RichTextField(JSON.stringify(state.toJSON()));
+ this.dataDoc[this.props.fieldKey] = new RichTextField(JSON.stringify(state.toJSON()), state.doc.textBetween(0, state.doc.content.size, "\n\n"));
this._applyingChange = false;
this.updateTitle();
this.tryUpdateHeight();
@@ -253,7 +249,7 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F
// replace text contents whend dragging with Alt
if (draggedDoc && draggedDoc.type === DocumentType.TEXT && !Doc.AreProtosEqual(draggedDoc, this.props.Document) && de.mods === "AltKey") {
if (draggedDoc.data instanceof RichTextField) {
- Doc.GetProto(this.dataDoc)[this.props.fieldKey] = new RichTextField(draggedDoc.data.Data);
+ Doc.GetProto(this.dataDoc)[this.props.fieldKey] = new RichTextField(draggedDoc.data.Data, draggedDoc.data.Text);
e.stopPropagation();
}
// apply as template when dragging with Meta
@@ -293,6 +289,7 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F
if (context === node) return { from: offset, to: offset + node.nodeSize };
if (node.isBlock) {
+ // tslint:disable-next-line: prefer-for-of
for (let i = 0; i < (context.content as any).content.length; i++) {
let result = this.getNodeEndpoints((context.content as any).content[i], node);
if (result) {
@@ -363,6 +360,7 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F
specificContextMenu = (e: React.MouseEvent): void => {
let funcs: ContextMenuProps[] = [];
+ funcs.push({ description: "Toggle Sidebar", event: () => { e.stopPropagation(); this.props.Document.sidebarWidthPercent = StrCast(this.props.Document.sidebarWidthPercent, "0%") === "0%" ? "25%" : "0%"; }, icon: "expand-arrows-alt" });
funcs.push({ description: "Record Bullet", event: () => { e.stopPropagation(); this.recordBullet(); }, icon: "expand-arrows-alt" });
["My Text", "Text from Others", "Todo Items", "Important Items", "Ignore Items", "Disagree Items", "By Recent Minute", "By Recent Hour"].forEach(option =>
funcs.push({
@@ -513,17 +511,6 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F
() => this.tryUpdateHeight()
);
- this._textReactionDisposer = reaction(
- () => this.extensionDoc,
- () => {
- if (this.extensionDoc && (this.dataDoc.text || this.dataDoc.lastModified)) {
- this.extensionDoc.text = this.dataDoc.text;
- this.extensionDoc.lastModified = DateCast(this.dataDoc.lastModified)[Copy]();
- this.dataDoc.text = undefined;
- this.dataDoc.lastModified = undefined;
- }
- }, { fireImmediately: true });
-
this.setupEditor(this.config, this.dataDoc, this.props.fieldKey);
@@ -552,8 +539,8 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F
return undefined;
},
action((rules: any) => {
- this._fontFamily = rules ? rules.font : "Arial";
- this._fontSize = rules ? rules.size : NumCast(this.layoutDoc.fontSize, 13);
+ this._ruleFontFamily = rules ? rules.font : "Arial";
+ this._ruleFontSize = rules ? rules.size : 0;
rules && setTimeout(() => {
const view = this._editorView!;
if (this._proseRef) {
@@ -790,7 +777,9 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F
while (refNode && !("getBoundingClientRect" in refNode)) refNode = refNode.parentElement;
let r1 = refNode && refNode.getBoundingClientRect();
let r3 = self._ref.current!.getBoundingClientRect();
- r1 && (self._ref.current!.scrollTop += (r1.top - r3.top) * self.props.ScreenToLocalTransform().Scale);
+ if (r1.top < r3.top || r1.top > r3.bottom) {
+ r1 && (self._ref.current!.scrollTop += (r1.top - r3.top) * self.props.ScreenToLocalTransform().Scale);
+ }
return true;
},
dispatchTransaction: this.dispatchTransaction,
@@ -837,7 +826,6 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F
this._rulesReactionDisposer && this._rulesReactionDisposer();
this._reactionDisposer && this._reactionDisposer();
this._proxyReactionDisposer && this._proxyReactionDisposer();
- this._textReactionDisposer && this._textReactionDisposer();
this._pushReactionDisposer && this._pushReactionDisposer();
this._pullReactionDisposer && this._pullReactionDisposer();
this._heightReactionDisposer && this._heightReactionDisposer();
@@ -845,6 +833,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) {
@@ -859,7 +848,10 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F
}
onPointerUp = (e: React.PointerEvent): void => {
- if (!(e.nativeEvent as any).formattedHandled) { FormattedTextBoxComment.textBox = this; }
+ if (!(e.nativeEvent as any).formattedHandled) {
+ FormattedTextBoxComment.textBox = this;
+ FormattedTextBoxComment.update(this._editorView!);
+ }
(e.nativeEvent as any).formattedHandled = true;
if (e.buttons === 1 && this.props.isSelected() && !e.altKey) {
@@ -886,38 +878,38 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F
onClick = (e: React.MouseEvent): void => {
if ((e.nativeEvent as any).formattedHandled) { e.stopPropagation(); return; }
(e.nativeEvent as any).formattedHandled = true;
- if (e.button === 0 && ((!this.props.isSelected() && !e.ctrlKey) || (this.props.isSelected() && e.ctrlKey)) && !e.metaKey && e.target) {
- let href = (e.target as any).href;
- let location: string;
- if ((e.target as any).attributes.location) {
- location = (e.target as any).attributes.location.value;
- }
- let pcords = this._editorView!.posAtCoords({ left: e.clientX, top: e.clientY });
- let node = pcords && this._editorView!.state.doc.nodeAt(pcords.pos);
- if (node) {
- let link = node.marks.find(m => m.type === this._editorView!.state.schema.marks.link);
- if (link && !(link.attrs.docref && link.attrs.title)) { // bcz: getting hacky. this indicates that we clicked on a PDF excerpt quotation. In this case, we don't want to follow the link (we follow only the actual hyperlink for the quotation which is handled above).
- href = link && link.attrs.href;
- location = link && link.attrs.location;
- }
- }
- if (href) {
- if (href.indexOf(Utils.prepend("/doc/")) === 0) {
- let linkClicked = href.replace(Utils.prepend("/doc/"), "").split("?")[0];
- if (linkClicked) {
- DocServer.GetRefField(linkClicked).then(async linkDoc => {
- (linkDoc instanceof Doc) &&
- DocumentManager.Instance.FollowLink(linkDoc, this.props.Document, document => this.props.addDocTab(document, undefined, location ? location : "inTab"), false);
- });
- }
- } else {
- let webDoc = Docs.Create.WebDocument(href, { x: NumCast(this.layoutDoc.x, 0) + NumCast(this.layoutDoc.width, 0), y: NumCast(this.layoutDoc.y) });
- this.props.addDocument && this.props.addDocument(webDoc);
- }
- e.stopPropagation();
- e.preventDefault();
- }
- }
+ // if (e.button === 0 && ((!this.props.isSelected() && !e.ctrlKey) || (this.props.isSelected() && e.ctrlKey)) && !e.metaKey && e.target) {
+ // let href = (e.target as any).href;
+ // let location: string;
+ // if ((e.target as any).attributes.location) {
+ // location = (e.target as any).attributes.location.value;
+ // }
+ // let pcords = this._editorView!.posAtCoords({ left: e.clientX, top: e.clientY });
+ // let node = pcords && this._editorView!.state.doc.nodeAt(pcords.pos);
+ // if (node) {
+ // let link = node.marks.find(m => m.type === this._editorView!.state.schema.marks.link);
+ // if (link && !(link.attrs.docref && link.attrs.title)) { // bcz: getting hacky. this indicates that we clicked on a PDF excerpt quotation. In this case, we don't want to follow the link (we follow only the actual hyperlink for the quotation which is handled above).
+ // href = link && link.attrs.href;
+ // location = link && link.attrs.location;
+ // }
+ // }
+ // if (href) {
+ // if (href.indexOf(Utils.prepend("/doc/")) === 0) {
+ // let linkClicked = href.replace(Utils.prepend("/doc/"), "").split("?")[0];
+ // if (linkClicked) {
+ // DocServer.GetRefField(linkClicked).then(async linkDoc => {
+ // (linkDoc instanceof Doc) &&
+ // DocumentManager.Instance.FollowLink(linkDoc, this.props.Document, document => this.props.addDocTab(document, undefined, location ? location : "inTab"), false);
+ // });
+ // }
+ // } else {
+ // let webDoc = Docs.Create.WebDocument(href, { x: NumCast(this.layoutDoc.x, 0) + NumCast(this.layoutDoc.width, 0), y: NumCast(this.layoutDoc.y) });
+ // this.props.addDocument && this.props.addDocument(webDoc);
+ // }
+ // e.stopPropagation();
+ // e.preventDefault();
+ // }
+ // }
this.hitBulletTargets(e.clientX, e.clientY, e.nativeEvent.offsetX, e.shiftKey);
if (this._recording) setTimeout(() => { this.stopDictation(true); setTimeout(() => this.recordDictation(), 500); }, 500);
@@ -1020,12 +1012,17 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F
}
}
+ @computed get sidebarWidthPercent() { return StrCast(this.props.Document.sidebarWidth, "0%"); }
+ @computed get sidebarWidth() { return Number(this.sidebarWidthPercent.substring(0, this.sidebarWidthPercent.length - 1)) / 100 * this.props.PanelWidth(); }
+ @computed get annotationsKey() { return "annotations"; }
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 (
<div className={`formattedTextBox-cont`} ref={this._ref}
@@ -1034,9 +1031,9 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F
background: this.props.hideOnLeave ? "rgba(0,0,0 ,0.4)" : undefined,
opacity: this.props.hideOnLeave ? (this._entered ? 1 : 0.1) : 1,
color: this.props.color ? this.props.color : this.props.hideOnLeave ? "white" : "inherit",
- pointerEvents: interactive,
- fontSize: this._fontSize,
- fontFamily: this._fontFamily,
+ pointerEvents: interactive ? "none" : "all",
+ fontSize: this._ruleFontSize ? this._ruleFontSize : NumCast(this.layoutDoc.fontSize, 13),
+ fontFamily: this._ruleFontFamily ? this._ruleFontFamily : StrCast(this.layoutDoc.fontFamily, "Crimson Text"),
}}
onContextMenu={this.specificContextMenu}
onKeyDown={this.onKeyPress}
@@ -1050,8 +1047,32 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F
onPointerEnter={action(() => this._entered = true)}
onPointerLeave={action(() => this._entered = false)}
>
- <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 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" }}>
+ <CollectionFreeFormView {...this.props}
+ PanelHeight={() => this.props.PanelHeight()}
+ PanelWidth={() => this.sidebarWidth}
+ annotationsKey={this.annotationsKey}
+ isAnnotationOverlay={true}
+ focus={this.props.focus}
+ isSelected={this.props.isSelected}
+ select={emptyFunction}
+ active={this.active}
+ ContentScaling={returnOne}
+ whenActiveChanged={this.whenActiveChanged}
+ removeDocument={this.removeDocument}
+ moveDocument={this.moveDocument}
+ addDocument={this.addDocument}
+ CollectionView={undefined}
+ ScreenToLocalTransform={() => this.props.ScreenToLocalTransform().translate(-(this.props.PanelWidth() - this.sidebarWidth), 0)}
+ ruleProvider={undefined}
+ renderDepth={this.props.renderDepth + 1}
+ ContainingCollectionDoc={this.props.ContainingCollectionDoc}
+ chromeCollapsed={true}>
+ </CollectionFreeFormView>
+ </div>}
<div className="formattedTextBox-dictation"
onClick={e => {
this._recording ? this.stopDictation(true) : this.recordDictation();
@@ -1059,7 +1080,7 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F
e.stopPropagation();
}} >
<FontAwesomeIcon className="formattedTExtBox-audioFont"
- style={{ color: this._recording ? "red" : "blue", opacity: this._recording ? 1 : 0.2 }} icon={"file-audio"} size="sm" />
+ style={{ color: this._recording ? "red" : "blue", opacity: this._recording ? 1 : 0.2 }} icon={"microphone"} size="sm" />
</div>
</div>
);
diff --git a/src/client/views/nodes/FormattedTextBoxComment.scss b/src/client/views/nodes/FormattedTextBoxComment.scss
index 792cee182..2dd63ec21 100644
--- a/src/client/views/nodes/FormattedTextBoxComment.scss
+++ b/src/client/views/nodes/FormattedTextBoxComment.scss
@@ -5,7 +5,6 @@
background: white;
border: 1px solid silver;
border-radius: 2px;
- padding: 2px 10px;
margin-bottom: 7px;
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
diff --git a/src/client/views/nodes/FormattedTextBoxComment.tsx b/src/client/views/nodes/FormattedTextBoxComment.tsx
index bde278be3..c076fd34a 100644
--- a/src/client/views/nodes/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/FormattedTextBoxComment.tsx
@@ -1,13 +1,20 @@
-import { Plugin, EditorState } from "prosemirror-state";
-import './FormattedTextBoxComment.scss';
-import { ResolvedPos, Mark } from "prosemirror-model";
+import { Mark, ResolvedPos } from "prosemirror-model";
+import { EditorState, Plugin } from "prosemirror-state";
import { EditorView } from "prosemirror-view";
+import * as ReactDOM from 'react-dom';
import { Doc } from "../../../new_fields/Doc";
-import { schema } from "../../util/RichTextSchema";
+import { Cast, FieldValue, NumCast } from "../../../new_fields/Types";
+import { emptyFunction, returnEmptyString, returnFalse, Utils } from "../../../Utils";
import { DocServer } from "../../DocServer";
-import { Utils } from "../../../Utils";
-import { StrCast } from "../../../new_fields/Types";
+import { DocumentManager } from "../../util/DocumentManager";
+import { schema } from "../../util/RichTextSchema";
+import { Transform } from "../../util/Transform";
+import { ContentFittingDocumentView } from "./ContentFittingDocumentView";
import { FormattedTextBox } from "./FormattedTextBox";
+import './FormattedTextBoxComment.scss';
+import React = require("react");
+import { Docs } from "../../documents/Documents";
+import wiki from "wikijs";
export let formattedTextBoxCommentPlugin = new Plugin({
view(editorView) { return new FormattedTextBoxComment(editorView); }
@@ -46,32 +53,50 @@ export function findEndOfMark(rpos: ResolvedPos, view: EditorView, finder: (mark
export class FormattedTextBoxComment {
static tooltip: HTMLElement;
static tooltipText: HTMLElement;
+ static tooltipInput: HTMLInputElement;
static start: number;
static end: number;
static mark: Mark;
static opened: boolean;
static textBox: FormattedTextBox | undefined;
+ static linkDoc: Doc | undefined;
constructor(view: any) {
if (!FormattedTextBoxComment.tooltip) {
const root = document.getElementById("root");
- let input = document.createElement("input");
- input.type = "checkbox";
+ FormattedTextBoxComment.tooltipInput = document.createElement("input");
+ FormattedTextBoxComment.tooltipInput.type = "checkbox";
FormattedTextBoxComment.tooltip = document.createElement("div");
FormattedTextBoxComment.tooltipText = document.createElement("div");
+ FormattedTextBoxComment.tooltipText.style.width = "100%";
+ FormattedTextBoxComment.tooltipText.style.height = "100%";
+ FormattedTextBoxComment.tooltipText.style.textOverflow = "ellipsis";
FormattedTextBoxComment.tooltip.appendChild(FormattedTextBoxComment.tooltipText);
FormattedTextBoxComment.tooltip.className = "FormattedTextBox-tooltip";
FormattedTextBoxComment.tooltip.style.pointerEvents = "all";
- FormattedTextBoxComment.tooltip.appendChild(input);
+ FormattedTextBoxComment.tooltip.style.maxWidth = "350px";
+ FormattedTextBoxComment.tooltip.style.maxHeight = "250px";
+ FormattedTextBoxComment.tooltip.style.width = "100%";
+ FormattedTextBoxComment.tooltip.style.height = "100%";
+ FormattedTextBoxComment.tooltip.style.overflow = "hidden";
+ FormattedTextBoxComment.tooltip.style.display = "none";
+ FormattedTextBoxComment.tooltip.appendChild(FormattedTextBoxComment.tooltipInput);
FormattedTextBoxComment.tooltip.onpointerdown = (e: PointerEvent) => {
let keep = e.target && (e.target as any).type === "checkbox" ? true : false;
+ const textBox = FormattedTextBoxComment.textBox;
+ if (FormattedTextBoxComment.linkDoc && !keep && textBox) {
+ DocumentManager.Instance.FollowLink(FormattedTextBoxComment.linkDoc, textBox.props.Document,
+ (doc: Doc, maxLocation: string) => textBox.props.addDocTab(doc, undefined, e.ctrlKey ? "inTab" : "onRight"));
+ } else if (textBox && (FormattedTextBoxComment.tooltipText as any).href) {
+ textBox.props.addDocTab(Docs.Create.WebDocument((FormattedTextBoxComment.tooltipText as any).href, { title: (FormattedTextBoxComment.tooltipText as any).href, width: 200, height: 400 }), undefined, "onRight");
+ }
FormattedTextBoxComment.opened = keep || !FormattedTextBoxComment.opened;
- FormattedTextBoxComment.textBox && FormattedTextBoxComment.start !== undefined && FormattedTextBoxComment.textBox.setAnnotation(
+ textBox && FormattedTextBoxComment.start !== undefined && textBox.setAnnotation(
FormattedTextBoxComment.start, FormattedTextBoxComment.end, FormattedTextBoxComment.mark,
FormattedTextBoxComment.opened, keep);
+ e.stopPropagation();
};
root && root.appendChild(FormattedTextBoxComment.tooltip);
}
- this.update(view, undefined);
}
public static Hide() {
@@ -87,68 +112,115 @@ export class FormattedTextBoxComment {
FormattedTextBoxComment.tooltip && (FormattedTextBoxComment.tooltip.style.display = "");
}
- update(view: EditorView, lastState?: EditorState) {
+ static update(view: EditorView, lastState?: EditorState) {
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;
+ }
+ FormattedTextBoxComment.linkDoc = undefined;
- 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;
+ FormattedTextBoxComment.tooltipInput.style.display = "none";
+ FormattedTextBoxComment.tooltip.style.width = "";
+ FormattedTextBoxComment.tooltip.style.height = "";
+ (FormattedTextBoxComment.tooltipText as any).href = "";
+ FormattedTextBoxComment.tooltipText.style.whiteSpace = "";
+ FormattedTextBoxComment.tooltipText.style.overflow = "";
+ // 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 = "";
+ FormattedTextBoxComment.tooltipInput.style.display = "";
}
}
+ // 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.startsWith("https://en.wikipedia.org/wiki/")) {
+ wiki().page(mark.attrs.href.replace("https://en.wikipedia.org/wiki/", "")).then(page => page.summary().then(summary => FormattedTextBoxComment.tooltipText.textContent = summary.substring(0, 500)));
+ } else {
+ FormattedTextBoxComment.tooltipText.style.whiteSpace = "pre";
+ FormattedTextBoxComment.tooltipText.style.overflow = "hidden";
+ }
+ (FormattedTextBoxComment.tooltipText as any).href = 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) {
+ FormattedTextBoxComment.linkDoc = linkDoc;
+ const target = FieldValue(Doc.AreProtosEqual(FieldValue(Cast(linkDoc.anchor1, Doc)), textBox.props.Document) ? Cast(linkDoc.anchor2, Doc) : Cast(linkDoc.anchor1, Doc));
+ try {
+ ReactDOM.unmountComponentAtNode(FormattedTextBoxComment.tooltipText);
+ } catch (e) { }
+ if (target) {
+ ReactDOM.render(<ContentFittingDocumentView
+ fitToBox={true}
+ Document={target}
+ moveDocument={returnFalse}
+ getTransform={Transform.Identity}
+ active={returnFalse}
+ setPreviewScript={returnEmptyString}
+ addDocument={returnFalse}
+ removeDocument={returnFalse}
+ ruleProvider={undefined}
+ addDocTab={returnFalse}
+ pinToPres={returnFalse}
+ dontRegisterView={true}
+ renderDepth={1}
+ PanelWidth={() => Math.min(350, NumCast(target.width, 350))}
+ PanelHeight={() => Math.min(250, NumCast(target.height, 250))}
+ focus={emptyFunction}
+ whenActiveChanged={returnFalse}
+ />, FormattedTextBoxComment.tooltipText);
+ FormattedTextBoxComment.tooltip.style.width = NumCast(target.width) ? `${NumCast(target.width)}` : "100%";
+ FormattedTextBoxComment.tooltip.style.height = NumCast(target.height) ? `${NumCast(target.height)}` : "100%";
+ }
+ // let ext = (target && target.type !== DocumentType.PDFANNO && 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 = (target && target.type === DocumentType.PDFANNO ? "Quoted from " : "") + "=> " + (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);
}
- destroy() { FormattedTextBoxComment.tooltip.style.display = "none"; }
+ destroy() { }
}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 188440292..212c99f9d 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -323,7 +323,7 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
style={{ height: `calc(${.1 * nativeHeight / nativeWidth * 100}%)` }}
>
<FontAwesomeIcon className="imageBox-audioFont"
- style={{ color: [DocListCast(extensionDoc.audioAnnotations).length ? "blue" : "gray", "green", "red"][this._audioState] }} icon={faFileAudio} size="sm" />
+ style={{ color: [DocListCast(extensionDoc.audioAnnotations).length ? "blue" : "gray", "green", "red"][this._audioState] }} icon={!DocListCast(extensionDoc.audioAnnotations).length ? "microphone" : faFileAudio} size="sm" />
</div>
{this.considerGooglePhotosLink()}
<FaceRectangles document={extensionDoc} color={"#0000FF"} backgroundColor={"#0000FF"} />
diff --git a/src/client/views/nodes/PDFBox.scss b/src/client/views/nodes/PDFBox.scss
index 8bec4fbe3..2d92c9581 100644
--- a/src/client/views/nodes/PDFBox.scss
+++ b/src/client/views/nodes/PDFBox.scss
@@ -7,6 +7,7 @@
overflow: hidden;
position:absolute;
cursor:auto;
+ transform-origin: top left;
}
.pdfBox-title-outer {
@@ -47,6 +48,7 @@
}
.pdfViewer-text {
.textLayer {
+ will-change: transform;
span {
user-select: none;
}
@@ -58,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 396a5356a..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 } 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,35 +32,37 @@ export class PDFBox extends DocAnnotatableComponent<FieldViewProps, PdfDocument>
private _valueValue: string = "";
private _scriptValue: string = "";
private _searchString: string = "";
+ 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.RefObject<HTMLInputElement> = React.createRef();
- private _keyRef: React.RefObject<HTMLInputElement> = React.createRef();
- private _valueRef: React.RefObject<HTMLInputElement> = React.createRef();
- private _scriptRef: React.RefObject<HTMLInputElement> = React.createRef();
- private _selectReaction: IReactionDisposer | undefined;
+ private _searchRef = React.createRef<HTMLInputElement>();
+ private _keyRef = React.createRef<HTMLInputElement>();
+ private _valueRef = React.createRef<HTMLInputElement>();
+ private _scriptRef = React.createRef<HTMLInputElement>();
+ private _selectReactionDisposer: IReactionDisposer | undefined;
@observable private _searching: boolean = false;
@observable private _flyout: boolean = false;
@observable private _pdf: Opt<Pdfjs.PDFDocumentProxy>;
@observable private _pageControls = false;
+ constructor(props: any) {
+ super(props);
+ this._initialScale = this.props.ScreenToLocalTransform().Scale;
+ }
+
componentWillUnmount() {
- this._selectReaction && this._selectReaction();
+ this._selectReactionDisposer && this._selectReactionDisposer();
}
componentDidMount() {
const pdfUrl = Cast(this.dataDoc[this.props.fieldKey], PdfField);
if (pdfUrl instanceof PdfField) {
Pdfjs.getDocument(pdfUrl.url.pathname).promise.then(pdf => runInAction(() => this._pdf = pdf));
}
- this._selectReaction = reaction(() => this.props.isSelected(),
+ this._selectReactionDisposer = reaction(() => this.props.isSelected(),
() => {
- if (this.props.isSelected()) {
- document.removeEventListener("keydown", this.onKeyDown);
- document.addEventListener("keydown", this.onKeyDown);
- } else {
- document.removeEventListener("keydown", this.onKeyDown);
- }
+ document.removeEventListener("keydown", this.onKeyDown);
+ this.props.isSelected() && document.addEventListener("keydown", this.onKeyDown);
}, { fireImmediately: true });
}
@@ -75,8 +77,8 @@ export class PDFBox extends DocAnnotatableComponent<FieldViewProps, PdfDocument>
public prevAnnotation() { this._pdfViewer && this._pdfViewer.prevAnnotation(); }
public nextAnnotation() { this._pdfViewer && this._pdfViewer.nextAnnotation(); }
public backPage() { this._pdfViewer!.gotoPage((this.Document.curPage || 1) - 1); }
- public gotoPage = (p: number) => { this._pdfViewer!.gotoPage(p); };
public forwardPage() { this._pdfViewer!.gotoPage((this.Document.curPage || 1) + 1); }
+ public gotoPage = (p: number) => { this._pdfViewer!.gotoPage(p); };
@undoBatch
onKeyDown = action((e: KeyboardEvent) => {
@@ -86,12 +88,8 @@ export class PDFBox extends DocAnnotatableComponent<FieldViewProps, PdfDocument>
e.stopImmediatePropagation();
e.preventDefault();
}
- if (e.key === "PageDown" || e.key === "ArrowDown" || e.key === "ArrowRight") {
- this.forwardPage();
- }
- if (e.key === "PageUp" || e.key === "ArrowUp" || e.key === "ArrowLeft") {
- this.backPage();
- }
+ if (e.key === "PageDown" || e.key === "ArrowDown" || e.key === "ArrowRight") this.forwardPage();
+ if (e.key === "PageUp" || e.key === "ArrowUp" || e.key === "ArrowLeft") this.backPage();
});
@undoBatch
@@ -120,14 +118,12 @@ export class PDFBox extends DocAnnotatableComponent<FieldViewProps, PdfDocument>
settingsPanel() {
let pageBtns = <>
<button className="pdfBox-overlayButton-iconCont" key="back" title="Page Back"
- onPointerDown={(e) => e.stopPropagation()}
- onClick={() => this.backPage()}
+ onPointerDown={e => e.stopPropagation()} onClick={this.backPage}
style={{ left: 50, top: 5, height: "30px", position: "absolute", pointerEvents: "all" }}>
<FontAwesomeIcon style={{ color: "white" }} icon={"arrow-left"} size="sm" />
</button>
<button className="pdfBox-overlayButton-iconCont" key="fwd" title="Page Forward"
- onPointerDown={(e) => e.stopPropagation()}
- onClick={() => this.forwardPage()}
+ onPointerDown={e => e.stopPropagation()} onClick={this.forwardPage}
style={{ left: 80, top: 5, height: "30px", position: "absolute", pointerEvents: "all" }}>
<FontAwesomeIcon style={{ color: "white" }} icon={"arrow-right"} size="sm" />
</button>
@@ -137,15 +133,13 @@ export class PDFBox extends DocAnnotatableComponent<FieldViewProps, PdfDocument>
onPointerDown={e => e.stopPropagation()} style={{ display: this.active() ? "flex" : "none", position: "absolute", width: "100%", height: "100%", zIndex: 1, pointerEvents: "none" }}>
<div className="pdfBox-overlayCont" key="cont" onPointerDown={(e) => e.stopPropagation()} style={{ left: `${this._searching ? 0 : 100}%` }}>
<button className="pdfBox-overlayButton" title="Open Search Bar" />
- <input className="pdfBox-searchBar" placeholder="Search" ref={this._searchRef} onChange={this.searchStringChanged} onKeyDown={e => {
- e.keyCode === KeyCodes.ENTER && this.search(this._searchString, !e.shiftKey);
- }} />
+ <input className="pdfBox-searchBar" placeholder="Search" ref={this._searchRef} onChange={this.searchStringChanged} onKeyDown={e => e.keyCode === KeyCodes.ENTER && this.search(this._searchString, !e.shiftKey)} />
<button title="Search" onClick={e => this.search(this._searchString, !e.shiftKey)}>
<FontAwesomeIcon icon="search" size="sm" color="white" /></button>
- <button className="pdfBox-prevIcon " title="Previous Annotation" onClick={e => this.prevAnnotation()} >
+ <button className="pdfBox-prevIcon " title="Previous Annotation" onClick={this.prevAnnotation} >
<FontAwesomeIcon style={{ color: "white" }} icon={"arrow-up"} size="sm" />
</button>
- <button className="pdfBox-nextIcon" title="Next Annotation" onClick={e => this.nextAnnotation()} >
+ <button className="pdfBox-nextIcon" title="Next Annotation" onClick={this.nextAnnotation} >
<FontAwesomeIcon style={{ color: "white" }} icon={"arrow-down"} size="sm" />
</button>
</div>
@@ -200,40 +194,47 @@ export class PDFBox extends DocAnnotatableComponent<FieldViewProps, PdfDocument>
ContextMenu.Instance.addItem({ description: "Pdf Funcs...", subitems: funcs, icon: "asterisk" });
}
- _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....
- render() {
+
+ @computed get renderTitleBox() {
+ let classname = "pdfBox-cont" + (this.active() ? "-interactive" : "");
+ return <div className="pdfBox-title-outer" >
+ <div className={classname} >
+ <strong className="pdfBox-title" >{` ${this.props.Document.title}`}</strong>
+ </div>
+ </div>;
+ }
+
+ @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 <div className={classname} style={{
+ width: this.props.Document.fitWidth ? `${100 / this.props.ContentScaling()}%` : undefined,
+ height: this.props.Document.fitWidth ? `${100 / this.props.ContentScaling()}%` : undefined,
+ transform: `scale(${this.props.Document.fitWidth ? this.props.ContentScaling() : 1})`
+ }} onContextMenu={this.specificContextMenu} onPointerDown={e => {
+ 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();
+ }
+ }}>
+ <PDFViewer {...this.props} pdf={this._pdf!} url={pdfUrl!.url.pathname} active={this.props.active} loaded={this.loaded}
+ setPdfViewer={this.setPdfViewer} ContainingCollectionView={this.props.ContainingCollectionView}
+ renderDepth={this.props.renderDepth} PanelHeight={this.props.PanelHeight} PanelWidth={this.props.PanelWidth}
+ Document={this.props.Document} DataDoc={this.dataDoc} ContentScaling={this.props.ContentScaling}
+ addDocTab={this.props.addDocTab} focus={this.props.focus}
+ pinToPres={this.props.pinToPres} addDocument={this.addDocument}
+ ScreenToLocalTransform={this.props.ScreenToLocalTransform} select={this.props.select}
+ isSelected={this.props.isSelected} whenActiveChanged={this.whenActiveChanged}
+ fieldKey={this.props.fieldKey} startupLive={this._initialScale < 2.5 ? true : false} />
+ {this.settingsPanel()}
+ </div>;
+ }
+
+ 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) ?
- <div className="pdfBox-title-outer" >
- <div className={classname} >
- <strong className="pdfBox-title" >{` ${this.props.Document.title}`}</strong>
- </div>
- </div> :
- <div className={classname} style={{
- transformOrigin: "top left",
- width: this.props.Document.fitWidth ? `${100 / this.props.ContentScaling()}%` : undefined,
- height: this.props.Document.fitWidth ? `${100 / this.props.ContentScaling()}%` : undefined,
- transform: `scale(${this.props.Document.fitWidth ? this.props.ContentScaling() : 1})`
- }} onContextMenu={this.specificContextMenu} onPointerDown={(e: React.PointerEvent) => {
- 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();
- }
- }}>
- <PDFViewer {...this.props} pdf={this._pdf!} url={pdfUrl!.url.pathname} active={this.props.active} loaded={this.loaded}
- setPdfViewer={this.setPdfViewer} ContainingCollectionView={this.props.ContainingCollectionView}
- renderDepth={this.props.renderDepth} PanelHeight={this.props.PanelHeight} PanelWidth={this.props.PanelWidth}
- Document={this.props.Document} DataDoc={this.dataDoc} ContentScaling={this.props.ContentScaling}
- addDocTab={this.props.addDocTab} GoToPage={this.gotoPage} focus={this.props.focus}
- pinToPres={this.props.pinToPres} addDocument={this.addDocument}
- ScreenToLocalTransform={this.props.ScreenToLocalTransform} select={this.props.select}
- isSelected={this.props.isSelected} whenActiveChanged={this.whenActiveChanged}
- fieldKey={this.props.fieldKey} startupLive={this._initialScale < 2.5 ? true : false} />
- {this.settingsPanel()}
- </div>);
+ return !pdfUrl || !this._pdf || !this.extensionDoc || (!this._everActive && this.props.ScreenToLocalTransform().Scale > 2.5) ?
+ this.renderTitleBox : this.renderPdfView;
}
} \ No newline at end of file